[clang] [compiler-rt] [clang][CodeGen] Model vtable pointer as TBAA member of polymorphic types (PR #209053)
Gustas JanuĊĦonis via cfe-commits
cfe-commits at lists.llvm.org
Sun Jul 12 13:25:13 PDT 2026
https://github.com/LeGusto created https://github.com/llvm/llvm-project/pull/209053
A polymorphic class's TBAA type descriptor did not include its vtable pointer as a member. TypeSanitizer stamps a global's storage with the class's type descriptor at startup, thus when the constructor then stores the vtable pointer at offset 0, that store was incorrectly reported as a type-aliasing violation, since the pre-stamped descriptor had no member at offset 0.
Fixed by inserting a vtable pointer as a member in the descriptor at offset 0 for classes that own a vptr.
Fixes #208651
Assisted-by: Claude (Anthropic)
>From 5480dc7c6f20e3bae9e047edf5d4ba8f011186df Mon Sep 17 00:00:00 2001
From: LeGusto <janusonis.gustas at gmail.com>
Date: Sun, 12 Jul 2026 23:21:19 +0300
Subject: [PATCH] [clang][CodeGen] Model the vtable pointer as a TBAA member of
polymorphic types
A polymorphic class's TBAA type descriptor did not include its vtable pointer as a member. TypeSanitizer stamps a global's storage with the class's type descriptor at startup, thus when the constructor then stores the vtable pointer at offset 0, that store was incorrectly reported as a type-aliasing violation, since the pre-stamped descriptor had no member at offset 0.
Fixed by inserting a vtable pointer as a member in the descriptor at offset 0 for classes that own a vptr.
Fixes #208651
Assisted-by: Claude (Anthropic)
---
clang/lib/CodeGen/CodeGenTBAA.cpp | 9 +++++++++
clang/test/CodeGen/tbaa-vptr-member.cpp | 18 ++++++++++++++++++
compiler-rt/test/tysan/global-vtable-ptr.cpp | 19 +++++++++++++++++++
3 files changed, 46 insertions(+)
create mode 100644 clang/test/CodeGen/tbaa-vptr-member.cpp
create mode 100644 compiler-rt/test/tysan/global-vtable-ptr.cpp
diff --git a/clang/lib/CodeGen/CodeGenTBAA.cpp b/clang/lib/CodeGen/CodeGenTBAA.cpp
index 1854df7c7c0f1..8bc0c10b27f1d 100644
--- a/clang/lib/CodeGen/CodeGenTBAA.cpp
+++ b/clang/lib/CodeGen/CodeGenTBAA.cpp
@@ -531,6 +531,15 @@ llvm::MDNode *CodeGenTBAA::getBaseTypeInfoHelper(const Type *Ty) {
// incomplete view for NewStructPathTBAA.
if (CodeGenOpts.NewStructPathTBAA && CXXRD->getNumVBases() != 0)
return nullptr;
+ // A polymorphic class holds a vtable pointer at offset 0 that is not part
+ // of the declared field list.
+ if (Layout.hasOwnVFPtr()) {
+ uint64_t PtrSize =
+ Context.getTypeSizeInChars(Context.VoidPtrTy).getQuantity();
+ Fields.push_back(llvm::MDBuilder::TBAAStructField(
+ 0, PtrSize,
+ createScalarTypeNode("vtable pointer", getRoot(), PtrSize)));
+ }
for (const CXXBaseSpecifier &B : CXXRD->bases()) {
if (B.isVirtual())
continue;
diff --git a/clang/test/CodeGen/tbaa-vptr-member.cpp b/clang/test/CodeGen/tbaa-vptr-member.cpp
new file mode 100644
index 0000000000000..f9ce2f297f978
--- /dev/null
+++ b/clang/test/CodeGen/tbaa-vptr-member.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -O1 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s
+//
+// A polymorphic class stores a vtable pointer at offset 0. Its TBAA type
+// descriptor must model that pointer as a member, so a vtable-pointer store
+// reconciles with the object's own type instead of looking like an aliasing
+// violation.
+
+struct A {
+ virtual ~A();
+ char byte;
+};
+
+// Reading a member forces A's struct-path base-type node to be emitted.
+char getByte(A *a) { return a->byte; }
+
+// A's base-type node lists the vtable pointer at offset 0, then 'byte' at 8:
+// CHECK: = !{!"_ZTS1A", [[VPTR:![0-9]+]], i64 0, {{![0-9]+}}, i64 8}
+// CHECK: [[VPTR]] = !{!"vtable pointer", {{.*}}, i64 0}
diff --git a/compiler-rt/test/tysan/global-vtable-ptr.cpp b/compiler-rt/test/tysan/global-vtable-ptr.cpp
new file mode 100644
index 0000000000000..6133cf896e271
--- /dev/null
+++ b/compiler-rt/test/tysan/global-vtable-ptr.cpp
@@ -0,0 +1,19 @@
+// RUN: %clangxx_tysan -O0 %s -o %t && %run %t 2>&1 | FileCheck --implicit-check-not ERROR %s
+
+// https://github.com/llvm/llvm-project/issues/208651
+
+#include <stdio.h>
+
+class A {
+public:
+ virtual ~A() = default;
+ char byte;
+};
+
+static A a;
+
+int main() {
+ printf("done\n");
+ // CHECK: done
+ return 0;
+}
More information about the cfe-commits
mailing list