https://github.com/gbMattN updated https://github.com/llvm/llvm-project/pull/227782
>From 9e91aaca49966ffe7a8665c562e8356cf4fae9a7 Mon Sep 17 00:00:00 2001 From: gbMattN <[email protected]> Date: Wed, 30 Sep 2026 17:07:22 +0100 Subject: [PATCH 1/2] [TySan] Let TypeSanitizer know about conservative path TBAA data --- clang/lib/CodeGen/CodeGenTBAA.cpp | 3 ++ compiler-rt/lib/tysan/tysan.cpp | 22 +++++++++++++-- .../tysan/no-false-positive-issue208646.cpp | 11 ++++++++ .../tysan/no-false-positive-issue208647.cpp | 10 +++++++ .../tysan/no-false-positive-issue208655.cpp | 15 ++++++++++ .../tysan/no-false-positive-issue210643.cpp | 11 ++++++++ .../Instrumentation/TypeSanitizer.cpp | 28 ++++++++++++++++++- 7 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 compiler-rt/test/tysan/no-false-positive-issue208646.cpp create mode 100644 compiler-rt/test/tysan/no-false-positive-issue208647.cpp create mode 100644 compiler-rt/test/tysan/no-false-positive-issue208655.cpp create mode 100644 compiler-rt/test/tysan/no-false-positive-issue210643.cpp diff --git a/clang/lib/CodeGen/CodeGenTBAA.cpp b/clang/lib/CodeGen/CodeGenTBAA.cpp index 1854df7c7c0f1..acdf6abc59b61 100644 --- a/clang/lib/CodeGen/CodeGenTBAA.cpp +++ b/clang/lib/CodeGen/CodeGenTBAA.cpp @@ -367,6 +367,9 @@ llvm::MDNode *CodeGenTBAA::getTypeInfoHelper(const Type *Ty) { } // For now, handle any other kind of type conservatively. + if(Features.Sanitize.has(SanitizerKind::Type)){ + return createScalarTypeNode("TysanConservativeTBAA", getChar(), 1); + } return getChar(); } diff --git a/compiler-rt/lib/tysan/tysan.cpp b/compiler-rt/lib/tysan/tysan.cpp index 8b3b60dc4cf83..cc638cef5db83 100644 --- a/compiler-rt/lib/tysan/tysan.cpp +++ b/compiler-rt/lib/tysan/tysan.cpp @@ -128,12 +128,27 @@ static tysan_type_descriptor *getRootTD(tysan_type_descriptor *TD) { return RootTD; } +// Currently, Clang's TBAA system does not correctly describe every possible +// type. For unhandled types, it makes the most conservative choice, emitting +// omnipotent char. TySan needs to handle this seperately to a real omnipotent +// char otherwise the user may get false positives. When compiling with TySan +// enabled, clang will emit a special TBAA type to show that the conservative +// path has been taken. When the transformation pass finds this TBAA, it will +// set this global variable. This then allows quick comparison of TDs at +// runtime. +static tysan_type_descriptor *__tysan_conservative_tbaa_descriptor = nullptr; +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void +__tysan_set_conservative_tbaa_descriptor( + tysan_type_descriptor *conservativeTBAATD) { + __tysan_conservative_tbaa_descriptor = conservativeTBAATD; +} + // Walk up TDA to see if it reaches TDB. static bool walkAliasTree(tysan_type_descriptor *TDA, tysan_type_descriptor *TDB, uptr OffsetA, uptr OffsetB) { do { - if (TDA == TDB) + if (TDA == TDB || TDA == __tysan_conservative_tbaa_descriptor) return OffsetA == OffsetB; if (TDA->Tag == TYSAN_STRUCT_TD) { @@ -182,7 +197,6 @@ static bool isAliasingLegalUp(tysan_type_descriptor *TDA, OffsetA = TDA->Member.Offset; TDA = TDA->Member.Base; } - return walkAliasTree(TDA, TDB, OffsetA, OffsetB); } @@ -213,7 +227,9 @@ static bool isAliasingLegalWithOffset(tysan_type_descriptor *TDA, static bool isAliasingLegal(tysan_type_descriptor *TDA, tysan_type_descriptor *TDB, uptr OffsetB = 0) { - if (TDA == TDB || !TDB || !TDA) + if (TDA == TDB || !TDB || !TDA || + TDA == __tysan_conservative_tbaa_descriptor || + TDB == __tysan_conservative_tbaa_descriptor) return true; // Aliasing is legal is the two types have different root nodes. diff --git a/compiler-rt/test/tysan/no-false-positive-issue208646.cpp b/compiler-rt/test/tysan/no-false-positive-issue208646.cpp new file mode 100644 index 0000000000000..236b4a86d0a2b --- /dev/null +++ b/compiler-rt/test/tysan/no-false-positive-issue208646.cpp @@ -0,0 +1,11 @@ +// RUN: %clangxx_tysan -O0 %s -o %t && %run %t + +#include <string> +#include <optional> + +static std::optional<std::string> optional_var = std::nullopt; + +int main() { + optional_var = "this is a random long string (short one does not reproduce)"; + return 0; +} diff --git a/compiler-rt/test/tysan/no-false-positive-issue208647.cpp b/compiler-rt/test/tysan/no-false-positive-issue208647.cpp new file mode 100644 index 0000000000000..ef8b004496a16 --- /dev/null +++ b/compiler-rt/test/tysan/no-false-positive-issue208647.cpp @@ -0,0 +1,10 @@ +// RUN: %clangxx_tysan -O0 %s -o %t && %run %t + +#include <variant> + +int main() { + std::variant<int, double> v; + v = 1; + v = 3.5; + return 0; +} diff --git a/compiler-rt/test/tysan/no-false-positive-issue208655.cpp b/compiler-rt/test/tysan/no-false-positive-issue208655.cpp new file mode 100644 index 0000000000000..7518b244513cd --- /dev/null +++ b/compiler-rt/test/tysan/no-false-positive-issue208655.cpp @@ -0,0 +1,15 @@ +// RUN: %clangxx_tysan -O0 %s -o %t && %run %t + +#include <vector> + +struct Registry { + std::vector<int> arr; + char temp_byte; + bool bool_var = false; +}; + +int main() { + static Registry r; + r.arr.push_back(0); + r.bool_var = true; +} diff --git a/compiler-rt/test/tysan/no-false-positive-issue210643.cpp b/compiler-rt/test/tysan/no-false-positive-issue210643.cpp new file mode 100644 index 0000000000000..d667f75646cfd --- /dev/null +++ b/compiler-rt/test/tysan/no-false-positive-issue210643.cpp @@ -0,0 +1,11 @@ +// RUN: %clangxx_tysan -O0 %s -o %t && %run %t + +struct A { + int elems[3]; +}; + +A a; + +int main() { + a.elems[0] = 1; +} diff --git a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp index cea6e9e316c1d..0f66904b0e8c2 100644 --- a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp @@ -80,6 +80,7 @@ struct TypeSanitizer { TypeSanitizer(Module &M); bool sanitizeFunction(Function &F, const TargetLibraryInfo &TLI); void instrumentGlobals(Module &M); + void setConservativeTBAA(Module &M); private: typedef SmallDenseMap<const MDNode *, GlobalVariable *, 8> @@ -127,6 +128,9 @@ struct TypeSanitizer { FunctionCallee TysanInstrumentWithShadowUpdate; FunctionCallee TysanSetShadowType; + FunctionCallee TysanSetConservativeTBAADescriptor; + GlobalVariable *ConservativeTBAADescriptor; + /// Callback to set types for gloabls. Function *TysanGlobalsSetTypeFunction; }; @@ -134,7 +138,8 @@ struct TypeSanitizer { TypeSanitizer::TypeSanitizer(Module &M) : TargetTriple(M.getTargetTriple()), - AnonNameRegex("^_ZTS.*N[1-9][0-9]*_GLOBAL__N") { + AnonNameRegex("^_ZTS.*N[1-9][0-9]*_GLOBAL__N"), + ConservativeTBAADescriptor(nullptr) { const DataLayout &DL = M.getDataLayout(); IntptrTy = DL.getIntPtrType(M.getContext()); PtrShift = countr_zero(IntptrTy->getPrimitiveSizeInBits() / 8); @@ -186,6 +191,12 @@ void TypeSanitizer::initializeCallbacks(Module &M) { IRB.getPtrTy(), // Pointer to the new type descriptor U64Ty // Size of data we access in bytes ); + + TysanSetConservativeTBAADescriptor = M.getOrInsertFunction( + "__tysan_set_conservative_tbaa_descriptor", Attr, IRB.getVoidTy(), + IRB.getPtrTy() // Pointer to the type descriptor that describes the TBAA + // clang generates under the conservative TBAA path + ); } void TypeSanitizer::instrumentGlobals(Module &M) { @@ -234,6 +245,16 @@ void TypeSanitizer::instrumentGlobals(Module &M) { } } +void TypeSanitizer::setConservativeTBAA(Module &M) { + if (ConservativeTBAADescriptor) { + IRBuilder<> IRB(cast<Function>(TysanCtorFunction.getCallee()) + ->getEntryBlock() + .getTerminator()); + IRB.CreateCall(TysanSetConservativeTBAADescriptor, + {ConservativeTBAADescriptor}); + } +} + static const char LUT[] = "0123456789abcdef"; static std::string encodeName(StringRef Name) { @@ -391,6 +412,9 @@ bool TypeSanitizer::generateBaseTypeDescriptor( TD, EncodedName); M.insertGlobalVariable(TDGV); + if (Name == "TysanConservativeTBAA") { + ConservativeTBAADescriptor = TDGV; + } if (ShouldBeComdat) { if (TargetTriple.isOSBinFormatELF()) { Comdat *TDComdat = M.getOrInsertComdat(EncodedName); @@ -973,5 +997,7 @@ PreservedAnalyses TypeSanitizerPass::run(Module &M, } } + TySan.setConservativeTBAA(M); + return PreservedAnalyses::none(); } >From 65e40b0402ea00242eafc96de7aa933f599c5c7f Mon Sep 17 00:00:00 2001 From: gbMattN <[email protected]> Date: Wed, 30 Sep 2026 17:52:42 +0100 Subject: [PATCH 2/2] Format repro's copied from issues --- .../test/tysan/no-false-positive-issue208646.cpp | 4 ++-- .../test/tysan/no-false-positive-issue208655.cpp | 12 ++++++------ .../test/tysan/no-false-positive-issue210643.cpp | 6 ++---- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/compiler-rt/test/tysan/no-false-positive-issue208646.cpp b/compiler-rt/test/tysan/no-false-positive-issue208646.cpp index 236b4a86d0a2b..fc8a2da6e8b11 100644 --- a/compiler-rt/test/tysan/no-false-positive-issue208646.cpp +++ b/compiler-rt/test/tysan/no-false-positive-issue208646.cpp @@ -1,11 +1,11 @@ // RUN: %clangxx_tysan -O0 %s -o %t && %run %t -#include <string> #include <optional> +#include <string> static std::optional<std::string> optional_var = std::nullopt; -int main() { +int main() { optional_var = "this is a random long string (short one does not reproduce)"; return 0; } diff --git a/compiler-rt/test/tysan/no-false-positive-issue208655.cpp b/compiler-rt/test/tysan/no-false-positive-issue208655.cpp index 7518b244513cd..cba71c5b5be49 100644 --- a/compiler-rt/test/tysan/no-false-positive-issue208655.cpp +++ b/compiler-rt/test/tysan/no-false-positive-issue208655.cpp @@ -3,13 +3,13 @@ #include <vector> struct Registry { - std::vector<int> arr; - char temp_byte; - bool bool_var = false; + std::vector<int> arr; + char temp_byte; + bool bool_var = false; }; int main() { - static Registry r; - r.arr.push_back(0); - r.bool_var = true; + static Registry r; + r.arr.push_back(0); + r.bool_var = true; } diff --git a/compiler-rt/test/tysan/no-false-positive-issue210643.cpp b/compiler-rt/test/tysan/no-false-positive-issue210643.cpp index d667f75646cfd..4a74abd43d02d 100644 --- a/compiler-rt/test/tysan/no-false-positive-issue210643.cpp +++ b/compiler-rt/test/tysan/no-false-positive-issue210643.cpp @@ -1,11 +1,9 @@ // RUN: %clangxx_tysan -O0 %s -o %t && %run %t struct A { - int elems[3]; + int elems[3]; }; A a; -int main() { - a.elems[0] = 1; -} +int main() { a.elems[0] = 1; } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
