https://github.com/LeGusto updated https://github.com/llvm/llvm-project/pull/209053
From 5480dc7c6f20e3bae9e047edf5d4ba8f011186df Mon Sep 17 00:00:00 2001 From: LeGusto <[email protected]> Date: Sun, 12 Jul 2026 23:21:19 +0300 Subject: [PATCH 1/2] [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; +} From cdb981290f5a042da935160afc1053852346343a Mon Sep 17 00:00:00 2001 From: LeGusto <[email protected]> Date: Mon, 13 Jul 2026 11:40:49 +0300 Subject: [PATCH 2/2] Updated old tests to expect the vtable pointer at offset 0 --- .../CodeGenCXX/load-reference-metadata.cpp | 5 +++-- clang/unittests/CodeGen/TBAAMetadataTest.cpp | 22 +++++++++---------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/clang/test/CodeGenCXX/load-reference-metadata.cpp b/clang/test/CodeGenCXX/load-reference-metadata.cpp index d3e3dc1cbe534..c378efcd983cd 100644 --- a/clang/test/CodeGenCXX/load-reference-metadata.cpp +++ b/clang/test/CodeGenCXX/load-reference-metadata.cpp @@ -93,6 +93,7 @@ char* test_deref_only(B &s) { // CHECK: [[_ZTS1BPTR_TBAA24]] = !{[[META25:![0-9]+]], [[META25]], i64 0} // CHECK: [[META25]] = !{!"p1 _ZTS1B", [[META8]], i64 0} // CHECK: [[CHAR_TBAA26]] = !{[[META27:![0-9]+]], [[META4]], i64 16} -// CHECK: [[META27]] = !{!"_ZTS1B", [[META28:![0-9]+]], i64 8, [[META4]], i64 16} -// CHECK: [[META28]] = !{!"long long", [[META4]], i64 0} +// CHECK: [[META27]] = !{!"_ZTS1B", [[META28:![0-9]+]], i64 0, [[META29:![0-9]+]], i64 8, [[META4]], i64 16} +// CHECK: [[META28]] = !{!"vtable pointer", [[META5]], i64 0} +// CHECK: [[META29]] = !{!"long long", [[META4]], i64 0} //. diff --git a/clang/unittests/CodeGen/TBAAMetadataTest.cpp b/clang/unittests/CodeGen/TBAAMetadataTest.cpp index f05c9787c63ea..b9295f735a08a 100644 --- a/clang/unittests/CodeGen/TBAAMetadataTest.cpp +++ b/clang/unittests/CodeGen/TBAAMetadataTest.cpp @@ -1036,12 +1036,11 @@ TEST(TBAAMetadataTest, PolymorphicClass) { const BasicBlock *BB = Compiler.compile(); auto ClassBase = MMTuple( - MMString("_ZTS4Base"), - MMTuple( - MMString("int"), - OmnipotentCharCXX, - MConstInt(0)), - MConstInt(Compiler.PtrSize)); + MMString("_ZTS4Base"), + MMTuple(MMString("vtable pointer"), MMTuple(MMString("Simple C++ TBAA")), + MConstInt(0)), + MConstInt(0), MMTuple(MMString("int"), OmnipotentCharCXX, MConstInt(0)), + MConstInt(Compiler.PtrSize)); auto ClassDerived = MMTuple(MMString("_ZTS7Derived"), ClassBase, MConstInt(0), @@ -1118,12 +1117,11 @@ TEST(TBAAMetadataTest, VirtualBase) { MConstInt(0)); auto ClassDerived = MMTuple( - MMString("_ZTS7Derived"), - MMTuple( - MMString("short"), - OmnipotentCharCXX, - MConstInt(0)), - MConstInt(Compiler.PtrSize)); + MMString("_ZTS7Derived"), + MMTuple(MMString("vtable pointer"), MMTuple(MMString("Simple C++ TBAA")), + MConstInt(0)), + MConstInt(0), MMTuple(MMString("short"), OmnipotentCharCXX, MConstInt(0)), + MConstInt(Compiler.PtrSize)); const Instruction *I = match(BB, MInstruction(Instruction::Store, _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
