From 4c3ac21386c4032f10701f9fd9d2f37244514c99 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Fri, 22 Dec 2023 19:18:24 +0000 Subject: [PATCH 01/24] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20?= =?UTF-8?q?initial=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.4 --- llvm/include/llvm/Bitcode/LLVMBitCodes.h | 1 + llvm/include/llvm/IR/Attributes.td | 4 + .../Instrumentation/TypeSanitizer.h | 38 + llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp | 28 +- llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 2 + llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 2 + llvm/lib/CodeGen/ShrinkWrap.cpp | 1 + llvm/lib/Passes/PassBuilder.cpp | 1 + llvm/lib/Passes/PassRegistry.def | 2 + .../Transforms/Instrumentation/CMakeLists.txt | 1 + .../Instrumentation/TypeSanitizer.cpp | 873 ++++++++++++++++++ llvm/lib/Transforms/Utils/CodeExtractor.cpp | 1 + .../TypeSanitizer/access-with-offfset.ll | 71 ++ .../Instrumentation/TypeSanitizer/alloca.ll | 29 + .../Instrumentation/TypeSanitizer/anon.ll | 283 ++++++ .../TypeSanitizer/basic-nosan.ll | 93 ++ .../Instrumentation/TypeSanitizer/basic.ll | 214 +++++ .../Instrumentation/TypeSanitizer/byval.ll | 88 ++ .../Instrumentation/TypeSanitizer/globals.ll | 66 ++ .../TypeSanitizer/invalid-metadata.ll | 25 + .../TypeSanitizer/memintrinsics.ll | 77 ++ .../TypeSanitizer/nosanitize.ll | 39 + .../TypeSanitizer/sanitize-no-tbaa.ll | 180 ++++ .../TypeSanitizer/swifterror.ll | 24 + 24 files changed, 2137 insertions(+), 6 deletions(-) create mode 100644 llvm/include/llvm/Transforms/Instrumentation/TypeSanitizer.h create mode 100644 llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp create mode 100644 llvm/test/Instrumentation/TypeSanitizer/access-with-offfset.ll create mode 100644 llvm/test/Instrumentation/TypeSanitizer/alloca.ll create mode 100644 llvm/test/Instrumentation/TypeSanitizer/anon.ll create mode 100644 llvm/test/Instrumentation/TypeSanitizer/basic-nosan.ll create mode 100644 llvm/test/Instrumentation/TypeSanitizer/basic.ll create mode 100644 llvm/test/Instrumentation/TypeSanitizer/byval.ll create mode 100644 llvm/test/Instrumentation/TypeSanitizer/globals.ll create mode 100644 llvm/test/Instrumentation/TypeSanitizer/invalid-metadata.ll create mode 100644 llvm/test/Instrumentation/TypeSanitizer/memintrinsics.ll create mode 100644 llvm/test/Instrumentation/TypeSanitizer/nosanitize.ll create mode 100644 llvm/test/Instrumentation/TypeSanitizer/sanitize-no-tbaa.ll create mode 100644 llvm/test/Instrumentation/TypeSanitizer/swifterror.ll diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h index 41909a8fc1d59..21fd27d9838db 100644 --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -787,6 +787,7 @@ enum AttributeKindCodes { ATTR_KIND_CORO_ELIDE_SAFE = 98, ATTR_KIND_NO_EXT = 99, ATTR_KIND_NO_DIVERGENCE_SOURCE = 100, + ATTR_KIND_SANITIZE_TYPE = 101, }; enum ComdatSelectionKindCodes { diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td index 49f4527bde66e..179238bc73383 100644 --- a/llvm/include/llvm/IR/Attributes.td +++ b/llvm/include/llvm/IR/Attributes.td @@ -317,6 +317,9 @@ def SanitizeAddress : EnumAttr<"sanitize_address", IntersectPreserve, [FnAttr]>; /// ThreadSanitizer is on. def SanitizeThread : EnumAttr<"sanitize_thread", IntersectPreserve, [FnAttr]>; +/// TypeSanitizer is on. +def SanitizeType : EnumAttr<"sanitize_type", [FnAttr]>; + /// MemorySanitizer is on. def SanitizeMemory : EnumAttr<"sanitize_memory", IntersectPreserve, [FnAttr]>; @@ -425,6 +428,7 @@ class CompatRuleStrAttr : CompatRule { def : CompatRule<"isEqual">; def : CompatRule<"isEqual">; +def : CompatRule<"isEqual">; def : CompatRule<"isEqual">; def : CompatRule<"isEqual">; def : CompatRule<"isEqual">; diff --git a/llvm/include/llvm/Transforms/Instrumentation/TypeSanitizer.h b/llvm/include/llvm/Transforms/Instrumentation/TypeSanitizer.h new file mode 100644 index 0000000000000..a6cc56df35f14 --- /dev/null +++ b/llvm/include/llvm/Transforms/Instrumentation/TypeSanitizer.h @@ -0,0 +1,38 @@ +//===- Transforms/Instrumentation/TypeSanitizer.h - TySan Pass -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the type sanitizer pass. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_INSTRUMENTATION_TYPESANITIZER_H +#define LLVM_TRANSFORMS_INSTRUMENTATION_TYPESANITIZER_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { +class Function; +class FunctionPass; +class Module; + +/// A function pass for tysan instrumentation. +struct TypeSanitizerPass : public PassInfoMixin { + PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM); + static bool isRequired() { return true; } +}; + +/// A module pass for tysan instrumentation. +/// +/// Create ctor and init functions. +struct ModuleTypeSanitizerPass : public PassInfoMixin { + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); + static bool isRequired() { return true; } +}; + +} // namespace llvm +#endif /* LLVM_TRANSFORMS_INSTRUMENTATION_TYPESANITIZER_H */ diff --git a/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp b/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp index fd11c3abc379e..a499e16ff0097 100644 --- a/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp +++ b/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp @@ -372,11 +372,27 @@ static bool isStructPathTBAA(const MDNode *MD) { return isa(MD->getOperand(0)) && MD->getNumOperands() >= 3; } +// When using the TypeSanitizer, don't use TBAA information for alias analysis. +// This might cause us to remove memory accesses that we need to verify at +// runtime. +static bool usingSanitizeType(const Value *V) { + const Function *F; + + if (auto *I = dyn_cast(V)) + F = I->getParent()->getParent(); + else if (auto *A = dyn_cast(V)) + F = A->getParent(); + else + return false; + + return F->hasFnAttribute(Attribute::SanitizeType); +} + AliasResult TypeBasedAAResult::alias(const MemoryLocation &LocA, const MemoryLocation &LocB, AAQueryInfo &AAQI, const Instruction *) { - if (!EnableTBAA) - return AliasResult::MayAlias; + if (!EnableTBAA || usingSanitizeType(LocA.Ptr) || usingSanitizeType(LocB.Ptr)) + return AAResultBase::alias(LocA, LocB, AAQI, nullptr); if (Aliases(LocA.AATags.TBAA, LocB.AATags.TBAA)) return AliasResult::MayAlias; @@ -426,8 +442,8 @@ MemoryEffects TypeBasedAAResult::getMemoryEffects(const Function *F) { ModRefInfo TypeBasedAAResult::getModRefInfo(const CallBase *Call, const MemoryLocation &Loc, AAQueryInfo &AAQI) { - if (!EnableTBAA) - return ModRefInfo::ModRef; + if (!EnableTBAA || usingSanitizeType(Call)) + return AAResultBase::getModRefInfo(Call, Loc, AAQI); if (const MDNode *L = Loc.AATags.TBAA) if (const MDNode *M = Call->getMetadata(LLVMContext::MD_tbaa)) @@ -440,8 +456,8 @@ ModRefInfo TypeBasedAAResult::getModRefInfo(const CallBase *Call, ModRefInfo TypeBasedAAResult::getModRefInfo(const CallBase *Call1, const CallBase *Call2, AAQueryInfo &AAQI) { - if (!EnableTBAA) - return ModRefInfo::ModRef; + if (!EnableTBAA || usingSanitizeType(Call1)) + return AAResultBase::getModRefInfo(Call1, Call2, AAQI); if (const MDNode *M1 = Call1->getMetadata(LLVMContext::MD_tbaa)) if (const MDNode *M2 = Call2->getMetadata(LLVMContext::MD_tbaa)) diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index 85c6fadeda6cc..a01ecf0d56642 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -2192,6 +2192,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) { return Attribute::SanitizeHWAddress; case bitc::ATTR_KIND_SANITIZE_THREAD: return Attribute::SanitizeThread; + case bitc::ATTR_KIND_SANITIZE_TYPE: + return Attribute::SanitizeType; case bitc::ATTR_KIND_SANITIZE_MEMORY: return Attribute::SanitizeMemory; case bitc::ATTR_KIND_SANITIZE_NUMERICAL_STABILITY: diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index 0444cb9e1bce5..b4efd3928a2e6 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -851,6 +851,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) { return bitc::ATTR_KIND_SANITIZE_HWADDRESS; case Attribute::SanitizeThread: return bitc::ATTR_KIND_SANITIZE_THREAD; + case Attribute::SanitizeType: + return bitc::ATTR_KIND_SANITIZE_TYPE; case Attribute::SanitizeMemory: return bitc::ATTR_KIND_SANITIZE_MEMORY; case Attribute::SanitizeNumericalStability: diff --git a/llvm/lib/CodeGen/ShrinkWrap.cpp b/llvm/lib/CodeGen/ShrinkWrap.cpp index 2742437ceb589..5029f45def226 100644 --- a/llvm/lib/CodeGen/ShrinkWrap.cpp +++ b/llvm/lib/CodeGen/ShrinkWrap.cpp @@ -986,6 +986,7 @@ bool ShrinkWrap::isShrinkWrapEnabled(const MachineFunction &MF) { !(MF.getFunction().hasFnAttribute(Attribute::SanitizeAddress) || MF.getFunction().hasFnAttribute(Attribute::SanitizeThread) || MF.getFunction().hasFnAttribute(Attribute::SanitizeMemory) || + MF.getFunction().hasFnAttribute(Attribute::SanitizeType) || MF.getFunction().hasFnAttribute(Attribute::SanitizeHWAddress)); // If EnableShrinkWrap is set, it takes precedence on whatever the // target sets. The rational is that we assume we want to test diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index 260a34f2e060d..bf9fd30d905b9 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -225,6 +225,7 @@ #include "llvm/Transforms/Instrumentation/SanitizerBinaryMetadata.h" #include "llvm/Transforms/Instrumentation/SanitizerCoverage.h" #include "llvm/Transforms/Instrumentation/ThreadSanitizer.h" +#include "llvm/Transforms/Instrumentation/TypeSanitizer.h" #include "llvm/Transforms/ObjCARC.h" #include "llvm/Transforms/Scalar/ADCE.h" #include "llvm/Transforms/Scalar/AlignmentFromAssumptions.h" diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def index 2ddebb07017c2..1ba26a30b7605 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -155,6 +155,7 @@ MODULE_PASS("strip-nonlinetable-debuginfo", StripNonLineTableDebugInfoPass()) MODULE_PASS("trigger-crash-module", TriggerCrashModulePass()) MODULE_PASS("trigger-verifier-error", TriggerVerifierErrorPass()) MODULE_PASS("tsan-module", ModuleThreadSanitizerPass()) +MODULE_PASS("tysan-module", ModuleTypeSanitizerPass()) MODULE_PASS("verify", VerifierPass()) MODULE_PASS("view-callgraph", CallGraphViewerPass()) MODULE_PASS("wholeprogramdevirt", WholeProgramDevirtPass()) @@ -478,6 +479,7 @@ FUNCTION_PASS("transform-warning", WarnMissedTransformationsPass()) FUNCTION_PASS("trigger-crash-function", TriggerCrashFunctionPass()) FUNCTION_PASS("trigger-verifier-error", TriggerVerifierErrorPass()) FUNCTION_PASS("tsan", ThreadSanitizerPass()) +FUNCTION_PASS("tysan", TypeSanitizerPass()) FUNCTION_PASS("typepromotion", TypePromotionPass(TM)) FUNCTION_PASS("unify-loop-exits", UnifyLoopExitsPass()) FUNCTION_PASS("vector-combine", VectorCombinePass()) diff --git a/llvm/lib/Transforms/Instrumentation/CMakeLists.txt b/llvm/lib/Transforms/Instrumentation/CMakeLists.txt index 3e3c3eced4bb9..5abc7fc805283 100644 --- a/llvm/lib/Transforms/Instrumentation/CMakeLists.txt +++ b/llvm/lib/Transforms/Instrumentation/CMakeLists.txt @@ -24,6 +24,7 @@ add_llvm_component_library(LLVMInstrumentation SanitizerBinaryMetadata.cpp ValueProfileCollector.cpp ThreadSanitizer.cpp + TypeSanitizer.cpp HWAddressSanitizer.cpp RealtimeSanitizer.cpp diff --git a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp new file mode 100644 index 0000000000000..ed4aba4ad612d --- /dev/null +++ b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp @@ -0,0 +1,873 @@ +//===----- TypeSanitizer.cpp - type-based-aliasing-violation detector -----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of TypeSanitizer, a type-based-aliasing-violation +// detector. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Instrumentation/TypeSanitizer.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Analysis/MemoryLocation.h" +#include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/MDBuilder.h" +#include "llvm/IR/Metadata.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/ProfileData/InstrProf.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/MD5.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/Regex.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/Instrumentation.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include "llvm/Transforms/Utils/Local.h" +#include "llvm/Transforms/Utils/ModuleUtils.h" + +#include + +using namespace llvm; + +#define DEBUG_TYPE "tysan" + +static const char *const kTysanModuleCtorName = "tysan.module_ctor"; +static const char *const kTysanInitName = "__tysan_init"; +static const char *const kTysanCheckName = "__tysan_check"; +static const char *const kTysanGVNamePrefix = "__tysan_v1_"; + +static const char *const kTysanShadowMemoryAddress = + "__tysan_shadow_memory_address"; +static const char *const kTysanAppMemMask = "__tysan_app_memory_mask"; + +static cl::opt + ClWritesAlwaysSetType("tysan-writes-always-set-type", + cl::desc("Writes always set the type"), cl::Hidden, + cl::init(false)); + +STATISTIC(NumInstrumentedAccesses, "Number of instrumented accesses"); + +static Regex AnonNameRegex("^_ZTS.*N[1-9][0-9]*_GLOBAL__N"); + +namespace { + +/// TypeSanitizer: instrument the code in module to find type-based aliasing +/// violations. +struct TypeSanitizer { + TypeSanitizer(Module &M); + bool run(Function &F, const TargetLibraryInfo &TLI); + void instrumentGlobals(); + +private: + typedef SmallDenseMap + TypeDescriptorsMapTy; + typedef SmallDenseMap TypeNameMapTy; + + void initializeCallbacks(Module &M); + + Value *getShadowBase(Function &F); + Value *getAppMemMask(Function &F); + + bool instrumentWithShadowUpdate(IRBuilder<> &IRB, const MDNode *TBAAMD, + Value *Ptr, uint64_t AccessSize, bool IsRead, + bool IsWrite, Value *&ShadowBase, + Value *&AppMemMask, bool ForceSetType, + bool SanitizeFunction, + TypeDescriptorsMapTy &TypeDescriptors, + const DataLayout &DL); + bool instrumentMemoryAccess(Instruction *I, MemoryLocation &MLoc, + Value *&ShadowBase, Value *&AppMemMask, + bool SanitizeFunction, + TypeDescriptorsMapTy &TypeDescriptors, + const DataLayout &DL); + bool instrumentMemInst(Value *I, Value *&ShadowBase, Value *&AppMemMask, + const DataLayout &DL); + + std::string getAnonymousStructIdentifier(const MDNode *MD, + TypeNameMapTy &TypeNames); + bool generateTypeDescriptor(const MDNode *MD, + TypeDescriptorsMapTy &TypeDescriptors, + TypeNameMapTy &TypeNames, Module &M); + bool generateBaseTypeDescriptor(const MDNode *MD, + TypeDescriptorsMapTy &TypeDescriptors, + TypeNameMapTy &TypeNames, Module &M); + + const Triple TargetTriple; + Type *IntptrTy; + uint64_t PtrShift; + IntegerType *OrdTy; + + // Callbacks to run-time library are computed in doInitialization. + Function *TysanCheck; + Function *TysanCtorFunction; + Function *TysanGlobalsSetTypeFunction; +}; +} // namespace + +TypeSanitizer::TypeSanitizer(Module &M) + : TargetTriple(Triple(M.getTargetTriple())) { + const DataLayout &DL = M.getDataLayout(); + IntptrTy = DL.getIntPtrType(M.getContext()); + PtrShift = countr_zero(IntptrTy->getPrimitiveSizeInBits() / 8); + + TysanGlobalsSetTypeFunction = M.getFunction("__tysan_set_globals_types"); + initializeCallbacks(M); +} + +void TypeSanitizer::initializeCallbacks(Module &M) { + IRBuilder<> IRB(M.getContext()); + OrdTy = IRB.getInt32Ty(); + + AttributeList Attr; + Attr = Attr.addFnAttribute(M.getContext(), Attribute::NoUnwind); + // Initialize the callbacks. + TysanCheck = cast( + M.getOrInsertFunction(kTysanCheckName, Attr, IRB.getVoidTy(), + IRB.getPtrTy(), // Pointer to data to be read. + OrdTy, // Size of the data in bytes. + IRB.getPtrTy(), // Pointer to type descriptor. + OrdTy // Flags. + ) + .getCallee()); + + TysanCtorFunction = cast( + M.getOrInsertFunction(kTysanModuleCtorName, Attr, IRB.getVoidTy()) + .getCallee()); +} + +void TypeSanitizer::instrumentGlobals() { + Module &M = *TysanCtorFunction->getParent(); + initializeCallbacks(M); + TysanGlobalsSetTypeFunction = nullptr; + + NamedMDNode *Globals = M.getNamedMetadata("llvm.tysan.globals"); + if (!Globals) + return; + + const DataLayout &DL = M.getDataLayout(); + Value *ShadowBase = nullptr, *AppMemMask = nullptr; + TypeDescriptorsMapTy TypeDescriptors; + TypeNameMapTy TypeNames; + + for (const auto &GMD : Globals->operands()) { + auto *GV = mdconst::dyn_extract_or_null(GMD->getOperand(0)); + if (!GV) + continue; + const MDNode *TBAAMD = cast(GMD->getOperand(1)); + if (!generateBaseTypeDescriptor(TBAAMD, TypeDescriptors, TypeNames, M)) + continue; + + if (!TysanGlobalsSetTypeFunction) { + TysanGlobalsSetTypeFunction = Function::Create( + FunctionType::get(Type::getVoidTy(M.getContext()), false), + GlobalValue::InternalLinkage, "__tysan_set_globals_types", &M); + BasicBlock *BB = + BasicBlock::Create(M.getContext(), "", TysanGlobalsSetTypeFunction); + ReturnInst::Create(M.getContext(), BB); + } + + IRBuilder<> IRB( + TysanGlobalsSetTypeFunction->getEntryBlock().getTerminator()); + Type *AccessTy = GV->getValueType(); + assert(AccessTy->isSized()); + uint64_t AccessSize = DL.getTypeStoreSize(AccessTy); + instrumentWithShadowUpdate(IRB, TBAAMD, GV, AccessSize, false, false, + ShadowBase, AppMemMask, true, false, + TypeDescriptors, DL); + } + + if (TysanGlobalsSetTypeFunction) { + IRBuilder<> IRB(TysanCtorFunction->getEntryBlock().getTerminator()); + IRB.CreateCall(TysanGlobalsSetTypeFunction, {}); + } +} + +static void insertModuleCtor(Module &M) { + Function *TysanCtorFunction; + std::tie(TysanCtorFunction, std::ignore) = + createSanitizerCtorAndInitFunctions(M, kTysanModuleCtorName, + kTysanInitName, /*InitArgTypes=*/{}, + /*InitArgs=*/{}); + + TypeSanitizer TySan(M); + TySan.instrumentGlobals(); + appendToGlobalCtors(M, TysanCtorFunction, 0); +} + +static const char LUT[] = "0123456789abcdef"; + +static std::string encodeName(StringRef Name) { + size_t Length = Name.size(); + std::string Output = kTysanGVNamePrefix; + Output.reserve(Output.size() + 3 * Length); + for (size_t i = 0; i < Length; ++i) { + const unsigned char c = Name[i]; + if (isalnum((int)c)) { + Output.push_back(c); + continue; + } + + if (c == '_') { + Output.append("__"); + continue; + } + + Output.push_back('_'); + Output.push_back(LUT[c >> 4]); + Output.push_back(LUT[c & 15]); + } + + return Output; +} + +static bool isAnonymousNamespaceName(StringRef Name) { + // Types that are in an anonymous namespace are local to this module. + // FIXME: This should really be marked by the frontend in the metadata + // instead of having us guess this from the mangled name. Moreover, the regex + // here can pick up (unlikely) names in the non-reserved namespace (because + // it needs to search into the type to pick up cases where the type in the + // anonymous namespace is a template parameter, etc.). + return AnonNameRegex.match(Name); +} + +std::string +TypeSanitizer::getAnonymousStructIdentifier(const MDNode *MD, + TypeNameMapTy &TypeNames) { + MD5 Hash; + + for (int i = 1, e = MD->getNumOperands(); i < e; i += 2) { + const MDNode *MemberNode = dyn_cast(MD->getOperand(i)); + if (!MemberNode) + return ""; + + auto TNI = TypeNames.find(MemberNode); + std::string MemberName; + if (TNI != TypeNames.end()) { + MemberName = TNI->second; + } else { + if (MemberNode->getNumOperands() < 1) + return ""; + MDString *MemberNameNode = dyn_cast(MemberNode->getOperand(0)); + if (!MemberNameNode) + return ""; + MemberName = MemberNameNode->getString().str(); + if (MemberName.empty()) + MemberName = getAnonymousStructIdentifier(MemberNode, TypeNames); + if (MemberName.empty()) + return ""; + TypeNames[MemberNode] = MemberName; + } + + Hash.update(MemberName); + Hash.update("\0"); + + uint64_t Offset = + mdconst::extract(MD->getOperand(i + 1))->getZExtValue(); + Hash.update(utostr(Offset)); + Hash.update("\0"); + } + + MD5::MD5Result HashResult; + Hash.final(HashResult); + return "__anonymous_" + std::string(HashResult.digest().str()); +} + +bool TypeSanitizer::generateBaseTypeDescriptor( + const MDNode *MD, TypeDescriptorsMapTy &TypeDescriptors, + TypeNameMapTy &TypeNames, Module &M) { + if (MD->getNumOperands() < 1) + return false; + + MDString *NameNode = dyn_cast(MD->getOperand(0)); + if (!NameNode) + return false; + + std::string Name = NameNode->getString().str(); + if (Name.empty()) + Name = getAnonymousStructIdentifier(MD, TypeNames); + if (Name.empty()) + return false; + TypeNames[MD] = Name; + std::string EncodedName = encodeName(Name); + + GlobalVariable *GV = + dyn_cast_or_null(M.getNamedValue(EncodedName)); + if (GV) { + TypeDescriptors[MD] = GV; + return true; + } + + SmallVector> Members; + for (int i = 1, e = MD->getNumOperands(); i < e; i += 2) { + const MDNode *MemberNode = dyn_cast(MD->getOperand(i)); + if (!MemberNode) + return false; + + Constant *Member; + auto TDI = TypeDescriptors.find(MemberNode); + if (TDI != TypeDescriptors.end()) { + Member = TDI->second; + } else { + if (!generateBaseTypeDescriptor(MemberNode, TypeDescriptors, TypeNames, + M)) + return false; + + Member = TypeDescriptors[MemberNode]; + } + + uint64_t Offset = + mdconst::extract(MD->getOperand(i + 1))->getZExtValue(); + + Members.push_back(std::make_pair(Member, Offset)); + } + + // The descriptor for a scalar is: + // [2, member count, [type pointer, offset]..., name] + + LLVMContext &C = MD->getContext(); + Constant *NameData = ConstantDataArray::getString(C, NameNode->getString()); + SmallVector TDSubTys; + SmallVector TDSubData; + + TDSubTys.push_back(IntptrTy); + TDSubData.push_back(ConstantInt::get(IntptrTy, 2)); + + TDSubTys.push_back(IntptrTy); + TDSubData.push_back(ConstantInt::get(IntptrTy, Members.size())); + + bool ShouldBeComdat = !isAnonymousNamespaceName(NameNode->getString()); + for (auto &Member : Members) { + TDSubTys.push_back(Member.first->getType()); + TDSubData.push_back(Member.first); + + TDSubTys.push_back(IntptrTy); + TDSubData.push_back(ConstantInt::get(IntptrTy, Member.second)); + } + + TDSubTys.push_back(NameData->getType()); + TDSubData.push_back(NameData); + + StructType *TDTy = StructType::get(C, TDSubTys); + Constant *TD = ConstantStruct::get(TDTy, TDSubData); + + GlobalVariable *TDGV = + new GlobalVariable(TDTy, true, + !ShouldBeComdat ? GlobalValue::InternalLinkage + : GlobalValue::LinkOnceODRLinkage, + TD, EncodedName); + M.insertGlobalVariable(TDGV); + + if (ShouldBeComdat) { + if (TargetTriple.isOSBinFormatELF()) { + Comdat *TDComdat = M.getOrInsertComdat(EncodedName); + TDGV->setComdat(TDComdat); + } + appendToUsed(M, TDGV); + } + + TypeDescriptors[MD] = TDGV; + return true; +} + +bool TypeSanitizer::generateTypeDescriptor( + const MDNode *MD, TypeDescriptorsMapTy &TypeDescriptors, + TypeNameMapTy &TypeNames, Module &M) { + // Here we need to generate a type descriptor corresponding to this TBAA + // metadata node. Under the current scheme there are three kinds of TBAA + // metadata nodes: scalar nodes, struct nodes, and struct tag nodes. + + if (MD->getNumOperands() < 3) + return false; + + const MDNode *BaseNode = dyn_cast(MD->getOperand(0)); + if (!BaseNode) + return false; + + // This is a struct tag (element-access) node. + + const MDNode *AccessNode = dyn_cast(MD->getOperand(1)); + if (!AccessNode) + return false; + + Constant *Base; + auto TDI = TypeDescriptors.find(BaseNode); + if (TDI != TypeDescriptors.end()) { + Base = TDI->second; + } else { + if (!generateBaseTypeDescriptor(BaseNode, TypeDescriptors, TypeNames, M)) + return false; + + Base = TypeDescriptors[BaseNode]; + } + + Constant *Access; + TDI = TypeDescriptors.find(AccessNode); + if (TDI != TypeDescriptors.end()) { + Access = TDI->second; + } else { + if (!generateBaseTypeDescriptor(AccessNode, TypeDescriptors, TypeNames, M)) + return false; + + Access = TypeDescriptors[AccessNode]; + } + + uint64_t Offset = + mdconst::extract(MD->getOperand(2))->getZExtValue(); + std::string EncodedName = + std::string(Base->getName()) + "_o_" + utostr(Offset); + + GlobalVariable *GV = + dyn_cast_or_null(M.getNamedValue(EncodedName)); + if (GV) { + TypeDescriptors[MD] = GV; + return true; + } + + // The descriptor for a scalar is: + // [1, base-type pointer, access-type pointer, offset] + + StructType *TDTy = + StructType::get(IntptrTy, Base->getType(), Access->getType(), IntptrTy); + Constant *TD = + ConstantStruct::get(TDTy, ConstantInt::get(IntptrTy, 1), Base, Access, + ConstantInt::get(IntptrTy, Offset)); + + bool ShouldBeComdat = cast(Base)->getLinkage() == + GlobalValue::LinkOnceODRLinkage; + + GlobalVariable *TDGV = + new GlobalVariable(TDTy, true, + !ShouldBeComdat ? GlobalValue::InternalLinkage + : GlobalValue::LinkOnceODRLinkage, + TD, EncodedName); + M.insertGlobalVariable(TDGV); + + if (ShouldBeComdat) { + if (TargetTriple.isOSBinFormatELF()) { + Comdat *TDComdat = M.getOrInsertComdat(EncodedName); + TDGV->setComdat(TDComdat); + } + appendToUsed(M, TDGV); + } + + TypeDescriptors[MD] = TDGV; + return true; +} + +Value *TypeSanitizer::getShadowBase(Function &F) { + IRBuilder<> IRB(&F.front().front()); + Constant *GlobalShadowAddress = + F.getParent()->getOrInsertGlobal(kTysanShadowMemoryAddress, IntptrTy); + return IRB.CreateLoad(IntptrTy, GlobalShadowAddress, "shadow.base"); +} + +Value *TypeSanitizer::getAppMemMask(Function &F) { + IRBuilder<> IRB(&F.front().front()); + Value *GlobalAppMemMask = + F.getParent()->getOrInsertGlobal(kTysanAppMemMask, IntptrTy); + return IRB.CreateLoad(IntptrTy, GlobalAppMemMask, "app.mem.mask"); +} + +bool TypeSanitizer::run(Function &F, const TargetLibraryInfo &TLI) { + // This is required to prevent instrumenting call to __tysan_init from within + // the module constructor. + if (&F == TysanCtorFunction || &F == TysanGlobalsSetTypeFunction) + return false; + initializeCallbacks(*F.getParent()); + + SmallVector> MemoryAccesses; + SmallSetVector TBAAMetadata; + SmallVector MemTypeResetInsts; + + bool Res = false; + bool SanitizeFunction = F.hasFnAttribute(Attribute::SanitizeType); + const DataLayout &DL = F.getParent()->getDataLayout(); + // Traverse all instructions, collect loads/stores/returns, check for calls. + for (auto &BB : F) { + for (auto &Inst : BB) { + // Skip memory accesses inserted by another instrumentation. + if (Inst.getMetadata(LLVMContext::MD_nosanitize)) + continue; + + if (isa(Inst) || isa(Inst) || + isa(Inst) || isa(Inst)) { + MemoryLocation MLoc = MemoryLocation::get(&Inst); + + // Swift errors are special (we can't introduce extra uses on them). + if (MLoc.Ptr->isSwiftError()) + continue; + + // Skip non-address-space-0 pointers; we don't know how to handle them. + Type *PtrTy = cast(MLoc.Ptr->getType()); + if (PtrTy->getPointerAddressSpace() != 0) + continue; + + if (MLoc.AATags.TBAA) + TBAAMetadata.insert(MLoc.AATags.TBAA); + MemoryAccesses.push_back(std::make_pair(&Inst, MLoc)); + } else if (isa(Inst) || isa(Inst)) { + if (CallInst *CI = dyn_cast(&Inst)) + maybeMarkSanitizerLibraryCallNoBuiltin(CI, &TLI); + + if (isa(Inst)) { + MemTypeResetInsts.push_back(&Inst); + } else if (auto *II = dyn_cast(&Inst)) { + if (II->getIntrinsicID() == Intrinsic::lifetime_start || + II->getIntrinsicID() == Intrinsic::lifetime_end) + MemTypeResetInsts.push_back(&Inst); + } + } else if (isa(Inst)) { + MemTypeResetInsts.push_back(&Inst); + } + } + } + + // byval arguments also need their types reset (they're new stack memory, + // just like allocas). + for (auto &A : F.args()) + if (A.hasByValAttr()) + MemTypeResetInsts.push_back(&A); + + // We have collected all loads and stores, and know for what TBAA nodes we + // need to generate type descriptors. + + Module &M = *F.getParent(); + TypeDescriptorsMapTy TypeDescriptors; + TypeNameMapTy TypeNames; + for (const MDNode *MD : TBAAMetadata) { + if (TypeDescriptors.count(MD)) + continue; + + if (!generateTypeDescriptor(MD, TypeDescriptors, TypeNames, M)) + return Res; // Giving up. + + Res = true; + } + + Value *ShadowBase = nullptr, *AppMemMask = nullptr; + for (auto &MA : MemoryAccesses) + Res |= instrumentMemoryAccess(MA.first, MA.second, ShadowBase, AppMemMask, + SanitizeFunction, TypeDescriptors, DL); + + for (auto Inst : MemTypeResetInsts) + Res |= instrumentMemInst(Inst, ShadowBase, AppMemMask, DL); + + return Res; +} + +static Value *ConvertToShadowDataInt(IRBuilder<> &IRB, Value *Ptr, + Type *IntptrTy, uint64_t PtrShift, + Value *ShadowBase, Value *AppMemMask) { + return IRB.CreateAdd( + IRB.CreateShl( + IRB.CreateAnd(IRB.CreatePtrToInt(Ptr, IntptrTy, "app.ptr.int"), + AppMemMask, "app.ptr.masked"), + PtrShift, "app.ptr.shifted"), + ShadowBase, "shadow.ptr.int"); +} + +bool TypeSanitizer::instrumentWithShadowUpdate( + IRBuilder<> &IRB, const MDNode *TBAAMD, Value *Ptr, uint64_t AccessSize, + bool IsRead, bool IsWrite, Value *&ShadowBase, Value *&AppMemMask, + bool ForceSetType, bool SanitizeFunction, + TypeDescriptorsMapTy &TypeDescriptors, const DataLayout &DL) { + if (!ShadowBase) + ShadowBase = getShadowBase(*IRB.GetInsertBlock()->getParent()); + if (!AppMemMask) + AppMemMask = getAppMemMask(*IRB.GetInsertBlock()->getParent()); + + Constant *TDGV; + if (TBAAMD) + TDGV = TypeDescriptors[TBAAMD]; + else + TDGV = Constant::getNullValue(IRB.getPtrTy()); + + Value *TD = IRB.CreateBitCast(TDGV, IRB.getPtrTy()); + + Value *ShadowDataInt = ConvertToShadowDataInt(IRB, Ptr, IntptrTy, PtrShift, + ShadowBase, AppMemMask); + Type *Int8PtrPtrTy = IRB.getPtrTy()->getPointerTo(); + Value *ShadowData = + IRB.CreateIntToPtr(ShadowDataInt, Int8PtrPtrTy, "shadow.ptr"); + + auto SetType = [&]() { + IRB.CreateStore(TD, ShadowData); + + // Now fill the remainder of the shadow memory corresponding to the + // remainder of the the bytes of the type with a bad type descriptor. + for (uint64_t i = 1; i < AccessSize; ++i) { + Value *BadShadowData = IRB.CreateIntToPtr( + IRB.CreateAdd(ShadowDataInt, + ConstantInt::get(IntptrTy, i << PtrShift), + "shadow.byte." + Twine(i) + ".offset"), + Int8PtrPtrTy, "shadow.byte." + Twine(i) + ".ptr"); + + // This is the TD value, -i, which is used to indicate that the byte is + // i bytes after the first byte of the type. + Value *BadTD = + IRB.CreateIntToPtr(ConstantInt::getSigned(IntptrTy, -i), + IRB.getPtrTy(), "bad.descriptor" + Twine(i)); + IRB.CreateStore(BadTD, BadShadowData); + } + }; + + if (!ForceSetType && (!ClWritesAlwaysSetType || IsRead)) { + // We need to check the type here. If the type is unknown, then the read + // sets the type. If the type is known, then it is checked. If the type + // doesn't match, then we call the runtime (which may yet determine that + // the mismatch is okay). + LLVMContext &C = IRB.getContext(); + MDNode *UnlikelyBW = MDBuilder(C).createBranchWeights(1, 100000); + + Constant *Flags = + ConstantInt::get(OrdTy, (int)IsRead | (((int)IsWrite) << 1)); + + Value *LoadedTD = + IRB.CreateLoad(IRB.getPtrTy(), ShadowData, "shadow.desc"); + if (SanitizeFunction) { + Value *BadTDCmp = IRB.CreateICmpNE(LoadedTD, TD, "bad.desc"); + Instruction *BadTDTerm, *GoodTDTerm; + SplitBlockAndInsertIfThenElse(BadTDCmp, &*IRB.GetInsertPoint(), + &BadTDTerm, &GoodTDTerm, UnlikelyBW); + IRB.SetInsertPoint(BadTDTerm); + + // We now know that the types did not match (we're on the slow path). If + // the type is unknown, then set it. + Value *NullTDCmp = IRB.CreateIsNull(LoadedTD); + Instruction *NullTDTerm, *MismatchTerm; + SplitBlockAndInsertIfThenElse(NullTDCmp, &*IRB.GetInsertPoint(), + &NullTDTerm, &MismatchTerm); + + // If the type is unknown, then set the type. + IRB.SetInsertPoint(NullTDTerm); + + // We're about to set the type. Make sure that all bytes in the value are + // also of unknown type. + Value *Size = ConstantInt::get(OrdTy, AccessSize); + Value *NotAllUnkTD = IRB.getFalse(); + for (uint64_t i = 1; i < AccessSize; ++i) { + Value *UnkShadowData = IRB.CreateIntToPtr( + IRB.CreateAdd(ShadowDataInt, + ConstantInt::get(IntptrTy, i << PtrShift)), + Int8PtrPtrTy); + Value *ILdTD = IRB.CreateLoad(IRB.getPtrTy(), UnkShadowData); + NotAllUnkTD = IRB.CreateOr(NotAllUnkTD, IRB.CreateIsNotNull(ILdTD)); + } + + Instruction *BeforeSetType = &*IRB.GetInsertPoint(); + Instruction *BadUTDTerm = SplitBlockAndInsertIfThen( + NotAllUnkTD, BeforeSetType, false, UnlikelyBW); + IRB.SetInsertPoint(BadUTDTerm); + IRB.CreateCall(TysanCheck, {IRB.CreateBitCast(Ptr, IRB.getPtrTy()), + Size, (Value *)TD, (Value *)Flags}); + + IRB.SetInsertPoint(BeforeSetType); + SetType(); + + // We have a non-trivial mismatch. Call the runtime. + IRB.SetInsertPoint(MismatchTerm); + IRB.CreateCall(TysanCheck, {IRB.CreateBitCast(Ptr, IRB.getPtrTy()), + Size, (Value *)TD, (Value *)Flags}); + + // We appear to have the right type. Make sure that all other bytes in + // the type are still marked as interior bytes. If not, call the runtime. + IRB.SetInsertPoint(GoodTDTerm); + Value *NotAllBadTD = IRB.getFalse(); + for (uint64_t i = 1; i < AccessSize; ++i) { + Value *BadShadowData = IRB.CreateIntToPtr( + IRB.CreateAdd(ShadowDataInt, + ConstantInt::get(IntptrTy, i << PtrShift)), + Int8PtrPtrTy); + Value *ILdTD = IRB.CreatePtrToInt( + IRB.CreateLoad(IRB.getPtrTy(), BadShadowData), IntptrTy); + NotAllBadTD = IRB.CreateOr( + NotAllBadTD, + IRB.CreateICmpSGE(ILdTD, ConstantInt::get(IntptrTy, 0))); + } + + Instruction *BadITDTerm = SplitBlockAndInsertIfThen( + NotAllBadTD, &*IRB.GetInsertPoint(), false, UnlikelyBW); + IRB.SetInsertPoint(BadITDTerm); + IRB.CreateCall(TysanCheck, {IRB.CreateBitCast(Ptr, IRB.getPtrTy()), + Size, (Value *)TD, (Value *)Flags}); + } else { + // If we're not sanitizing this function, then we only care whether we + // need to *set* the type. + Value *NullTDCmp = IRB.CreateIsNull(LoadedTD, "desc.set"); + Instruction *NullTDTerm = SplitBlockAndInsertIfThen( + NullTDCmp, &*IRB.GetInsertPoint(), false, UnlikelyBW); + IRB.SetInsertPoint(NullTDTerm); + NullTDTerm->getParent()->setName("set.type"); + SetType(); + } + } else if (ForceSetType || IsWrite) { + // In the mode where writes always set the type, for a write (which does + // not also read), we just set the type. + SetType(); + } + + return true; +} + +bool TypeSanitizer::instrumentMemoryAccess( + Instruction *I, MemoryLocation &MLoc, Value *&ShadowBase, + Value *&AppMemMask, bool SanitizeFunction, + TypeDescriptorsMapTy &TypeDescriptors, const DataLayout &DL) { + IRBuilder<> IRB(I); + assert(MLoc.Size.isPrecise()); + if (instrumentWithShadowUpdate( + IRB, MLoc.AATags.TBAA, const_cast(MLoc.Ptr), + MLoc.Size.getValue(), I->mayReadFromMemory(), I->mayWriteToMemory(), + ShadowBase, AppMemMask, false, SanitizeFunction, TypeDescriptors, + DL)) { + ++NumInstrumentedAccesses; + return true; + } + + return false; +} + +// Memory-related intrinsics/instructions reset the type of the destination +// memory (including allocas and byval arguments). +bool TypeSanitizer::instrumentMemInst(Value *V, Value *&ShadowBase, + Value *&AppMemMask, + const DataLayout &DL) { + BasicBlock::iterator IP; + BasicBlock *BB; + Function *F; + + if (auto *I = dyn_cast(V)) { + IP = BasicBlock::iterator(I); + BB = I->getParent(); + F = BB->getParent(); + } else { + auto *A = cast(V); + F = A->getParent(); + BB = &F->getEntryBlock(); + IP = BB->getFirstInsertionPt(); + + if (auto *I = cast_or_null(ShadowBase)) { + if (IP->comesBefore(I)) + IP = I->getNextNode()->getIterator(); + } + if (auto *I = cast_or_null(AppMemMask)) { + if (IP->comesBefore(I)) + IP = I->getNextNode()->getIterator(); + } + } + + Value *Dest, *Size, *Src = nullptr; + bool NeedsMemMove = false; + IRBuilder<> IRB(BB, IP); + + if (auto *A = dyn_cast(V)) { + assert(A->hasByValAttr() && "Type reset for non-byval argument?"); + + Dest = A; + Size = + ConstantInt::get(IntptrTy, DL.getTypeAllocSize(A->getParamByValType())); + } else { + auto *I = cast(V); + if (auto *MI = dyn_cast(I)) { + if (MI->getDestAddressSpace() != 0) + return false; + + Dest = MI->getDest(); + Size = MI->getLength(); + + if (auto *MTI = dyn_cast(MI)) { + if (MTI->getSourceAddressSpace() == 0) { + Src = MTI->getSource(); + NeedsMemMove = isa(MTI); + } + } + } else if (auto *II = dyn_cast(I)) { + if (II->getIntrinsicID() != Intrinsic::lifetime_start && + II->getIntrinsicID() != Intrinsic::lifetime_end) + return false; + + Size = II->getArgOperand(0); + Dest = II->getArgOperand(1); + } else if (auto *AI = dyn_cast(I)) { + // We need to clear the types for new stack allocations (or else we might + // read stale type information from a previous function execution). + + IRB.SetInsertPoint(&*std::next(BasicBlock::iterator(I))); + IRB.SetInstDebugLocation(I); + + Size = IRB.CreateMul( + IRB.CreateZExtOrTrunc(AI->getArraySize(), IntptrTy), + ConstantInt::get(IntptrTy, + DL.getTypeAllocSize(AI->getAllocatedType()))); + Dest = I; + } else { + return false; + } + } + + if (!ShadowBase) + ShadowBase = getShadowBase(*F); + if (!AppMemMask) + AppMemMask = getAppMemMask(*F); + + Value *ShadowDataInt = IRB.CreateAdd( + IRB.CreateShl( + IRB.CreateAnd(IRB.CreatePtrToInt(Dest, IntptrTy), AppMemMask), + PtrShift), + ShadowBase); + Value *ShadowData = IRB.CreateIntToPtr(ShadowDataInt, IRB.getPtrTy()); + + if (!Src) { + IRB.CreateMemSet(ShadowData, IRB.getInt8(0), IRB.CreateShl(Size, PtrShift), + Align(1u << PtrShift)); + return true; + } + + Value *SrcShadowDataInt = IRB.CreateAdd( + IRB.CreateShl( + IRB.CreateAnd(IRB.CreatePtrToInt(Src, IntptrTy), AppMemMask), + PtrShift), + ShadowBase); + Value *SrcShadowData = + IRB.CreateIntToPtr(SrcShadowDataInt, IRB.getPtrTy()); + + if (NeedsMemMove) { + IRB.CreateMemMove(ShadowData, Align(1u << PtrShift), SrcShadowData, + Align(1u << PtrShift), IRB.CreateShl(Size, PtrShift)); + } else { + IRB.CreateMemCpy(ShadowData, Align(1u << PtrShift), SrcShadowData, + Align(1u << PtrShift), IRB.CreateShl(Size, PtrShift)); + } + + return true; +} + +PreservedAnalyses TypeSanitizerPass::run(Function &F, + FunctionAnalysisManager &FAM) { + TypeSanitizer TySan(*F.getParent()); + TySan.run(F, FAM.getResult(F)); + return PreservedAnalyses::none(); +} + +PreservedAnalyses ModuleTypeSanitizerPass::run(Module &M, + ModuleAnalysisManager &AM) { + insertModuleCtor(M); + return PreservedAnalyses::none(); +} diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp index 6539f924c2edf..610a77bc4c31e 100644 --- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp +++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp @@ -935,6 +935,7 @@ Function *CodeExtractor::constructFunctionDeclaration( case Attribute::SanitizeMemory: case Attribute::SanitizeNumericalStability: case Attribute::SanitizeThread: + case Attribute::SanitizeType: case Attribute::SanitizeHWAddress: case Attribute::SanitizeMemTag: case Attribute::SanitizeRealtime: diff --git a/llvm/test/Instrumentation/TypeSanitizer/access-with-offfset.ll b/llvm/test/Instrumentation/TypeSanitizer/access-with-offfset.ll new file mode 100644 index 0000000000000..297ee83527b5c --- /dev/null +++ b/llvm/test/Instrumentation/TypeSanitizer/access-with-offfset.ll @@ -0,0 +1,71 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals +; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s + +;. +; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }] +; CHECK: @[[__TYSAN_V1_SIMPLE_20C_2FC_2B_2B_20TBAA:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, [18 x i8] } { i64 2, i64 0, [18 x i8] c"Simple C/C++ TBAA\00" }, comdat +; CHECK: @[[__TYSAN_V1_OMNIPOTENT_20CHAR:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [16 x i8] } { i64 2, i64 1, ptr @__tysan_v1_Simple_20C_2fC_2b_2b_20TBAA, i64 0, [16 x i8] c"omnipotent char\00" }, comdat +; CHECK: @[[__TYSAN_V1_ANY_20POINTER:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [12 x i8] } { i64 2, i64 1, ptr @__tysan_v1_omnipotent_20char, i64 0, [12 x i8] c"any pointer\00" }, comdat +; CHECK: @[[__TYSAN_V1_ANY_20POINTER_O_0:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1_any_20pointer, ptr @__tysan_v1_any_20pointer, i64 0 }, comdat +; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [5 x ptr] [ptr @tysan.module_ctor, ptr @__tysan_v1_Simple_20C_2fC_2b_2b_20TBAA, ptr @__tysan_v1_omnipotent_20char, ptr @__tysan_v1_any_20pointer, ptr @__tysan_v1_any_20pointer_o_0], section "llvm.metadata" +; CHECK: @[[__TYSAN_SHADOW_MEMORY_ADDRESS:[a-zA-Z0-9_$"\\.-]+]] = external global i64 +; CHECK: @[[__TYSAN_APP_MEMORY_MASK:[a-zA-Z0-9_$"\\.-]+]] = external global i64 +;. +define ptr @test_load_offset(ptr %argv) { +; CHECK-LABEL: @test_load_offset( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 4 +; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 4 +; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 0, [[APP_MEM_MASK]] +; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3 +; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]] +; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr +; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8 +; CHECK-NEXT: [[DESC_SET:%.*]] = icmp eq ptr [[SHADOW_DESC]], null +; CHECK-NEXT: br i1 [[DESC_SET]], label [[SET_TYPE:%.*]], label [[TMP0:%.*]], !prof [[PROF0:![0-9]+]] +; CHECK: set.type: +; CHECK-NEXT: store ptr @__tysan_v1_any_20pointer_o_0, ptr [[SHADOW_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8 +; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16 +; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24 +; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_4_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 32 +; CHECK-NEXT: [[SHADOW_BYTE_4_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_4_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -4 to ptr), ptr [[SHADOW_BYTE_4_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_5_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 40 +; CHECK-NEXT: [[SHADOW_BYTE_5_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_5_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -5 to ptr), ptr [[SHADOW_BYTE_5_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_6_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 48 +; CHECK-NEXT: [[SHADOW_BYTE_6_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_6_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -6 to ptr), ptr [[SHADOW_BYTE_6_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_7_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 56 +; CHECK-NEXT: [[SHADOW_BYTE_7_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_7_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -7 to ptr), ptr [[SHADOW_BYTE_7_PTR]], align 8 +; CHECK-NEXT: br label [[TMP0]] +; CHECK: 0: +; CHECK-NEXT: [[L:%.*]] = load ptr, ptr null, align 8, !tbaa [[TBAA1:![0-9]+]] +; CHECK-NEXT: ret ptr [[L]] +; +entry: + %l = load ptr, ptr null, align 8, !tbaa !0 + ret ptr %l +} + +!0 = !{!1, !1, i64 0} +!1 = !{!"any pointer", !2, i64 0} +!2 = !{!"omnipotent char", !3, i64 0} +!3 = !{!"Simple C/C++ TBAA"} +;. +; CHECK: attributes #[[ATTR0:[0-9]+]] = { nounwind } +;. +; CHECK: [[PROF0]] = !{!"branch_weights", i32 1, i32 100000} +; CHECK: [[TBAA1]] = !{!2, !2, i64 0} +; CHECK: [[META2:![0-9]+]] = !{!"any pointer", !3, i64 0} +; CHECK: [[META3:![0-9]+]] = !{!"omnipotent char", !4, i64 0} +; CHECK: [[META4:![0-9]+]] = !{!"Simple C/C++ TBAA"} +;. diff --git a/llvm/test/Instrumentation/TypeSanitizer/alloca.ll b/llvm/test/Instrumentation/TypeSanitizer/alloca.ll new file mode 100644 index 0000000000000..94098bd8a1739 --- /dev/null +++ b/llvm/test/Instrumentation/TypeSanitizer/alloca.ll @@ -0,0 +1,29 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; Test basic type sanitizer instrumentation. +; +; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +declare void @alloca_test_use(ptr) + +define void @alloca_test() sanitize_type { +; CHECK-LABEL: @alloca_test( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8 +; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8 +; CHECK-NEXT: [[X:%.*]] = alloca [10 x i8], align 1 +; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[X]] to i64 +; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], [[APP_MEM_MASK]] +; CHECK-NEXT: [[TMP2:%.*]] = shl i64 [[TMP1]], 3 +; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[TMP2]], [[SHADOW_BASE]] +; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr +; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[TMP4]], i8 0, i64 80, i1 false) +; CHECK-NEXT: call void @alloca_test_use(ptr [[X]]) +; CHECK-NEXT: ret void +; +entry: + %x = alloca [10 x i8], align 1 + call void @alloca_test_use([10 x i8]* %x) + ret void +} diff --git a/llvm/test/Instrumentation/TypeSanitizer/anon.ll b/llvm/test/Instrumentation/TypeSanitizer/anon.ll new file mode 100644 index 0000000000000..70f5dcefde64c --- /dev/null +++ b/llvm/test/Instrumentation/TypeSanitizer/anon.ll @@ -0,0 +1,283 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals +; Test basic type sanitizer instrumentation. +; +; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }] +; CHECK: @[[__TYSAN_V1_SIMPLE_20C_2B_2B_20TBAA:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, [16 x i8] } { i64 2, i64 0, [16 x i8] c"Simple C++ TBAA\00" }, comdat +; CHECK: @[[__TYSAN_V1_OMNIPOTENT_20CHAR:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [16 x i8] } { i64 2, i64 1, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, i64 0, [16 x i8] c"omnipotent char\00" }, comdat +; CHECK: @[[__TYSAN_V1_INT:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [4 x i8] } { i64 2, i64 1, ptr @__tysan_v1_omnipotent_20char, i64 0, [4 x i8] c"int\00" }, comdat +; CHECK: @[[__TYSAN_V1___ZTSN12__GLOBAL____N__11ZE:[a-zA-Z0-9_$"\\.-]+]] = internal constant { i64, i64, ptr, i64, [23 x i8] } { i64 2, i64 1, ptr @__tysan_v1_int, i64 24, [23 x i8] c"_ZTSN12_GLOBAL__N_11zE\00" } +; CHECK: @[[__TYSAN_V1___ZTSN12__GLOBAL____N__11ZE_O_24:[a-zA-Z0-9_$"\\.-]+]] = internal constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1___ZTSN12__GLOBAL____N__11zE, ptr @__tysan_v1_int, i64 24 } +; CHECK: @[[__TYSAN_V1___ZTS1YIN12__GLOBAL____N__11ZEE:[a-zA-Z0-9_$"\\.-]+]] = internal constant { i64, i64, ptr, i64, [27 x i8] } { i64 2, i64 1, ptr @__tysan_v1_int, i64 24, [27 x i8] c"_ZTS1yIN12_GLOBAL__N_11zEE\00" } +; CHECK: @[[__TYSAN_V1___ZTS1YIN12__GLOBAL____N__11ZEE_O_24:[a-zA-Z0-9_$"\\.-]+]] = internal constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1___ZTS1yIN12__GLOBAL____N__11zEE, ptr @__tysan_v1_int, i64 24 } +; CHECK: @[[__TYSAN_SHADOW_MEMORY_ADDRESS:[a-zA-Z0-9_$"\\.-]+]] = external global i64 +; CHECK: @[[__TYSAN_APP_MEMORY_MASK:[a-zA-Z0-9_$"\\.-]+]] = external global i64 +; CHECK: @[[__TYSAN_V1_____ANONYMOUS__027D9E575C5D34CB5D60D6A1D6276F95:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [1 x i8] } { i64 2, i64 1, ptr @__tysan_v1_int, i64 24, [1 x i8] zeroinitializer }, comdat +; CHECK: @[[__TYSAN_V1_____ANONYMOUS__027D9E575C5D34CB5D60D6A1D6276F95_O_24:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95, ptr @__tysan_v1_int, i64 24 }, comdat +; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [6 x ptr] [ptr @tysan.module_ctor, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, ptr @__tysan_v1_omnipotent_20char, ptr @__tysan_v1_int, ptr @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95, ptr @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95_o_24], section "llvm.metadata" + + +define void @test_anon_ns(ptr %a, ptr %b) sanitize_type { +; CHECK-LABEL: @test_anon_ns( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8 +; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8 +; CHECK-NEXT: [[APP_PTR_INT:%.*]] = ptrtoint ptr [[A:%.*]] to i64 +; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 [[APP_PTR_INT]], [[APP_MEM_MASK]] +; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3 +; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]] +; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr +; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8 +; CHECK-NEXT: [[BAD_DESC:%.*]] = icmp ne ptr [[SHADOW_DESC]], @__tysan_v1___ZTSN12__GLOBAL____N__11zE_o_24 +; CHECK-NEXT: br i1 [[BAD_DESC]], label [[TMP0:%.*]], label [[TMP22:%.*]], !prof [[PROF0:![0-9]+]] +; CHECK: 0: +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq ptr [[SHADOW_DESC]], null +; CHECK-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP20:%.*]] +; CHECK: 2: +; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[SHADOW_PTR_INT]], 8 +; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr +; CHECK-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP4]], align 8 +; CHECK-NEXT: [[TMP6:%.*]] = icmp ne ptr [[TMP5]], null +; CHECK-NEXT: [[TMP7:%.*]] = or i1 false, [[TMP6]] +; CHECK-NEXT: [[TMP8:%.*]] = add i64 [[SHADOW_PTR_INT]], 16 +; CHECK-NEXT: [[TMP9:%.*]] = inttoptr i64 [[TMP8]] to ptr +; CHECK-NEXT: [[TMP10:%.*]] = load ptr, ptr [[TMP9]], align 8 +; CHECK-NEXT: [[TMP11:%.*]] = icmp ne ptr [[TMP10]], null +; CHECK-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]] +; CHECK-NEXT: [[TMP13:%.*]] = add i64 [[SHADOW_PTR_INT]], 24 +; CHECK-NEXT: [[TMP14:%.*]] = inttoptr i64 [[TMP13]] to ptr +; CHECK-NEXT: [[TMP15:%.*]] = load ptr, ptr [[TMP14]], align 8 +; CHECK-NEXT: [[TMP16:%.*]] = icmp ne ptr [[TMP15]], null +; CHECK-NEXT: [[TMP17:%.*]] = or i1 [[TMP12]], [[TMP16]] +; CHECK-NEXT: br i1 [[TMP17]], label [[TMP18:%.*]], label [[TMP19:%.*]], !prof [[PROF0]] +; CHECK: 18: +; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1___ZTSN12__GLOBAL____N__11zE_o_24, i32 2) +; CHECK-NEXT: br label [[TMP19]] +; CHECK: 19: +; CHECK-NEXT: store ptr @__tysan_v1___ZTSN12__GLOBAL____N__11zE_o_24, ptr [[SHADOW_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8 +; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16 +; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24 +; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8 +; CHECK-NEXT: br label [[TMP21:%.*]] +; CHECK: 20: +; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1___ZTSN12__GLOBAL____N__11zE_o_24, i32 2) +; CHECK-NEXT: br label [[TMP21]] +; CHECK: 21: +; CHECK-NEXT: br label [[TMP43:%.*]] +; CHECK: 22: +; CHECK-NEXT: [[TMP23:%.*]] = add i64 [[SHADOW_PTR_INT]], 8 +; CHECK-NEXT: [[TMP24:%.*]] = inttoptr i64 [[TMP23]] to ptr +; CHECK-NEXT: [[TMP25:%.*]] = load ptr, ptr [[TMP24]], align 8 +; CHECK-NEXT: [[TMP26:%.*]] = ptrtoint ptr [[TMP25]] to i64 +; CHECK-NEXT: [[TMP27:%.*]] = icmp sge i64 [[TMP26]], 0 +; CHECK-NEXT: [[TMP28:%.*]] = or i1 false, [[TMP27]] +; CHECK-NEXT: [[TMP29:%.*]] = add i64 [[SHADOW_PTR_INT]], 16 +; CHECK-NEXT: [[TMP30:%.*]] = inttoptr i64 [[TMP29]] to ptr +; CHECK-NEXT: [[TMP31:%.*]] = load ptr, ptr [[TMP30]], align 8 +; CHECK-NEXT: [[TMP32:%.*]] = ptrtoint ptr [[TMP31]] to i64 +; CHECK-NEXT: [[TMP33:%.*]] = icmp sge i64 [[TMP32]], 0 +; CHECK-NEXT: [[TMP34:%.*]] = or i1 [[TMP28]], [[TMP33]] +; CHECK-NEXT: [[TMP35:%.*]] = add i64 [[SHADOW_PTR_INT]], 24 +; CHECK-NEXT: [[TMP36:%.*]] = inttoptr i64 [[TMP35]] to ptr +; CHECK-NEXT: [[TMP37:%.*]] = load ptr, ptr [[TMP36]], align 8 +; CHECK-NEXT: [[TMP38:%.*]] = ptrtoint ptr [[TMP37]] to i64 +; CHECK-NEXT: [[TMP39:%.*]] = icmp sge i64 [[TMP38]], 0 +; CHECK-NEXT: [[TMP40:%.*]] = or i1 [[TMP34]], [[TMP39]] +; CHECK-NEXT: br i1 [[TMP40]], label [[TMP41:%.*]], label [[TMP42:%.*]], !prof [[PROF0]] +; CHECK: 41: +; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1___ZTSN12__GLOBAL____N__11zE_o_24, i32 2) +; CHECK-NEXT: br label [[TMP42]] +; CHECK: 42: +; CHECK-NEXT: br label [[TMP43]] +; CHECK: 43: +; CHECK-NEXT: store i32 42, ptr [[A]], align 4, !tbaa [[TBAA1:![0-9]+]] +; CHECK-NEXT: [[APP_PTR_INT1:%.*]] = ptrtoint ptr [[B:%.*]] to i64 +; CHECK-NEXT: [[APP_PTR_MASKED2:%.*]] = and i64 [[APP_PTR_INT1]], [[APP_MEM_MASK]] +; CHECK-NEXT: [[APP_PTR_SHIFTED3:%.*]] = shl i64 [[APP_PTR_MASKED2]], 3 +; CHECK-NEXT: [[SHADOW_PTR_INT4:%.*]] = add i64 [[APP_PTR_SHIFTED3]], [[SHADOW_BASE]] +; CHECK-NEXT: [[SHADOW_PTR5:%.*]] = inttoptr i64 [[SHADOW_PTR_INT4]] to ptr +; CHECK-NEXT: [[SHADOW_DESC6:%.*]] = load ptr, ptr [[SHADOW_PTR5]], align 8 +; CHECK-NEXT: [[BAD_DESC7:%.*]] = icmp ne ptr [[SHADOW_DESC6]], @__tysan_v1___ZTS1yIN12__GLOBAL____N__11zEE_o_24 +; CHECK-NEXT: br i1 [[BAD_DESC7]], label [[TMP44:%.*]], label [[TMP66:%.*]], !prof [[PROF0]] +; CHECK: 44: +; CHECK-NEXT: [[TMP45:%.*]] = icmp eq ptr [[SHADOW_DESC6]], null +; CHECK-NEXT: br i1 [[TMP45]], label [[TMP46:%.*]], label [[TMP64:%.*]] +; CHECK: 46: +; CHECK-NEXT: [[TMP47:%.*]] = add i64 [[SHADOW_PTR_INT4]], 8 +; CHECK-NEXT: [[TMP48:%.*]] = inttoptr i64 [[TMP47]] to ptr +; CHECK-NEXT: [[TMP49:%.*]] = load ptr, ptr [[TMP48]], align 8 +; CHECK-NEXT: [[TMP50:%.*]] = icmp ne ptr [[TMP49]], null +; CHECK-NEXT: [[TMP51:%.*]] = or i1 false, [[TMP50]] +; CHECK-NEXT: [[TMP52:%.*]] = add i64 [[SHADOW_PTR_INT4]], 16 +; CHECK-NEXT: [[TMP53:%.*]] = inttoptr i64 [[TMP52]] to ptr +; CHECK-NEXT: [[TMP54:%.*]] = load ptr, ptr [[TMP53]], align 8 +; CHECK-NEXT: [[TMP55:%.*]] = icmp ne ptr [[TMP54]], null +; CHECK-NEXT: [[TMP56:%.*]] = or i1 [[TMP51]], [[TMP55]] +; CHECK-NEXT: [[TMP57:%.*]] = add i64 [[SHADOW_PTR_INT4]], 24 +; CHECK-NEXT: [[TMP58:%.*]] = inttoptr i64 [[TMP57]] to ptr +; CHECK-NEXT: [[TMP59:%.*]] = load ptr, ptr [[TMP58]], align 8 +; CHECK-NEXT: [[TMP60:%.*]] = icmp ne ptr [[TMP59]], null +; CHECK-NEXT: [[TMP61:%.*]] = or i1 [[TMP56]], [[TMP60]] +; CHECK-NEXT: br i1 [[TMP61]], label [[TMP62:%.*]], label [[TMP63:%.*]], !prof [[PROF0]] +; CHECK: 62: +; CHECK-NEXT: call void @__tysan_check(ptr [[B]], i32 4, ptr @__tysan_v1___ZTS1yIN12__GLOBAL____N__11zEE_o_24, i32 2) +; CHECK-NEXT: br label [[TMP63]] +; CHECK: 63: +; CHECK-NEXT: store ptr @__tysan_v1___ZTS1yIN12__GLOBAL____N__11zEE_o_24, ptr [[SHADOW_PTR5]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET8:%.*]] = add i64 [[SHADOW_PTR_INT4]], 8 +; CHECK-NEXT: [[SHADOW_BYTE_1_PTR9:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET8]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR9]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET10:%.*]] = add i64 [[SHADOW_PTR_INT4]], 16 +; CHECK-NEXT: [[SHADOW_BYTE_2_PTR11:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET10]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR11]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET12:%.*]] = add i64 [[SHADOW_PTR_INT4]], 24 +; CHECK-NEXT: [[SHADOW_BYTE_3_PTR13:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET12]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR13]], align 8 +; CHECK-NEXT: br label [[TMP65:%.*]] +; CHECK: 64: +; CHECK-NEXT: call void @__tysan_check(ptr [[B]], i32 4, ptr @__tysan_v1___ZTS1yIN12__GLOBAL____N__11zEE_o_24, i32 2) +; CHECK-NEXT: br label [[TMP65]] +; CHECK: 65: +; CHECK-NEXT: br label [[TMP87:%.*]] +; CHECK: 66: +; CHECK-NEXT: [[TMP67:%.*]] = add i64 [[SHADOW_PTR_INT4]], 8 +; CHECK-NEXT: [[TMP68:%.*]] = inttoptr i64 [[TMP67]] to ptr +; CHECK-NEXT: [[TMP69:%.*]] = load ptr, ptr [[TMP68]], align 8 +; CHECK-NEXT: [[TMP70:%.*]] = ptrtoint ptr [[TMP69]] to i64 +; CHECK-NEXT: [[TMP71:%.*]] = icmp sge i64 [[TMP70]], 0 +; CHECK-NEXT: [[TMP72:%.*]] = or i1 false, [[TMP71]] +; CHECK-NEXT: [[TMP73:%.*]] = add i64 [[SHADOW_PTR_INT4]], 16 +; CHECK-NEXT: [[TMP74:%.*]] = inttoptr i64 [[TMP73]] to ptr +; CHECK-NEXT: [[TMP75:%.*]] = load ptr, ptr [[TMP74]], align 8 +; CHECK-NEXT: [[TMP76:%.*]] = ptrtoint ptr [[TMP75]] to i64 +; CHECK-NEXT: [[TMP77:%.*]] = icmp sge i64 [[TMP76]], 0 +; CHECK-NEXT: [[TMP78:%.*]] = or i1 [[TMP72]], [[TMP77]] +; CHECK-NEXT: [[TMP79:%.*]] = add i64 [[SHADOW_PTR_INT4]], 24 +; CHECK-NEXT: [[TMP80:%.*]] = inttoptr i64 [[TMP79]] to ptr +; CHECK-NEXT: [[TMP81:%.*]] = load ptr, ptr [[TMP80]], align 8 +; CHECK-NEXT: [[TMP82:%.*]] = ptrtoint ptr [[TMP81]] to i64 +; CHECK-NEXT: [[TMP83:%.*]] = icmp sge i64 [[TMP82]], 0 +; CHECK-NEXT: [[TMP84:%.*]] = or i1 [[TMP78]], [[TMP83]] +; CHECK-NEXT: br i1 [[TMP84]], label [[TMP85:%.*]], label [[TMP86:%.*]], !prof [[PROF0]] +; CHECK: 85: +; CHECK-NEXT: call void @__tysan_check(ptr [[B]], i32 4, ptr @__tysan_v1___ZTS1yIN12__GLOBAL____N__11zEE_o_24, i32 2) +; CHECK-NEXT: br label [[TMP86]] +; CHECK: 86: +; CHECK-NEXT: br label [[TMP87]] +; CHECK: 87: +; CHECK-NEXT: store i32 43, ptr [[B]], align 4, !tbaa [[TBAA6:![0-9]+]] +; CHECK-NEXT: ret void +; +entry: + store i32 42, ptr %a, align 4, !tbaa !8 + store i32 43, ptr %b, align 4, !tbaa !10 + ret void + +} + +define void @test_anon_type(ptr %a) sanitize_type { +; CHECK-LABEL: @test_anon_type( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8 +; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8 +; CHECK-NEXT: [[APP_PTR_INT:%.*]] = ptrtoint ptr [[A:%.*]] to i64 +; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 [[APP_PTR_INT]], [[APP_MEM_MASK]] +; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3 +; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]] +; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr +; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8 +; CHECK-NEXT: [[BAD_DESC:%.*]] = icmp ne ptr [[SHADOW_DESC]], @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95_o_24 +; CHECK-NEXT: br i1 [[BAD_DESC]], label [[TMP0:%.*]], label [[TMP22:%.*]], !prof [[PROF0]] +; CHECK: 0: +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq ptr [[SHADOW_DESC]], null +; CHECK-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP20:%.*]] +; CHECK: 2: +; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[SHADOW_PTR_INT]], 8 +; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr +; CHECK-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP4]], align 8 +; CHECK-NEXT: [[TMP6:%.*]] = icmp ne ptr [[TMP5]], null +; CHECK-NEXT: [[TMP7:%.*]] = or i1 false, [[TMP6]] +; CHECK-NEXT: [[TMP8:%.*]] = add i64 [[SHADOW_PTR_INT]], 16 +; CHECK-NEXT: [[TMP9:%.*]] = inttoptr i64 [[TMP8]] to ptr +; CHECK-NEXT: [[TMP10:%.*]] = load ptr, ptr [[TMP9]], align 8 +; CHECK-NEXT: [[TMP11:%.*]] = icmp ne ptr [[TMP10]], null +; CHECK-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]] +; CHECK-NEXT: [[TMP13:%.*]] = add i64 [[SHADOW_PTR_INT]], 24 +; CHECK-NEXT: [[TMP14:%.*]] = inttoptr i64 [[TMP13]] to ptr +; CHECK-NEXT: [[TMP15:%.*]] = load ptr, ptr [[TMP14]], align 8 +; CHECK-NEXT: [[TMP16:%.*]] = icmp ne ptr [[TMP15]], null +; CHECK-NEXT: [[TMP17:%.*]] = or i1 [[TMP12]], [[TMP16]] +; CHECK-NEXT: br i1 [[TMP17]], label [[TMP18:%.*]], label [[TMP19:%.*]], !prof [[PROF0]] +; CHECK: 18: +; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95_o_24, i32 2) +; CHECK-NEXT: br label [[TMP19]] +; CHECK: 19: +; CHECK-NEXT: store ptr @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95_o_24, ptr [[SHADOW_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8 +; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16 +; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24 +; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8 +; CHECK-NEXT: br label [[TMP21:%.*]] +; CHECK: 20: +; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95_o_24, i32 2) +; CHECK-NEXT: br label [[TMP21]] +; CHECK: 21: +; CHECK-NEXT: br label [[TMP43:%.*]] +; CHECK: 22: +; CHECK-NEXT: [[TMP23:%.*]] = add i64 [[SHADOW_PTR_INT]], 8 +; CHECK-NEXT: [[TMP24:%.*]] = inttoptr i64 [[TMP23]] to ptr +; CHECK-NEXT: [[TMP25:%.*]] = load ptr, ptr [[TMP24]], align 8 +; CHECK-NEXT: [[TMP26:%.*]] = ptrtoint ptr [[TMP25]] to i64 +; CHECK-NEXT: [[TMP27:%.*]] = icmp sge i64 [[TMP26]], 0 +; CHECK-NEXT: [[TMP28:%.*]] = or i1 false, [[TMP27]] +; CHECK-NEXT: [[TMP29:%.*]] = add i64 [[SHADOW_PTR_INT]], 16 +; CHECK-NEXT: [[TMP30:%.*]] = inttoptr i64 [[TMP29]] to ptr +; CHECK-NEXT: [[TMP31:%.*]] = load ptr, ptr [[TMP30]], align 8 +; CHECK-NEXT: [[TMP32:%.*]] = ptrtoint ptr [[TMP31]] to i64 +; CHECK-NEXT: [[TMP33:%.*]] = icmp sge i64 [[TMP32]], 0 +; CHECK-NEXT: [[TMP34:%.*]] = or i1 [[TMP28]], [[TMP33]] +; CHECK-NEXT: [[TMP35:%.*]] = add i64 [[SHADOW_PTR_INT]], 24 +; CHECK-NEXT: [[TMP36:%.*]] = inttoptr i64 [[TMP35]] to ptr +; CHECK-NEXT: [[TMP37:%.*]] = load ptr, ptr [[TMP36]], align 8 +; CHECK-NEXT: [[TMP38:%.*]] = ptrtoint ptr [[TMP37]] to i64 +; CHECK-NEXT: [[TMP39:%.*]] = icmp sge i64 [[TMP38]], 0 +; CHECK-NEXT: [[TMP40:%.*]] = or i1 [[TMP34]], [[TMP39]] +; CHECK-NEXT: br i1 [[TMP40]], label [[TMP41:%.*]], label [[TMP42:%.*]], !prof [[PROF0]] +; CHECK: 41: +; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95_o_24, i32 2) +; CHECK-NEXT: br label [[TMP42]] +; CHECK: 42: +; CHECK-NEXT: br label [[TMP43]] +; CHECK: 43: +; CHECK-NEXT: store i32 42, ptr [[A]], align 4, !tbaa [[TBAA8:![0-9]+]] +; CHECK-NEXT: ret void +; +entry: + store i32 42, ptr %a, align 4, !tbaa !12 + ret void + +} + +!0 = !{!"Simple C++ TBAA"} +!1 = !{!"omnipotent char", !0, i64 0} +!2 = !{!"int", !1, i64 0} +!7 = !{!"_ZTSN12_GLOBAL__N_11zE", !2, i64 24} +!8 = !{!7, !2, i64 24} +!9 = !{!"_ZTS1yIN12_GLOBAL__N_11zEE", !2, i64 24} +!10 = !{!9, !2, i64 24} +!11 = !{!"", !2, i64 24} +!12 = !{!11, !2, i64 24} diff --git a/llvm/test/Instrumentation/TypeSanitizer/basic-nosan.ll b/llvm/test/Instrumentation/TypeSanitizer/basic-nosan.ll new file mode 100644 index 0000000000000..7f25e36e6660e --- /dev/null +++ b/llvm/test/Instrumentation/TypeSanitizer/basic-nosan.ll @@ -0,0 +1,93 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals --include-generated-funcs +; Test basic type sanitizer instrumentation. +; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }] +; CHECK: @[[__TYSAN_V1_SIMPLE_20C_2B_2B_20TBAA:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, [16 x i8] } { i64 2, i64 0, [16 x i8] c"Simple C++ TBAA\00" }, comdat +; CHECK: @[[__TYSAN_V1_OMNIPOTENT_20CHAR:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [16 x i8] } { i64 2, i64 1, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, i64 0, [16 x i8] c"omnipotent char\00" }, comdat +; CHECK: @[[__TYSAN_V1_INT:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [4 x i8] } { i64 2, i64 1, ptr @__tysan_v1_omnipotent_20char, i64 0, [4 x i8] c"int\00" }, comdat +; CHECK: @[[__TYSAN_V1_INT_O_0:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1_int, ptr @__tysan_v1_int, i64 0 }, comdat +; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [5 x ptr] [ptr @tysan.module_ctor, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, ptr @__tysan_v1_omnipotent_20char, ptr @__tysan_v1_int, ptr @__tysan_v1_int_o_0], section "llvm.metadata" +; CHECK: @[[__TYSAN_SHADOW_MEMORY_ADDRESS:[a-zA-Z0-9_$"\\.-]+]] = external global i64 +; CHECK: @[[__TYSAN_APP_MEMORY_MASK:[a-zA-Z0-9_$"\\.-]+]] = external global i64 +; +define i32 @test_load_nsan(ptr %a) { +; CHECK-LABEL: @test_load_nsan( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8 +; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8 +; CHECK-NEXT: [[APP_PTR_INT:%.*]] = ptrtoint ptr [[A:%.*]] to i64 +; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 [[APP_PTR_INT]], [[APP_MEM_MASK]] +; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3 +; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]] +; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr +; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8 +; CHECK-NEXT: [[DESC_SET:%.*]] = icmp eq ptr [[SHADOW_DESC]], null +; CHECK-NEXT: br i1 [[DESC_SET]], label [[SET_TYPE:%.*]], label [[TMP0:%.*]], !prof [[PROF0:![0-9]+]] +; CHECK: set.type: +; CHECK-NEXT: store ptr @__tysan_v1_int_o_0, ptr [[SHADOW_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8 +; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16 +; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24 +; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8 +; CHECK-NEXT: br label [[TMP0]] +; CHECK: 0: +; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[A]], align 4, !tbaa [[TBAA1:![0-9]+]] +; CHECK-NEXT: ret i32 [[TMP1]] +; +entry: + %tmp1 = load i32, ptr %a, align 4, !tbaa !3 + ret i32 %tmp1 +} + +define void @test_store_nsan(ptr %a) { +; CHECK-LABEL: @test_store_nsan( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8 +; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8 +; CHECK-NEXT: [[APP_PTR_INT:%.*]] = ptrtoint ptr [[A:%.*]] to i64 +; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 [[APP_PTR_INT]], [[APP_MEM_MASK]] +; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3 +; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]] +; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr +; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8 +; CHECK-NEXT: [[DESC_SET:%.*]] = icmp eq ptr [[SHADOW_DESC]], null +; CHECK-NEXT: br i1 [[DESC_SET]], label [[SET_TYPE:%.*]], label [[TMP0:%.*]], !prof [[PROF0]] +; CHECK: set.type: +; CHECK-NEXT: store ptr @__tysan_v1_int_o_0, ptr [[SHADOW_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8 +; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16 +; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24 +; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8 +; CHECK-NEXT: br label [[TMP0]] +; CHECK: 0: +; CHECK-NEXT: store i32 42, ptr [[A]], align 4, !tbaa [[TBAA1]] +; CHECK-NEXT: ret void +; +entry: + store i32 42, ptr %a, align 4, !tbaa !3 + ret void +} + +; CHECK-LABEL: @tysan.module_ctor( +; CHECK-NEXT: call void @__tysan_init() +; CHECK-NEXT: ret void +; +; CHECK: [[PROF0]] = !{!"branch_weights", i32 1, i32 100000} + +!0 = !{!"Simple C++ TBAA"} +!1 = !{!"omnipotent char", !0, i64 0} +!2 = !{!"int", !1, i64 0} +!3 = !{!2, !2, i64 0} diff --git a/llvm/test/Instrumentation/TypeSanitizer/basic.ll b/llvm/test/Instrumentation/TypeSanitizer/basic.ll new file mode 100644 index 0000000000000..132df722e83c2 --- /dev/null +++ b/llvm/test/Instrumentation/TypeSanitizer/basic.ll @@ -0,0 +1,214 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals +; Test basic type sanitizer instrumentation. +; +; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + +; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }] +; CHECK: @[[__TYSAN_V1_SIMPLE_20C_2B_2B_20TBAA:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, [16 x i8] } { i64 2, i64 0, [16 x i8] c"Simple C++ TBAA\00" }, comdat +; CHECK: @[[__TYSAN_V1_OMNIPOTENT_20CHAR:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [16 x i8] } { i64 2, i64 1, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, i64 0, [16 x i8] c"omnipotent char\00" }, comdat +; CHECK: @[[__TYSAN_V1_INT:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [4 x i8] } { i64 2, i64 1, ptr @__tysan_v1_omnipotent_20char, i64 0, [4 x i8] c"int\00" }, comdat +; CHECK: @[[__TYSAN_V1_INT_O_0:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1_int, ptr @__tysan_v1_int, i64 0 }, comdat +; CHECK: @[[__TYSAN_SHADOW_MEMORY_ADDRESS:[a-zA-Z0-9_$"\\.-]+]] = external global i64 +; CHECK: @[[__TYSAN_APP_MEMORY_MASK:[a-zA-Z0-9_$"\\.-]+]] = external global i64 +; CHECK: @[[__TYSAN_V1___ZTS1X:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, ptr, i64, [7 x i8] } { i64 2, i64 2, ptr @__tysan_v1_int, i64 0, ptr @__tysan_v1_int, i64 4, [7 x i8] c"_ZTS1x\00" }, comdat +; CHECK: @[[__TYSAN_V1___ZTS1V:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, ptr, i64, ptr, i64, [7 x i8] } { i64 2, i64 3, ptr @__tysan_v1_int, i64 8, ptr @__tysan_v1_int, i64 12, ptr @__tysan_v1___ZTS1x, i64 16, [7 x i8] c"_ZTS1v\00" }, comdat +; CHECK: @[[__TYSAN_V1___ZTS1V_O_12:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1___ZTS1v, ptr @__tysan_v1_int, i64 12 }, comdat +; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [8 x ptr] [ptr @tysan.module_ctor, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, ptr @__tysan_v1_omnipotent_20char, ptr @__tysan_v1_int, ptr @__tysan_v1_int_o_0, ptr @__tysan_v1___ZTS1x, ptr @__tysan_v1___ZTS1v, ptr @__tysan_v1___ZTS1v_o_12], section "llvm.metadata" + +define i32 @test_load(ptr %a) sanitize_type { +; CHECK-LABEL: @test_load( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8 +; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8 +; CHECK-NEXT: [[APP_PTR_INT:%.*]] = ptrtoint ptr [[A:%.*]] to i64 +; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 [[APP_PTR_INT]], [[APP_MEM_MASK]] +; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3 +; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]] +; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr +; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8 +; CHECK-NEXT: [[BAD_DESC:%.*]] = icmp ne ptr [[SHADOW_DESC]], @__tysan_v1_int_o_0 +; CHECK-NEXT: br i1 [[BAD_DESC]], label [[TMP0:%.*]], label [[TMP22:%.*]], !prof [[PROF0:![0-9]+]] +; CHECK: 0: +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq ptr [[SHADOW_DESC]], null +; CHECK-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP20:%.*]] +; CHECK: 2: +; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[SHADOW_PTR_INT]], 8 +; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr +; CHECK-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP4]], align 8 +; CHECK-NEXT: [[TMP6:%.*]] = icmp ne ptr [[TMP5]], null +; CHECK-NEXT: [[TMP7:%.*]] = or i1 false, [[TMP6]] +; CHECK-NEXT: [[TMP8:%.*]] = add i64 [[SHADOW_PTR_INT]], 16 +; CHECK-NEXT: [[TMP9:%.*]] = inttoptr i64 [[TMP8]] to ptr +; CHECK-NEXT: [[TMP10:%.*]] = load ptr, ptr [[TMP9]], align 8 +; CHECK-NEXT: [[TMP11:%.*]] = icmp ne ptr [[TMP10]], null +; CHECK-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]] +; CHECK-NEXT: [[TMP13:%.*]] = add i64 [[SHADOW_PTR_INT]], 24 +; CHECK-NEXT: [[TMP14:%.*]] = inttoptr i64 [[TMP13]] to ptr +; CHECK-NEXT: [[TMP15:%.*]] = load ptr, ptr [[TMP14]], align 8 +; CHECK-NEXT: [[TMP16:%.*]] = icmp ne ptr [[TMP15]], null +; CHECK-NEXT: [[TMP17:%.*]] = or i1 [[TMP12]], [[TMP16]] +; CHECK-NEXT: br i1 [[TMP17]], label [[TMP18:%.*]], label [[TMP19:%.*]], !prof [[PROF0]] +; CHECK: 18: +; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1_int_o_0, i32 1) +; CHECK-NEXT: br label [[TMP19]] +; CHECK: 19: +; CHECK-NEXT: store ptr @__tysan_v1_int_o_0, ptr [[SHADOW_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8 +; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16 +; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24 +; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8 +; CHECK-NEXT: br label [[TMP21:%.*]] +; CHECK: 20: +; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1_int_o_0, i32 1) +; CHECK-NEXT: br label [[TMP21]] +; CHECK: 21: +; CHECK-NEXT: br label [[TMP43:%.*]] +; CHECK: 22: +; CHECK-NEXT: [[TMP23:%.*]] = add i64 [[SHADOW_PTR_INT]], 8 +; CHECK-NEXT: [[TMP24:%.*]] = inttoptr i64 [[TMP23]] to ptr +; CHECK-NEXT: [[TMP25:%.*]] = load ptr, ptr [[TMP24]], align 8 +; CHECK-NEXT: [[TMP26:%.*]] = ptrtoint ptr [[TMP25]] to i64 +; CHECK-NEXT: [[TMP27:%.*]] = icmp sge i64 [[TMP26]], 0 +; CHECK-NEXT: [[TMP28:%.*]] = or i1 false, [[TMP27]] +; CHECK-NEXT: [[TMP29:%.*]] = add i64 [[SHADOW_PTR_INT]], 16 +; CHECK-NEXT: [[TMP30:%.*]] = inttoptr i64 [[TMP29]] to ptr +; CHECK-NEXT: [[TMP31:%.*]] = load ptr, ptr [[TMP30]], align 8 +; CHECK-NEXT: [[TMP32:%.*]] = ptrtoint ptr [[TMP31]] to i64 +; CHECK-NEXT: [[TMP33:%.*]] = icmp sge i64 [[TMP32]], 0 +; CHECK-NEXT: [[TMP34:%.*]] = or i1 [[TMP28]], [[TMP33]] +; CHECK-NEXT: [[TMP35:%.*]] = add i64 [[SHADOW_PTR_INT]], 24 +; CHECK-NEXT: [[TMP36:%.*]] = inttoptr i64 [[TMP35]] to ptr +; CHECK-NEXT: [[TMP37:%.*]] = load ptr, ptr [[TMP36]], align 8 +; CHECK-NEXT: [[TMP38:%.*]] = ptrtoint ptr [[TMP37]] to i64 +; CHECK-NEXT: [[TMP39:%.*]] = icmp sge i64 [[TMP38]], 0 +; CHECK-NEXT: [[TMP40:%.*]] = or i1 [[TMP34]], [[TMP39]] +; CHECK-NEXT: br i1 [[TMP40]], label [[TMP41:%.*]], label [[TMP42:%.*]], !prof [[PROF0]] +; CHECK: 41: +; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1_int_o_0, i32 1) +; CHECK-NEXT: br label [[TMP42]] +; CHECK: 42: +; CHECK-NEXT: br label [[TMP43]] +; CHECK: 43: +; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[A]], align 4, !tbaa [[TBAA1:![0-9]+]] +; CHECK-NEXT: ret i32 [[TMP1]] +; +entry: + %tmp1 = load i32, ptr %a, align 4, !tbaa !3 + ret i32 %tmp1 +} + +define void @test_store(ptr %a) sanitize_type { +; CHECK-LABEL: @test_store( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8 +; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8 +; CHECK-NEXT: [[APP_PTR_INT:%.*]] = ptrtoint ptr [[A:%.*]] to i64 +; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 [[APP_PTR_INT]], [[APP_MEM_MASK]] +; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3 +; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]] +; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr +; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8 +; CHECK-NEXT: [[BAD_DESC:%.*]] = icmp ne ptr [[SHADOW_DESC]], @__tysan_v1___ZTS1v_o_12 +; CHECK-NEXT: br i1 [[BAD_DESC]], label [[TMP0:%.*]], label [[TMP22:%.*]], !prof [[PROF0]] +; CHECK: 0: +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq ptr [[SHADOW_DESC]], null +; CHECK-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP20:%.*]] +; CHECK: 2: +; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[SHADOW_PTR_INT]], 8 +; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr +; CHECK-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP4]], align 8 +; CHECK-NEXT: [[TMP6:%.*]] = icmp ne ptr [[TMP5]], null +; CHECK-NEXT: [[TMP7:%.*]] = or i1 false, [[TMP6]] +; CHECK-NEXT: [[TMP8:%.*]] = add i64 [[SHADOW_PTR_INT]], 16 +; CHECK-NEXT: [[TMP9:%.*]] = inttoptr i64 [[TMP8]] to ptr +; CHECK-NEXT: [[TMP10:%.*]] = load ptr, ptr [[TMP9]], align 8 +; CHECK-NEXT: [[TMP11:%.*]] = icmp ne ptr [[TMP10]], null +; CHECK-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]] +; CHECK-NEXT: [[TMP13:%.*]] = add i64 [[SHADOW_PTR_INT]], 24 +; CHECK-NEXT: [[TMP14:%.*]] = inttoptr i64 [[TMP13]] to ptr +; CHECK-NEXT: [[TMP15:%.*]] = load ptr, ptr [[TMP14]], align 8 +; CHECK-NEXT: [[TMP16:%.*]] = icmp ne ptr [[TMP15]], null +; CHECK-NEXT: [[TMP17:%.*]] = or i1 [[TMP12]], [[TMP16]] +; CHECK-NEXT: br i1 [[TMP17]], label [[TMP18:%.*]], label [[TMP19:%.*]], !prof [[PROF0]] +; CHECK: 18: +; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1___ZTS1v_o_12, i32 2) +; CHECK-NEXT: br label [[TMP19]] +; CHECK: 19: +; CHECK-NEXT: store ptr @__tysan_v1___ZTS1v_o_12, ptr [[SHADOW_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8 +; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16 +; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24 +; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8 +; CHECK-NEXT: br label [[TMP21:%.*]] +; CHECK: 20: +; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1___ZTS1v_o_12, i32 2) +; CHECK-NEXT: br label [[TMP21]] +; CHECK: 21: +; CHECK-NEXT: br label [[TMP43:%.*]] +; CHECK: 22: +; CHECK-NEXT: [[TMP23:%.*]] = add i64 [[SHADOW_PTR_INT]], 8 +; CHECK-NEXT: [[TMP24:%.*]] = inttoptr i64 [[TMP23]] to ptr +; CHECK-NEXT: [[TMP25:%.*]] = load ptr, ptr [[TMP24]], align 8 +; CHECK-NEXT: [[TMP26:%.*]] = ptrtoint ptr [[TMP25]] to i64 +; CHECK-NEXT: [[TMP27:%.*]] = icmp sge i64 [[TMP26]], 0 +; CHECK-NEXT: [[TMP28:%.*]] = or i1 false, [[TMP27]] +; CHECK-NEXT: [[TMP29:%.*]] = add i64 [[SHADOW_PTR_INT]], 16 +; CHECK-NEXT: [[TMP30:%.*]] = inttoptr i64 [[TMP29]] to ptr +; CHECK-NEXT: [[TMP31:%.*]] = load ptr, ptr [[TMP30]], align 8 +; CHECK-NEXT: [[TMP32:%.*]] = ptrtoint ptr [[TMP31]] to i64 +; CHECK-NEXT: [[TMP33:%.*]] = icmp sge i64 [[TMP32]], 0 +; CHECK-NEXT: [[TMP34:%.*]] = or i1 [[TMP28]], [[TMP33]] +; CHECK-NEXT: [[TMP35:%.*]] = add i64 [[SHADOW_PTR_INT]], 24 +; CHECK-NEXT: [[TMP36:%.*]] = inttoptr i64 [[TMP35]] to ptr +; CHECK-NEXT: [[TMP37:%.*]] = load ptr, ptr [[TMP36]], align 8 +; CHECK-NEXT: [[TMP38:%.*]] = ptrtoint ptr [[TMP37]] to i64 +; CHECK-NEXT: [[TMP39:%.*]] = icmp sge i64 [[TMP38]], 0 +; CHECK-NEXT: [[TMP40:%.*]] = or i1 [[TMP34]], [[TMP39]] +; CHECK-NEXT: br i1 [[TMP40]], label [[TMP41:%.*]], label [[TMP42:%.*]], !prof [[PROF0]] +; CHECK: 41: +; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1___ZTS1v_o_12, i32 2) +; CHECK-NEXT: br label [[TMP42]] +; CHECK: 42: +; CHECK-NEXT: br label [[TMP43]] +; CHECK: 43: +; CHECK-NEXT: store i32 42, ptr [[A]], align 4, !tbaa [[TBAA5:![0-9]+]] +; CHECK-NEXT: ret void +; +entry: + store i32 42, ptr %a, align 4, !tbaa !6 + ret void +} + +!0 = !{!"Simple C++ TBAA"} +!1 = !{!"omnipotent char", !0, i64 0} +!2 = !{!"int", !1, i64 0} +!3 = !{!2, !2, i64 0} +!4 = !{!"_ZTS1x", !2, i64 0, !2, i64 4} +!5 = !{!"_ZTS1v", !2, i64 8, !2, i64 12, !4, i64 16} +!6 = !{!5, !2, i64 12} +;. +; CHECK: attributes #[[ATTR0:[0-9]+]] = { sanitize_type } +; CHECK: attributes #[[ATTR1:[0-9]+]] = { nounwind } +;. +; CHECK: [[PROF0]] = !{!"branch_weights", i32 1, i32 100000} +; CHECK: [[TBAA1]] = !{!2, !2, i64 0} +; CHECK: [[META2:![0-9]+]] = !{!"int", !3, i64 0} +; CHECK: [[META3:![0-9]+]] = !{!"omnipotent char", !4, i64 0} +; CHECK: [[META4:![0-9]+]] = !{!"Simple C++ TBAA"} +; CHECK: [[TBAA5]] = !{!6, !2, i64 12} +; CHECK: [[META6:![0-9]+]] = !{!"_ZTS1v", !2, i64 8, !2, i64 12, !7, i64 16} +; CHECK: [[META7:![0-9]+]] = !{!"_ZTS1x", !2, i64 0, !2, i64 4} +;. diff --git a/llvm/test/Instrumentation/TypeSanitizer/byval.ll b/llvm/test/Instrumentation/TypeSanitizer/byval.ll new file mode 100644 index 0000000000000..68ab1327b225b --- /dev/null +++ b/llvm/test/Instrumentation/TypeSanitizer/byval.ll @@ -0,0 +1,88 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals --include-generated-funcs +; Test basic type sanitizer instrumentation. +; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +;. +; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x ptr] [ptr @tysan.module_ctor], section "llvm.metadata" +; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }] +; CHECK: @[[__TYSAN_SHADOW_MEMORY_ADDRESS:[a-zA-Z0-9_$"\\.-]+]] = external global i64 +; CHECK: @[[__TYSAN_APP_MEMORY_MASK:[a-zA-Z0-9_$"\\.-]+]] = external global i64 +;. + +%struct.s20 = type { i32, i32, [24 x i8] } +define void @byval_test(ptr byval(%struct.s20) align 32 %x) sanitize_type { +; CHECK-LABEL: @byval_test( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8 +; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8 +; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[X:%.*]] to i64 +; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], [[APP_MEM_MASK]] +; CHECK-NEXT: [[TMP2:%.*]] = shl i64 [[TMP1]], 3 +; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[TMP2]], [[SHADOW_BASE]] +; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr +; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[TMP4]], i8 0, i64 256, i1 false) +; CHECK-NEXT: ret void +; +entry: + ret void +; NOTE: Ideally, we'd get the type from the caller's copy of the data (instead +; of setting it all to unknown). +} + +%struct = type { ptr, ptr } + +define ptr @test_insert_point(ptr byval(%struct) %v) { +; CHECK-LABEL: @test_insert_point( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8 +; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8 +; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[V:%.*]] to i64 +; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], [[APP_MEM_MASK]] +; CHECK-NEXT: [[TMP2:%.*]] = shl i64 [[TMP1]], 3 +; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[TMP2]], [[SHADOW_BASE]] +; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr +; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[TMP4]], i8 0, i64 128, i1 false) +; CHECK-NEXT: [[NAME:%.*]] = getelementptr inbounds [[STRUCT:%.*]], ptr [[V]], i64 0, i32 1 +; CHECK-NEXT: [[APP_PTR_INT:%.*]] = ptrtoint ptr [[NAME]] to i64 +; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 [[APP_PTR_INT]], [[APP_MEM_MASK]] +; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3 +; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]] +; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr +; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8 +; CHECK-NEXT: [[DESC_SET:%.*]] = icmp eq ptr [[SHADOW_DESC]], null +; CHECK-NEXT: br i1 [[DESC_SET]], label [[SET_TYPE:%.*]], label [[TMP5:%.*]], !prof [[PROF0:![0-9]+]] +; CHECK: set.type: +; CHECK-NEXT: store ptr null, ptr [[SHADOW_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8 +; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16 +; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24 +; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_4_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 32 +; CHECK-NEXT: [[SHADOW_BYTE_4_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_4_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -4 to ptr), ptr [[SHADOW_BYTE_4_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_5_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 40 +; CHECK-NEXT: [[SHADOW_BYTE_5_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_5_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -5 to ptr), ptr [[SHADOW_BYTE_5_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_6_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 48 +; CHECK-NEXT: [[SHADOW_BYTE_6_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_6_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -6 to ptr), ptr [[SHADOW_BYTE_6_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_7_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 56 +; CHECK-NEXT: [[SHADOW_BYTE_7_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_7_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -7 to ptr), ptr [[SHADOW_BYTE_7_PTR]], align 8 +; CHECK-NEXT: br label [[TMP5]] +; CHECK: 5: +; CHECK-NEXT: [[TMP6:%.*]] = load ptr, ptr [[NAME]], align 8 +; CHECK-NEXT: ret ptr [[TMP6]] +; +entry: + %name = getelementptr inbounds %struct, ptr %v, i64 0, i32 1 + %0 = load ptr, ptr %name, align 8 + ret ptr %0 +} diff --git a/llvm/test/Instrumentation/TypeSanitizer/globals.ll b/llvm/test/Instrumentation/TypeSanitizer/globals.ll new file mode 100644 index 0000000000000..05d0fd348444d --- /dev/null +++ b/llvm/test/Instrumentation/TypeSanitizer/globals.ll @@ -0,0 +1,66 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals --include-generated-funcs +; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +@global1 = global i32 0, align 4 +@global2 = global i32 0, align 4 + +; CHECK: @[[GLOBAL1:[a-zA-Z0-9_$"\\.-]+]] = global i32 0, align 4 +; CHECK: @[[GLOBAL2:[a-zA-Z0-9_$"\\.-]+]] = global i32 0, align 4 +; CHECK: @[[__TYSAN_V1_SIMPLE_20C_2B_2B_20TBAA:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, [16 x i8] } { i64 2, i64 0, [16 x i8] c"Simple C++ TBAA\00" }, comdat +; CHECK: @[[__TYSAN_V1_OMNIPOTENT_20CHAR:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [16 x i8] } { i64 2, i64 1, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, i64 0, [16 x i8] c"omnipotent char\00" }, comdat +; CHECK: @[[__TYSAN_V1_INT:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [4 x i8] } { i64 2, i64 1, ptr @__tysan_v1_omnipotent_20char, i64 0, [4 x i8] c"int\00" }, comdat +; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [4 x ptr] [ptr @tysan.module_ctor, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, ptr @__tysan_v1_omnipotent_20char, ptr @__tysan_v1_int], section "llvm.metadata" +; CHECK: @[[__TYSAN_SHADOW_MEMORY_ADDRESS:[a-zA-Z0-9_$"\\.-]+]] = external global i64 +; CHECK: @[[__TYSAN_APP_MEMORY_MASK:[a-zA-Z0-9_$"\\.-]+]] = external global i64 +; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }] +;. +; CHECK-LABEL: define internal void @tysan.module_ctor( +; CHECK-NEXT: call void @__tysan_init() +; CHECK-NEXT: call void @__tysan_set_globals_types() +; CHECK-NEXT: ret void +; +; +; CHECK-LABEL: define internal void @__tysan_set_globals_types( +; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8 +; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8 +; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 ptrtoint (ptr @global1 to i64), [[APP_MEM_MASK]] +; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3 +; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]] +; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr +; CHECK-NEXT: store ptr @__tysan_v1_int, ptr [[SHADOW_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8 +; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16 +; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24 +; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8 +; CHECK-NEXT: [[APP_PTR_MASKED1:%.*]] = and i64 ptrtoint (ptr @global1 to i64), [[APP_MEM_MASK]] +; CHECK-NEXT: [[APP_PTR_SHIFTED2:%.*]] = shl i64 [[APP_PTR_MASKED1]], 3 +; CHECK-NEXT: [[SHADOW_PTR_INT3:%.*]] = add i64 [[APP_PTR_SHIFTED2]], [[SHADOW_BASE]] +; CHECK-NEXT: [[SHADOW_PTR4:%.*]] = inttoptr i64 [[SHADOW_PTR_INT3]] to ptr +; CHECK-NEXT: store ptr @__tysan_v1_int, ptr [[SHADOW_PTR4]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET5:%.*]] = add i64 [[SHADOW_PTR_INT3]], 8 +; CHECK-NEXT: [[SHADOW_BYTE_1_PTR6:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET5]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR6]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET7:%.*]] = add i64 [[SHADOW_PTR_INT3]], 16 +; CHECK-NEXT: [[SHADOW_BYTE_2_PTR8:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET7]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR8]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET9:%.*]] = add i64 [[SHADOW_PTR_INT3]], 24 +; CHECK-NEXT: [[SHADOW_BYTE_3_PTR10:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET9]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR10]], align 8 +; CHECK-NEXT: ret void + + + +!llvm.tysan.globals = !{!13, !14} + +!0 = !{!"Simple C++ TBAA"} +!1 = !{!"omnipotent char", !0, i64 0} +!2 = !{!"int", !1, i64 0} +!13 = !{ptr @global1, !2} +!14 = !{ptr @global1, !2} diff --git a/llvm/test/Instrumentation/TypeSanitizer/invalid-metadata.ll b/llvm/test/Instrumentation/TypeSanitizer/invalid-metadata.ll new file mode 100644 index 0000000000000..4527aa5cf2a01 --- /dev/null +++ b/llvm/test/Instrumentation/TypeSanitizer/invalid-metadata.ll @@ -0,0 +1,25 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals --include-generated-funcs +; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s + +!llvm.tysan.globals = !{!0} + +!0 = distinct !{ptr undef, !1} +!1 = !{!"any pointer", !2, i64 0} +!2 = !{!"omnipotent char", !3, i64 0} +!3 = !{!"Simple C/C++ TBAA"} +;. +; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x ptr] [ptr @tysan.module_ctor], section "llvm.metadata" +; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }] +;. +; CHECK-LABEL: @tysan.module_ctor( +; CHECK-NEXT: call void @__tysan_init() +; CHECK-NEXT: ret void +; +;. +; CHECK: attributes #[[ATTR0:[0-9]+]] = { nounwind } +;. +; CHECK: [[META0:![0-9]+]] = distinct !{ptr undef, !1} +; CHECK: [[META1:![0-9]+]] = !{!"any pointer", !2, i64 0} +; CHECK: [[META2:![0-9]+]] = !{!"omnipotent char", !3, i64 0} +; CHECK: [[META3:![0-9]+]] = !{!"Simple C/C++ TBAA"} +;. diff --git a/llvm/test/Instrumentation/TypeSanitizer/memintrinsics.ll b/llvm/test/Instrumentation/TypeSanitizer/memintrinsics.ll new file mode 100644 index 0000000000000..26f7c186748cb --- /dev/null +++ b/llvm/test/Instrumentation/TypeSanitizer/memintrinsics.ll @@ -0,0 +1,77 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; Test basic type sanitizer instrumentation. +; +; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +declare void @llvm.memset.p0.i64(ptr nocapture, i8, i64, i32, i1) nounwind +declare void @llvm.memmove.p0.p0.i64(ptr nocapture, ptr nocapture readonly, i64, i32, i1) nounwind +declare void @llvm.memcpy.p0.p0.i64(ptr nocapture, ptr nocapture readonly, i64, i32, i1) nounwind + +define void @test_memset(ptr %a, ptr %b) nounwind uwtable sanitize_type { +; CHECK-LABEL: @test_memset( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8 +; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8 +; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[A:%.*]] to i64 +; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], [[APP_MEM_MASK]] +; CHECK-NEXT: [[TMP2:%.*]] = shl i64 [[TMP1]], 3 +; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[TMP2]], [[SHADOW_BASE]] +; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr +; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[TMP4]], i8 0, i64 800, i1 false) +; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 1 [[A]], i8 0, i64 100, i1 false) +; CHECK-NEXT: ret void +; + entry: + tail call void @llvm.memset.p0.i64(ptr %a, i8 0, i64 100, i32 1, i1 false) + ret void +} + +define void @test_memmove(ptr %a, ptr %b) nounwind uwtable sanitize_type { +; CHECK-LABEL: @test_memmove( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8 +; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8 +; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[A:%.*]] to i64 +; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], [[APP_MEM_MASK]] +; CHECK-NEXT: [[TMP2:%.*]] = shl i64 [[TMP1]], 3 +; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[TMP2]], [[SHADOW_BASE]] +; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr +; CHECK-NEXT: [[TMP5:%.*]] = ptrtoint ptr [[B:%.*]] to i64 +; CHECK-NEXT: [[TMP6:%.*]] = and i64 [[TMP5]], [[APP_MEM_MASK]] +; CHECK-NEXT: [[TMP7:%.*]] = shl i64 [[TMP6]], 3 +; CHECK-NEXT: [[TMP8:%.*]] = add i64 [[TMP7]], [[SHADOW_BASE]] +; CHECK-NEXT: [[TMP9:%.*]] = inttoptr i64 [[TMP8]] to ptr +; CHECK-NEXT: call void @llvm.memmove.p0.p0.i64(ptr align 8 [[TMP4]], ptr align 8 [[TMP9]], i64 800, i1 false) +; CHECK-NEXT: call void @llvm.memmove.p0.p0.i64(ptr align 1 [[A]], ptr align 1 [[B]], i64 100, i1 false) +; CHECK-NEXT: ret void +; + entry: + tail call void @llvm.memmove.p0.p0.i64(ptr %a, ptr %b, i64 100, i32 1, i1 false) + ret void +} + +define void @test_memcpy(ptr %a, ptr %b) nounwind uwtable sanitize_type { +; CHECK-LABEL: @test_memcpy( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8 +; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8 +; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[A:%.*]] to i64 +; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], [[APP_MEM_MASK]] +; CHECK-NEXT: [[TMP2:%.*]] = shl i64 [[TMP1]], 3 +; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[TMP2]], [[SHADOW_BASE]] +; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr +; CHECK-NEXT: [[TMP5:%.*]] = ptrtoint ptr [[B:%.*]] to i64 +; CHECK-NEXT: [[TMP6:%.*]] = and i64 [[TMP5]], [[APP_MEM_MASK]] +; CHECK-NEXT: [[TMP7:%.*]] = shl i64 [[TMP6]], 3 +; CHECK-NEXT: [[TMP8:%.*]] = add i64 [[TMP7]], [[SHADOW_BASE]] +; CHECK-NEXT: [[TMP9:%.*]] = inttoptr i64 [[TMP8]] to ptr +; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[TMP4]], ptr align 8 [[TMP9]], i64 800, i1 false) +; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[A]], ptr align 1 [[B]], i64 100, i1 false) +; CHECK-NEXT: ret void +; + entry: + tail call void @llvm.memcpy.p0.p0.i64(ptr %a, ptr %b, i64 100, i32 1, i1 false) + ret void +} diff --git a/llvm/test/Instrumentation/TypeSanitizer/nosanitize.ll b/llvm/test/Instrumentation/TypeSanitizer/nosanitize.ll new file mode 100644 index 0000000000000..67e408439ec16 --- /dev/null +++ b/llvm/test/Instrumentation/TypeSanitizer/nosanitize.ll @@ -0,0 +1,39 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals +; Test basic type sanitizer instrumentation. +; +; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +;. +; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x ptr] [ptr @tysan.module_ctor], section "llvm.metadata" +; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }] +;. +define i32 @test_load(ptr %a) sanitize_type { +; CHECK-LABEL: @test_load( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[A:%.*]], align 4, !tbaa [[TBAA0:![0-9]+]], !nosanitize !4 +; CHECK-NEXT: ret i32 [[TMP1]] +; +entry: + %tmp1 = load i32, ptr %a, align 4, !tbaa !3, !nosanitize !{} + ret i32 %tmp1 +} + +!0 = !{!"Simple C++ TBAA"} +!1 = !{!"omnipotent char", !0, i64 0} +!2 = !{!"int", !1, i64 0} +!3 = !{!2, !2, i64 0} +!4 = !{!"_ZTS1x", !2, i64 0, !2, i64 4} +!5 = !{!"_ZTS1v", !2, i64 8, !2, i64 12, !4, i64 16} +!6 = !{!5, !2, i64 12} +;. +; CHECK: attributes #[[ATTR0:[0-9]+]] = { sanitize_type } +; CHECK: attributes #[[ATTR1:[0-9]+]] = { nounwind } +;. +; CHECK: [[TBAA0]] = !{!1, !1, i64 0} +; CHECK: [[META1:![0-9]+]] = !{!"int", !2, i64 0} +; CHECK: [[META2:![0-9]+]] = !{!"omnipotent char", !3, i64 0} +; CHECK: [[META3:![0-9]+]] = !{!"Simple C++ TBAA"} +; CHECK: [[META4:![0-9]+]] = !{} +;. diff --git a/llvm/test/Instrumentation/TypeSanitizer/sanitize-no-tbaa.ll b/llvm/test/Instrumentation/TypeSanitizer/sanitize-no-tbaa.ll new file mode 100644 index 0000000000000..3cb7b8365866b --- /dev/null +++ b/llvm/test/Instrumentation/TypeSanitizer/sanitize-no-tbaa.ll @@ -0,0 +1,180 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; Test basic type sanitizer instrumentation. +; +; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +define i32 @test_load_unk(ptr %a) sanitize_type { +; CHECK-LABEL: @test_load_unk( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8 +; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8 +; CHECK-NEXT: [[APP_PTR_INT:%.*]] = ptrtoint ptr [[A:%.*]] to i64 +; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 [[APP_PTR_INT]], [[APP_MEM_MASK]] +; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3 +; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]] +; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr +; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8 +; CHECK-NEXT: [[BAD_DESC:%.*]] = icmp ne ptr [[SHADOW_DESC]], null +; CHECK-NEXT: br i1 [[BAD_DESC]], label [[TMP0:%.*]], label [[TMP22:%.*]], !prof [[PROF0:![0-9]+]] +; CHECK: 0: +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq ptr [[SHADOW_DESC]], null +; CHECK-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP20:%.*]] +; CHECK: 2: +; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[SHADOW_PTR_INT]], 8 +; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr +; CHECK-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP4]], align 8 +; CHECK-NEXT: [[TMP6:%.*]] = icmp ne ptr [[TMP5]], null +; CHECK-NEXT: [[TMP7:%.*]] = or i1 false, [[TMP6]] +; CHECK-NEXT: [[TMP8:%.*]] = add i64 [[SHADOW_PTR_INT]], 16 +; CHECK-NEXT: [[TMP9:%.*]] = inttoptr i64 [[TMP8]] to ptr +; CHECK-NEXT: [[TMP10:%.*]] = load ptr, ptr [[TMP9]], align 8 +; CHECK-NEXT: [[TMP11:%.*]] = icmp ne ptr [[TMP10]], null +; CHECK-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]] +; CHECK-NEXT: [[TMP13:%.*]] = add i64 [[SHADOW_PTR_INT]], 24 +; CHECK-NEXT: [[TMP14:%.*]] = inttoptr i64 [[TMP13]] to ptr +; CHECK-NEXT: [[TMP15:%.*]] = load ptr, ptr [[TMP14]], align 8 +; CHECK-NEXT: [[TMP16:%.*]] = icmp ne ptr [[TMP15]], null +; CHECK-NEXT: [[TMP17:%.*]] = or i1 [[TMP12]], [[TMP16]] +; CHECK-NEXT: br i1 [[TMP17]], label [[TMP18:%.*]], label [[TMP19:%.*]], !prof [[PROF0]] +; CHECK: 18: +; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr null, i32 1) +; CHECK-NEXT: br label [[TMP19]] +; CHECK: 19: +; CHECK-NEXT: store ptr null, ptr [[SHADOW_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8 +; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16 +; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24 +; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8 +; CHECK-NEXT: br label [[TMP21:%.*]] +; CHECK: 20: +; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr null, i32 1) +; CHECK-NEXT: br label [[TMP21]] +; CHECK: 21: +; CHECK-NEXT: br label [[TMP43:%.*]] +; CHECK: 22: +; CHECK-NEXT: [[TMP23:%.*]] = add i64 [[SHADOW_PTR_INT]], 8 +; CHECK-NEXT: [[TMP24:%.*]] = inttoptr i64 [[TMP23]] to ptr +; CHECK-NEXT: [[TMP25:%.*]] = load ptr, ptr [[TMP24]], align 8 +; CHECK-NEXT: [[TMP26:%.*]] = ptrtoint ptr [[TMP25]] to i64 +; CHECK-NEXT: [[TMP27:%.*]] = icmp sge i64 [[TMP26]], 0 +; CHECK-NEXT: [[TMP28:%.*]] = or i1 false, [[TMP27]] +; CHECK-NEXT: [[TMP29:%.*]] = add i64 [[SHADOW_PTR_INT]], 16 +; CHECK-NEXT: [[TMP30:%.*]] = inttoptr i64 [[TMP29]] to ptr +; CHECK-NEXT: [[TMP31:%.*]] = load ptr, ptr [[TMP30]], align 8 +; CHECK-NEXT: [[TMP32:%.*]] = ptrtoint ptr [[TMP31]] to i64 +; CHECK-NEXT: [[TMP33:%.*]] = icmp sge i64 [[TMP32]], 0 +; CHECK-NEXT: [[TMP34:%.*]] = or i1 [[TMP28]], [[TMP33]] +; CHECK-NEXT: [[TMP35:%.*]] = add i64 [[SHADOW_PTR_INT]], 24 +; CHECK-NEXT: [[TMP36:%.*]] = inttoptr i64 [[TMP35]] to ptr +; CHECK-NEXT: [[TMP37:%.*]] = load ptr, ptr [[TMP36]], align 8 +; CHECK-NEXT: [[TMP38:%.*]] = ptrtoint ptr [[TMP37]] to i64 +; CHECK-NEXT: [[TMP39:%.*]] = icmp sge i64 [[TMP38]], 0 +; CHECK-NEXT: [[TMP40:%.*]] = or i1 [[TMP34]], [[TMP39]] +; CHECK-NEXT: br i1 [[TMP40]], label [[TMP41:%.*]], label [[TMP42:%.*]], !prof [[PROF0]] +; CHECK: 41: +; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr null, i32 1) +; CHECK-NEXT: br label [[TMP42]] +; CHECK: 42: +; CHECK-NEXT: br label [[TMP43]] +; CHECK: 43: +; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[A]], align 4 +; CHECK-NEXT: ret i32 [[TMP1]] +; +entry: + %tmp1 = load i32, ptr %a, align 4 + ret i32 %tmp1 +} + +define void @test_store_unk(ptr %a) sanitize_type { +; CHECK-LABEL: @test_store_unk( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8 +; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8 +; CHECK-NEXT: [[APP_PTR_INT:%.*]] = ptrtoint ptr [[A:%.*]] to i64 +; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 [[APP_PTR_INT]], [[APP_MEM_MASK]] +; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3 +; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]] +; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr +; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8 +; CHECK-NEXT: [[BAD_DESC:%.*]] = icmp ne ptr [[SHADOW_DESC]], null +; CHECK-NEXT: br i1 [[BAD_DESC]], label [[TMP0:%.*]], label [[TMP22:%.*]], !prof [[PROF0]] +; CHECK: 0: +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq ptr [[SHADOW_DESC]], null +; CHECK-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP20:%.*]] +; CHECK: 2: +; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[SHADOW_PTR_INT]], 8 +; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr +; CHECK-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP4]], align 8 +; CHECK-NEXT: [[TMP6:%.*]] = icmp ne ptr [[TMP5]], null +; CHECK-NEXT: [[TMP7:%.*]] = or i1 false, [[TMP6]] +; CHECK-NEXT: [[TMP8:%.*]] = add i64 [[SHADOW_PTR_INT]], 16 +; CHECK-NEXT: [[TMP9:%.*]] = inttoptr i64 [[TMP8]] to ptr +; CHECK-NEXT: [[TMP10:%.*]] = load ptr, ptr [[TMP9]], align 8 +; CHECK-NEXT: [[TMP11:%.*]] = icmp ne ptr [[TMP10]], null +; CHECK-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]] +; CHECK-NEXT: [[TMP13:%.*]] = add i64 [[SHADOW_PTR_INT]], 24 +; CHECK-NEXT: [[TMP14:%.*]] = inttoptr i64 [[TMP13]] to ptr +; CHECK-NEXT: [[TMP15:%.*]] = load ptr, ptr [[TMP14]], align 8 +; CHECK-NEXT: [[TMP16:%.*]] = icmp ne ptr [[TMP15]], null +; CHECK-NEXT: [[TMP17:%.*]] = or i1 [[TMP12]], [[TMP16]] +; CHECK-NEXT: br i1 [[TMP17]], label [[TMP18:%.*]], label [[TMP19:%.*]], !prof [[PROF0]] +; CHECK: 18: +; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr null, i32 2) +; CHECK-NEXT: br label [[TMP19]] +; CHECK: 19: +; CHECK-NEXT: store ptr null, ptr [[SHADOW_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8 +; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16 +; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8 +; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24 +; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr +; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8 +; CHECK-NEXT: br label [[TMP21:%.*]] +; CHECK: 20: +; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr null, i32 2) +; CHECK-NEXT: br label [[TMP21]] +; CHECK: 21: +; CHECK-NEXT: br label [[TMP43:%.*]] +; CHECK: 22: +; CHECK-NEXT: [[TMP23:%.*]] = add i64 [[SHADOW_PTR_INT]], 8 +; CHECK-NEXT: [[TMP24:%.*]] = inttoptr i64 [[TMP23]] to ptr +; CHECK-NEXT: [[TMP25:%.*]] = load ptr, ptr [[TMP24]], align 8 +; CHECK-NEXT: [[TMP26:%.*]] = ptrtoint ptr [[TMP25]] to i64 +; CHECK-NEXT: [[TMP27:%.*]] = icmp sge i64 [[TMP26]], 0 +; CHECK-NEXT: [[TMP28:%.*]] = or i1 false, [[TMP27]] +; CHECK-NEXT: [[TMP29:%.*]] = add i64 [[SHADOW_PTR_INT]], 16 +; CHECK-NEXT: [[TMP30:%.*]] = inttoptr i64 [[TMP29]] to ptr +; CHECK-NEXT: [[TMP31:%.*]] = load ptr, ptr [[TMP30]], align 8 +; CHECK-NEXT: [[TMP32:%.*]] = ptrtoint ptr [[TMP31]] to i64 +; CHECK-NEXT: [[TMP33:%.*]] = icmp sge i64 [[TMP32]], 0 +; CHECK-NEXT: [[TMP34:%.*]] = or i1 [[TMP28]], [[TMP33]] +; CHECK-NEXT: [[TMP35:%.*]] = add i64 [[SHADOW_PTR_INT]], 24 +; CHECK-NEXT: [[TMP36:%.*]] = inttoptr i64 [[TMP35]] to ptr +; CHECK-NEXT: [[TMP37:%.*]] = load ptr, ptr [[TMP36]], align 8 +; CHECK-NEXT: [[TMP38:%.*]] = ptrtoint ptr [[TMP37]] to i64 +; CHECK-NEXT: [[TMP39:%.*]] = icmp sge i64 [[TMP38]], 0 +; CHECK-NEXT: [[TMP40:%.*]] = or i1 [[TMP34]], [[TMP39]] +; CHECK-NEXT: br i1 [[TMP40]], label [[TMP41:%.*]], label [[TMP42:%.*]], !prof [[PROF0]] +; CHECK: 41: +; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr null, i32 2) +; CHECK-NEXT: br label [[TMP42]] +; CHECK: 42: +; CHECK-NEXT: br label [[TMP43]] +; CHECK: 43: +; CHECK-NEXT: store i32 42, ptr [[A]], align 4 +; CHECK-NEXT: ret void +; +entry: + store i32 42, ptr %a, align 4 + ret void +} diff --git a/llvm/test/Instrumentation/TypeSanitizer/swifterror.ll b/llvm/test/Instrumentation/TypeSanitizer/swifterror.ll new file mode 100644 index 0000000000000..5711fb4b839f4 --- /dev/null +++ b/llvm/test/Instrumentation/TypeSanitizer/swifterror.ll @@ -0,0 +1,24 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; Test basic type sanitizer instrumentation. +; +; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +define void @test_swifterror(ptr swifterror) sanitize_type { +; CHECK-LABEL: @test_swifterror( +; CHECK-NEXT: [[SWIFTERROR_PTR_VALUE:%.*]] = load ptr, ptr [[TMP0:%.*]], align 8 +; CHECK-NEXT: ret void +; + %swifterror_ptr_value = load ptr, ptr %0 + ret void +} + +define void @test_swifterror_2(ptr swifterror) sanitize_type { +; CHECK-LABEL: @test_swifterror_2( +; CHECK-NEXT: store ptr null, ptr [[TMP0:%.*]], align 8 +; CHECK-NEXT: ret void +; + store ptr null, ptr %0 + ret void +} From e5158df6521b4b210ff8d9f510771c4d1b973e68 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Thu, 18 Apr 2024 22:52:16 +0100 Subject: [PATCH 02/24] !fixup address comments, thanks --- .../llvm/Analysis/TypeBasedAliasAnalysis.h | 8 ++++++ llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp | 26 ++++--------------- .../Instrumentation/TypeSanitizer.cpp | 22 +++++++--------- .../Analysis/AliasSetTrackerTest.cpp | 2 +- 4 files changed, 24 insertions(+), 34 deletions(-) diff --git a/llvm/include/llvm/Analysis/TypeBasedAliasAnalysis.h b/llvm/include/llvm/Analysis/TypeBasedAliasAnalysis.h index 36dd39c033aa6..0ec84a461a3db 100644 --- a/llvm/include/llvm/Analysis/TypeBasedAliasAnalysis.h +++ b/llvm/include/llvm/Analysis/TypeBasedAliasAnalysis.h @@ -29,7 +29,15 @@ class MemoryLocation; /// A simple AA result that uses TBAA metadata to answer queries. class TypeBasedAAResult : public AAResultBase { + /// True if type sanitizer is enabled. When TypeSanitizer is used, don't use + /// TBAA information for alias analysis as this might cause us to remove + /// memory accesses that we need to verify at runtime. + bool UsingTypeSanitizer; + public: + TypeBasedAAResult(bool UsingTypeSanitizer) + : UsingTypeSanitizer(UsingTypeSanitizer) {} + /// Handle invalidation events from the new pass manager. /// /// By definition, this result is stateless and so remains valid. diff --git a/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp b/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp index a499e16ff0097..08c7736af477e 100644 --- a/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp +++ b/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp @@ -372,26 +372,10 @@ static bool isStructPathTBAA(const MDNode *MD) { return isa(MD->getOperand(0)) && MD->getNumOperands() >= 3; } -// When using the TypeSanitizer, don't use TBAA information for alias analysis. -// This might cause us to remove memory accesses that we need to verify at -// runtime. -static bool usingSanitizeType(const Value *V) { - const Function *F; - - if (auto *I = dyn_cast(V)) - F = I->getParent()->getParent(); - else if (auto *A = dyn_cast(V)) - F = A->getParent(); - else - return false; - - return F->hasFnAttribute(Attribute::SanitizeType); -} - AliasResult TypeBasedAAResult::alias(const MemoryLocation &LocA, const MemoryLocation &LocB, AAQueryInfo &AAQI, const Instruction *) { - if (!EnableTBAA || usingSanitizeType(LocA.Ptr) || usingSanitizeType(LocB.Ptr)) + if (!EnableTBAA || UsingTypeSanitizer || UsingTypeSanitizer) return AAResultBase::alias(LocA, LocB, AAQI, nullptr); if (Aliases(LocA.AATags.TBAA, LocB.AATags.TBAA)) @@ -442,7 +426,7 @@ MemoryEffects TypeBasedAAResult::getMemoryEffects(const Function *F) { ModRefInfo TypeBasedAAResult::getModRefInfo(const CallBase *Call, const MemoryLocation &Loc, AAQueryInfo &AAQI) { - if (!EnableTBAA || usingSanitizeType(Call)) + if (!EnableTBAA || UsingTypeSanitizer) return AAResultBase::getModRefInfo(Call, Loc, AAQI); if (const MDNode *L = Loc.AATags.TBAA) @@ -456,7 +440,7 @@ ModRefInfo TypeBasedAAResult::getModRefInfo(const CallBase *Call, ModRefInfo TypeBasedAAResult::getModRefInfo(const CallBase *Call1, const CallBase *Call2, AAQueryInfo &AAQI) { - if (!EnableTBAA || usingSanitizeType(Call1)) + if (!EnableTBAA || UsingTypeSanitizer) return AAResultBase::getModRefInfo(Call1, Call2, AAQI); if (const MDNode *M1 = Call1->getMetadata(LLVMContext::MD_tbaa)) @@ -724,7 +708,7 @@ bool TypeBasedAAResult::Aliases(const MDNode *A, const MDNode *B) const { AnalysisKey TypeBasedAA::Key; TypeBasedAAResult TypeBasedAA::run(Function &F, FunctionAnalysisManager &AM) { - return TypeBasedAAResult(); + return TypeBasedAAResult(F.hasFnAttribute(Attribute::SanitizeType)); } char TypeBasedAAWrapperPass::ID = 0; @@ -740,7 +724,7 @@ TypeBasedAAWrapperPass::TypeBasedAAWrapperPass() : ImmutablePass(ID) { } bool TypeBasedAAWrapperPass::doInitialization(Module &M) { - Result.reset(new TypeBasedAAResult()); + Result.reset(new TypeBasedAAResult(false)); return false; } diff --git a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp index ed4aba4ad612d..2ca9b8a8d8ce4 100644 --- a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp @@ -110,6 +110,7 @@ struct TypeSanitizer { TypeNameMapTy &TypeNames, Module &M); const Triple TargetTriple; + Regex AnonNameRegex; Type *IntptrTy; uint64_t PtrShift; IntegerType *OrdTy; @@ -122,7 +123,8 @@ struct TypeSanitizer { } // namespace TypeSanitizer::TypeSanitizer(Module &M) - : TargetTriple(Triple(M.getTargetTriple())) { + : TargetTriple(Triple(M.getTargetTriple())), + AnonNameRegex("^_ZTS.*N[1-9][0-9]*_GLOBAL__N") { const DataLayout &DL = M.getDataLayout(); IntptrTy = DL.getIntPtrType(M.getContext()); PtrShift = countr_zero(IntptrTy->getPrimitiveSizeInBits() / 8); @@ -237,16 +239,6 @@ static std::string encodeName(StringRef Name) { return Output; } -static bool isAnonymousNamespaceName(StringRef Name) { - // Types that are in an anonymous namespace are local to this module. - // FIXME: This should really be marked by the frontend in the metadata - // instead of having us guess this from the mangled name. Moreover, the regex - // here can pick up (unlikely) names in the non-reserved namespace (because - // it needs to search into the type to pick up cases where the type in the - // anonymous namespace is a template parameter, etc.). - return AnonNameRegex.match(Name); -} - std::string TypeSanitizer::getAnonymousStructIdentifier(const MDNode *MD, TypeNameMapTy &TypeNames) { @@ -352,7 +344,13 @@ bool TypeSanitizer::generateBaseTypeDescriptor( TDSubTys.push_back(IntptrTy); TDSubData.push_back(ConstantInt::get(IntptrTy, Members.size())); - bool ShouldBeComdat = !isAnonymousNamespaceName(NameNode->getString()); + // Types that are in an anonymous namespace are local to this module. + // FIXME: This should really be marked by the frontend in the metadata + // instead of having us guess this from the mangled name. Moreover, the regex + // here can pick up (unlikely) names in the non-reserved namespace (because + // it needs to search into the type to pick up cases where the type in the + // anonymous namespace is a template parameter, etc.). + bool ShouldBeComdat = !AnonNameRegex.match(NameNode->getString()); for (auto &Member : Members) { TDSubTys.push_back(Member.first->getType()); TDSubData.push_back(Member.first); diff --git a/llvm/unittests/Analysis/AliasSetTrackerTest.cpp b/llvm/unittests/Analysis/AliasSetTrackerTest.cpp index 68bd41a1e8589..e784e6eefb79c 100644 --- a/llvm/unittests/Analysis/AliasSetTrackerTest.cpp +++ b/llvm/unittests/Analysis/AliasSetTrackerTest.cpp @@ -62,7 +62,7 @@ TEST(AliasSetTracker, AliasUnknownInst) { TargetLibraryInfoImpl TLII(Trip); TargetLibraryInfo TLI(TLII); AAResults AA(TLI); - TypeBasedAAResult TBAAR; + TypeBasedAAResult TBAAR(false); AA.addAAResult(TBAAR); // Initialize the alias set tracker for the @test function. From 9e30a88cd14462349497b3742f81bb2d1319ded3 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Thu, 27 Jun 2024 15:08:19 +0100 Subject: [PATCH 03/24] !fiupx address comments, thanks! --- llvm/include/llvm/IR/Attributes.td | 2 +- .../Instrumentation/TypeSanitizer.cpp | 24 +++++++++---------- ...-with-offfset.ll => access-with-offset.ll} | 0 3 files changed, 12 insertions(+), 14 deletions(-) rename llvm/test/Instrumentation/TypeSanitizer/{access-with-offfset.ll => access-with-offset.ll} (100%) diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td index 179238bc73383..61955cf883c3f 100644 --- a/llvm/include/llvm/IR/Attributes.td +++ b/llvm/include/llvm/IR/Attributes.td @@ -318,7 +318,7 @@ def SanitizeAddress : EnumAttr<"sanitize_address", IntersectPreserve, [FnAttr]>; def SanitizeThread : EnumAttr<"sanitize_thread", IntersectPreserve, [FnAttr]>; /// TypeSanitizer is on. -def SanitizeType : EnumAttr<"sanitize_type", [FnAttr]>; +def SanitizeType : EnumAttr<"sanitize_type", IntersectPreserve, [FnAttr]>; /// MemorySanitizer is on. def SanitizeMemory : EnumAttr<"sanitize_memory", IntersectPreserve, [FnAttr]>; diff --git a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp index 2ca9b8a8d8ce4..6f5f7108ada0d 100644 --- a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp @@ -143,9 +143,9 @@ void TypeSanitizer::initializeCallbacks(Module &M) { TysanCheck = cast( M.getOrInsertFunction(kTysanCheckName, Attr, IRB.getVoidTy(), IRB.getPtrTy(), // Pointer to data to be read. - OrdTy, // Size of the data in bytes. + OrdTy, // Size of the data in bytes. IRB.getPtrTy(), // Pointer to type descriptor. - OrdTy // Flags. + OrdTy // Flags. ) .getCallee()); @@ -601,7 +601,7 @@ bool TypeSanitizer::instrumentWithShadowUpdate( Value *ShadowDataInt = ConvertToShadowDataInt(IRB, Ptr, IntptrTy, PtrShift, ShadowBase, AppMemMask); - Type *Int8PtrPtrTy = IRB.getPtrTy()->getPointerTo(); + Type *Int8PtrPtrTy = PointerType::get(IRB.getPtrTy(), 0); Value *ShadowData = IRB.CreateIntToPtr(ShadowDataInt, Int8PtrPtrTy, "shadow.ptr"); @@ -637,8 +637,7 @@ bool TypeSanitizer::instrumentWithShadowUpdate( Constant *Flags = ConstantInt::get(OrdTy, (int)IsRead | (((int)IsWrite) << 1)); - Value *LoadedTD = - IRB.CreateLoad(IRB.getPtrTy(), ShadowData, "shadow.desc"); + Value *LoadedTD = IRB.CreateLoad(IRB.getPtrTy(), ShadowData, "shadow.desc"); if (SanitizeFunction) { Value *BadTDCmp = IRB.CreateICmpNE(LoadedTD, TD, "bad.desc"); Instruction *BadTDTerm, *GoodTDTerm; @@ -673,16 +672,16 @@ bool TypeSanitizer::instrumentWithShadowUpdate( Instruction *BadUTDTerm = SplitBlockAndInsertIfThen( NotAllUnkTD, BeforeSetType, false, UnlikelyBW); IRB.SetInsertPoint(BadUTDTerm); - IRB.CreateCall(TysanCheck, {IRB.CreateBitCast(Ptr, IRB.getPtrTy()), - Size, (Value *)TD, (Value *)Flags}); + IRB.CreateCall(TysanCheck, {IRB.CreateBitCast(Ptr, IRB.getPtrTy()), Size, + (Value *)TD, (Value *)Flags}); IRB.SetInsertPoint(BeforeSetType); SetType(); // We have a non-trivial mismatch. Call the runtime. IRB.SetInsertPoint(MismatchTerm); - IRB.CreateCall(TysanCheck, {IRB.CreateBitCast(Ptr, IRB.getPtrTy()), - Size, (Value *)TD, (Value *)Flags}); + IRB.CreateCall(TysanCheck, {IRB.CreateBitCast(Ptr, IRB.getPtrTy()), Size, + (Value *)TD, (Value *)Flags}); // We appear to have the right type. Make sure that all other bytes in // the type are still marked as interior bytes. If not, call the runtime. @@ -703,8 +702,8 @@ bool TypeSanitizer::instrumentWithShadowUpdate( Instruction *BadITDTerm = SplitBlockAndInsertIfThen( NotAllBadTD, &*IRB.GetInsertPoint(), false, UnlikelyBW); IRB.SetInsertPoint(BadITDTerm); - IRB.CreateCall(TysanCheck, {IRB.CreateBitCast(Ptr, IRB.getPtrTy()), - Size, (Value *)TD, (Value *)Flags}); + IRB.CreateCall(TysanCheck, {IRB.CreateBitCast(Ptr, IRB.getPtrTy()), Size, + (Value *)TD, (Value *)Flags}); } else { // If we're not sanitizing this function, then we only care whether we // need to *set* the type. @@ -843,8 +842,7 @@ bool TypeSanitizer::instrumentMemInst(Value *V, Value *&ShadowBase, IRB.CreateAnd(IRB.CreatePtrToInt(Src, IntptrTy), AppMemMask), PtrShift), ShadowBase); - Value *SrcShadowData = - IRB.CreateIntToPtr(SrcShadowDataInt, IRB.getPtrTy()); + Value *SrcShadowData = IRB.CreateIntToPtr(SrcShadowDataInt, IRB.getPtrTy()); if (NeedsMemMove) { IRB.CreateMemMove(ShadowData, Align(1u << PtrShift), SrcShadowData, diff --git a/llvm/test/Instrumentation/TypeSanitizer/access-with-offfset.ll b/llvm/test/Instrumentation/TypeSanitizer/access-with-offset.ll similarity index 100% rename from llvm/test/Instrumentation/TypeSanitizer/access-with-offfset.ll rename to llvm/test/Instrumentation/TypeSanitizer/access-with-offset.ll From 557abfc62ecc286af9de21a2483633fcace63e66 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Fri, 6 Dec 2024 10:39:03 +0000 Subject: [PATCH 04/24] !fixup remove Instrumentation.h include --- llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp index 6f5f7108ada0d..4b2820ff03f07 100644 --- a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp @@ -37,7 +37,6 @@ #include "llvm/Support/MathExtras.h" #include "llvm/Support/Regex.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/Local.h" #include "llvm/Transforms/Utils/ModuleUtils.h" From f0355888d41b0061cf2bddb3942c57b590b4ee8b Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Fri, 6 Dec 2024 13:26:07 +0000 Subject: [PATCH 05/24] !fixup address latest comments, thanks! --- .../llvm/Analysis/TypeBasedAliasAnalysis.h | 4 + llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp | 16 +- .../Instrumentation/TypeSanitizer.cpp | 181 +++++++++--------- .../TypeSanitizer/invalid-metadata.ll | 17 +- 4 files changed, 116 insertions(+), 102 deletions(-) diff --git a/llvm/include/llvm/Analysis/TypeBasedAliasAnalysis.h b/llvm/include/llvm/Analysis/TypeBasedAliasAnalysis.h index 0ec84a461a3db..e70f35174e4ca 100644 --- a/llvm/include/llvm/Analysis/TypeBasedAliasAnalysis.h +++ b/llvm/include/llvm/Analysis/TypeBasedAliasAnalysis.h @@ -60,6 +60,10 @@ class TypeBasedAAResult : public AAResultBase { private: bool Aliases(const MDNode *A, const MDNode *B) const; + + /// Returns true if TBAA metadata should be used, that is if TBAA is enabled + /// and type sanitizer is not used. + bool shouldUseTBAA() const; }; /// Analysis pass providing a never-invalidated alias analysis result. diff --git a/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp b/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp index 08c7736af477e..98da4e37a1404 100644 --- a/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp +++ b/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp @@ -375,7 +375,7 @@ static bool isStructPathTBAA(const MDNode *MD) { AliasResult TypeBasedAAResult::alias(const MemoryLocation &LocA, const MemoryLocation &LocB, AAQueryInfo &AAQI, const Instruction *) { - if (!EnableTBAA || UsingTypeSanitizer || UsingTypeSanitizer) + if (!shouldUseTBAA()) return AAResultBase::alias(LocA, LocB, AAQI, nullptr); if (Aliases(LocA.AATags.TBAA, LocB.AATags.TBAA)) @@ -388,7 +388,7 @@ AliasResult TypeBasedAAResult::alias(const MemoryLocation &LocA, ModRefInfo TypeBasedAAResult::getModRefInfoMask(const MemoryLocation &Loc, AAQueryInfo &AAQI, bool IgnoreLocals) { - if (!EnableTBAA) + if (!shouldUseTBAA()) return ModRefInfo::ModRef; const MDNode *M = Loc.AATags.TBAA; @@ -406,7 +406,7 @@ ModRefInfo TypeBasedAAResult::getModRefInfoMask(const MemoryLocation &Loc, MemoryEffects TypeBasedAAResult::getMemoryEffects(const CallBase *Call, AAQueryInfo &AAQI) { - if (!EnableTBAA) + if (!shouldUseTBAA()) return MemoryEffects::unknown(); // If this is an "immutable" type, the access is not observable. @@ -426,7 +426,7 @@ MemoryEffects TypeBasedAAResult::getMemoryEffects(const Function *F) { ModRefInfo TypeBasedAAResult::getModRefInfo(const CallBase *Call, const MemoryLocation &Loc, AAQueryInfo &AAQI) { - if (!EnableTBAA || UsingTypeSanitizer) + if (!shouldUseTBAA()) return AAResultBase::getModRefInfo(Call, Loc, AAQI); if (const MDNode *L = Loc.AATags.TBAA) @@ -440,7 +440,7 @@ ModRefInfo TypeBasedAAResult::getModRefInfo(const CallBase *Call, ModRefInfo TypeBasedAAResult::getModRefInfo(const CallBase *Call1, const CallBase *Call2, AAQueryInfo &AAQI) { - if (!EnableTBAA || UsingTypeSanitizer) + if (!shouldUseTBAA()) return AAResultBase::getModRefInfo(Call1, Call2, AAQI); if (const MDNode *M1 = Call1->getMetadata(LLVMContext::MD_tbaa)) @@ -705,6 +705,10 @@ bool TypeBasedAAResult::Aliases(const MDNode *A, const MDNode *B) const { return matchAccessTags(A, B); } +bool TypeBasedAAResult::shouldUseTBAA() const { + return EnableTBAA && !UsingTypeSanitizer; +} + AnalysisKey TypeBasedAA::Key; TypeBasedAAResult TypeBasedAA::run(Function &F, FunctionAnalysisManager &AM) { @@ -724,7 +728,7 @@ TypeBasedAAWrapperPass::TypeBasedAAWrapperPass() : ImmutablePass(ID) { } bool TypeBasedAAWrapperPass::doInitialization(Module &M) { - Result.reset(new TypeBasedAAResult(false)); + Result.reset(new TypeBasedAAResult(/*UsingTypeSanitizer=*/false)); return false; } diff --git a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp index 4b2820ff03f07..c382c67d18ab7 100644 --- a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp @@ -22,6 +22,7 @@ #include "llvm/IR/DataLayout.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" +#include "llvm/IR/InstIterator.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" @@ -72,7 +73,7 @@ namespace { struct TypeSanitizer { TypeSanitizer(Module &M); bool run(Function &F, const TargetLibraryInfo &TLI); - void instrumentGlobals(); + void instrumentGlobals(Module &M); private: typedef SmallDenseMap @@ -114,9 +115,11 @@ struct TypeSanitizer { uint64_t PtrShift; IntegerType *OrdTy; - // Callbacks to run-time library are computed in doInitialization. - Function *TysanCheck; - Function *TysanCtorFunction; + /// Callbacks to run-time library are computed in initializeCallbacks. + FunctionCallee TysanCheck; + FunctionCallee TysanCtorFunction; + + /// Callback to set types for gloabls. Function *TysanGlobalsSetTypeFunction; }; } // namespace @@ -139,29 +142,33 @@ void TypeSanitizer::initializeCallbacks(Module &M) { AttributeList Attr; Attr = Attr.addFnAttribute(M.getContext(), Attribute::NoUnwind); // Initialize the callbacks. - TysanCheck = cast( + TysanCheck = M.getOrInsertFunction(kTysanCheckName, Attr, IRB.getVoidTy(), IRB.getPtrTy(), // Pointer to data to be read. OrdTy, // Size of the data in bytes. IRB.getPtrTy(), // Pointer to type descriptor. OrdTy // Flags. - ) - .getCallee()); + ); TysanCtorFunction = cast( M.getOrInsertFunction(kTysanModuleCtorName, Attr, IRB.getVoidTy()) .getCallee()); } -void TypeSanitizer::instrumentGlobals() { - Module &M = *TysanCtorFunction->getParent(); - initializeCallbacks(M); +void TypeSanitizer::instrumentGlobals(Module &M) { TysanGlobalsSetTypeFunction = nullptr; NamedMDNode *Globals = M.getNamedMetadata("llvm.tysan.globals"); if (!Globals) return; + TysanGlobalsSetTypeFunction = Function::Create( + FunctionType::get(Type::getVoidTy(M.getContext()), false), + GlobalValue::InternalLinkage, "__tysan_set_globals_types", &M); + BasicBlock *BB = + BasicBlock::Create(M.getContext(), "", TysanGlobalsSetTypeFunction); + ReturnInst::Create(M.getContext(), BB); + const DataLayout &DL = M.getDataLayout(); Value *ShadowBase = nullptr, *AppMemMask = nullptr; TypeDescriptorsMapTy TypeDescriptors; @@ -175,15 +182,6 @@ void TypeSanitizer::instrumentGlobals() { if (!generateBaseTypeDescriptor(TBAAMD, TypeDescriptors, TypeNames, M)) continue; - if (!TysanGlobalsSetTypeFunction) { - TysanGlobalsSetTypeFunction = Function::Create( - FunctionType::get(Type::getVoidTy(M.getContext()), false), - GlobalValue::InternalLinkage, "__tysan_set_globals_types", &M); - BasicBlock *BB = - BasicBlock::Create(M.getContext(), "", TysanGlobalsSetTypeFunction); - ReturnInst::Create(M.getContext(), BB); - } - IRBuilder<> IRB( TysanGlobalsSetTypeFunction->getEntryBlock().getTerminator()); Type *AccessTy = GV->getValueType(); @@ -195,23 +193,13 @@ void TypeSanitizer::instrumentGlobals() { } if (TysanGlobalsSetTypeFunction) { - IRBuilder<> IRB(TysanCtorFunction->getEntryBlock().getTerminator()); + IRBuilder<> IRB(cast(TysanCtorFunction.getCallee()) + ->getEntryBlock() + .getTerminator()); IRB.CreateCall(TysanGlobalsSetTypeFunction, {}); } } -static void insertModuleCtor(Module &M) { - Function *TysanCtorFunction; - std::tie(TysanCtorFunction, std::ignore) = - createSanitizerCtorAndInitFunctions(M, kTysanModuleCtorName, - kTysanInitName, /*InitArgTypes=*/{}, - /*InitArgs=*/{}); - - TypeSanitizer TySan(M); - TySan.instrumentGlobals(); - appendToGlobalCtors(M, TysanCtorFunction, 0); -} - static const char LUT[] = "0123456789abcdef"; static std::string encodeName(StringRef Name) { @@ -220,7 +208,7 @@ static std::string encodeName(StringRef Name) { Output.reserve(Output.size() + 3 * Length); for (size_t i = 0; i < Length; ++i) { const unsigned char c = Name[i]; - if (isalnum((int)c)) { + if (isalnum(c)) { Output.push_back(c); continue; } @@ -337,11 +325,13 @@ bool TypeSanitizer::generateBaseTypeDescriptor( SmallVector TDSubTys; SmallVector TDSubData; - TDSubTys.push_back(IntptrTy); - TDSubData.push_back(ConstantInt::get(IntptrTy, 2)); + auto PushTDSub = [&](Constant *C) { + TDSubTys.push_back(C->getType()); + TDSubData.push_back(C); + }; - TDSubTys.push_back(IntptrTy); - TDSubData.push_back(ConstantInt::get(IntptrTy, Members.size())); + PushTDSub(ConstantInt::get(IntptrTy, 2)); + PushTDSub(ConstantInt::get(IntptrTy, Members.size())); // Types that are in an anonymous namespace are local to this module. // FIXME: This should really be marked by the frontend in the metadata @@ -351,15 +341,11 @@ bool TypeSanitizer::generateBaseTypeDescriptor( // anonymous namespace is a template parameter, etc.). bool ShouldBeComdat = !AnonNameRegex.match(NameNode->getString()); for (auto &Member : Members) { - TDSubTys.push_back(Member.first->getType()); - TDSubData.push_back(Member.first); - - TDSubTys.push_back(IntptrTy); - TDSubData.push_back(ConstantInt::get(IntptrTy, Member.second)); + PushTDSub(Member.first); + PushTDSub(ConstantInt::get(IntptrTy, Member.second)); } - TDSubTys.push_back(NameData->getType()); - TDSubData.push_back(NameData); + PushTDSub(NameData); StructType *TDTy = StructType::get(C, TDSubTys); Constant *TD = ConstantStruct::get(TDTy, TDSubData); @@ -482,59 +468,65 @@ Value *TypeSanitizer::getAppMemMask(Function &F) { return IRB.CreateLoad(IntptrTy, GlobalAppMemMask, "app.mem.mask"); } -bool TypeSanitizer::run(Function &F, const TargetLibraryInfo &TLI) { - // This is required to prevent instrumenting call to __tysan_init from within - // the module constructor. - if (&F == TysanCtorFunction || &F == TysanGlobalsSetTypeFunction) - return false; - initializeCallbacks(*F.getParent()); - - SmallVector> MemoryAccesses; - SmallSetVector TBAAMetadata; - SmallVector MemTypeResetInsts; - - bool Res = false; - bool SanitizeFunction = F.hasFnAttribute(Attribute::SanitizeType); - const DataLayout &DL = F.getParent()->getDataLayout(); +/// Collect all loads and stores, and for what TBAA nodes we need to generate +/// type descriptors. +void collectMemAccessInfo( + Function &F, const TargetLibraryInfo &TLI, + SmallVectorImpl> &MemoryAccesses, + SmallSetVector &TBAAMetadata, + SmallVectorImpl &MemTypeResetInsts) { // Traverse all instructions, collect loads/stores/returns, check for calls. - for (auto &BB : F) { - for (auto &Inst : BB) { - // Skip memory accesses inserted by another instrumentation. - if (Inst.getMetadata(LLVMContext::MD_nosanitize)) - continue; + for (Instruction &Inst : instructions(F)) { + // Skip memory accesses inserted by another instrumentation. + if (Inst.getMetadata(LLVMContext::MD_nosanitize)) + continue; - if (isa(Inst) || isa(Inst) || - isa(Inst) || isa(Inst)) { - MemoryLocation MLoc = MemoryLocation::get(&Inst); + if (isa(Inst) || isa(Inst) || + isa(Inst) || isa(Inst)) { + MemoryLocation MLoc = MemoryLocation::get(&Inst); - // Swift errors are special (we can't introduce extra uses on them). - if (MLoc.Ptr->isSwiftError()) - continue; + // Swift errors are special (we can't introduce extra uses on them). + if (MLoc.Ptr->isSwiftError()) + continue; - // Skip non-address-space-0 pointers; we don't know how to handle them. - Type *PtrTy = cast(MLoc.Ptr->getType()); - if (PtrTy->getPointerAddressSpace() != 0) - continue; + // Skip non-address-space-0 pointers; we don't know how to handle them. + Type *PtrTy = cast(MLoc.Ptr->getType()); + if (PtrTy->getPointerAddressSpace() != 0) + continue; - if (MLoc.AATags.TBAA) - TBAAMetadata.insert(MLoc.AATags.TBAA); - MemoryAccesses.push_back(std::make_pair(&Inst, MLoc)); - } else if (isa(Inst) || isa(Inst)) { - if (CallInst *CI = dyn_cast(&Inst)) - maybeMarkSanitizerLibraryCallNoBuiltin(CI, &TLI); + if (MLoc.AATags.TBAA) + TBAAMetadata.insert(MLoc.AATags.TBAA); + MemoryAccesses.push_back(std::make_pair(&Inst, MLoc)); + } else if (isa(Inst) || isa(Inst)) { + if (CallInst *CI = dyn_cast(&Inst)) + maybeMarkSanitizerLibraryCallNoBuiltin(CI, &TLI); - if (isa(Inst)) { - MemTypeResetInsts.push_back(&Inst); - } else if (auto *II = dyn_cast(&Inst)) { - if (II->getIntrinsicID() == Intrinsic::lifetime_start || - II->getIntrinsicID() == Intrinsic::lifetime_end) - MemTypeResetInsts.push_back(&Inst); - } - } else if (isa(Inst)) { + if (isa(Inst)) { MemTypeResetInsts.push_back(&Inst); + } else if (auto *II = dyn_cast(&Inst)) { + if (II->getIntrinsicID() == Intrinsic::lifetime_start || + II->getIntrinsicID() == Intrinsic::lifetime_end) + MemTypeResetInsts.push_back(&Inst); } + } else if (isa(Inst)) { + MemTypeResetInsts.push_back(&Inst); } } +} + +bool TypeSanitizer::run(Function &F, const TargetLibraryInfo &TLI) { + // This is required to prevent instrumenting call to __tysan_init from within + // the module constructor. + if (&F == TysanCtorFunction.getCallee() || &F == TysanGlobalsSetTypeFunction) + return false; + initializeCallbacks(*F.getParent()); + + // We need to collect all loads and stores, and know for what TBAA nodes we + // need to generate type descriptors. + SmallVector> MemoryAccesses; + SmallSetVector TBAAMetadata; + SmallVector MemTypeResetInsts; + collectMemAccessInfo(F, TLI, MemoryAccesses, TBAAMetadata, MemTypeResetInsts); // byval arguments also need their types reset (they're new stack memory, // just like allocas). @@ -542,12 +534,11 @@ bool TypeSanitizer::run(Function &F, const TargetLibraryInfo &TLI) { if (A.hasByValAttr()) MemTypeResetInsts.push_back(&A); - // We have collected all loads and stores, and know for what TBAA nodes we - // need to generate type descriptors. Module &M = *F.getParent(); TypeDescriptorsMapTy TypeDescriptors; TypeNameMapTy TypeNames; + bool Res = false; for (const MDNode *MD : TBAAMetadata) { if (TypeDescriptors.count(MD)) continue; @@ -558,6 +549,8 @@ bool TypeSanitizer::run(Function &F, const TargetLibraryInfo &TLI) { Res = true; } + const DataLayout &DL = F.getParent()->getDataLayout(); + bool SanitizeFunction = F.hasFnAttribute(Attribute::SanitizeType); Value *ShadowBase = nullptr, *AppMemMask = nullptr; for (auto &MA : MemoryAccesses) Res |= instrumentMemoryAccess(MA.first, MA.second, ShadowBase, AppMemMask, @@ -863,6 +856,14 @@ PreservedAnalyses TypeSanitizerPass::run(Function &F, PreservedAnalyses ModuleTypeSanitizerPass::run(Module &M, ModuleAnalysisManager &AM) { - insertModuleCtor(M); + Function *TysanCtorFunction; + std::tie(TysanCtorFunction, std::ignore) = + createSanitizerCtorAndInitFunctions(M, kTysanModuleCtorName, + kTysanInitName, /*InitArgTypes=*/{}, + /*InitArgs=*/{}); + + TypeSanitizer TySan(M); + TySan.instrumentGlobals(M); + appendToGlobalCtors(M, TysanCtorFunction, 0); return PreservedAnalyses::none(); } diff --git a/llvm/test/Instrumentation/TypeSanitizer/invalid-metadata.ll b/llvm/test/Instrumentation/TypeSanitizer/invalid-metadata.ll index 4527aa5cf2a01..43ce283c72605 100644 --- a/llvm/test/Instrumentation/TypeSanitizer/invalid-metadata.ll +++ b/llvm/test/Instrumentation/TypeSanitizer/invalid-metadata.ll @@ -8,18 +8,23 @@ !2 = !{!"omnipotent char", !3, i64 0} !3 = !{!"Simple C/C++ TBAA"} ;. -; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x ptr] [ptr @tysan.module_ctor], section "llvm.metadata" -; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }] +; CHECK: @llvm.used = appending global [1 x ptr] [ptr @tysan.module_ctor], section "llvm.metadata" +; CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }] ;. ; CHECK-LABEL: @tysan.module_ctor( ; CHECK-NEXT: call void @__tysan_init() +; CHECK-NEXT: call void @__tysan_set_globals_types() +; CHECK-NEXT: ret void +; +; +; CHECK-LABEL: @__tysan_set_globals_types( ; CHECK-NEXT: ret void ; ;. ; CHECK: attributes #[[ATTR0:[0-9]+]] = { nounwind } ;. -; CHECK: [[META0:![0-9]+]] = distinct !{ptr undef, !1} -; CHECK: [[META1:![0-9]+]] = !{!"any pointer", !2, i64 0} -; CHECK: [[META2:![0-9]+]] = !{!"omnipotent char", !3, i64 0} -; CHECK: [[META3:![0-9]+]] = !{!"Simple C/C++ TBAA"} +; CHECK: [[META0:![0-9]+]] = distinct !{ptr undef, [[META1:![0-9]+]]} +; CHECK: [[META1]] = !{!"any pointer", [[META2:![0-9]+]], i64 0} +; CHECK: [[META2]] = !{!"omnipotent char", [[META3:![0-9]+]], i64 0} +; CHECK: [[META3]] = !{!"Simple C/C++ TBAA"} ;. From 9e05f83123426f26007eda146b75e8a6175c4249 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Fri, 6 Dec 2024 13:27:06 +0000 Subject: [PATCH 06/24] !fixup modernize check lines. --- .../TypeSanitizer/access-with-offset.ll | 24 ++++---- .../Instrumentation/TypeSanitizer/anon.ll | 43 +++++++++---- .../TypeSanitizer/basic-nosan.ll | 61 +++++++++++-------- .../Instrumentation/TypeSanitizer/basic.ll | 38 ++++++------ .../Instrumentation/TypeSanitizer/byval.ll | 53 ++++++++++------ .../Instrumentation/TypeSanitizer/globals.ll | 52 +++++++++------- .../TypeSanitizer/nosanitize.ll | 16 ++--- 7 files changed, 170 insertions(+), 117 deletions(-) diff --git a/llvm/test/Instrumentation/TypeSanitizer/access-with-offset.ll b/llvm/test/Instrumentation/TypeSanitizer/access-with-offset.ll index 297ee83527b5c..78f3816c9aefa 100644 --- a/llvm/test/Instrumentation/TypeSanitizer/access-with-offset.ll +++ b/llvm/test/Instrumentation/TypeSanitizer/access-with-offset.ll @@ -2,14 +2,14 @@ ; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s ;. -; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }] -; CHECK: @[[__TYSAN_V1_SIMPLE_20C_2FC_2B_2B_20TBAA:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, [18 x i8] } { i64 2, i64 0, [18 x i8] c"Simple C/C++ TBAA\00" }, comdat -; CHECK: @[[__TYSAN_V1_OMNIPOTENT_20CHAR:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [16 x i8] } { i64 2, i64 1, ptr @__tysan_v1_Simple_20C_2fC_2b_2b_20TBAA, i64 0, [16 x i8] c"omnipotent char\00" }, comdat -; CHECK: @[[__TYSAN_V1_ANY_20POINTER:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [12 x i8] } { i64 2, i64 1, ptr @__tysan_v1_omnipotent_20char, i64 0, [12 x i8] c"any pointer\00" }, comdat -; CHECK: @[[__TYSAN_V1_ANY_20POINTER_O_0:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1_any_20pointer, ptr @__tysan_v1_any_20pointer, i64 0 }, comdat -; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [5 x ptr] [ptr @tysan.module_ctor, ptr @__tysan_v1_Simple_20C_2fC_2b_2b_20TBAA, ptr @__tysan_v1_omnipotent_20char, ptr @__tysan_v1_any_20pointer, ptr @__tysan_v1_any_20pointer_o_0], section "llvm.metadata" -; CHECK: @[[__TYSAN_SHADOW_MEMORY_ADDRESS:[a-zA-Z0-9_$"\\.-]+]] = external global i64 -; CHECK: @[[__TYSAN_APP_MEMORY_MASK:[a-zA-Z0-9_$"\\.-]+]] = external global i64 +; CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }] +; CHECK: @__tysan_v1_Simple_20C_2fC_2b_2b_20TBAA = linkonce_odr constant { i64, i64, [18 x i8] } { i64 2, i64 0, [18 x i8] c"Simple C/C++ TBAA\00" }, comdat +; CHECK: @__tysan_v1_omnipotent_20char = linkonce_odr constant { i64, i64, ptr, i64, [16 x i8] } { i64 2, i64 1, ptr @__tysan_v1_Simple_20C_2fC_2b_2b_20TBAA, i64 0, [16 x i8] c"omnipotent char\00" }, comdat +; CHECK: @__tysan_v1_any_20pointer = linkonce_odr constant { i64, i64, ptr, i64, [12 x i8] } { i64 2, i64 1, ptr @__tysan_v1_omnipotent_20char, i64 0, [12 x i8] c"any pointer\00" }, comdat +; CHECK: @__tysan_v1_any_20pointer_o_0 = linkonce_odr constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1_any_20pointer, ptr @__tysan_v1_any_20pointer, i64 0 }, comdat +; CHECK: @llvm.used = appending global [5 x ptr] [ptr @tysan.module_ctor, ptr @__tysan_v1_Simple_20C_2fC_2b_2b_20TBAA, ptr @__tysan_v1_omnipotent_20char, ptr @__tysan_v1_any_20pointer, ptr @__tysan_v1_any_20pointer_o_0], section "llvm.metadata" +; CHECK: @__tysan_shadow_memory_address = external global i64 +; CHECK: @__tysan_app_memory_mask = external global i64 ;. define ptr @test_load_offset(ptr %argv) { ; CHECK-LABEL: @test_load_offset( @@ -64,8 +64,8 @@ entry: ; CHECK: attributes #[[ATTR0:[0-9]+]] = { nounwind } ;. ; CHECK: [[PROF0]] = !{!"branch_weights", i32 1, i32 100000} -; CHECK: [[TBAA1]] = !{!2, !2, i64 0} -; CHECK: [[META2:![0-9]+]] = !{!"any pointer", !3, i64 0} -; CHECK: [[META3:![0-9]+]] = !{!"omnipotent char", !4, i64 0} -; CHECK: [[META4:![0-9]+]] = !{!"Simple C/C++ TBAA"} +; CHECK: [[TBAA1]] = !{[[META2:![0-9]+]], [[META2]], i64 0} +; CHECK: [[META2]] = !{!"any pointer", [[META3:![0-9]+]], i64 0} +; CHECK: [[META3]] = !{!"omnipotent char", [[META4:![0-9]+]], i64 0} +; CHECK: [[META4]] = !{!"Simple C/C++ TBAA"} ;. diff --git a/llvm/test/Instrumentation/TypeSanitizer/anon.ll b/llvm/test/Instrumentation/TypeSanitizer/anon.ll index 70f5dcefde64c..ce4f0c1be0a4f 100644 --- a/llvm/test/Instrumentation/TypeSanitizer/anon.ll +++ b/llvm/test/Instrumentation/TypeSanitizer/anon.ll @@ -5,21 +5,23 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }] -; CHECK: @[[__TYSAN_V1_SIMPLE_20C_2B_2B_20TBAA:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, [16 x i8] } { i64 2, i64 0, [16 x i8] c"Simple C++ TBAA\00" }, comdat -; CHECK: @[[__TYSAN_V1_OMNIPOTENT_20CHAR:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [16 x i8] } { i64 2, i64 1, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, i64 0, [16 x i8] c"omnipotent char\00" }, comdat -; CHECK: @[[__TYSAN_V1_INT:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [4 x i8] } { i64 2, i64 1, ptr @__tysan_v1_omnipotent_20char, i64 0, [4 x i8] c"int\00" }, comdat -; CHECK: @[[__TYSAN_V1___ZTSN12__GLOBAL____N__11ZE:[a-zA-Z0-9_$"\\.-]+]] = internal constant { i64, i64, ptr, i64, [23 x i8] } { i64 2, i64 1, ptr @__tysan_v1_int, i64 24, [23 x i8] c"_ZTSN12_GLOBAL__N_11zE\00" } -; CHECK: @[[__TYSAN_V1___ZTSN12__GLOBAL____N__11ZE_O_24:[a-zA-Z0-9_$"\\.-]+]] = internal constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1___ZTSN12__GLOBAL____N__11zE, ptr @__tysan_v1_int, i64 24 } -; CHECK: @[[__TYSAN_V1___ZTS1YIN12__GLOBAL____N__11ZEE:[a-zA-Z0-9_$"\\.-]+]] = internal constant { i64, i64, ptr, i64, [27 x i8] } { i64 2, i64 1, ptr @__tysan_v1_int, i64 24, [27 x i8] c"_ZTS1yIN12_GLOBAL__N_11zEE\00" } -; CHECK: @[[__TYSAN_V1___ZTS1YIN12__GLOBAL____N__11ZEE_O_24:[a-zA-Z0-9_$"\\.-]+]] = internal constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1___ZTS1yIN12__GLOBAL____N__11zEE, ptr @__tysan_v1_int, i64 24 } -; CHECK: @[[__TYSAN_SHADOW_MEMORY_ADDRESS:[a-zA-Z0-9_$"\\.-]+]] = external global i64 -; CHECK: @[[__TYSAN_APP_MEMORY_MASK:[a-zA-Z0-9_$"\\.-]+]] = external global i64 -; CHECK: @[[__TYSAN_V1_____ANONYMOUS__027D9E575C5D34CB5D60D6A1D6276F95:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [1 x i8] } { i64 2, i64 1, ptr @__tysan_v1_int, i64 24, [1 x i8] zeroinitializer }, comdat -; CHECK: @[[__TYSAN_V1_____ANONYMOUS__027D9E575C5D34CB5D60D6A1D6276F95_O_24:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95, ptr @__tysan_v1_int, i64 24 }, comdat -; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [6 x ptr] [ptr @tysan.module_ctor, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, ptr @__tysan_v1_omnipotent_20char, ptr @__tysan_v1_int, ptr @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95, ptr @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95_o_24], section "llvm.metadata" +;. +; CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }] +; CHECK: @__tysan_v1_Simple_20C_2b_2b_20TBAA = linkonce_odr constant { i64, i64, [16 x i8] } { i64 2, i64 0, [16 x i8] c"Simple C++ TBAA\00" }, comdat +; CHECK: @__tysan_v1_omnipotent_20char = linkonce_odr constant { i64, i64, ptr, i64, [16 x i8] } { i64 2, i64 1, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, i64 0, [16 x i8] c"omnipotent char\00" }, comdat +; CHECK: @__tysan_v1_int = linkonce_odr constant { i64, i64, ptr, i64, [4 x i8] } { i64 2, i64 1, ptr @__tysan_v1_omnipotent_20char, i64 0, [4 x i8] c"int\00" }, comdat +; CHECK: @__tysan_v1___ZTSN12__GLOBAL____N__11zE = internal constant { i64, i64, ptr, i64, [23 x i8] } { i64 2, i64 1, ptr @__tysan_v1_int, i64 24, [23 x i8] c"_ZTSN12_GLOBAL__N_11zE\00" } +; CHECK: @__tysan_v1___ZTSN12__GLOBAL____N__11zE_o_24 = internal constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1___ZTSN12__GLOBAL____N__11zE, ptr @__tysan_v1_int, i64 24 } +; CHECK: @__tysan_v1___ZTS1yIN12__GLOBAL____N__11zEE = internal constant { i64, i64, ptr, i64, [27 x i8] } { i64 2, i64 1, ptr @__tysan_v1_int, i64 24, [27 x i8] c"_ZTS1yIN12_GLOBAL__N_11zEE\00" } +; CHECK: @__tysan_v1___ZTS1yIN12__GLOBAL____N__11zEE_o_24 = internal constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1___ZTS1yIN12__GLOBAL____N__11zEE, ptr @__tysan_v1_int, i64 24 } +; CHECK: @__tysan_shadow_memory_address = external global i64 +; CHECK: @__tysan_app_memory_mask = external global i64 +; CHECK: @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95 = linkonce_odr constant { i64, i64, ptr, i64, [1 x i8] } { i64 2, i64 1, ptr @__tysan_v1_int, i64 24, [1 x i8] zeroinitializer }, comdat +; CHECK: @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95_o_24 = linkonce_odr constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95, ptr @__tysan_v1_int, i64 24 }, comdat +; CHECK: @llvm.used = appending global [6 x ptr] [ptr @tysan.module_ctor, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, ptr @__tysan_v1_omnipotent_20char, ptr @__tysan_v1_int, ptr @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95, ptr @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95_o_24], section "llvm.metadata" +;. define void @test_anon_ns(ptr %a, ptr %b) sanitize_type { ; CHECK-LABEL: @test_anon_ns( ; CHECK-NEXT: entry: @@ -281,3 +283,18 @@ entry: !10 = !{!9, !2, i64 24} !11 = !{!"", !2, i64 24} !12 = !{!11, !2, i64 24} +;. +; CHECK: attributes #[[ATTR0:[0-9]+]] = { sanitize_type } +; CHECK: attributes #[[ATTR1:[0-9]+]] = { nounwind } +;. +; CHECK: [[PROF0]] = !{!"branch_weights", i32 1, i32 100000} +; CHECK: [[TBAA1]] = !{[[META2:![0-9]+]], [[META3:![0-9]+]], i64 24} +; CHECK: [[META2]] = !{!"_ZTSN12_GLOBAL__N_11zE", [[META3]], i64 24} +; CHECK: [[META3]] = !{!"int", [[META4:![0-9]+]], i64 0} +; CHECK: [[META4]] = !{!"omnipotent char", [[META5:![0-9]+]], i64 0} +; CHECK: [[META5]] = !{!"Simple C++ TBAA"} +; CHECK: [[TBAA6]] = !{[[META7:![0-9]+]], [[META3]], i64 24} +; CHECK: [[META7]] = !{!"_ZTS1yIN12_GLOBAL__N_11zEE", [[META3]], i64 24} +; CHECK: [[TBAA8]] = !{[[META9:![0-9]+]], [[META3]], i64 24} +; CHECK: [[META9]] = !{!"", [[META3]], i64 24} +;. diff --git a/llvm/test/Instrumentation/TypeSanitizer/basic-nosan.ll b/llvm/test/Instrumentation/TypeSanitizer/basic-nosan.ll index 7f25e36e6660e..9b9522f3dba1c 100644 --- a/llvm/test/Instrumentation/TypeSanitizer/basic-nosan.ll +++ b/llvm/test/Instrumentation/TypeSanitizer/basic-nosan.ll @@ -4,16 +4,33 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }] -; CHECK: @[[__TYSAN_V1_SIMPLE_20C_2B_2B_20TBAA:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, [16 x i8] } { i64 2, i64 0, [16 x i8] c"Simple C++ TBAA\00" }, comdat -; CHECK: @[[__TYSAN_V1_OMNIPOTENT_20CHAR:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [16 x i8] } { i64 2, i64 1, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, i64 0, [16 x i8] c"omnipotent char\00" }, comdat -; CHECK: @[[__TYSAN_V1_INT:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [4 x i8] } { i64 2, i64 1, ptr @__tysan_v1_omnipotent_20char, i64 0, [4 x i8] c"int\00" }, comdat -; CHECK: @[[__TYSAN_V1_INT_O_0:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1_int, ptr @__tysan_v1_int, i64 0 }, comdat -; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [5 x ptr] [ptr @tysan.module_ctor, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, ptr @__tysan_v1_omnipotent_20char, ptr @__tysan_v1_int, ptr @__tysan_v1_int_o_0], section "llvm.metadata" -; CHECK: @[[__TYSAN_SHADOW_MEMORY_ADDRESS:[a-zA-Z0-9_$"\\.-]+]] = external global i64 -; CHECK: @[[__TYSAN_APP_MEMORY_MASK:[a-zA-Z0-9_$"\\.-]+]] = external global i64 -; define i32 @test_load_nsan(ptr %a) { +entry: + %tmp1 = load i32, ptr %a, align 4, !tbaa !3 + ret i32 %tmp1 +} + +define void @test_store_nsan(ptr %a) { +entry: + store i32 42, ptr %a, align 4, !tbaa !3 + ret void +} + + +!0 = !{!"Simple C++ TBAA"} +!1 = !{!"omnipotent char", !0, i64 0} +!2 = !{!"int", !1, i64 0} +!3 = !{!2, !2, i64 0} +;. +; CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }] +; CHECK: @__tysan_v1_Simple_20C_2b_2b_20TBAA = linkonce_odr constant { i64, i64, [16 x i8] } { i64 2, i64 0, [16 x i8] c"Simple C++ TBAA\00" }, comdat +; CHECK: @__tysan_v1_omnipotent_20char = linkonce_odr constant { i64, i64, ptr, i64, [16 x i8] } { i64 2, i64 1, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, i64 0, [16 x i8] c"omnipotent char\00" }, comdat +; CHECK: @__tysan_v1_int = linkonce_odr constant { i64, i64, ptr, i64, [4 x i8] } { i64 2, i64 1, ptr @__tysan_v1_omnipotent_20char, i64 0, [4 x i8] c"int\00" }, comdat +; CHECK: @__tysan_v1_int_o_0 = linkonce_odr constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1_int, ptr @__tysan_v1_int, i64 0 }, comdat +; CHECK: @llvm.used = appending global [5 x ptr] [ptr @tysan.module_ctor, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, ptr @__tysan_v1_omnipotent_20char, ptr @__tysan_v1_int, ptr @__tysan_v1_int_o_0], section "llvm.metadata" +; CHECK: @__tysan_shadow_memory_address = external global i64 +; CHECK: @__tysan_app_memory_mask = external global i64 +;. ; CHECK-LABEL: @test_load_nsan( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8 @@ -42,12 +59,7 @@ define i32 @test_load_nsan(ptr %a) { ; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[A]], align 4, !tbaa [[TBAA1:![0-9]+]] ; CHECK-NEXT: ret i32 [[TMP1]] ; -entry: - %tmp1 = load i32, ptr %a, align 4, !tbaa !3 - ret i32 %tmp1 -} - -define void @test_store_nsan(ptr %a) { +; ; CHECK-LABEL: @test_store_nsan( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8 @@ -76,18 +88,17 @@ define void @test_store_nsan(ptr %a) { ; CHECK-NEXT: store i32 42, ptr [[A]], align 4, !tbaa [[TBAA1]] ; CHECK-NEXT: ret void ; -entry: - store i32 42, ptr %a, align 4, !tbaa !3 - ret void -} - +; ; CHECK-LABEL: @tysan.module_ctor( ; CHECK-NEXT: call void @__tysan_init() ; CHECK-NEXT: ret void ; +;. +; CHECK: attributes #[[ATTR0:[0-9]+]] = { nounwind } +;. ; CHECK: [[PROF0]] = !{!"branch_weights", i32 1, i32 100000} - -!0 = !{!"Simple C++ TBAA"} -!1 = !{!"omnipotent char", !0, i64 0} -!2 = !{!"int", !1, i64 0} -!3 = !{!2, !2, i64 0} +; CHECK: [[TBAA1]] = !{[[META2:![0-9]+]], [[META2]], i64 0} +; CHECK: [[META2]] = !{!"int", [[META3:![0-9]+]], i64 0} +; CHECK: [[META3]] = !{!"omnipotent char", [[META4:![0-9]+]], i64 0} +; CHECK: [[META4]] = !{!"Simple C++ TBAA"} +;. diff --git a/llvm/test/Instrumentation/TypeSanitizer/basic.ll b/llvm/test/Instrumentation/TypeSanitizer/basic.ll index 132df722e83c2..41d7c999e1d36 100644 --- a/llvm/test/Instrumentation/TypeSanitizer/basic.ll +++ b/llvm/test/Instrumentation/TypeSanitizer/basic.ll @@ -6,18 +6,20 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }] -; CHECK: @[[__TYSAN_V1_SIMPLE_20C_2B_2B_20TBAA:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, [16 x i8] } { i64 2, i64 0, [16 x i8] c"Simple C++ TBAA\00" }, comdat -; CHECK: @[[__TYSAN_V1_OMNIPOTENT_20CHAR:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [16 x i8] } { i64 2, i64 1, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, i64 0, [16 x i8] c"omnipotent char\00" }, comdat -; CHECK: @[[__TYSAN_V1_INT:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [4 x i8] } { i64 2, i64 1, ptr @__tysan_v1_omnipotent_20char, i64 0, [4 x i8] c"int\00" }, comdat -; CHECK: @[[__TYSAN_V1_INT_O_0:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1_int, ptr @__tysan_v1_int, i64 0 }, comdat -; CHECK: @[[__TYSAN_SHADOW_MEMORY_ADDRESS:[a-zA-Z0-9_$"\\.-]+]] = external global i64 -; CHECK: @[[__TYSAN_APP_MEMORY_MASK:[a-zA-Z0-9_$"\\.-]+]] = external global i64 -; CHECK: @[[__TYSAN_V1___ZTS1X:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, ptr, i64, [7 x i8] } { i64 2, i64 2, ptr @__tysan_v1_int, i64 0, ptr @__tysan_v1_int, i64 4, [7 x i8] c"_ZTS1x\00" }, comdat -; CHECK: @[[__TYSAN_V1___ZTS1V:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, ptr, i64, ptr, i64, [7 x i8] } { i64 2, i64 3, ptr @__tysan_v1_int, i64 8, ptr @__tysan_v1_int, i64 12, ptr @__tysan_v1___ZTS1x, i64 16, [7 x i8] c"_ZTS1v\00" }, comdat -; CHECK: @[[__TYSAN_V1___ZTS1V_O_12:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1___ZTS1v, ptr @__tysan_v1_int, i64 12 }, comdat -; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [8 x ptr] [ptr @tysan.module_ctor, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, ptr @__tysan_v1_omnipotent_20char, ptr @__tysan_v1_int, ptr @__tysan_v1_int_o_0, ptr @__tysan_v1___ZTS1x, ptr @__tysan_v1___ZTS1v, ptr @__tysan_v1___ZTS1v_o_12], section "llvm.metadata" +;. +; CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }] +; CHECK: @__tysan_v1_Simple_20C_2b_2b_20TBAA = linkonce_odr constant { i64, i64, [16 x i8] } { i64 2, i64 0, [16 x i8] c"Simple C++ TBAA\00" }, comdat +; CHECK: @__tysan_v1_omnipotent_20char = linkonce_odr constant { i64, i64, ptr, i64, [16 x i8] } { i64 2, i64 1, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, i64 0, [16 x i8] c"omnipotent char\00" }, comdat +; CHECK: @__tysan_v1_int = linkonce_odr constant { i64, i64, ptr, i64, [4 x i8] } { i64 2, i64 1, ptr @__tysan_v1_omnipotent_20char, i64 0, [4 x i8] c"int\00" }, comdat +; CHECK: @__tysan_v1_int_o_0 = linkonce_odr constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1_int, ptr @__tysan_v1_int, i64 0 }, comdat +; CHECK: @__tysan_shadow_memory_address = external global i64 +; CHECK: @__tysan_app_memory_mask = external global i64 +; CHECK: @__tysan_v1___ZTS1x = linkonce_odr constant { i64, i64, ptr, i64, ptr, i64, [7 x i8] } { i64 2, i64 2, ptr @__tysan_v1_int, i64 0, ptr @__tysan_v1_int, i64 4, [7 x i8] c"_ZTS1x\00" }, comdat +; CHECK: @__tysan_v1___ZTS1v = linkonce_odr constant { i64, i64, ptr, i64, ptr, i64, ptr, i64, [7 x i8] } { i64 2, i64 3, ptr @__tysan_v1_int, i64 8, ptr @__tysan_v1_int, i64 12, ptr @__tysan_v1___ZTS1x, i64 16, [7 x i8] c"_ZTS1v\00" }, comdat +; CHECK: @__tysan_v1___ZTS1v_o_12 = linkonce_odr constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1___ZTS1v, ptr @__tysan_v1_int, i64 12 }, comdat +; CHECK: @llvm.used = appending global [8 x ptr] [ptr @tysan.module_ctor, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, ptr @__tysan_v1_omnipotent_20char, ptr @__tysan_v1_int, ptr @__tysan_v1_int_o_0, ptr @__tysan_v1___ZTS1x, ptr @__tysan_v1___ZTS1v, ptr @__tysan_v1___ZTS1v_o_12], section "llvm.metadata" +;. define i32 @test_load(ptr %a) sanitize_type { ; CHECK-LABEL: @test_load( ; CHECK-NEXT: entry: @@ -204,11 +206,11 @@ entry: ; CHECK: attributes #[[ATTR1:[0-9]+]] = { nounwind } ;. ; CHECK: [[PROF0]] = !{!"branch_weights", i32 1, i32 100000} -; CHECK: [[TBAA1]] = !{!2, !2, i64 0} -; CHECK: [[META2:![0-9]+]] = !{!"int", !3, i64 0} -; CHECK: [[META3:![0-9]+]] = !{!"omnipotent char", !4, i64 0} -; CHECK: [[META4:![0-9]+]] = !{!"Simple C++ TBAA"} -; CHECK: [[TBAA5]] = !{!6, !2, i64 12} -; CHECK: [[META6:![0-9]+]] = !{!"_ZTS1v", !2, i64 8, !2, i64 12, !7, i64 16} -; CHECK: [[META7:![0-9]+]] = !{!"_ZTS1x", !2, i64 0, !2, i64 4} +; CHECK: [[TBAA1]] = !{[[META2:![0-9]+]], [[META2]], i64 0} +; CHECK: [[META2]] = !{!"int", [[META3:![0-9]+]], i64 0} +; CHECK: [[META3]] = !{!"omnipotent char", [[META4:![0-9]+]], i64 0} +; CHECK: [[META4]] = !{!"Simple C++ TBAA"} +; CHECK: [[TBAA5]] = !{[[META6:![0-9]+]], [[META2]], i64 12} +; CHECK: [[META6]] = !{!"_ZTS1v", [[META2]], i64 8, [[META2]], i64 12, [[META7:![0-9]+]], i64 16} +; CHECK: [[META7]] = !{!"_ZTS1x", [[META2]], i64 0, [[META2]], i64 4} ;. diff --git a/llvm/test/Instrumentation/TypeSanitizer/byval.ll b/llvm/test/Instrumentation/TypeSanitizer/byval.ll index 68ab1327b225b..23ed1b00173bf 100644 --- a/llvm/test/Instrumentation/TypeSanitizer/byval.ll +++ b/llvm/test/Instrumentation/TypeSanitizer/byval.ll @@ -4,15 +4,29 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -;. -; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x ptr] [ptr @tysan.module_ctor], section "llvm.metadata" -; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }] -; CHECK: @[[__TYSAN_SHADOW_MEMORY_ADDRESS:[a-zA-Z0-9_$"\\.-]+]] = external global i64 -; CHECK: @[[__TYSAN_APP_MEMORY_MASK:[a-zA-Z0-9_$"\\.-]+]] = external global i64 -;. %struct.s20 = type { i32, i32, [24 x i8] } define void @byval_test(ptr byval(%struct.s20) align 32 %x) sanitize_type { +entry: + ret void +; NOTE: Ideally, we'd get the type from the caller's copy of the data (instead +; of setting it all to unknown). +} + +%struct = type { ptr, ptr } + +define ptr @test_insert_point(ptr byval(%struct) %v) { +entry: + %name = getelementptr inbounds %struct, ptr %v, i64 0, i32 1 + %0 = load ptr, ptr %name, align 8 + ret ptr %0 +} +;. +; CHECK: @llvm.used = appending global [1 x ptr] [ptr @tysan.module_ctor], section "llvm.metadata" +; CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }] +; CHECK: @__tysan_shadow_memory_address = external global i64 +; CHECK: @__tysan_app_memory_mask = external global i64 +;. ; CHECK-LABEL: @byval_test( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8 @@ -25,15 +39,7 @@ define void @byval_test(ptr byval(%struct.s20) align 32 %x) sanitize_type { ; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[TMP4]], i8 0, i64 256, i1 false) ; CHECK-NEXT: ret void ; -entry: - ret void -; NOTE: Ideally, we'd get the type from the caller's copy of the data (instead -; of setting it all to unknown). -} - -%struct = type { ptr, ptr } - -define ptr @test_insert_point(ptr byval(%struct) %v) { +; ; CHECK-LABEL: @test_insert_point( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8 @@ -81,8 +87,15 @@ define ptr @test_insert_point(ptr byval(%struct) %v) { ; CHECK-NEXT: [[TMP6:%.*]] = load ptr, ptr [[NAME]], align 8 ; CHECK-NEXT: ret ptr [[TMP6]] ; -entry: - %name = getelementptr inbounds %struct, ptr %v, i64 0, i32 1 - %0 = load ptr, ptr %name, align 8 - ret ptr %0 -} +; +; CHECK-LABEL: @tysan.module_ctor( +; CHECK-NEXT: call void @__tysan_init() +; CHECK-NEXT: ret void +; +;. +; CHECK: attributes #[[ATTR0:[0-9]+]] = { sanitize_type } +; CHECK: attributes #[[ATTR1:[0-9]+]] = { nounwind } +; CHECK: attributes #[[ATTR2:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: write) } +;. +; CHECK: [[PROF0]] = !{!"branch_weights", i32 1, i32 100000} +;. diff --git a/llvm/test/Instrumentation/TypeSanitizer/globals.ll b/llvm/test/Instrumentation/TypeSanitizer/globals.ll index 05d0fd348444d..f4f933f017090 100644 --- a/llvm/test/Instrumentation/TypeSanitizer/globals.ll +++ b/llvm/test/Instrumentation/TypeSanitizer/globals.ll @@ -6,23 +6,34 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" @global1 = global i32 0, align 4 @global2 = global i32 0, align 4 -; CHECK: @[[GLOBAL1:[a-zA-Z0-9_$"\\.-]+]] = global i32 0, align 4 -; CHECK: @[[GLOBAL2:[a-zA-Z0-9_$"\\.-]+]] = global i32 0, align 4 -; CHECK: @[[__TYSAN_V1_SIMPLE_20C_2B_2B_20TBAA:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, [16 x i8] } { i64 2, i64 0, [16 x i8] c"Simple C++ TBAA\00" }, comdat -; CHECK: @[[__TYSAN_V1_OMNIPOTENT_20CHAR:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [16 x i8] } { i64 2, i64 1, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, i64 0, [16 x i8] c"omnipotent char\00" }, comdat -; CHECK: @[[__TYSAN_V1_INT:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [4 x i8] } { i64 2, i64 1, ptr @__tysan_v1_omnipotent_20char, i64 0, [4 x i8] c"int\00" }, comdat -; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [4 x ptr] [ptr @tysan.module_ctor, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, ptr @__tysan_v1_omnipotent_20char, ptr @__tysan_v1_int], section "llvm.metadata" -; CHECK: @[[__TYSAN_SHADOW_MEMORY_ADDRESS:[a-zA-Z0-9_$"\\.-]+]] = external global i64 -; CHECK: @[[__TYSAN_APP_MEMORY_MASK:[a-zA-Z0-9_$"\\.-]+]] = external global i64 -; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }] + + + +!llvm.tysan.globals = !{!13, !14} + +!0 = !{!"Simple C++ TBAA"} +!1 = !{!"omnipotent char", !0, i64 0} +!2 = !{!"int", !1, i64 0} +!13 = !{ptr @global1, !2} +!14 = !{ptr @global1, !2} ;. -; CHECK-LABEL: define internal void @tysan.module_ctor( +; CHECK: @global1 = global i32 0, align 4 +; CHECK: @global2 = global i32 0, align 4 +; CHECK: @__tysan_v1_Simple_20C_2b_2b_20TBAA = linkonce_odr constant { i64, i64, [16 x i8] } { i64 2, i64 0, [16 x i8] c"Simple C++ TBAA\00" }, comdat +; CHECK: @__tysan_v1_omnipotent_20char = linkonce_odr constant { i64, i64, ptr, i64, [16 x i8] } { i64 2, i64 1, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, i64 0, [16 x i8] c"omnipotent char\00" }, comdat +; CHECK: @__tysan_v1_int = linkonce_odr constant { i64, i64, ptr, i64, [4 x i8] } { i64 2, i64 1, ptr @__tysan_v1_omnipotent_20char, i64 0, [4 x i8] c"int\00" }, comdat +; CHECK: @llvm.used = appending global [4 x ptr] [ptr @tysan.module_ctor, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, ptr @__tysan_v1_omnipotent_20char, ptr @__tysan_v1_int], section "llvm.metadata" +; CHECK: @__tysan_shadow_memory_address = external global i64 +; CHECK: @__tysan_app_memory_mask = external global i64 +; CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }] +;. +; CHECK-LABEL: @tysan.module_ctor( ; CHECK-NEXT: call void @__tysan_init() ; CHECK-NEXT: call void @__tysan_set_globals_types() ; CHECK-NEXT: ret void ; ; -; CHECK-LABEL: define internal void @__tysan_set_globals_types( +; CHECK-LABEL: @__tysan_set_globals_types( ; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8 ; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8 ; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 ptrtoint (ptr @global1 to i64), [[APP_MEM_MASK]] @@ -54,13 +65,12 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" ; CHECK-NEXT: [[SHADOW_BYTE_3_PTR10:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET9]] to ptr ; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR10]], align 8 ; CHECK-NEXT: ret void - - - -!llvm.tysan.globals = !{!13, !14} - -!0 = !{!"Simple C++ TBAA"} -!1 = !{!"omnipotent char", !0, i64 0} -!2 = !{!"int", !1, i64 0} -!13 = !{ptr @global1, !2} -!14 = !{ptr @global1, !2} +; +;. +; CHECK: attributes #[[ATTR0:[0-9]+]] = { nounwind } +;. +; CHECK: [[META0:![0-9]+]] = !{ptr @global1, [[META1:![0-9]+]]} +; CHECK: [[META1]] = !{!"int", [[META2:![0-9]+]], i64 0} +; CHECK: [[META2]] = !{!"omnipotent char", [[META3:![0-9]+]], i64 0} +; CHECK: [[META3]] = !{!"Simple C++ TBAA"} +;. diff --git a/llvm/test/Instrumentation/TypeSanitizer/nosanitize.ll b/llvm/test/Instrumentation/TypeSanitizer/nosanitize.ll index 67e408439ec16..7b07a42379b3a 100644 --- a/llvm/test/Instrumentation/TypeSanitizer/nosanitize.ll +++ b/llvm/test/Instrumentation/TypeSanitizer/nosanitize.ll @@ -6,13 +6,13 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" ;. -; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x ptr] [ptr @tysan.module_ctor], section "llvm.metadata" -; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }] +; CHECK: @llvm.used = appending global [1 x ptr] [ptr @tysan.module_ctor], section "llvm.metadata" +; CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }] ;. define i32 @test_load(ptr %a) sanitize_type { ; CHECK-LABEL: @test_load( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[A:%.*]], align 4, !tbaa [[TBAA0:![0-9]+]], !nosanitize !4 +; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[A:%.*]], align 4, !tbaa [[TBAA0:![0-9]+]], !nosanitize [[META4:![0-9]+]] ; CHECK-NEXT: ret i32 [[TMP1]] ; entry: @@ -31,9 +31,9 @@ entry: ; CHECK: attributes #[[ATTR0:[0-9]+]] = { sanitize_type } ; CHECK: attributes #[[ATTR1:[0-9]+]] = { nounwind } ;. -; CHECK: [[TBAA0]] = !{!1, !1, i64 0} -; CHECK: [[META1:![0-9]+]] = !{!"int", !2, i64 0} -; CHECK: [[META2:![0-9]+]] = !{!"omnipotent char", !3, i64 0} -; CHECK: [[META3:![0-9]+]] = !{!"Simple C++ TBAA"} -; CHECK: [[META4:![0-9]+]] = !{} +; CHECK: [[TBAA0]] = !{[[META1:![0-9]+]], [[META1]], i64 0} +; CHECK: [[META1]] = !{!"int", [[META2:![0-9]+]], i64 0} +; CHECK: [[META2]] = !{!"omnipotent char", [[META3:![0-9]+]], i64 0} +; CHECK: [[META3]] = !{!"Simple C++ TBAA"} +; CHECK: [[META4]] = !{} ;. From 1dd1d14ff9343ec15909c1e52ceddc5f860bca51 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Fri, 6 Dec 2024 13:37:52 +0000 Subject: [PATCH 07/24] !fixup pass ShadowBase/AppMemMask by value. --- .../Instrumentation/TypeSanitizer.cpp | 25 ++++++++----------- .../Instrumentation/TypeSanitizer/globals.ll | 13 +++++----- .../TypeSanitizer/invalid-metadata.ll | 13 +++++++--- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp index c382c67d18ab7..a02eedad7f61c 100644 --- a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp @@ -87,13 +87,13 @@ struct TypeSanitizer { bool instrumentWithShadowUpdate(IRBuilder<> &IRB, const MDNode *TBAAMD, Value *Ptr, uint64_t AccessSize, bool IsRead, - bool IsWrite, Value *&ShadowBase, - Value *&AppMemMask, bool ForceSetType, + bool IsWrite, Value *ShadowBase, + Value *AppMemMask, bool ForceSetType, bool SanitizeFunction, TypeDescriptorsMapTy &TypeDescriptors, const DataLayout &DL); bool instrumentMemoryAccess(Instruction *I, MemoryLocation &MLoc, - Value *&ShadowBase, Value *&AppMemMask, + Value *ShadowBase, Value *AppMemMask, bool SanitizeFunction, TypeDescriptorsMapTy &TypeDescriptors, const DataLayout &DL); @@ -170,7 +170,8 @@ void TypeSanitizer::instrumentGlobals(Module &M) { ReturnInst::Create(M.getContext(), BB); const DataLayout &DL = M.getDataLayout(); - Value *ShadowBase = nullptr, *AppMemMask = nullptr; + Value *ShadowBase = getShadowBase(*TysanGlobalsSetTypeFunction); + Value *AppMemMask = getAppMemMask(*TysanGlobalsSetTypeFunction); TypeDescriptorsMapTy TypeDescriptors; TypeNameMapTy TypeNames; @@ -551,7 +552,8 @@ bool TypeSanitizer::run(Function &F, const TargetLibraryInfo &TLI) { const DataLayout &DL = F.getParent()->getDataLayout(); bool SanitizeFunction = F.hasFnAttribute(Attribute::SanitizeType); - Value *ShadowBase = nullptr, *AppMemMask = nullptr; + Value *ShadowBase = MemoryAccesses.empty() ? nullptr : getShadowBase(F); + Value *AppMemMask = MemoryAccesses.empty() ? nullptr : getAppMemMask(F); for (auto &MA : MemoryAccesses) Res |= instrumentMemoryAccess(MA.first, MA.second, ShadowBase, AppMemMask, SanitizeFunction, TypeDescriptors, DL); @@ -575,14 +577,9 @@ static Value *ConvertToShadowDataInt(IRBuilder<> &IRB, Value *Ptr, bool TypeSanitizer::instrumentWithShadowUpdate( IRBuilder<> &IRB, const MDNode *TBAAMD, Value *Ptr, uint64_t AccessSize, - bool IsRead, bool IsWrite, Value *&ShadowBase, Value *&AppMemMask, + bool IsRead, bool IsWrite, Value *ShadowBase, Value *AppMemMask, bool ForceSetType, bool SanitizeFunction, TypeDescriptorsMapTy &TypeDescriptors, const DataLayout &DL) { - if (!ShadowBase) - ShadowBase = getShadowBase(*IRB.GetInsertBlock()->getParent()); - if (!AppMemMask) - AppMemMask = getAppMemMask(*IRB.GetInsertBlock()->getParent()); - Constant *TDGV; if (TBAAMD) TDGV = TypeDescriptors[TBAAMD]; @@ -716,9 +713,9 @@ bool TypeSanitizer::instrumentWithShadowUpdate( } bool TypeSanitizer::instrumentMemoryAccess( - Instruction *I, MemoryLocation &MLoc, Value *&ShadowBase, - Value *&AppMemMask, bool SanitizeFunction, - TypeDescriptorsMapTy &TypeDescriptors, const DataLayout &DL) { + Instruction *I, MemoryLocation &MLoc, Value *ShadowBase, Value *AppMemMask, + bool SanitizeFunction, TypeDescriptorsMapTy &TypeDescriptors, + const DataLayout &DL) { IRBuilder<> IRB(I); assert(MLoc.Size.isPrecise()); if (instrumentWithShadowUpdate( diff --git a/llvm/test/Instrumentation/TypeSanitizer/globals.ll b/llvm/test/Instrumentation/TypeSanitizer/globals.ll index f4f933f017090..1f57c2a3816d9 100644 --- a/llvm/test/Instrumentation/TypeSanitizer/globals.ll +++ b/llvm/test/Instrumentation/TypeSanitizer/globals.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals --include-generated-funcs +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-globals --include-generated-funcs ; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" @@ -19,21 +19,22 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" ;. ; CHECK: @global1 = global i32 0, align 4 ; CHECK: @global2 = global i32 0, align 4 +; CHECK: @__tysan_shadow_memory_address = external global i64 +; CHECK: @__tysan_app_memory_mask = external global i64 ; CHECK: @__tysan_v1_Simple_20C_2b_2b_20TBAA = linkonce_odr constant { i64, i64, [16 x i8] } { i64 2, i64 0, [16 x i8] c"Simple C++ TBAA\00" }, comdat ; CHECK: @__tysan_v1_omnipotent_20char = linkonce_odr constant { i64, i64, ptr, i64, [16 x i8] } { i64 2, i64 1, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, i64 0, [16 x i8] c"omnipotent char\00" }, comdat ; CHECK: @__tysan_v1_int = linkonce_odr constant { i64, i64, ptr, i64, [4 x i8] } { i64 2, i64 1, ptr @__tysan_v1_omnipotent_20char, i64 0, [4 x i8] c"int\00" }, comdat ; CHECK: @llvm.used = appending global [4 x ptr] [ptr @tysan.module_ctor, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, ptr @__tysan_v1_omnipotent_20char, ptr @__tysan_v1_int], section "llvm.metadata" -; CHECK: @__tysan_shadow_memory_address = external global i64 -; CHECK: @__tysan_app_memory_mask = external global i64 ; CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }] ;. -; CHECK-LABEL: @tysan.module_ctor( +; CHECK-LABEL: define {{[^@]+}}@tysan.module_ctor +; CHECK-SAME: () #[[ATTR0:[0-9]+]] { ; CHECK-NEXT: call void @__tysan_init() ; CHECK-NEXT: call void @__tysan_set_globals_types() ; CHECK-NEXT: ret void ; ; -; CHECK-LABEL: @__tysan_set_globals_types( +; CHECK-LABEL: define {{[^@]+}}@__tysan_set_globals_types() { ; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8 ; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8 ; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 ptrtoint (ptr @global1 to i64), [[APP_MEM_MASK]] @@ -67,7 +68,7 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" ; CHECK-NEXT: ret void ; ;. -; CHECK: attributes #[[ATTR0:[0-9]+]] = { nounwind } +; CHECK: attributes #[[ATTR0]] = { nounwind } ;. ; CHECK: [[META0:![0-9]+]] = !{ptr @global1, [[META1:![0-9]+]]} ; CHECK: [[META1]] = !{!"int", [[META2:![0-9]+]], i64 0} diff --git a/llvm/test/Instrumentation/TypeSanitizer/invalid-metadata.ll b/llvm/test/Instrumentation/TypeSanitizer/invalid-metadata.ll index 43ce283c72605..da7401e9f8871 100644 --- a/llvm/test/Instrumentation/TypeSanitizer/invalid-metadata.ll +++ b/llvm/test/Instrumentation/TypeSanitizer/invalid-metadata.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals --include-generated-funcs +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-globals --include-generated-funcs ; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s !llvm.tysan.globals = !{!0} @@ -9,19 +9,24 @@ !3 = !{!"Simple C/C++ TBAA"} ;. ; CHECK: @llvm.used = appending global [1 x ptr] [ptr @tysan.module_ctor], section "llvm.metadata" +; CHECK: @__tysan_shadow_memory_address = external global i64 +; CHECK: @__tysan_app_memory_mask = external global i64 ; CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }] ;. -; CHECK-LABEL: @tysan.module_ctor( +; CHECK-LABEL: define {{[^@]+}}@tysan.module_ctor +; CHECK-SAME: () #[[ATTR0:[0-9]+]] { ; CHECK-NEXT: call void @__tysan_init() ; CHECK-NEXT: call void @__tysan_set_globals_types() ; CHECK-NEXT: ret void ; ; -; CHECK-LABEL: @__tysan_set_globals_types( +; CHECK-LABEL: define {{[^@]+}}@__tysan_set_globals_types() { +; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 4 +; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 4 ; CHECK-NEXT: ret void ; ;. -; CHECK: attributes #[[ATTR0:[0-9]+]] = { nounwind } +; CHECK: attributes #[[ATTR0]] = { nounwind } ;. ; CHECK: [[META0:![0-9]+]] = distinct !{ptr undef, [[META1:![0-9]+]]} ; CHECK: [[META1]] = !{!"any pointer", [[META2:![0-9]+]], i64 0} From 4c19928ef39f9e63d7f1d7cd2f422c7f0f2574ae Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Tue, 10 Dec 2024 10:24:58 +0000 Subject: [PATCH 08/24] !fixup address first set of comments, thanks! --- .../Instrumentation/TypeSanitizer.cpp | 59 +++++++------------ .../TypeSanitizer/alloca-only.ll | 49 +++++++++++++++ .../Instrumentation/TypeSanitizer/basic.ll | 2 - 3 files changed, 71 insertions(+), 39 deletions(-) create mode 100644 llvm/test/Instrumentation/TypeSanitizer/alloca-only.ll diff --git a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp index a02eedad7f61c..6cbb9b8b9ed33 100644 --- a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp @@ -64,11 +64,9 @@ static cl::opt STATISTIC(NumInstrumentedAccesses, "Number of instrumented accesses"); -static Regex AnonNameRegex("^_ZTS.*N[1-9][0-9]*_GLOBAL__N"); - namespace { -/// TypeSanitizer: instrument the code in module to find type-based aliasing +/// TypeSanitizer: instrument the code in module to find type-based aliasing /// violations. struct TypeSanitizer { TypeSanitizer(Module &M); @@ -92,11 +90,9 @@ struct TypeSanitizer { bool SanitizeFunction, TypeDescriptorsMapTy &TypeDescriptors, const DataLayout &DL); - bool instrumentMemoryAccess(Instruction *I, MemoryLocation &MLoc, - Value *ShadowBase, Value *AppMemMask, - bool SanitizeFunction, - TypeDescriptorsMapTy &TypeDescriptors, - const DataLayout &DL); + + /// Memory-related intrinsics/instructions reset the type of the destination + /// memory (including allocas and byval arguments). bool instrumentMemInst(Value *I, Value *&ShadowBase, Value *&AppMemMask, const DataLayout &DL); @@ -150,9 +146,8 @@ void TypeSanitizer::initializeCallbacks(Module &M) { OrdTy // Flags. ); - TysanCtorFunction = cast( - M.getOrInsertFunction(kTysanModuleCtorName, Attr, IRB.getVoidTy()) - .getCallee()); + TysanCtorFunction = + M.getOrInsertFunction(kTysanModuleCtorName, Attr, IRB.getVoidTy()); } void TypeSanitizer::instrumentGlobals(Module &M) { @@ -535,7 +530,6 @@ bool TypeSanitizer::run(Function &F, const TargetLibraryInfo &TLI) { if (A.hasByValAttr()) MemTypeResetInsts.push_back(&A); - Module &M = *F.getParent(); TypeDescriptorsMapTy TypeDescriptors; TypeNameMapTy TypeNames; @@ -552,11 +546,22 @@ bool TypeSanitizer::run(Function &F, const TargetLibraryInfo &TLI) { const DataLayout &DL = F.getParent()->getDataLayout(); bool SanitizeFunction = F.hasFnAttribute(Attribute::SanitizeType); - Value *ShadowBase = MemoryAccesses.empty() ? nullptr : getShadowBase(F); - Value *AppMemMask = MemoryAccesses.empty() ? nullptr : getAppMemMask(F); - for (auto &MA : MemoryAccesses) - Res |= instrumentMemoryAccess(MA.first, MA.second, ShadowBase, AppMemMask, - SanitizeFunction, TypeDescriptors, DL); + bool NeedsInstrumentation = + MemTypeResetInsts.empty() && MemoryAccesses.empty(); + Value *ShadowBase = NeedsInstrumentation ? nullptr : getShadowBase(F); + Value *AppMemMask = NeedsInstrumentation ? nullptr : getAppMemMask(F); + for (const auto &[I, MLoc] : MemoryAccesses) { + IRBuilder<> IRB(I); + assert(MLoc.Size.isPrecise()); + if (instrumentWithShadowUpdate( + IRB, MLoc.AATags.TBAA, const_cast(MLoc.Ptr), + MLoc.Size.getValue(), I->mayReadFromMemory(), I->mayWriteToMemory(), + ShadowBase, AppMemMask, false, SanitizeFunction, TypeDescriptors, + DL)) { + ++NumInstrumentedAccesses; + Res = true; + } + } for (auto Inst : MemTypeResetInsts) Res |= instrumentMemInst(Inst, ShadowBase, AppMemMask, DL); @@ -712,26 +717,6 @@ bool TypeSanitizer::instrumentWithShadowUpdate( return true; } -bool TypeSanitizer::instrumentMemoryAccess( - Instruction *I, MemoryLocation &MLoc, Value *ShadowBase, Value *AppMemMask, - bool SanitizeFunction, TypeDescriptorsMapTy &TypeDescriptors, - const DataLayout &DL) { - IRBuilder<> IRB(I); - assert(MLoc.Size.isPrecise()); - if (instrumentWithShadowUpdate( - IRB, MLoc.AATags.TBAA, const_cast(MLoc.Ptr), - MLoc.Size.getValue(), I->mayReadFromMemory(), I->mayWriteToMemory(), - ShadowBase, AppMemMask, false, SanitizeFunction, TypeDescriptors, - DL)) { - ++NumInstrumentedAccesses; - return true; - } - - return false; -} - -// Memory-related intrinsics/instructions reset the type of the destination -// memory (including allocas and byval arguments). bool TypeSanitizer::instrumentMemInst(Value *V, Value *&ShadowBase, Value *&AppMemMask, const DataLayout &DL) { diff --git a/llvm/test/Instrumentation/TypeSanitizer/alloca-only.ll b/llvm/test/Instrumentation/TypeSanitizer/alloca-only.ll new file mode 100644 index 0000000000000..1aa47cacc1275 --- /dev/null +++ b/llvm/test/Instrumentation/TypeSanitizer/alloca-only.ll @@ -0,0 +1,49 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals +; Test basic type sanitizer instrumentation. +; +; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +;. +; CHECK: @llvm.used = appending global [1 x ptr] [ptr @tysan.module_ctor], section "llvm.metadata" +; CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }] +; CHECK: @__tysan_shadow_memory_address = external global i64 +; CHECK: @__tysan_app_memory_mask = external global i64 +;. +define void @test_alloca_only() sanitize_type { +; CHECK-LABEL: @test_alloca_only( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8 +; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8 +; CHECK-NEXT: [[TMP1:%.*]] = alloca i32, align 4 +; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[TMP1]] to i64 +; CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP0]], [[APP_MEM_MASK]] +; CHECK-NEXT: [[TMP2:%.*]] = shl i64 [[TMP5]], 3 +; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[TMP2]], [[SHADOW_BASE]] +; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr +; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[TMP4]], i8 0, i64 32, i1 false) +; CHECK-NEXT: call void @foo(ptr [[TMP1]]) +; CHECK-NEXT: ret void +; +entry: + %a = alloca i32 + call void @foo(ptr %a) + ret void +} + +declare void @foo(ptr) + + +!0 = !{!"Simple C++ TBAA"} +!1 = !{!"omnipotent char", !0, i64 0} +!2 = !{!"int", !1, i64 0} +!3 = !{!2, !2, i64 0} +!4 = !{!"_ZTS1x", !2, i64 0, !2, i64 4} +!5 = !{!"_ZTS1v", !2, i64 8, !2, i64 12, !4, i64 16} +!6 = !{!5, !2, i64 12} +;. +; CHECK: attributes #[[ATTR0:[0-9]+]] = { sanitize_type } +; CHECK: attributes #[[ATTR1:[0-9]+]] = { nounwind } +; CHECK: attributes #[[ATTR2:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: write) } +;. diff --git a/llvm/test/Instrumentation/TypeSanitizer/basic.ll b/llvm/test/Instrumentation/TypeSanitizer/basic.ll index 41d7c999e1d36..8873a40798b18 100644 --- a/llvm/test/Instrumentation/TypeSanitizer/basic.ll +++ b/llvm/test/Instrumentation/TypeSanitizer/basic.ll @@ -5,8 +5,6 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" - - ;. ; CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }] ; CHECK: @__tysan_v1_Simple_20C_2b_2b_20TBAA = linkonce_odr constant { i64, i64, [16 x i8] } { i64 2, i64 0, [16 x i8] c"Simple C++ TBAA\00" }, comdat From 694cb2cbe5216294723f416c2fc404b879ae4e74 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Tue, 10 Dec 2024 11:42:29 +0000 Subject: [PATCH 09/24] !Fixup address remaining comments, thanks! --- llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp | 6 +- .../Instrumentation/TypeSanitizer.cpp | 263 +++++++++++------- 2 files changed, 158 insertions(+), 111 deletions(-) diff --git a/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp b/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp index 98da4e37a1404..3f44f746eb173 100644 --- a/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp +++ b/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp @@ -376,7 +376,7 @@ AliasResult TypeBasedAAResult::alias(const MemoryLocation &LocA, const MemoryLocation &LocB, AAQueryInfo &AAQI, const Instruction *) { if (!shouldUseTBAA()) - return AAResultBase::alias(LocA, LocB, AAQI, nullptr); + return AliasResult::MayAlias; if (Aliases(LocA.AATags.TBAA, LocB.AATags.TBAA)) return AliasResult::MayAlias; @@ -427,7 +427,7 @@ ModRefInfo TypeBasedAAResult::getModRefInfo(const CallBase *Call, const MemoryLocation &Loc, AAQueryInfo &AAQI) { if (!shouldUseTBAA()) - return AAResultBase::getModRefInfo(Call, Loc, AAQI); + return ModRefInfo::ModRef; if (const MDNode *L = Loc.AATags.TBAA) if (const MDNode *M = Call->getMetadata(LLVMContext::MD_tbaa)) @@ -441,7 +441,7 @@ ModRefInfo TypeBasedAAResult::getModRefInfo(const CallBase *Call1, const CallBase *Call2, AAQueryInfo &AAQI) { if (!shouldUseTBAA()) - return AAResultBase::getModRefInfo(Call1, Call2, AAQI); + return ModRefInfo::ModRef; if (const MDNode *M1 = Call1->getMetadata(LLVMContext::MD_tbaa)) if (const MDNode *M2 = Call2->getMetadata(LLVMContext::MD_tbaa)) diff --git a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp index 6cbb9b8b9ed33..a2310983c63e3 100644 --- a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp @@ -80,8 +80,8 @@ struct TypeSanitizer { void initializeCallbacks(Module &M); - Value *getShadowBase(Function &F); - Value *getAppMemMask(Function &F); + Instruction *getShadowBase(Function &F); + Instruction *getAppMemMask(Function &F); bool instrumentWithShadowUpdate(IRBuilder<> &IRB, const MDNode *TBAAMD, Value *Ptr, uint64_t AccessSize, bool IsRead, @@ -93,8 +93,8 @@ struct TypeSanitizer { /// Memory-related intrinsics/instructions reset the type of the destination /// memory (including allocas and byval arguments). - bool instrumentMemInst(Value *I, Value *&ShadowBase, Value *&AppMemMask, - const DataLayout &DL); + bool instrumentMemInst(Value *I, Instruction *ShadowBase, + Instruction *AppMemMask, const DataLayout &DL); std::string getAnonymousStructIdentifier(const MDNode *MD, TypeNameMapTy &TypeNames); @@ -450,14 +450,14 @@ bool TypeSanitizer::generateTypeDescriptor( return true; } -Value *TypeSanitizer::getShadowBase(Function &F) { +Instruction *TypeSanitizer::getShadowBase(Function &F) { IRBuilder<> IRB(&F.front().front()); Constant *GlobalShadowAddress = F.getParent()->getOrInsertGlobal(kTysanShadowMemoryAddress, IntptrTy); return IRB.CreateLoad(IntptrTy, GlobalShadowAddress, "shadow.base"); } -Value *TypeSanitizer::getAppMemMask(Function &F) { +Instruction *TypeSanitizer::getAppMemMask(Function &F) { IRBuilder<> IRB(&F.front().front()); Value *GlobalAppMemMask = F.getParent()->getOrInsertGlobal(kTysanAppMemMask, IntptrTy); @@ -548,8 +548,8 @@ bool TypeSanitizer::run(Function &F, const TargetLibraryInfo &TLI) { bool SanitizeFunction = F.hasFnAttribute(Attribute::SanitizeType); bool NeedsInstrumentation = MemTypeResetInsts.empty() && MemoryAccesses.empty(); - Value *ShadowBase = NeedsInstrumentation ? nullptr : getShadowBase(F); - Value *AppMemMask = NeedsInstrumentation ? nullptr : getAppMemMask(F); + Instruction *ShadowBase = NeedsInstrumentation ? nullptr : getShadowBase(F); + Instruction *AppMemMask = NeedsInstrumentation ? nullptr : getAppMemMask(F); for (const auto &[I, MLoc] : MemoryAccesses) { IRBuilder<> IRB(I); assert(MLoc.Size.isPrecise()); @@ -569,7 +569,7 @@ bool TypeSanitizer::run(Function &F, const TargetLibraryInfo &TLI) { return Res; } -static Value *ConvertToShadowDataInt(IRBuilder<> &IRB, Value *Ptr, +static Value *convertToShadowDataInt(IRBuilder<> &IRB, Value *Ptr, Type *IntptrTy, uint64_t PtrShift, Value *ShadowBase, Value *AppMemMask) { return IRB.CreateAdd( @@ -593,7 +593,7 @@ bool TypeSanitizer::instrumentWithShadowUpdate( Value *TD = IRB.CreateBitCast(TDGV, IRB.getPtrTy()); - Value *ShadowDataInt = ConvertToShadowDataInt(IRB, Ptr, IntptrTy, PtrShift, + Value *ShadowDataInt = convertToShadowDataInt(IRB, Ptr, IntptrTy, PtrShift, ShadowBase, AppMemMask); Type *Int8PtrPtrTy = PointerType::get(IRB.getPtrTy(), 0); Value *ShadowData = @@ -620,105 +620,155 @@ bool TypeSanitizer::instrumentWithShadowUpdate( } }; - if (!ForceSetType && (!ClWritesAlwaysSetType || IsRead)) { - // We need to check the type here. If the type is unknown, then the read - // sets the type. If the type is known, then it is checked. If the type - // doesn't match, then we call the runtime (which may yet determine that - // the mismatch is okay). - LLVMContext &C = IRB.getContext(); - MDNode *UnlikelyBW = MDBuilder(C).createBranchWeights(1, 100000); + if (ForceSetType || (ClWritesAlwaysSetType && IsWrite)) { + // In the mode where writes always set the type, for a write (which does + // not also read), we just set the type. + SetType(); + return true; + } - Constant *Flags = - ConstantInt::get(OrdTy, (int)IsRead | (((int)IsWrite) << 1)); + assert((!ClWritesAlwaysSetType || IsRead) && + "should have handled case above"); + LLVMContext &C = IRB.getContext(); + MDNode *UnlikelyBW = MDBuilder(C).createBranchWeights(1, 100000); + if (!SanitizeFunction) { + // If we're not sanitizing this function, then we only care whether we + // need to *set* the type. Value *LoadedTD = IRB.CreateLoad(IRB.getPtrTy(), ShadowData, "shadow.desc"); - if (SanitizeFunction) { - Value *BadTDCmp = IRB.CreateICmpNE(LoadedTD, TD, "bad.desc"); - Instruction *BadTDTerm, *GoodTDTerm; - SplitBlockAndInsertIfThenElse(BadTDCmp, &*IRB.GetInsertPoint(), - &BadTDTerm, &GoodTDTerm, UnlikelyBW); - IRB.SetInsertPoint(BadTDTerm); - - // We now know that the types did not match (we're on the slow path). If - // the type is unknown, then set it. - Value *NullTDCmp = IRB.CreateIsNull(LoadedTD); - Instruction *NullTDTerm, *MismatchTerm; - SplitBlockAndInsertIfThenElse(NullTDCmp, &*IRB.GetInsertPoint(), - &NullTDTerm, &MismatchTerm); - - // If the type is unknown, then set the type. - IRB.SetInsertPoint(NullTDTerm); - - // We're about to set the type. Make sure that all bytes in the value are - // also of unknown type. - Value *Size = ConstantInt::get(OrdTy, AccessSize); - Value *NotAllUnkTD = IRB.getFalse(); - for (uint64_t i = 1; i < AccessSize; ++i) { - Value *UnkShadowData = IRB.CreateIntToPtr( - IRB.CreateAdd(ShadowDataInt, - ConstantInt::get(IntptrTy, i << PtrShift)), - Int8PtrPtrTy); - Value *ILdTD = IRB.CreateLoad(IRB.getPtrTy(), UnkShadowData); - NotAllUnkTD = IRB.CreateOr(NotAllUnkTD, IRB.CreateIsNotNull(ILdTD)); - } - - Instruction *BeforeSetType = &*IRB.GetInsertPoint(); - Instruction *BadUTDTerm = SplitBlockAndInsertIfThen( - NotAllUnkTD, BeforeSetType, false, UnlikelyBW); - IRB.SetInsertPoint(BadUTDTerm); - IRB.CreateCall(TysanCheck, {IRB.CreateBitCast(Ptr, IRB.getPtrTy()), Size, - (Value *)TD, (Value *)Flags}); - - IRB.SetInsertPoint(BeforeSetType); - SetType(); - - // We have a non-trivial mismatch. Call the runtime. - IRB.SetInsertPoint(MismatchTerm); - IRB.CreateCall(TysanCheck, {IRB.CreateBitCast(Ptr, IRB.getPtrTy()), Size, - (Value *)TD, (Value *)Flags}); - - // We appear to have the right type. Make sure that all other bytes in - // the type are still marked as interior bytes. If not, call the runtime. - IRB.SetInsertPoint(GoodTDTerm); - Value *NotAllBadTD = IRB.getFalse(); - for (uint64_t i = 1; i < AccessSize; ++i) { - Value *BadShadowData = IRB.CreateIntToPtr( - IRB.CreateAdd(ShadowDataInt, - ConstantInt::get(IntptrTy, i << PtrShift)), - Int8PtrPtrTy); - Value *ILdTD = IRB.CreatePtrToInt( - IRB.CreateLoad(IRB.getPtrTy(), BadShadowData), IntptrTy); - NotAllBadTD = IRB.CreateOr( - NotAllBadTD, - IRB.CreateICmpSGE(ILdTD, ConstantInt::get(IntptrTy, 0))); - } - - Instruction *BadITDTerm = SplitBlockAndInsertIfThen( - NotAllBadTD, &*IRB.GetInsertPoint(), false, UnlikelyBW); - IRB.SetInsertPoint(BadITDTerm); - IRB.CreateCall(TysanCheck, {IRB.CreateBitCast(Ptr, IRB.getPtrTy()), Size, - (Value *)TD, (Value *)Flags}); - } else { - // If we're not sanitizing this function, then we only care whether we - // need to *set* the type. - Value *NullTDCmp = IRB.CreateIsNull(LoadedTD, "desc.set"); - Instruction *NullTDTerm = SplitBlockAndInsertIfThen( - NullTDCmp, &*IRB.GetInsertPoint(), false, UnlikelyBW); - IRB.SetInsertPoint(NullTDTerm); - NullTDTerm->getParent()->setName("set.type"); - SetType(); - } - } else if (ForceSetType || IsWrite) { - // In the mode where writes always set the type, for a write (which does - // not also read), we just set the type. + Value *NullTDCmp = IRB.CreateIsNull(LoadedTD, "desc.set"); + Instruction *NullTDTerm = SplitBlockAndInsertIfThen( + NullTDCmp, &*IRB.GetInsertPoint(), false, UnlikelyBW); + IRB.SetInsertPoint(NullTDTerm); + NullTDTerm->getParent()->setName("set.type"); SetType(); + return true; + } + // We need to check the type here. If the type is unknown, then the read + // sets the type. If the type is known, then it is checked. If the type + // doesn't match, then we call the runtime (which may yet determine that + // the mismatch is okay). + // + // The checks generated below have the following strucutre. + // + // ; First we load the descriptor for the load from shadow memory and + // ; compare it against the type descriptor for the current access type. + // %shadow.desc = load ptr %shadow.data + // %bad.desc = icmp ne %shadow.desc, %td + // br %bad.desc, %bad.bb, %good.bb + // + // bad.bb: + // %shadow.desc.null = icmp eq %shadow.desc, null + // br %shadow.desc.null, %null.td.bb, %good.td.bb + // + // null.td.bb: + // ; The typ is unknown, set it if all bytes in the value are also unknown. + // ; To check, we load the shadow data for all bytes of the access. For the + // ; pseudo code below, assume an access of size 1. + // %shadow.data.int = add %shadow.data.int, 0 + // %l = load (inttoptr %shadow.data.int) + // %is.not.null = icmp ne %l, null + // %not.all.unknown = %is.not.null + // br %no.all.unknown, before.set.type.bb + // + // before.set.type.bb: + // ; Call runtime to check mismatch. + // call void @__tysan_check() + // br %set.type.bb + // + // set.type.bb: + // ; Now fill the remainder of the shadow memory corresponding to the + // ; remainder of the the bytes of the type with a bad type descriptor. + // store %TD, %shadow.data + // br %continue.bb + // + // good.td.bb:: + // ; We have a non-trivial mismatch. Call the runtime. + // call void @__tysan_check() + // br %continue.bb + // + // good.bb: + // ; We appear to have the right type. Make sure that all other bytes in + // ; the type are still marked as interior bytes. If not, call the runtime. + // %shadow.data.int = add %shadow.data.int, 0 + // %l = load (inttoptr %shadow.data.int) + // %not.all.interior = icmp sge %l, 0 + // br %not.all.interior, label %check.rt.bb, label %continue.bb + // + // check.rt.bb: + // call void @__tysan_check() + // br %continue.bb + + Constant *Flags = ConstantInt::get(OrdTy, int(IsRead) | (int(IsWrite) << 1)); + + Value *LoadedTD = IRB.CreateLoad(IRB.getPtrTy(), ShadowData, "shadow.desc"); + Value *BadTDCmp = IRB.CreateICmpNE(LoadedTD, TD, "bad.desc"); + Instruction *BadTDTerm, *GoodTDTerm; + SplitBlockAndInsertIfThenElse(BadTDCmp, &*IRB.GetInsertPoint(), &BadTDTerm, + &GoodTDTerm, UnlikelyBW); + IRB.SetInsertPoint(BadTDTerm); + + // We now know that the types did not match (we're on the slow path). If + // the type is unknown, then set it. + Value *NullTDCmp = IRB.CreateIsNull(LoadedTD); + Instruction *NullTDTerm, *MismatchTerm; + SplitBlockAndInsertIfThenElse(NullTDCmp, &*IRB.GetInsertPoint(), &NullTDTerm, + &MismatchTerm); + + // If the type is unknown, then set the type. + IRB.SetInsertPoint(NullTDTerm); + + // We're about to set the type. Make sure that all bytes in the value are + // also of unknown type. + Value *Size = ConstantInt::get(OrdTy, AccessSize); + Value *NotAllUnkTD = IRB.getFalse(); + for (uint64_t i = 1; i < AccessSize; ++i) { + Value *UnkShadowData = IRB.CreateIntToPtr( + IRB.CreateAdd(ShadowDataInt, ConstantInt::get(IntptrTy, i << PtrShift)), + Int8PtrPtrTy); + Value *ILdTD = IRB.CreateLoad(IRB.getPtrTy(), UnkShadowData); + NotAllUnkTD = IRB.CreateOr(NotAllUnkTD, IRB.CreateIsNotNull(ILdTD)); } + Instruction *BeforeSetType = &*IRB.GetInsertPoint(); + Instruction *BadUTDTerm = + SplitBlockAndInsertIfThen(NotAllUnkTD, BeforeSetType, false, UnlikelyBW); + IRB.SetInsertPoint(BadUTDTerm); + IRB.CreateCall(TysanCheck, {IRB.CreateBitCast(Ptr, IRB.getPtrTy()), Size, + (Value *)TD, (Value *)Flags}); + + IRB.SetInsertPoint(BeforeSetType); + SetType(); + + // We have a non-trivial mismatch. Call the runtime. + IRB.SetInsertPoint(MismatchTerm); + IRB.CreateCall(TysanCheck, {IRB.CreateBitCast(Ptr, IRB.getPtrTy()), Size, + (Value *)TD, (Value *)Flags}); + + // We appear to have the right type. Make sure that all other bytes in + // the type are still marked as interior bytes. If not, call the runtime. + IRB.SetInsertPoint(GoodTDTerm); + Value *NotAllBadTD = IRB.getFalse(); + for (uint64_t i = 1; i < AccessSize; ++i) { + Value *BadShadowData = IRB.CreateIntToPtr( + IRB.CreateAdd(ShadowDataInt, ConstantInt::get(IntptrTy, i << PtrShift)), + Int8PtrPtrTy); + Value *ILdTD = IRB.CreatePtrToInt( + IRB.CreateLoad(IRB.getPtrTy(), BadShadowData), IntptrTy); + NotAllBadTD = IRB.CreateOr( + NotAllBadTD, IRB.CreateICmpSGE(ILdTD, ConstantInt::get(IntptrTy, 0))); + } + + Instruction *BadITDTerm = SplitBlockAndInsertIfThen( + NotAllBadTD, &*IRB.GetInsertPoint(), false, UnlikelyBW); + IRB.SetInsertPoint(BadITDTerm); + IRB.CreateCall(TysanCheck, {IRB.CreateBitCast(Ptr, IRB.getPtrTy()), Size, + (Value *)TD, (Value *)Flags}); return true; } -bool TypeSanitizer::instrumentMemInst(Value *V, Value *&ShadowBase, - Value *&AppMemMask, +bool TypeSanitizer::instrumentMemInst(Value *V, Instruction *ShadowBase, + Instruction *AppMemMask, const DataLayout &DL) { BasicBlock::iterator IP; BasicBlock *BB; @@ -734,14 +784,11 @@ bool TypeSanitizer::instrumentMemInst(Value *V, Value *&ShadowBase, BB = &F->getEntryBlock(); IP = BB->getFirstInsertionPt(); - if (auto *I = cast_or_null(ShadowBase)) { - if (IP->comesBefore(I)) - IP = I->getNextNode()->getIterator(); - } - if (auto *I = cast_or_null(AppMemMask)) { - if (IP->comesBefore(I)) - IP = I->getNextNode()->getIterator(); - } + // Find the next insert point after both ShadowBase and AppMemMask. + if (IP->comesBefore(ShadowBase)) + IP = ShadowBase->getNextNode()->getIterator(); + if (IP->comesBefore(AppMemMask)) + IP = AppMemMask->getNextNode()->getIterator(); } Value *Dest, *Size, *Src = nullptr; From be6f7598cc936c5d7fff722fdee50bd254a64396 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Thu, 18 Apr 2024 23:01:03 +0100 Subject: [PATCH 10/24] [TySan] A Type Sanitizer (Clang) --- clang/include/clang/Basic/Features.def | 1 + clang/include/clang/Basic/Sanitizers.def | 3 ++ clang/include/clang/Driver/SanitizerArgs.h | 1 + clang/lib/CodeGen/BackendUtil.cpp | 6 ++++ clang/lib/CodeGen/CGDecl.cpp | 3 +- clang/lib/CodeGen/CGDeclCXX.cpp | 4 +++ clang/lib/CodeGen/CodeGenFunction.cpp | 2 ++ clang/lib/CodeGen/CodeGenModule.cpp | 12 ++++--- clang/lib/CodeGen/CodeGenTBAA.cpp | 6 ++-- clang/lib/CodeGen/SanitizerMetadata.cpp | 40 +++++++++++++++++----- clang/lib/CodeGen/SanitizerMetadata.h | 13 +++---- clang/lib/Driver/SanitizerArgs.cpp | 13 ++++--- clang/lib/Driver/ToolChains/CommonArgs.cpp | 6 +++- clang/lib/Driver/ToolChains/Darwin.cpp | 6 ++++ clang/lib/Driver/ToolChains/Linux.cpp | 2 ++ clang/test/Driver/sanitizer-ld.c | 23 +++++++++++++ 16 files changed, 114 insertions(+), 27 deletions(-) diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def index 15c59c6bcdf29..c82b6d9b5f6c1 100644 --- a/clang/include/clang/Basic/Features.def +++ b/clang/include/clang/Basic/Features.def @@ -102,6 +102,7 @@ FEATURE(numerical_stability_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Nume FEATURE(memory_sanitizer, LangOpts.Sanitize.hasOneOf(SanitizerKind::Memory | SanitizerKind::KernelMemory)) +FEATURE(type_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Type)) FEATURE(thread_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Thread)) FEATURE(dataflow_sanitizer, LangOpts.Sanitize.has(SanitizerKind::DataFlow)) FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo)) diff --git a/clang/include/clang/Basic/Sanitizers.def b/clang/include/clang/Basic/Sanitizers.def index 9223f62b3639a..f234488eaa80c 100644 --- a/clang/include/clang/Basic/Sanitizers.def +++ b/clang/include/clang/Basic/Sanitizers.def @@ -73,6 +73,9 @@ SANITIZER("fuzzer", Fuzzer) // libFuzzer-required instrumentation, no linking. SANITIZER("fuzzer-no-link", FuzzerNoLink) +// TypeSanitizer +SANITIZER("type", Type) + // ThreadSanitizer SANITIZER("thread", Thread) diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h index 0c6f3869549ef..4f08ea2b26017 100644 --- a/clang/include/clang/Driver/SanitizerArgs.h +++ b/clang/include/clang/Driver/SanitizerArgs.h @@ -87,6 +87,7 @@ class SanitizerArgs { bool needsHwasanAliasesRt() const { return needsHwasanRt() && HwasanUseAliases; } + bool needsTysanRt() const { return Sanitizers.has(SanitizerKind::Type); } bool needsTsanRt() const { return Sanitizers.has(SanitizerKind::Thread); } bool needsMsanRt() const { return Sanitizers.has(SanitizerKind::Memory); } bool needsFuzzer() const { return Sanitizers.has(SanitizerKind::Fuzzer); } diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 8cf44592a1747..e719926ac47f4 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -77,6 +77,7 @@ #include "llvm/Transforms/Instrumentation/SanitizerBinaryMetadata.h" #include "llvm/Transforms/Instrumentation/SanitizerCoverage.h" #include "llvm/Transforms/Instrumentation/ThreadSanitizer.h" +#include "llvm/Transforms/Instrumentation/TypeSanitizer.h" #include "llvm/Transforms/ObjCARC.h" #include "llvm/Transforms/Scalar/EarlyCSE.h" #include "llvm/Transforms/Scalar/GVN.h" @@ -735,6 +736,11 @@ static void addSanitizers(const Triple &TargetTriple, MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass())); } + if (LangOpts.Sanitize.has(SanitizerKind::Type)) { + MPM.addPass(ModuleTypeSanitizerPass()); + MPM.addPass(createModuleToFunctionPassAdaptor(TypeSanitizerPass())); + } + if (LangOpts.Sanitize.has(SanitizerKind::NumericalStability)) MPM.addPass(NumericalStabilitySanitizerPass()); diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 47b21bc9f63f0..bb9d120c37ca8 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -458,7 +458,8 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D, LocalDeclMap.find(&D)->second = Address(castedAddr, elemTy, alignment); CGM.setStaticLocalDeclAddress(&D, castedAddr); - CGM.getSanitizerMetadata()->reportGlobal(var, D); + CGM.getSanitizerMetadata()->reportGlobalToASan(var, D); + CGM.getSanitizerMetadata()->reportGlobalToTySan(var, D); // Emit global variable debug descriptor for static vars. CGDebugInfo *DI = getDebugInfo(); diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp index 2c3054605ee75..96517511b2111 100644 --- a/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/clang/lib/CodeGen/CGDeclCXX.cpp @@ -479,6 +479,10 @@ llvm::Function *CodeGenModule::CreateGlobalInitOrCleanUpFunction( !isInNoSanitizeList(SanitizerKind::MemtagStack, Fn, Loc)) Fn->addFnAttr(llvm::Attribute::SanitizeMemTag); + if (getLangOpts().Sanitize.has(SanitizerKind::Type) && + !isInNoSanitizeList(SanitizerKind::Type, Fn, Loc)) + Fn->addFnAttr(llvm::Attribute::SanitizeType); + if (getLangOpts().Sanitize.has(SanitizerKind::Thread) && !isInNoSanitizeList(SanitizerKind::Thread, Fn, Loc)) Fn->addFnAttr(llvm::Attribute::SanitizeThread); diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 2bc10cdd2d344..af58fa64f8658 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -837,6 +837,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, Fn->addFnAttr(llvm::Attribute::SanitizeMemTag); if (SanOpts.has(SanitizerKind::Thread)) Fn->addFnAttr(llvm::Attribute::SanitizeThread); + if (SanOpts.has(SanitizerKind::Type)) + Fn->addFnAttr(llvm::Attribute::SanitizeType); if (SanOpts.has(SanitizerKind::NumericalStability)) Fn->addFnAttr(llvm::Attribute::SanitizeNumericalStability); if (SanOpts.hasOneOf(SanitizerKind::Memory | SanitizerKind::KernelMemory)) diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index d3d5c0743a520..a2f6a8a481113 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -397,8 +397,8 @@ CodeGenModule::CodeGenModule(ASTContext &C, if (LangOpts.HLSL) createHLSLRuntime(); - // Enable TBAA unless it's suppressed. ThreadSanitizer needs TBAA even at O0. - if (LangOpts.Sanitize.has(SanitizerKind::Thread) || + // Enable TBAA unless it's suppressed. TSan and TySan need TBAA even at O0. + if (LangOpts.Sanitize.hasOneOf(SanitizerKind::Thread | SanitizerKind::Type) || (!CodeGenOpts.RelaxedAliasing && CodeGenOpts.OptimizationLevel > 0)) TBAA.reset(new CodeGenTBAA(Context, getTypes(), TheModule, CodeGenOpts, getLangOpts())); @@ -5162,7 +5162,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, llvm::Type *Ty, } if (D) - SanitizerMD->reportGlobal(GV, *D); + SanitizerMD->reportGlobalToASan(GV, *D); LangAS ExpectedAS = D ? D->getType().getAddressSpace() @@ -5728,7 +5728,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, if (NeedsGlobalCtor || NeedsGlobalDtor) EmitCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor); - SanitizerMD->reportGlobal(GV, *D, NeedsGlobalCtor); + SanitizerMD->reportGlobalToASan(GV, *D, NeedsGlobalCtor); + SanitizerMD->reportGlobalToTySan(GV, *D); // Emit global variable debug information. if (CGDebugInfo *DI = getModuleDebugInfo()) @@ -6618,7 +6619,8 @@ CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S, if (Entry) *Entry = GV; - SanitizerMD->reportGlobal(GV, S->getStrTokenLoc(0), ""); + SanitizerMD->reportGlobalToASan(GV, S->getStrTokenLoc(0), ""); + // FIXME: Should we also report to the TySan? return ConstantAddress(castStringLiteralToDefaultAddressSpace(*this, GV), GV->getValueType(), Alignment); diff --git a/clang/lib/CodeGen/CodeGenTBAA.cpp b/clang/lib/CodeGen/CodeGenTBAA.cpp index 6eed8e1d2b671..75e66bae79afd 100644 --- a/clang/lib/CodeGen/CodeGenTBAA.cpp +++ b/clang/lib/CodeGen/CodeGenTBAA.cpp @@ -314,8 +314,10 @@ llvm::MDNode *CodeGenTBAA::getTypeInfoHelper(const Type *Ty) { } llvm::MDNode *CodeGenTBAA::getTypeInfo(QualType QTy) { - // At -O0 or relaxed aliasing, TBAA is not emitted for regular types. - if (CodeGenOpts.OptimizationLevel == 0 || CodeGenOpts.RelaxedAliasing) + // At -O0 or relaxed aliasing, TBAA is not emitted for regular types (unless + // we're running TypeSanitizer). + if (!Features.Sanitize.has(SanitizerKind::Type) && + (CodeGenOpts.OptimizationLevel == 0 || CodeGenOpts.RelaxedAliasing)) return nullptr; // If the type has the may_alias attribute (even on a typedef), it is diff --git a/clang/lib/CodeGen/SanitizerMetadata.cpp b/clang/lib/CodeGen/SanitizerMetadata.cpp index c1a6b223480a1..c551a2529805c 100644 --- a/clang/lib/CodeGen/SanitizerMetadata.cpp +++ b/clang/lib/CodeGen/SanitizerMetadata.cpp @@ -31,11 +31,11 @@ static SanitizerMask expandKernelSanitizerMasks(SanitizerMask Mask) { return Mask; } -void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, - SourceLocation Loc, StringRef Name, - QualType Ty, - SanitizerMask NoSanitizeAttrMask, - bool IsDynInit) { +void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV, + SourceLocation Loc, StringRef Name, + QualType Ty, + SanitizerMask NoSanitizeAttrMask, + bool IsDynInit) { SanitizerSet FsanitizeArgument = CGM.getLangOpts().Sanitize; if (!isAsanHwasanOrMemTag(FsanitizeArgument)) return; @@ -72,8 +72,8 @@ void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, GV->setSanitizerMetadata(Meta); } -void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D, - bool IsDynInit) { +void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV, + const VarDecl &D, bool IsDynInit) { if (!isAsanHwasanOrMemTag(CGM.getLangOpts().Sanitize)) return; std::string QualName; @@ -95,6 +95,30 @@ void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D, IsDynInit); } +void SanitizerMetadata::reportGlobalToTySan(llvm::GlobalVariable *GV, + const VarDecl &D) { + if (!CGM.getLangOpts().Sanitize.has(SanitizerKind::Type)) + return; + + for (auto Attr : D.specific_attrs()) + if (Attr->getMask() & SanitizerKind::Type) + return; + + QualType QTy = D.getType(); + llvm::MDNode *TBAAInfo = CGM.getTBAATypeInfo(QTy); + if (!TBAAInfo || TBAAInfo == CGM.getTBAATypeInfo(CGM.getContext().CharTy)) + return; + + llvm::Metadata *GlobalMetadata[] = {llvm::ConstantAsMetadata::get(GV), + TBAAInfo}; + + llvm::MDNode *ThisGlobal = + llvm::MDNode::get(CGM.getLLVMContext(), GlobalMetadata); + llvm::NamedMDNode *TysanGlobals = + CGM.getModule().getOrInsertNamedMetadata("llvm.tysan.globals"); + TysanGlobals->addOperand(ThisGlobal); +} + void SanitizerMetadata::disableSanitizerForGlobal(llvm::GlobalVariable *GV) { - reportGlobal(GV, SourceLocation(), "", QualType(), SanitizerKind::All); + reportGlobalToASan(GV, SourceLocation(), "", QualType(), SanitizerKind::All); } diff --git a/clang/lib/CodeGen/SanitizerMetadata.h b/clang/lib/CodeGen/SanitizerMetadata.h index 000f02cf8dcf1..9de087c518c6a 100644 --- a/clang/lib/CodeGen/SanitizerMetadata.h +++ b/clang/lib/CodeGen/SanitizerMetadata.h @@ -37,12 +37,13 @@ class SanitizerMetadata { public: SanitizerMetadata(CodeGenModule &CGM); - void reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D, - bool IsDynInit = false); - void reportGlobal(llvm::GlobalVariable *GV, SourceLocation Loc, - StringRef Name, QualType Ty = {}, - SanitizerMask NoSanitizeAttrMask = {}, - bool IsDynInit = false); + void reportGlobalToASan(llvm::GlobalVariable *GV, const VarDecl &D, + bool IsDynInit = false); + void reportGlobalToASan(llvm::GlobalVariable *GV, SourceLocation Loc, + StringRef Name, QualType Ty = {}, + SanitizerMask NoSanitizeAttrMask = {}, + bool IsDynInit = false); + void reportGlobalToTySan(llvm::GlobalVariable *GV, const VarDecl &D); void disableSanitizerForGlobal(llvm::GlobalVariable *GV); }; } // end namespace CodeGen diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 1abfe8fd92807..e826cd627693f 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -37,15 +37,15 @@ static const SanitizerMask NotAllowedWithMinimalRuntime = SanitizerKind::Vptr; static const SanitizerMask NotAllowedWithExecuteOnly = SanitizerKind::Function | SanitizerKind::KCFI; static const SanitizerMask NeedsUnwindTables = - SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Thread | + SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Type | SanitizerKind::Thread | SanitizerKind::Memory | SanitizerKind::DataFlow | SanitizerKind::NumericalStability; static const SanitizerMask SupportsCoverage = SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::KernelAddress | SanitizerKind::KernelHWAddress | - SanitizerKind::MemtagStack | SanitizerKind::MemtagHeap | - SanitizerKind::MemtagGlobals | SanitizerKind::Memory | - SanitizerKind::KernelMemory | SanitizerKind::Leak | + SanitizerKind::Type | SanitizerKind::MemtagStack | + SanitizerKind::MemtagHeap | SanitizerKind::MemtagGlobals | + SanitizerKind::Memory | SanitizerKind::KernelMemory | SanitizerKind::Leak | SanitizerKind::Undefined | SanitizerKind::Integer | SanitizerKind::Bounds | SanitizerKind::ImplicitConversion | SanitizerKind::Nullability | SanitizerKind::DataFlow | SanitizerKind::Fuzzer | @@ -182,6 +182,7 @@ static void addDefaultIgnorelists(const Driver &D, SanitizerMask Kinds, {"msan_ignorelist.txt", SanitizerKind::Memory}, {"nsan_ignorelist.txt", SanitizerKind::NumericalStability}, {"tsan_ignorelist.txt", SanitizerKind::Thread}, + {"tysan_blacklist.txt", SanitizerKind::Type}, {"dfsan_abilist.txt", SanitizerKind::DataFlow}, {"cfi_ignorelist.txt", SanitizerKind::CFI}, {"ubsan_ignorelist.txt", @@ -526,6 +527,10 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, std::pair IncompatibleGroups[] = { std::make_pair(SanitizerKind::Address, SanitizerKind::Thread | SanitizerKind::Memory), + std::make_pair(SanitizerKind::Type, + SanitizerKind::Address | SanitizerKind::KernelAddress | + SanitizerKind::Memory | SanitizerKind::Leak | + SanitizerKind::Thread | SanitizerKind::KernelAddress), std::make_pair(SanitizerKind::Thread, SanitizerKind::Memory), std::make_pair(SanitizerKind::Leak, SanitizerKind::Thread | SanitizerKind::Memory), diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 03dbdc27975b4..cb545b6def92c 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -1445,8 +1445,10 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, if (SanArgs.needsScudoRt()) { SharedRuntimes.push_back("scudo_standalone"); } - if (SanArgs.needsTsanRt()) + if (SanArgs.needsTsanRt() && SanArgs.linkRuntimes()) SharedRuntimes.push_back("tsan"); + if (SanArgs.needsTysanRt()) + StaticRuntimes.push_back("tysan"); if (SanArgs.needsHwasanRt()) { if (SanArgs.needsHwasanAliasesRt()) SharedRuntimes.push_back("hwasan_aliases"); @@ -1519,6 +1521,8 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, if (SanArgs.linkCXXRuntimes()) StaticRuntimes.push_back("tsan_cxx"); } + if (!SanArgs.needsSharedRt() && SanArgs.needsTysanRt()) + StaticRuntimes.push_back("tysan"); if (!SanArgs.needsSharedRt() && SanArgs.needsUbsanRt()) { if (SanArgs.requiresMinimalRuntime()) { StaticRuntimes.push_back("ubsan_minimal"); diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp index 87380869f6fda..7bd3179deb227 100644 --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -1596,6 +1596,8 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, "Static sanitizer runtimes not supported"); AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan"); } + if (Sanitize.needsTysanRt()) + AddLinkSanitizerLibArgs(Args, CmdArgs, "tysan"); if (Sanitize.needsFuzzer() && !Args.hasArg(options::OPT_dynamiclib)) { AddLinkSanitizerLibArgs(Args, CmdArgs, "fuzzer", /*shared=*/false); @@ -3599,6 +3601,10 @@ SanitizerMask Darwin::getSupportedSanitizers() const { Res |= SanitizerKind::Thread; } + if ((IsX86_64 || IsAArch64) && isTargetMacOSBased()) { + Res |= SanitizerKind::Type; + } + if (IsX86_64) Res |= SanitizerKind::NumericalStability; diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp index 46962e88d4550..c91b55b5a2948 100644 --- a/clang/lib/Driver/ToolChains/Linux.cpp +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -837,6 +837,8 @@ SanitizerMask Linux::getSupportedSanitizers() const { if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64 || IsSystemZ || IsLoongArch64 || IsRISCV64) Res |= SanitizerKind::Thread; + if (IsX86_64 || IsAArch64) + Res |= SanitizerKind::Type; if (IsX86_64 || IsSystemZ || IsPowerPC64) Res |= SanitizerKind::KernelMemory; if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsMIPS || IsArmArch || diff --git a/clang/test/Driver/sanitizer-ld.c b/clang/test/Driver/sanitizer-ld.c index 877a01c3de304..2083a3c4c67a4 100644 --- a/clang/test/Driver/sanitizer-ld.c +++ b/clang/test/Driver/sanitizer-ld.c @@ -274,6 +274,29 @@ // CHECK-ASAN-ANDROID-SHARED-NOT: "-lpthread" // CHECK-ASAN-ANDROID-SHARED-NOT: "-lresolv" + +// RUN: %clangxx %s -### -o %t.o 2>&1 \ +// RUN: --target=x86_64-unknown-linux -fuse-ld=ld -stdlib=platform -lstdc++ \ +// RUN: -fsanitize=type \ +// RUN: -resource-dir=%S/Inputs/resource_dir \ +// RUN: --sysroot=%S/Inputs/basic_linux_tree \ +// RUN: | FileCheck --check-prefix=CHECK-TYSAN-LINUX-CXX %s +// +// CHECK-TYSAN-LINUX-CXX: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}" +// CHECK-TYSAN-LINUX-CXX-NOT: stdc++ +// CHECK-TYSAN-LINUX-CXX: "--whole-archive" "{{.*}}libclang_rt.tysan{{[^.]*}}.a" "--no-whole-archive" +// CHECK-TYSAN-LINUX-CXX: stdc++ + +// RUN: %clangxx -fsanitize=type -### %s 2>&1 \ +// RUN: -mmacosx-version-min=10.6 \ +// RUN: --target=x86_64-apple-darwin13.4.0 -fuse-ld=ld -stdlib=platform \ +// RUN: -resource-dir=%S/Inputs/resource_dir \ +// RUN: --sysroot=%S/Inputs/basic_linux_tree \ +// RUN: | FileCheck --check-prefix=CHECK-TYSAN-DARWIN-CXX %s +// CHECK-TYSAN-DARWIN-CXX: "{{.*}}ld{{(.exe)?}}" +// CHECK-TYSAN-DARWIN-CXX: libclang_rt.tysan_osx_dynamic.dylib +// CHECK-TYSAN-DARWIN-CXX-NOT: -lc++abi + // RUN: %clangxx -### %s 2>&1 \ // RUN: --target=x86_64-unknown-linux -fuse-ld=ld -stdlib=platform -lstdc++ \ // RUN: -fsanitize=thread \ From 9adf5bed94b43a017a31e47219db9368715a88c2 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Thu, 18 Apr 2024 23:03:05 +0100 Subject: [PATCH 11/24] !fixup: add test --- clang/lib/CodeGen/SanitizerMetadata.cpp | 2 +- clang/test/CodeGen/sanitize-type-attr.cpp | 74 +++++++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 clang/test/CodeGen/sanitize-type-attr.cpp diff --git a/clang/lib/CodeGen/SanitizerMetadata.cpp b/clang/lib/CodeGen/SanitizerMetadata.cpp index c551a2529805c..903ee65dd3eaa 100644 --- a/clang/lib/CodeGen/SanitizerMetadata.cpp +++ b/clang/lib/CodeGen/SanitizerMetadata.cpp @@ -91,7 +91,7 @@ void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV, return NoSanitizeMask; }; - reportGlobal(GV, D.getLocation(), QualName, D.getType(), getNoSanitizeMask(D), + reportGlobalToASan(GV, D.getLocation(), QualName, D.getType(), getNoSanitizeMask(D), IsDynInit); } diff --git a/clang/test/CodeGen/sanitize-type-attr.cpp b/clang/test/CodeGen/sanitize-type-attr.cpp new file mode 100644 index 0000000000000..4da8488e1f948 --- /dev/null +++ b/clang/test/CodeGen/sanitize-type-attr.cpp @@ -0,0 +1,74 @@ +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=WITHOUT %s +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s -fsanitize=type | FileCheck -check-prefix=TYSAN %s +// RUN: echo "src:%s" | sed -e 's/\\/\\\\/g' > %t +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s -fsanitize=type -fsanitize-blacklist=%t | FileCheck -check-prefix=BL %s + +// The sanitize_type attribute should be attached to functions +// when TypeSanitizer is enabled, unless no_sanitize("type") attribute +// is present. + +// WITHOUT: NoTYSAN1{{.*}}) [[NOATTR:#[0-9]+]] +// BL: NoTYSAN1{{.*}}) [[NOATTR:#[0-9]+]] +// TYSAN: NoTYSAN1{{.*}}) [[NOATTR:#[0-9]+]] +__attribute__((no_sanitize("type"))) int NoTYSAN1(int *a) { return *a; } + +// WITHOUT: NoTYSAN2{{.*}}) [[NOATTR]] +// BL: NoTYSAN2{{.*}}) [[NOATTR]] +// TYSAN: NoTYSAN2{{.*}}) [[NOATTR]] +__attribute__((no_sanitize("type"))) int NoTYSAN2(int *a); +int NoTYSAN2(int *a) { return *a; } + +// WITHOUT: NoTYSAN3{{.*}}) [[NOATTR:#[0-9]+]] +// BL: NoTYSAN3{{.*}}) [[NOATTR:#[0-9]+]] +// TYSAN: NoTYSAN3{{.*}}) [[NOATTR:#[0-9]+]] +__attribute__((no_sanitize("type"))) int NoTYSAN3(int *a) { return *a; } + +// WITHOUT: TYSANOk{{.*}}) [[NOATTR]] +// BL: TYSANOk{{.*}}) [[NOATTR]] +// TYSAN: TYSANOk{{.*}}) [[WITH:#[0-9]+]] +int TYSANOk(int *a) { return *a; } + +// WITHOUT: TemplateTYSANOk{{.*}}) [[NOATTR]] +// BL: TemplateTYSANOk{{.*}}) [[NOATTR]] +// TYSAN: TemplateTYSANOk{{.*}}) [[WITH]] +template +int TemplateTYSANOk() { return i; } + +// WITHOUT: TemplateNoTYSAN{{.*}}) [[NOATTR]] +// BL: TemplateNoTYSAN{{.*}}) [[NOATTR]] +// TYSAN: TemplateNoTYSAN{{.*}}) [[NOATTR]] +template +__attribute__((no_sanitize("type"))) int TemplateNoTYSAN() { return i; } + +int force_instance = TemplateTYSANOk<42>() + TemplateNoTYSAN<42>(); + +// Check that __cxx_global_var_init* get the sanitize_type attribute. +int global1 = 0; +int global2 = *(int *)((char *)&global1 + 1); +// WITHOUT: @__cxx_global_var_init{{.*}}[[NOATTR:#[0-9]+]] +// BL: @__cxx_global_var_init{{.*}}[[NOATTR:#[0-9]+]] +// TYSAN: @__cxx_global_var_init{{.*}}[[WITH:#[0-9]+]] + +// Make sure that we don't add globals to the list for which we don't have a +// specific type description. +// FIXME: We now have a type description for this type and a global is added. Should it? +struct SX { + int a, b; +}; +SX sx; + +// WITHOUT: attributes [[NOATTR]] = { noinline nounwind{{.*}} } + +// BL: attributes [[NOATTR]] = { noinline nounwind{{.*}} } + +// TYSAN: attributes [[NOATTR]] = { mustprogress noinline nounwind{{.*}} } +// TYSAN: attributes [[WITH]] = { noinline nounwind sanitize_type{{.*}} } + +// TYSAN-DAG: !llvm.tysan.globals = !{[[G1MD:![0-9]+]], [[G2MD:![0-9]+]], [[G3MD:![0-9]+]], [[SXMD:![0-9]+]]} +// TYSAN-DAG: [[G1MD]] = !{ptr @force_instance, [[INTMD:![0-9]+]]} +// TYSAN-DAG: [[INTMD]] = !{!"int", +// TYSAN-DAG: [[G2MD]] = !{ptr @global1, [[INTMD]]} +// TYSAN-DAG: [[G3MD]] = !{ptr @global2, [[INTMD]]} +// TYSAN-DAG: [[SXMD]] = !{ptr @sx, [[SXTYMD:![0-9]+]]} +// TYSAN-DAG: [[SXTYMD]] = !{!"_ZTS2SX", [[INTMD]], i64 0, !1, i64 4} +// TYSAN-DAG: Simple C++ TBAA From 349c32d23e02161b4b23f9d9bdccec727c035574 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Fri, 22 Nov 2024 19:23:16 +0000 Subject: [PATCH 12/24] !fixup formatting and add release note. --- clang/docs/ReleaseNotes.rst | 4 ++++ clang/lib/CodeGen/SanitizerMetadata.cpp | 4 ++-- clang/lib/Driver/SanitizerArgs.cpp | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index a541d399d1e74..b7bf7b2955dc0 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -1155,6 +1155,10 @@ Sanitizers `_. See that link for examples. +- Introduced an experimental Type Sanitizer, activated by using the + -fsanitize=type flag. This sanitizer detects violations of C/C++ type-based + aliasing rules. + Python Binding Changes ---------------------- - Fixed an issue that led to crashes when calling ``Type.get_exception_specification_kind``. diff --git a/clang/lib/CodeGen/SanitizerMetadata.cpp b/clang/lib/CodeGen/SanitizerMetadata.cpp index 903ee65dd3eaa..af9c986be6f8e 100644 --- a/clang/lib/CodeGen/SanitizerMetadata.cpp +++ b/clang/lib/CodeGen/SanitizerMetadata.cpp @@ -91,8 +91,8 @@ void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV, return NoSanitizeMask; }; - reportGlobalToASan(GV, D.getLocation(), QualName, D.getType(), getNoSanitizeMask(D), - IsDynInit); + reportGlobalToASan(GV, D.getLocation(), QualName, D.getType(), + getNoSanitizeMask(D), IsDynInit); } void SanitizerMetadata::reportGlobalToTySan(llvm::GlobalVariable *GV, diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index e826cd627693f..c9b412cde4cf0 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -37,8 +37,8 @@ static const SanitizerMask NotAllowedWithMinimalRuntime = SanitizerKind::Vptr; static const SanitizerMask NotAllowedWithExecuteOnly = SanitizerKind::Function | SanitizerKind::KCFI; static const SanitizerMask NeedsUnwindTables = - SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Type | SanitizerKind::Thread | - SanitizerKind::Memory | SanitizerKind::DataFlow | + SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Type | + SanitizerKind::Thread | SanitizerKind::Memory | SanitizerKind::DataFlow | SanitizerKind::NumericalStability; static const SanitizerMask SupportsCoverage = SanitizerKind::Address | SanitizerKind::HWAddress | From 2c3ac3d07f6d8bef0338c84fd73a55dbb80bf58d Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Wed, 27 Nov 2024 20:42:24 +0000 Subject: [PATCH 13/24] !fixup merge reportGlobal again, adjust release notes. --- clang/docs/ReleaseNotes.rst | 2 +- clang/lib/CodeGen/CGDecl.cpp | 3 +- clang/lib/CodeGen/CodeGenModule.cpp | 8 +-- clang/lib/CodeGen/SanitizerMetadata.cpp | 74 ++++++++++++------------- clang/lib/CodeGen/SanitizerMetadata.h | 13 ++--- 5 files changed, 47 insertions(+), 53 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index b7bf7b2955dc0..a73a849f4818f 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -1156,7 +1156,7 @@ Sanitizers for examples. - Introduced an experimental Type Sanitizer, activated by using the - -fsanitize=type flag. This sanitizer detects violations of C/C++ type-based + ``-fsanitize=type flag. This sanitizer detects violations of C/C++ type-based aliasing rules. Python Binding Changes diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index bb9d120c37ca8..47b21bc9f63f0 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -458,8 +458,7 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D, LocalDeclMap.find(&D)->second = Address(castedAddr, elemTy, alignment); CGM.setStaticLocalDeclAddress(&D, castedAddr); - CGM.getSanitizerMetadata()->reportGlobalToASan(var, D); - CGM.getSanitizerMetadata()->reportGlobalToTySan(var, D); + CGM.getSanitizerMetadata()->reportGlobal(var, D); // Emit global variable debug descriptor for static vars. CGDebugInfo *DI = getDebugInfo(); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index a2f6a8a481113..c1f7d1ba97604 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -5162,7 +5162,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, llvm::Type *Ty, } if (D) - SanitizerMD->reportGlobalToASan(GV, *D); + SanitizerMD->reportGlobal(GV, *D); LangAS ExpectedAS = D ? D->getType().getAddressSpace() @@ -5728,8 +5728,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, if (NeedsGlobalCtor || NeedsGlobalDtor) EmitCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor); - SanitizerMD->reportGlobalToASan(GV, *D, NeedsGlobalCtor); - SanitizerMD->reportGlobalToTySan(GV, *D); + SanitizerMD->reportGlobal(GV, *D, NeedsGlobalCtor); // Emit global variable debug information. if (CGDebugInfo *DI = getModuleDebugInfo()) @@ -6619,8 +6618,7 @@ CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S, if (Entry) *Entry = GV; - SanitizerMD->reportGlobalToASan(GV, S->getStrTokenLoc(0), ""); - // FIXME: Should we also report to the TySan? + SanitizerMD->reportGlobal(GV, S->getStrTokenLoc(0), ""); return ConstantAddress(castStringLiteralToDefaultAddressSpace(*this, GV), GV->getValueType(), Alignment); diff --git a/clang/lib/CodeGen/SanitizerMetadata.cpp b/clang/lib/CodeGen/SanitizerMetadata.cpp index af9c986be6f8e..ef13a04deceba 100644 --- a/clang/lib/CodeGen/SanitizerMetadata.cpp +++ b/clang/lib/CodeGen/SanitizerMetadata.cpp @@ -19,9 +19,10 @@ using namespace CodeGen; SanitizerMetadata::SanitizerMetadata(CodeGenModule &CGM) : CGM(CGM) {} -static bool isAsanHwasanOrMemTag(const SanitizerSet &SS) { +static bool isAsanHwasanMemTagOrTysan(const SanitizerSet &SS) { return SS.hasOneOf(SanitizerKind::Address | SanitizerKind::KernelAddress | - SanitizerKind::HWAddress | SanitizerKind::MemTag); + SanitizerKind::HWAddress | SanitizerKind::MemTag | + SanitizerKind::Type); } static SanitizerMask expandKernelSanitizerMasks(SanitizerMask Mask) { @@ -31,13 +32,13 @@ static SanitizerMask expandKernelSanitizerMasks(SanitizerMask Mask) { return Mask; } -void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV, - SourceLocation Loc, StringRef Name, - QualType Ty, - SanitizerMask NoSanitizeAttrMask, - bool IsDynInit) { +void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, + SourceLocation Loc, StringRef Name, + QualType Ty, + SanitizerMask NoSanitizeAttrMask, + bool IsDynInit) { SanitizerSet FsanitizeArgument = CGM.getLangOpts().Sanitize; - if (!isAsanHwasanOrMemTag(FsanitizeArgument)) + if (!isAsanHwasanMemTagOrTysan(FsanitizeArgument)) return; FsanitizeArgument.Mask = expandKernelSanitizerMasks(FsanitizeArgument.Mask); @@ -70,11 +71,32 @@ void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV, GV, Loc, Ty, "init"); GV->setSanitizerMetadata(Meta); + + if (!CGM.getLangOpts().Sanitize.has(SanitizerKind::Type) || + NoSanitizeAttrMask & SanitizerKind::Type) + return; + + llvm::MDNode *TBAAInfo = CGM.getTBAATypeInfo(Ty); + if (!TBAAInfo || TBAAInfo == CGM.getTBAATypeInfo(CGM.getContext().CharTy)) + return; + + llvm::Metadata *GlobalMetadata[] = {llvm::ConstantAsMetadata::get(GV), + TBAAInfo}; + + // Metadata for the global already registered. + if (llvm::MDNode::getIfExists(CGM.getLLVMContext(), GlobalMetadata)) + return; + + llvm::MDNode *ThisGlobal = + llvm::MDNode::get(CGM.getLLVMContext(), GlobalMetadata); + llvm::NamedMDNode *TysanGlobals = + CGM.getModule().getOrInsertNamedMetadata("llvm.tysan.globals"); + TysanGlobals->addOperand(ThisGlobal); } -void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV, - const VarDecl &D, bool IsDynInit) { - if (!isAsanHwasanOrMemTag(CGM.getLangOpts().Sanitize)) +void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D, + bool IsDynInit) { + if (!isAsanHwasanMemTagOrTysan(CGM.getLangOpts().Sanitize)) return; std::string QualName; llvm::raw_string_ostream OS(QualName); @@ -91,34 +113,10 @@ void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV, return NoSanitizeMask; }; - reportGlobalToASan(GV, D.getLocation(), QualName, D.getType(), - getNoSanitizeMask(D), IsDynInit); -} - -void SanitizerMetadata::reportGlobalToTySan(llvm::GlobalVariable *GV, - const VarDecl &D) { - if (!CGM.getLangOpts().Sanitize.has(SanitizerKind::Type)) - return; - - for (auto Attr : D.specific_attrs()) - if (Attr->getMask() & SanitizerKind::Type) - return; - - QualType QTy = D.getType(); - llvm::MDNode *TBAAInfo = CGM.getTBAATypeInfo(QTy); - if (!TBAAInfo || TBAAInfo == CGM.getTBAATypeInfo(CGM.getContext().CharTy)) - return; - - llvm::Metadata *GlobalMetadata[] = {llvm::ConstantAsMetadata::get(GV), - TBAAInfo}; - - llvm::MDNode *ThisGlobal = - llvm::MDNode::get(CGM.getLLVMContext(), GlobalMetadata); - llvm::NamedMDNode *TysanGlobals = - CGM.getModule().getOrInsertNamedMetadata("llvm.tysan.globals"); - TysanGlobals->addOperand(ThisGlobal); + reportGlobal(GV, D.getLocation(), QualName, D.getType(), getNoSanitizeMask(D), + IsDynInit); } void SanitizerMetadata::disableSanitizerForGlobal(llvm::GlobalVariable *GV) { - reportGlobalToASan(GV, SourceLocation(), "", QualType(), SanitizerKind::All); + reportGlobal(GV, SourceLocation(), "", QualType(), SanitizerKind::All); } diff --git a/clang/lib/CodeGen/SanitizerMetadata.h b/clang/lib/CodeGen/SanitizerMetadata.h index 9de087c518c6a..000f02cf8dcf1 100644 --- a/clang/lib/CodeGen/SanitizerMetadata.h +++ b/clang/lib/CodeGen/SanitizerMetadata.h @@ -37,13 +37,12 @@ class SanitizerMetadata { public: SanitizerMetadata(CodeGenModule &CGM); - void reportGlobalToASan(llvm::GlobalVariable *GV, const VarDecl &D, - bool IsDynInit = false); - void reportGlobalToASan(llvm::GlobalVariable *GV, SourceLocation Loc, - StringRef Name, QualType Ty = {}, - SanitizerMask NoSanitizeAttrMask = {}, - bool IsDynInit = false); - void reportGlobalToTySan(llvm::GlobalVariable *GV, const VarDecl &D); + void reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D, + bool IsDynInit = false); + void reportGlobal(llvm::GlobalVariable *GV, SourceLocation Loc, + StringRef Name, QualType Ty = {}, + SanitizerMask NoSanitizeAttrMask = {}, + bool IsDynInit = false); void disableSanitizerForGlobal(llvm::GlobalVariable *GV); }; } // end namespace CodeGen From bac1590f7350277d6538dfceeded9cadadbb2958 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Wed, 27 Nov 2024 20:53:32 +0000 Subject: [PATCH 14/24] !fixup add missing `` --- clang/docs/ReleaseNotes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index a73a849f4818f..3fd1af31c0e8e 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -1156,7 +1156,7 @@ Sanitizers for examples. - Introduced an experimental Type Sanitizer, activated by using the - ``-fsanitize=type flag. This sanitizer detects violations of C/C++ type-based + ``-fsanitize=type`` flag. This sanitizer detects violations of C/C++ type-based aliasing rules. Python Binding Changes From 8dfaca81c8286385713afe33961efc7baf1a3ff1 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Fri, 6 Dec 2024 11:46:31 +0000 Subject: [PATCH 15/24] !fixup undo unrelated changes, fix runtimes to push --- clang/lib/Driver/ToolChains/CommonArgs.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index cb545b6def92c..b393049669aa3 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -1445,10 +1445,10 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, if (SanArgs.needsScudoRt()) { SharedRuntimes.push_back("scudo_standalone"); } - if (SanArgs.needsTsanRt() && SanArgs.linkRuntimes()) + if (SanArgs.needsTsanRt()) SharedRuntimes.push_back("tsan"); if (SanArgs.needsTysanRt()) - StaticRuntimes.push_back("tysan"); + SharedRuntimes.push_back("tysan"); if (SanArgs.needsHwasanRt()) { if (SanArgs.needsHwasanAliasesRt()) SharedRuntimes.push_back("hwasan_aliases"); From 13c4092708f82809aeec5320c093387aa4e17993 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Tue, 10 Dec 2024 12:18:03 +0000 Subject: [PATCH 16/24] !fixup account for globals without types. --- clang/lib/CodeGen/SanitizerMetadata.cpp | 2 +- clang/test/CodeGen/sanitize-type-attr.cpp | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/clang/lib/CodeGen/SanitizerMetadata.cpp b/clang/lib/CodeGen/SanitizerMetadata.cpp index ef13a04deceba..e7a88cf5646ef 100644 --- a/clang/lib/CodeGen/SanitizerMetadata.cpp +++ b/clang/lib/CodeGen/SanitizerMetadata.cpp @@ -72,7 +72,7 @@ void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, GV->setSanitizerMetadata(Meta); - if (!CGM.getLangOpts().Sanitize.has(SanitizerKind::Type) || + if (Ty.isNull() || !CGM.getLangOpts().Sanitize.has(SanitizerKind::Type) || NoSanitizeAttrMask & SanitizerKind::Type) return; diff --git a/clang/test/CodeGen/sanitize-type-attr.cpp b/clang/test/CodeGen/sanitize-type-attr.cpp index 4da8488e1f948..eaae9aa98a47a 100644 --- a/clang/test/CodeGen/sanitize-type-attr.cpp +++ b/clang/test/CodeGen/sanitize-type-attr.cpp @@ -57,6 +57,17 @@ struct SX { }; SX sx; +void consumer(const char *); + +void char_caller() { + // TYSAN: void @_Z11char_callerv() + // TYSAN-NEXT: entry: + // TYSAN-NEXT: call void @_Z8consumerPKc(ptr noundef @.str) + // TYSAN-NEXT: ret void + + consumer("foo"); +} + // WITHOUT: attributes [[NOATTR]] = { noinline nounwind{{.*}} } // BL: attributes [[NOATTR]] = { noinline nounwind{{.*}} } From 524eb555b0473bd93401297c5deba77f4dbd83fe Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Fri, 22 Nov 2024 15:01:41 +0000 Subject: [PATCH 17/24] [TySan] A Type Sanitizer (Runtime Library) --- clang/runtime/CMakeLists.txt | 2 +- .../cmake/Modules/AllSupportedArchDefs.cmake | 1 + compiler-rt/cmake/config-ix.cmake | 15 +- compiler-rt/lib/tysan/CMakeLists.txt | 64 ++++ compiler-rt/lib/tysan/lit.cfg | 35 ++ compiler-rt/lib/tysan/lit.site.cfg.in | 12 + compiler-rt/lib/tysan/tysan.cpp | 344 ++++++++++++++++++ compiler-rt/lib/tysan/tysan.h | 79 ++++ compiler-rt/lib/tysan/tysan.syms.extra | 2 + compiler-rt/lib/tysan/tysan_flags.inc | 17 + compiler-rt/lib/tysan/tysan_interceptors.cpp | 250 +++++++++++++ compiler-rt/lib/tysan/tysan_platform.h | 93 +++++ compiler-rt/test/tysan/CMakeLists.txt | 32 ++ compiler-rt/test/tysan/anon-ns.cpp | 41 +++ compiler-rt/test/tysan/anon-same-struct.c | 26 ++ compiler-rt/test/tysan/anon-struct.c | 27 ++ compiler-rt/test/tysan/basic.c | 65 ++++ compiler-rt/test/tysan/char-memcpy.c | 45 +++ .../test/tysan/constexpr-subobject.cpp | 25 ++ compiler-rt/test/tysan/global.c | 31 ++ compiler-rt/test/tysan/int-long.c | 21 ++ compiler-rt/test/tysan/lit.cfg.py | 139 +++++++ compiler-rt/test/tysan/lit.site.cfg.py.in | 17 + compiler-rt/test/tysan/ptr-float.c | 19 + ...ruct-offset-multiple-compilation-units.cpp | 51 +++ compiler-rt/test/tysan/struct-offset.c | 26 ++ compiler-rt/test/tysan/struct.c | 39 ++ compiler-rt/test/tysan/union-wr-wr.c | 18 + compiler-rt/test/tysan/violation-pr45282.c | 32 ++ compiler-rt/test/tysan/violation-pr47137.c | 40 ++ compiler-rt/test/tysan/violation-pr51837.c | 34 ++ compiler-rt/test/tysan/violation-pr62544.c | 24 ++ compiler-rt/test/tysan/violation-pr62828.cpp | 44 +++ compiler-rt/test/tysan/violation-pr68655.cpp | 40 ++ compiler-rt/test/tysan/violation-pr86685.c | 29 ++ 35 files changed, 1777 insertions(+), 2 deletions(-) create mode 100644 compiler-rt/lib/tysan/CMakeLists.txt create mode 100644 compiler-rt/lib/tysan/lit.cfg create mode 100644 compiler-rt/lib/tysan/lit.site.cfg.in create mode 100644 compiler-rt/lib/tysan/tysan.cpp create mode 100644 compiler-rt/lib/tysan/tysan.h create mode 100644 compiler-rt/lib/tysan/tysan.syms.extra create mode 100644 compiler-rt/lib/tysan/tysan_flags.inc create mode 100644 compiler-rt/lib/tysan/tysan_interceptors.cpp create mode 100644 compiler-rt/lib/tysan/tysan_platform.h create mode 100644 compiler-rt/test/tysan/CMakeLists.txt create mode 100644 compiler-rt/test/tysan/anon-ns.cpp create mode 100644 compiler-rt/test/tysan/anon-same-struct.c create mode 100644 compiler-rt/test/tysan/anon-struct.c create mode 100644 compiler-rt/test/tysan/basic.c create mode 100644 compiler-rt/test/tysan/char-memcpy.c create mode 100644 compiler-rt/test/tysan/constexpr-subobject.cpp create mode 100644 compiler-rt/test/tysan/global.c create mode 100644 compiler-rt/test/tysan/int-long.c create mode 100644 compiler-rt/test/tysan/lit.cfg.py create mode 100644 compiler-rt/test/tysan/lit.site.cfg.py.in create mode 100644 compiler-rt/test/tysan/ptr-float.c create mode 100644 compiler-rt/test/tysan/struct-offset-multiple-compilation-units.cpp create mode 100644 compiler-rt/test/tysan/struct-offset.c create mode 100644 compiler-rt/test/tysan/struct.c create mode 100644 compiler-rt/test/tysan/union-wr-wr.c create mode 100644 compiler-rt/test/tysan/violation-pr45282.c create mode 100644 compiler-rt/test/tysan/violation-pr47137.c create mode 100644 compiler-rt/test/tysan/violation-pr51837.c create mode 100644 compiler-rt/test/tysan/violation-pr62544.c create mode 100644 compiler-rt/test/tysan/violation-pr62828.cpp create mode 100644 compiler-rt/test/tysan/violation-pr68655.cpp create mode 100644 compiler-rt/test/tysan/violation-pr86685.c diff --git a/clang/runtime/CMakeLists.txt b/clang/runtime/CMakeLists.txt index 65fcdc2868f03..ff2605b23d25b 100644 --- a/clang/runtime/CMakeLists.txt +++ b/clang/runtime/CMakeLists.txt @@ -122,7 +122,7 @@ if(LLVM_BUILD_EXTERNAL_COMPILER_RT AND EXISTS ${COMPILER_RT_SRC_ROOT}/) COMPONENT compiler-rt) # Add top-level targets that build specific compiler-rt runtimes. - set(COMPILER_RT_RUNTIMES fuzzer asan builtins dfsan lsan msan profile tsan ubsan ubsan-minimal) + set(COMPILER_RT_RUNTIMES fuzzer asan builtins dfsan lsan msan profile tsan tysan ubsan ubsan-minimal) foreach(runtime ${COMPILER_RT_RUNTIMES}) get_ext_project_build_command(build_runtime_cmd ${runtime}) add_custom_target(${runtime} diff --git a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake index b29ae179c2b4f..ad6784c7ba883 100644 --- a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake +++ b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake @@ -85,6 +85,7 @@ else() set(ALL_TSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64} ${S390X} ${LOONGARCH64} ${RISCV64}) endif() +set(ALL_TYSAN_SUPPORTED_ARCH ${X86_64} ${ARM64}) set(ALL_UBSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${RISCV64} ${MIPS32} ${MIPS64} ${PPC64} ${S390X} ${SPARC} ${SPARCV9} ${HEXAGON} ${LOONGARCH64}) diff --git a/compiler-rt/cmake/config-ix.cmake b/compiler-rt/cmake/config-ix.cmake index 6d52eecc9a91f..cf729c3adb1f5 100644 --- a/compiler-rt/cmake/config-ix.cmake +++ b/compiler-rt/cmake/config-ix.cmake @@ -458,6 +458,7 @@ if(APPLE) set(SANITIZER_COMMON_SUPPORTED_OS osx) set(PROFILE_SUPPORTED_OS osx) set(TSAN_SUPPORTED_OS osx) + set(TYSAN_SUPPORTED_OS osx) set(XRAY_SUPPORTED_OS osx) set(FUZZER_SUPPORTED_OS osx) set(ORC_SUPPORTED_OS) @@ -593,6 +594,7 @@ if(APPLE) list(APPEND FUZZER_SUPPORTED_OS ${platform}) list(APPEND ORC_SUPPORTED_OS ${platform}) list(APPEND UBSAN_SUPPORTED_OS ${platform}) + list(APPEND TYSAN_SUPPORTED_OS ${platform}) list(APPEND LSAN_SUPPORTED_OS ${platform}) list(APPEND STATS_SUPPORTED_OS ${platform}) endif() @@ -651,6 +653,9 @@ if(APPLE) list_intersect(CTX_PROFILE_SUPPORTED_ARCH ALL_CTX_PROFILE_SUPPORTED_ARCH SANITIZER_COMMON_SUPPORTED_ARCH) + list_intersect(TYSAN_SUPPORTED_ARCH + ALL_TYSAN_SUPPORTED_ARCH + SANITIZER_COMMON_SUPPORTED_ARCH) list_intersect(TSAN_SUPPORTED_ARCH ALL_TSAN_SUPPORTED_ARCH SANITIZER_COMMON_SUPPORTED_ARCH) @@ -703,6 +708,7 @@ else() filter_available_targets(PROFILE_SUPPORTED_ARCH ${ALL_PROFILE_SUPPORTED_ARCH}) filter_available_targets(CTX_PROFILE_SUPPORTED_ARCH ${ALL_CTX_PROFILE_SUPPORTED_ARCH}) filter_available_targets(TSAN_SUPPORTED_ARCH ${ALL_TSAN_SUPPORTED_ARCH}) + filter_available_targets(TYSAN_SUPPORTED_ARCH ${ALL_TYSAN_SUPPORTED_ARCH}) filter_available_targets(UBSAN_SUPPORTED_ARCH ${ALL_UBSAN_SUPPORTED_ARCH}) filter_available_targets(SAFESTACK_SUPPORTED_ARCH ${ALL_SAFESTACK_SUPPORTED_ARCH}) @@ -748,7 +754,7 @@ if(COMPILER_RT_SUPPORTED_ARCH) endif() message(STATUS "Compiler-RT supported architectures: ${COMPILER_RT_SUPPORTED_ARCH}") -set(ALL_SANITIZERS asan;rtsan;dfsan;msan;hwasan;tsan;safestack;cfi;scudo_standalone;ubsan_minimal;gwp_asan;nsan;asan_abi) +set(ALL_SANITIZERS asan;rtsan;dfsan;msan;hwasan;tsan;tysan;safestack;cfi;scudo_standalone;ubsan_minimal;gwp_asan;nsan;asan_abi) set(COMPILER_RT_SANITIZERS_TO_BUILD all CACHE STRING "sanitizers to build if supported on the target (all;${ALL_SANITIZERS})") list_replace(COMPILER_RT_SANITIZERS_TO_BUILD all "${ALL_SANITIZERS}") @@ -843,6 +849,13 @@ else() set(COMPILER_RT_HAS_CTX_PROFILE FALSE) endif() +if (COMPILER_RT_HAS_SANITIZER_COMMON AND TYSAN_SUPPORTED_ARCH AND + OS_NAME MATCHES "Linux|Darwin") + set(COMPILER_RT_HAS_TYSAN TRUE) +else() + set(COMPILER_RT_HAS_TYSAN FALSE) +endif() + if (COMPILER_RT_HAS_SANITIZER_COMMON AND TSAN_SUPPORTED_ARCH) if (OS_NAME MATCHES "Linux|Darwin|FreeBSD|NetBSD") set(COMPILER_RT_HAS_TSAN TRUE) diff --git a/compiler-rt/lib/tysan/CMakeLists.txt b/compiler-rt/lib/tysan/CMakeLists.txt new file mode 100644 index 0000000000000..859b67928f004 --- /dev/null +++ b/compiler-rt/lib/tysan/CMakeLists.txt @@ -0,0 +1,64 @@ +include_directories(..) + +# Runtime library sources and build flags. +set(TYSAN_SOURCES + tysan.cpp + tysan_interceptors.cpp) +set(TYSAN_COMMON_CFLAGS ${SANITIZER_COMMON_CFLAGS}) +append_rtti_flag(OFF TYSAN_COMMON_CFLAGS) +# Prevent clang from generating libc calls. +append_list_if(COMPILER_RT_HAS_FFREESTANDING_FLAG -ffreestanding TYSAN_COMMON_CFLAGS) + +add_compiler_rt_object_libraries(RTTysan_dynamic + OS ${SANITIZER_COMMON_SUPPORTED_OS} + ARCHS ${TYSAN_SUPPORTED_ARCH} + SOURCES ${TYSAN_SOURCES} + ADDITIONAL_HEADERS ${TYSAN_HEADERS} + CFLAGS ${TYSAN_DYNAMIC_CFLAGS} + DEFS ${TYSAN_DYNAMIC_DEFINITIONS}) + + +# Static runtime library. +add_compiler_rt_component(tysan) + + +if(APPLE) + add_weak_symbols("sanitizer_common" WEAK_SYMBOL_LINK_FLAGS) + + add_compiler_rt_runtime(clang_rt.tysan + SHARED + OS ${SANITIZER_COMMON_SUPPORTED_OS} + ARCHS ${TYSAN_SUPPORTED_ARCH} + OBJECT_LIBS RTTysan_dynamic + RTInterception + RTSanitizerCommon + RTSanitizerCommonLibc + RTSanitizerCommonSymbolizer + CFLAGS ${TYSAN_DYNAMIC_CFLAGS} + LINK_FLAGS ${WEAK_SYMBOL_LINK_FLAGS} + DEFS ${TYSAN_DYNAMIC_DEFINITIONS} + PARENT_TARGET tysan) + + add_compiler_rt_runtime(clang_rt.tysan_static + STATIC + ARCHS ${TYSAN_SUPPORTED_ARCH} + OBJECT_LIBS RTTysan_static + CFLAGS ${TYSAN_CFLAGS} + DEFS ${TYSAN_COMMON_DEFINITIONS} + PARENT_TARGET tysan) +else() + foreach(arch ${TYSAN_SUPPORTED_ARCH}) + set(TYSAN_CFLAGS ${TYSAN_COMMON_CFLAGS}) + append_list_if(COMPILER_RT_HAS_FPIE_FLAG -fPIE TYSAN_CFLAGS) + add_compiler_rt_runtime(clang_rt.tysan + STATIC + ARCHS ${arch} + SOURCES ${TYSAN_SOURCES} + $ + $ + $ + $ + CFLAGS ${TYSAN_CFLAGS} + PARENT_TARGET tysan) + endforeach() +endif() diff --git a/compiler-rt/lib/tysan/lit.cfg b/compiler-rt/lib/tysan/lit.cfg new file mode 100644 index 0000000000000..bd2bbe855529a --- /dev/null +++ b/compiler-rt/lib/tysan/lit.cfg @@ -0,0 +1,35 @@ +# -*- Python -*- + +import os + +# Setup config name. +config.name = 'TypeSanitizer' + getattr(config, 'name_suffix', 'default') + +# Setup source root. +config.test_source_root = os.path.dirname(__file__) + +# Setup default compiler flags used with -fsanitize=type option. +clang_tysan_cflags = (["-fsanitize=type", + "-mno-omit-leaf-frame-pointer", + "-fno-omit-frame-pointer", + "-fno-optimize-sibling-calls"] + + [config.target_cflags] + + config.debug_info_flags) +clang_tysan_cxxflags = config.cxx_mode_flags + clang_tysan_cflags + +def build_invocation(compile_flags): + return " " + " ".join([config.clang] + compile_flags) + " " + +config.substitutions.append( ("%clang_tysan ", build_invocation(clang_tysan_cflags)) ) +config.substitutions.append( ("%clangxx_tysan ", build_invocation(clang_tysan_cxxflags)) ) + +# Default test suffixes. +config.suffixes = ['.c', '.cc', '.cpp'] + +# TypeSanitizer tests are currently supported on Linux only. +if config.host_os not in ['Linux']: + config.unsupported = True + +if config.target_arch != 'aarch64': + config.available_features.add('stable-runtime') + diff --git a/compiler-rt/lib/tysan/lit.site.cfg.in b/compiler-rt/lib/tysan/lit.site.cfg.in new file mode 100644 index 0000000000000..673d04e514379 --- /dev/null +++ b/compiler-rt/lib/tysan/lit.site.cfg.in @@ -0,0 +1,12 @@ +@LIT_SITE_CFG_IN_HEADER@ + +# Tool-specific config options. +config.name_suffix = "@TYSAN_TEST_CONFIG_SUFFIX@" +config.target_cflags = "@TYSAN_TEST_TARGET_CFLAGS@" +config.target_arch = "@TYSAN_TEST_TARGET_ARCH@" + +# Load common config for all compiler-rt lit tests. +lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured") + +# Load tool-specific config that would do the real work. +lit_config.load_config(config, "@TYSAN_LIT_SOURCE_DIR@/lit.cfg") diff --git a/compiler-rt/lib/tysan/tysan.cpp b/compiler-rt/lib/tysan/tysan.cpp new file mode 100644 index 0000000000000..f1b6bdcf0d826 --- /dev/null +++ b/compiler-rt/lib/tysan/tysan.cpp @@ -0,0 +1,344 @@ +//===-- tysan.cpp ---------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of TypeSanitizer. +// +// TypeSanitizer runtime. +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_atomic.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_flag_parser.h" +#include "sanitizer_common/sanitizer_flags.h" +#include "sanitizer_common/sanitizer_libc.h" +#include "sanitizer_common/sanitizer_report_decorator.h" +#include "sanitizer_common/sanitizer_stacktrace.h" +#include "sanitizer_common/sanitizer_symbolizer.h" + +#include "tysan/tysan.h" + +using namespace __sanitizer; +using namespace __tysan; + +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void +tysan_set_type_unknown(const void *addr, uptr size) { + if (tysan_inited) + internal_memset(shadow_for(addr), 0, size * sizeof(uptr)); +} + +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void +tysan_copy_types(const void *daddr, const void *saddr, uptr size) { + if (tysan_inited) + internal_memmove(shadow_for(daddr), shadow_for(saddr), size * sizeof(uptr)); +} + +static const char *getDisplayName(const char *Name) { + if (Name[0] == '\0') + return ""; + + // Clang generates tags for C++ types that demangle as typeinfo. Remove the + // prefix from the generated string. + const char TIPrefix[] = "typeinfo name for "; + + const char *DName = Symbolizer::GetOrInit()->Demangle(Name); + if (!internal_strncmp(DName, TIPrefix, sizeof(TIPrefix) - 1)) + DName += sizeof(TIPrefix) - 1; + + return DName; +} + +static void printTDName(tysan_type_descriptor *td) { + if (((sptr)td) <= 0) { + Printf(""); + return; + } + + switch (td->Tag) { + default: + DCHECK(0); + break; + case TYSAN_MEMBER_TD: + printTDName(td->Member.Access); + if (td->Member.Access != td->Member.Base) { + Printf(" (in "); + printTDName(td->Member.Base); + Printf(" at offset %zu)", td->Member.Offset); + } + break; + case TYSAN_STRUCT_TD: + Printf("%s", getDisplayName( + (char *)(td->Struct.Members + td->Struct.MemberCount))); + break; + } +} + +static tysan_type_descriptor *getRootTD(tysan_type_descriptor *TD) { + tysan_type_descriptor *RootTD = TD; + + do { + RootTD = TD; + + if (TD->Tag == TYSAN_STRUCT_TD) { + if (TD->Struct.MemberCount > 0) + TD = TD->Struct.Members[0].Type; + else + TD = nullptr; + } else if (TD->Tag == TYSAN_MEMBER_TD) { + TD = TD->Member.Access; + } else { + DCHECK(0); + break; + } + } while (TD); + + return RootTD; +} + +static bool isAliasingLegalUp(tysan_type_descriptor *TDA, + tysan_type_descriptor *TDB, int TDAOffset) { + // Walk up the tree starting with TDA to see if we reach TDB. + uptr OffsetA = 0, OffsetB = 0; + if (TDB->Tag == TYSAN_MEMBER_TD) { + OffsetB = TDB->Member.Offset; + TDB = TDB->Member.Base; + } + + if (TDA->Tag == TYSAN_MEMBER_TD) { + OffsetA = TDA->Member.Offset - TDAOffset; + TDA = TDA->Member.Base; + } + + do { + if (TDA == TDB) { + return OffsetA == OffsetB; + } + + if (TDA->Tag == TYSAN_STRUCT_TD) { + // Reached root type descriptor. + if (!TDA->Struct.MemberCount) + break; + + uptr Idx = 0; + for (; Idx < TDA->Struct.MemberCount - 1; ++Idx) { + if (TDA->Struct.Members[Idx].Offset >= OffsetA) + break; + } + + OffsetA -= TDA->Struct.Members[Idx].Offset; + TDA = TDA->Struct.Members[Idx].Type; + } else { + DCHECK(0); + break; + } + } while (TDA); + + return false; +} + +static bool isAliasingLegal(tysan_type_descriptor *TDA, + tysan_type_descriptor *TDB, int TDAOffset = 0) { + if (TDA == TDB || !TDB || !TDA) + return true; + + // Aliasing is legal is the two types have different root nodes. + if (getRootTD(TDA) != getRootTD(TDB)) + return true; + + // TDB may have been adjusted by offset TDAOffset in the caller to point to + // the outer type. Check for aliasing with and without adjusting for this + // offset. + return isAliasingLegalUp(TDA, TDB, 0) || isAliasingLegalUp(TDB, TDA, 0) || + isAliasingLegalUp(TDA, TDB, TDAOffset); +} + +namespace __tysan { +class Decorator : public __sanitizer::SanitizerCommonDecorator { +public: + Decorator() : SanitizerCommonDecorator() {} + const char *Warning() { return Red(); } + const char *Name() { return Green(); } + const char *End() { return Default(); } +}; +} // namespace __tysan + +ALWAYS_INLINE +static void reportError(void *Addr, int Size, tysan_type_descriptor *TD, + tysan_type_descriptor *OldTD, const char *AccessStr, + const char *DescStr, int Offset, uptr pc, uptr bp, + uptr sp) { + Decorator d; + Printf("%s", d.Warning()); + Report("ERROR: TypeSanitizer: type-aliasing-violation on address %p" + " (pc %p bp %p sp %p tid %llu)\n", + Addr, (void *)pc, (void *)bp, (void *)sp, GetTid()); + Printf("%s", d.End()); + Printf("%s of size %d at %p with type ", AccessStr, Size, Addr); + + Printf("%s", d.Name()); + printTDName(TD); + Printf("%s", d.End()); + + Printf(" %s of type ", DescStr); + + Printf("%s", d.Name()); + printTDName(OldTD); + Printf("%s", d.End()); + + if (Offset != 0) + Printf(" that starts at offset %d\n", Offset); + else + Printf("\n"); + + if (pc) { + + bool request_fast = StackTrace::WillUseFastUnwind(true); + BufferedStackTrace ST; + ST.Unwind(kStackTraceMax, pc, bp, 0, 0, 0, request_fast); + ST.Print(); + } else { + Printf("\n"); + } +} + +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void +__tysan_check(void *addr, int size, tysan_type_descriptor *td, int flags) { + GET_CALLER_PC_BP_SP; + + bool IsRead = flags & 1; + bool IsWrite = flags & 2; + const char *AccessStr; + if (IsRead && !IsWrite) + AccessStr = "READ"; + else if (!IsRead && IsWrite) + AccessStr = "WRITE"; + else + AccessStr = "ATOMIC UPDATE"; + + tysan_type_descriptor **OldTDPtr = shadow_for(addr); + tysan_type_descriptor *OldTD = *OldTDPtr; + if (((sptr)OldTD) < 0) { + int i = -((sptr)OldTD); + OldTDPtr -= i; + OldTD = *OldTDPtr; + + if (!isAliasingLegal(td, OldTD, i)) + reportError(addr, size, td, OldTD, AccessStr, + "accesses part of an existing object", -i, pc, bp, sp); + + return; + } + + if (!isAliasingLegal(td, OldTD)) { + reportError(addr, size, td, OldTD, AccessStr, "accesses an existing object", + 0, pc, bp, sp); + return; + } + + // These types are allowed to alias (or the stored type is unknown), report + // an error if we find an interior type. + + for (int i = 0; i < size; ++i) { + OldTDPtr = shadow_for((void *)(((uptr)addr) + i)); + OldTD = *OldTDPtr; + if (((sptr)OldTD) >= 0 && !isAliasingLegal(td, OldTD)) + reportError(addr, size, td, OldTD, AccessStr, + "partially accesses an object", i, pc, bp, sp); + } +} + +Flags __tysan::flags_data; + +SANITIZER_INTERFACE_ATTRIBUTE uptr __tysan_shadow_memory_address; +SANITIZER_INTERFACE_ATTRIBUTE uptr __tysan_app_memory_mask; + +#ifdef TYSAN_RUNTIME_VMA +// Runtime detected VMA size. +int __tysan::vmaSize; +#endif + +void Flags::SetDefaults() { +#define TYSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; +#include "tysan_flags.inc" +#undef TYSAN_FLAG +} + +static void RegisterTySanFlags(FlagParser *parser, Flags *f) { +#define TYSAN_FLAG(Type, Name, DefaultValue, Description) \ + RegisterFlag(parser, #Name, Description, &f->Name); +#include "tysan_flags.inc" +#undef TYSAN_FLAG +} + +static void InitializeFlags() { + SetCommonFlagsDefaults(); + { + CommonFlags cf; + cf.CopyFrom(*common_flags()); + cf.external_symbolizer_path = GetEnv("TYSAN_SYMBOLIZER_PATH"); + OverrideCommonFlags(cf); + } + + flags().SetDefaults(); + + FlagParser parser; + RegisterCommonFlags(&parser); + RegisterTySanFlags(&parser, &flags()); + parser.ParseString(GetEnv("TYSAN_OPTIONS")); + InitializeCommonFlags(); + if (Verbosity()) + ReportUnrecognizedFlags(); + if (common_flags()->help) + parser.PrintFlagDescriptions(); +} + +static void TySanInitializePlatformEarly() { + AvoidCVE_2016_2143(); +#ifdef TYSAN_RUNTIME_VMA + vmaSize = (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1); +#if defined(__aarch64__) && !SANITIZER_APPLE + if (vmaSize != 39 && vmaSize != 42 && vmaSize != 48) { + Printf("FATAL: TypeSanitizer: unsupported VMA range\n"); + Printf("FATAL: Found %d - Supported 39, 42 and 48\n", vmaSize); + Die(); + } +#endif +#endif + + __sanitizer::InitializePlatformEarly(); + + __tysan_shadow_memory_address = ShadowAddr(); + __tysan_app_memory_mask = AppMask(); +} + +namespace __tysan { +bool tysan_inited = false; +bool tysan_init_is_running; +} // namespace __tysan + +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __tysan_init() { + CHECK(!tysan_init_is_running); + if (tysan_inited) + return; + tysan_init_is_running = true; + + InitializeFlags(); + TySanInitializePlatformEarly(); + + InitializeInterceptors(); + + if (!MmapFixedNoReserve(ShadowAddr(), AppAddr() - ShadowAddr())) + Die(); + + tysan_init_is_running = false; + tysan_inited = true; +} + +#if SANITIZER_CAN_USE_PREINIT_ARRAY +__attribute__((section(".preinit_array"), + used)) static void (*tysan_init_ptr)() = __tysan_init; +#endif diff --git a/compiler-rt/lib/tysan/tysan.h b/compiler-rt/lib/tysan/tysan.h new file mode 100644 index 0000000000000..ec6f9587e9ce5 --- /dev/null +++ b/compiler-rt/lib/tysan/tysan.h @@ -0,0 +1,79 @@ +//===-- tysan.h -------------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of TypeSanitizer. +// +// Private TySan header. +//===----------------------------------------------------------------------===// + +#ifndef TYSAN_H +#define TYSAN_H + +#include "sanitizer_common/sanitizer_internal_defs.h" + +using __sanitizer::sptr; +using __sanitizer::u16; +using __sanitizer::uptr; + +#include "tysan_platform.h" + +extern "C" { +void tysan_set_type_unknown(const void *addr, uptr size); +void tysan_copy_types(const void *daddr, const void *saddr, uptr size); +} + +namespace __tysan { +extern bool tysan_inited; +extern bool tysan_init_is_running; + +void InitializeInterceptors(); + +enum { TYSAN_MEMBER_TD = 1, TYSAN_STRUCT_TD = 2 }; + +struct tysan_member_type_descriptor { + struct tysan_type_descriptor *Base; + struct tysan_type_descriptor *Access; + uptr Offset; +}; + +struct tysan_struct_type_descriptor { + uptr MemberCount; + struct { + struct tysan_type_descriptor *Type; + uptr Offset; + } Members[1]; // Tail allocated. + // char Name[]; // Tail allocated. +}; + +struct tysan_type_descriptor { + uptr Tag; + union { + tysan_member_type_descriptor Member; + tysan_struct_type_descriptor Struct; + }; +}; + +inline tysan_type_descriptor **shadow_for(const void *ptr) { + return (tysan_type_descriptor **)((((uptr)ptr) & AppMask()) * sizeof(ptr) + + ShadowAddr()); +} + +struct Flags { +#define TYSAN_FLAG(Type, Name, DefaultValue, Description) Type Name; +#include "tysan_flags.inc" +#undef TYSAN_FLAG + + void SetDefaults(); +}; + +extern Flags flags_data; +inline Flags &flags() { return flags_data; } + +} // namespace __tysan + +#endif // TYSAN_H diff --git a/compiler-rt/lib/tysan/tysan.syms.extra b/compiler-rt/lib/tysan/tysan.syms.extra new file mode 100644 index 0000000000000..04e7854316199 --- /dev/null +++ b/compiler-rt/lib/tysan/tysan.syms.extra @@ -0,0 +1,2 @@ +tysan_* +__tysan_* diff --git a/compiler-rt/lib/tysan/tysan_flags.inc b/compiler-rt/lib/tysan/tysan_flags.inc new file mode 100644 index 0000000000000..98b6591f844ef --- /dev/null +++ b/compiler-rt/lib/tysan/tysan_flags.inc @@ -0,0 +1,17 @@ +//===-- tysan_flags.inc ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// TySan runtime flags. +// +//===----------------------------------------------------------------------===// +#ifndef TYSAN_FLAG +#error "Define TYSAN_FLAG prior to including this file!" +#endif + +// TYSAN_FLAG(Type, Name, DefaultValue, Description) +// See COMMON_FLAG in sanitizer_flags.inc for more details. diff --git a/compiler-rt/lib/tysan/tysan_interceptors.cpp b/compiler-rt/lib/tysan/tysan_interceptors.cpp new file mode 100644 index 0000000000000..5fc6f24412272 --- /dev/null +++ b/compiler-rt/lib/tysan/tysan_interceptors.cpp @@ -0,0 +1,250 @@ +//===-- tysan_interceptors.cpp --------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of TypeSanitizer. +// +// Interceptors for standard library functions. +//===----------------------------------------------------------------------===// + +#include "interception/interception.h" +#include "sanitizer_common/sanitizer_common.h" +#include "tysan/tysan.h" + +#if SANITIZER_LINUX && !SANITIZER_ANDROID +#define TYSAN_INTERCEPT___STRDUP 1 +#else +#define TYSAN_INTERCEPT___STRDUP 0 +#endif + +#if SANITIZER_LINUX +extern "C" int mallopt(int param, int value); +#endif + +using namespace __sanitizer; +using namespace __tysan; + +static const uptr early_alloc_buf_size = 16384; +static uptr allocated_bytes; +static char early_alloc_buf[early_alloc_buf_size]; + +static bool isInEarlyAllocBuf(const void *ptr) { + return ((uptr)ptr >= (uptr)early_alloc_buf && + ((uptr)ptr - (uptr)early_alloc_buf) < sizeof(early_alloc_buf)); +} + +// Handle allocation requests early (before all interceptors are setup). dlsym, +// for example, calls calloc. +static void *handleEarlyAlloc(uptr size) { + void *mem = (void *)&early_alloc_buf[allocated_bytes]; + allocated_bytes += size; + CHECK_LT(allocated_bytes, early_alloc_buf_size); + return mem; +} + +INTERCEPTOR(void *, memset, void *dst, int v, uptr size) { + if (!tysan_inited && REAL(memset) == nullptr) + return internal_memset(dst, v, size); + + void *res = REAL(memset)(dst, v, size); + tysan_set_type_unknown(dst, size); + return res; +} + +INTERCEPTOR(void *, memmove, void *dst, const void *src, uptr size) { + if (!tysan_inited && REAL(memmove) == nullptr) + return internal_memmove(dst, src, size); + + void *res = REAL(memmove)(dst, src, size); + tysan_copy_types(dst, src, size); + return res; +} + +INTERCEPTOR(void *, memcpy, void *dst, const void *src, uptr size) { + if (!tysan_inited && REAL(memcpy) == nullptr) { + // memmove is used here because on some platforms this will also + // intercept the memmove implementation. + return internal_memmove(dst, src, size); + } + + void *res = REAL(memcpy)(dst, src, size); + tysan_copy_types(dst, src, size); + return res; +} + +INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags, + int fd, OFF_T offset) { + void *res = REAL(mmap)(addr, length, prot, flags, fd, offset); + if (res != (void *)-1) + tysan_set_type_unknown(res, RoundUpTo(length, GetPageSize())); + return res; +} + +#if !SANITIZER_APPLE +INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags, + int fd, OFF64_T offset) { + void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset); + if (res != (void *)-1) + tysan_set_type_unknown(res, RoundUpTo(length, GetPageSize())); + return res; +} +#endif + +INTERCEPTOR(char *, strdup, const char *s) { + char *res = REAL(strdup)(s); + if (res) + tysan_copy_types(res, const_cast(s), internal_strlen(s)); + return res; +} + +#if TYSAN_INTERCEPT___STRDUP +INTERCEPTOR(char *, __strdup, const char *s) { + char *res = REAL(__strdup)(s); + if (res) + tysan_copy_types(res, const_cast(s), internal_strlen(s)); + return res; +} +#endif // TYSAN_INTERCEPT___STRDUP + +INTERCEPTOR(void *, malloc, uptr size) { + if (tysan_init_is_running && REAL(malloc) == nullptr) + return handleEarlyAlloc(size); + + void *res = REAL(malloc)(size); + if (res) + tysan_set_type_unknown(res, size); + return res; +} + +INTERCEPTOR(void *, realloc, void *ptr, uptr size) { + void *res = REAL(realloc)(ptr, size); + // We might want to copy the types from the original allocation (although + // that would require that we knew its size). + if (res) + tysan_set_type_unknown(res, size); + return res; +} + +INTERCEPTOR(void *, calloc, uptr nmemb, uptr size) { + if (tysan_init_is_running && REAL(calloc) == nullptr) + return handleEarlyAlloc(nmemb * size); + + void *res = REAL(calloc)(nmemb, size); + if (res) + tysan_set_type_unknown(res, nmemb * size); + return res; +} + +INTERCEPTOR(void, free, void *p) { + // There are only a few early allocation requests, + // so we simply skip the free. + if (isInEarlyAllocBuf(p)) + return; + REAL(free)(p); +} + +INTERCEPTOR(void *, valloc, uptr size) { + void *res = REAL(valloc)(size); + if (res) + tysan_set_type_unknown(res, size); + return res; +} + +#if SANITIZER_INTERCEPT_MEMALIGN +INTERCEPTOR(void *, memalign, uptr alignment, uptr size) { + void *res = REAL(memalign)(alignment, size); + if (res) + tysan_set_type_unknown(res, size); + return res; +} +#define TYSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign) +#else +#define TYSAN_MAYBE_INTERCEPT_MEMALIGN +#endif // SANITIZER_INTERCEPT_MEMALIGN + +#if SANITIZER_INTERCEPT___LIBC_MEMALIGN +INTERCEPTOR(void *, __libc_memalign, uptr alignment, uptr size) { + void *res = REAL(__libc_memalign)(alignment, size); + if (res) + tysan_set_type_unknown(res, size); + return res; +} +#define TYSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN \ + INTERCEPT_FUNCTION(__libc_memalign) +#else +#define TYSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN +#endif // SANITIZER_INTERCEPT___LIBC_MEMALIGN + +#if SANITIZER_INTERCEPT_PVALLOC +INTERCEPTOR(void *, pvalloc, uptr size) { + void *res = REAL(pvalloc)(size); + if (res) + tysan_set_type_unknown(res, size); + return res; +} +#define TYSAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc) +#else +#define TYSAN_MAYBE_INTERCEPT_PVALLOC +#endif // SANITIZER_INTERCEPT_PVALLOC + +#if SANITIZER_INTERCEPT_ALIGNED_ALLOC +INTERCEPTOR(void *, aligned_alloc, uptr alignment, uptr size) { + void *res = REAL(aligned_alloc)(alignment, size); + if (res) + tysan_set_type_unknown(res, size); + return res; +} +#define TYSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC INTERCEPT_FUNCTION(aligned_alloc) +#else +#define TYSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC +#endif + +INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) { + int res = REAL(posix_memalign)(memptr, alignment, size); + if (res == 0 && *memptr) + tysan_set_type_unknown(*memptr, size); + return res; +} + +namespace __tysan { +void InitializeInterceptors() { + static int inited = 0; + CHECK_EQ(inited, 0); + + // Instruct libc malloc to consume less memory. +#if SANITIZER_LINUX + mallopt(1, 0); // M_MXFAST + mallopt(-3, 32 * 1024); // M_MMAP_THRESHOLD +#endif + + INTERCEPT_FUNCTION(mmap); + + INTERCEPT_FUNCTION(mmap64); + + INTERCEPT_FUNCTION(strdup); +#if TYSAN_INTERCEPT___STRDUP + INTERCEPT_FUNCTION(__strdup); +#endif + + INTERCEPT_FUNCTION(malloc); + INTERCEPT_FUNCTION(calloc); + INTERCEPT_FUNCTION(free); + INTERCEPT_FUNCTION(realloc); + INTERCEPT_FUNCTION(valloc); + TYSAN_MAYBE_INTERCEPT_MEMALIGN; + TYSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN; + TYSAN_MAYBE_INTERCEPT_PVALLOC; + TYSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC + INTERCEPT_FUNCTION(posix_memalign); + + INTERCEPT_FUNCTION(memset); + INTERCEPT_FUNCTION(memmove); + INTERCEPT_FUNCTION(memcpy); + + inited = 1; +} +} // namespace __tysan diff --git a/compiler-rt/lib/tysan/tysan_platform.h b/compiler-rt/lib/tysan/tysan_platform.h new file mode 100644 index 0000000000000..f01392885d939 --- /dev/null +++ b/compiler-rt/lib/tysan/tysan_platform.h @@ -0,0 +1,93 @@ +//===------------------------ tysan_platform.h ----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of TypeSanitizer. +// +// Platform specific information for TySan. +//===----------------------------------------------------------------------===// + +#ifndef TYSAN_PLATFORM_H +#define TYSAN_PLATFORM_H + +namespace __tysan { + +#if defined(__x86_64__) || SANITIZER_APPLE +struct Mapping { + static const uptr kShadowAddr = 0x010000000000ull; + static const uptr kAppAddr = 0x550000000000ull; + static const uptr kAppMemMsk = ~0x780000000000ull; +}; +#elif defined(__aarch64__) +struct Mapping39 { + static const uptr kShadowAddr = 0x0800000000ull; + static const uptr kAppAddr = 0x5500000000ull; + static const uptr kAppMemMsk = ~0x7800000000ull; +}; + +struct Mapping42 { + static const uptr kShadowAddr = 0x10000000000ull; + static const uptr kAppAddr = 0x2aa00000000ull; + static const uptr kAppMemMsk = ~0x3c000000000ull; +}; + +struct Mapping48 { + static const uptr kShadowAddr = 0x0002000000000ull; + static const uptr kAppAddr = 0x0aaaa00000000ull; + static const uptr kAppMemMsk = ~0x0fff800000000ull; +}; +#define TYSAN_RUNTIME_VMA 1 +#else +#error "TySan not supported for this platform!" +#endif + +#if TYSAN_RUNTIME_VMA +extern int vmaSize; +#endif + +enum MappingType { MAPPING_SHADOW_ADDR, MAPPING_APP_ADDR, MAPPING_APP_MASK }; + +template uptr MappingImpl(void) { + switch (Type) { + case MAPPING_SHADOW_ADDR: + return Mapping::kShadowAddr; + case MAPPING_APP_ADDR: + return Mapping::kAppAddr; + case MAPPING_APP_MASK: + return Mapping::kAppMemMsk; + } +} + +template uptr MappingArchImpl(void) { +#if defined(__aarch64__) && !SANITIZER_APPLE + switch (vmaSize) { + case 39: + return MappingImpl(); + case 42: + return MappingImpl(); + case 48: + return MappingImpl(); + } + DCHECK(0); + return 0; +#else + return MappingImpl(); +#endif +} + +ALWAYS_INLINE +uptr ShadowAddr() { return MappingArchImpl(); } + +ALWAYS_INLINE +uptr AppAddr() { return MappingArchImpl(); } + +ALWAYS_INLINE +uptr AppMask() { return MappingArchImpl(); } + +} // namespace __tysan + +#endif diff --git a/compiler-rt/test/tysan/CMakeLists.txt b/compiler-rt/test/tysan/CMakeLists.txt new file mode 100644 index 0000000000000..76f57501e854e --- /dev/null +++ b/compiler-rt/test/tysan/CMakeLists.txt @@ -0,0 +1,32 @@ +set(TYSAN_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + +set(TYSAN_TESTSUITES) + +set(TYSAN_TEST_ARCH ${TYSAN_SUPPORTED_ARCH}) +if(APPLE) + darwin_filter_host_archs(TYSAN_SUPPORTED_ARCH TYSAN_TEST_ARCH) +endif() + +foreach(arch ${TYSAN_TEST_ARCH}) + set(TYSAN_TEST_TARGET_ARCH ${arch}) + string(TOLOWER "-${arch}" TYSAN_TEST_CONFIG_SUFFIX) + get_test_cc_for_arch(${arch} TYSAN_TEST_TARGET_CC TYSAN_TEST_TARGET_CFLAGS) + string(TOUPPER ${arch} ARCH_UPPER_CASE) + set(CONFIG_NAME ${ARCH_UPPER_CASE}Config) + + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in + ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg.py) + list(APPEND TYSAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}) +endforeach() + +set(TYSAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) +if(NOT COMPILER_RT_STANDALONE_BUILD) + list(APPEND TYSAN_TEST_DEPS tysan) +endif() + +add_lit_testsuite(check-tysan "Running the TypeSanitizer tests" + ${TYSAN_TESTSUITES} + DEPENDS ${TYSAN_TEST_DEPS} + ) +set_target_properties(check-tysan PROPERTIES FOLDER "Compiler-RT Misc") diff --git a/compiler-rt/test/tysan/anon-ns.cpp b/compiler-rt/test/tysan/anon-ns.cpp new file mode 100644 index 0000000000000..681304411df31 --- /dev/null +++ b/compiler-rt/test/tysan/anon-ns.cpp @@ -0,0 +1,41 @@ +// RUN: %clangxx_tysan -O0 %s -c -o %t.o +// RUN: %clangxx_tysan -O0 %s -DPMAIN -c -o %tm.o +// RUN: %clangxx_tysan -O0 %t.o %tm.o -o %t +// RUN: %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include + +// This test demonstrates that the types from anonymous namespaces are +// different in different translation units (while the char* type is the same). + +namespace { +struct X { + X(int i, int j) : a(i), b(j) {} + int a; + int b; +}; +} // namespace + +#ifdef PMAIN +void foo(void *context, int i); +char fbyte(void *context); + +int main() { + X x(5, 6); + foo((void *)&x, 8); + std::cout << "fbyte: " << fbyte((void *)&x) << "\n"; +} +#else +void foo(void *context, int i) { + X *x = (X *)context; + x->b = i; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type int (in (anonymous namespace)::X at offset 4) accesses an existing object of type int (in (anonymous namespace)::X at offset 4) + // CHECK: {{#0 0x.* in foo\(void\*, int\) .*anon-ns.cpp:}}[[@LINE-3]] +} + +char fbyte(void *context) { return *(char *)context; } +#endif + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation diff --git a/compiler-rt/test/tysan/anon-same-struct.c b/compiler-rt/test/tysan/anon-same-struct.c new file mode 100644 index 0000000000000..b9044f2a0a73c --- /dev/null +++ b/compiler-rt/test/tysan/anon-same-struct.c @@ -0,0 +1,26 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include + +// The two anonymous structs are structurally identical. As a result, we don't +// report an aliasing violation here. +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation + +typedef struct { + int i1; +} s1; +typedef struct { + int i2; +} s2; + +void f(s1 *s1p, s2 *s2p) { + s1p->i1 = 2; + s2p->i2 = 3; + printf("%i\n", s1p->i1); +} + +int main() { + s1 s = {.i1 = 1}; + f(&s, (s2 *)&s); +} diff --git a/compiler-rt/test/tysan/anon-struct.c b/compiler-rt/test/tysan/anon-struct.c new file mode 100644 index 0000000000000..25f6633545928 --- /dev/null +++ b/compiler-rt/test/tysan/anon-struct.c @@ -0,0 +1,27 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include + +typedef struct { + int i1, i1b; +} s1; +typedef struct { + int i2, i2b, i2c; +} s2; + +void f(s1 *s1p, s2 *s2p) { + s1p->i1 = 2; + s2p->i2 = 3; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type int (in at offset 0) accesses an existing object of type int (in at offset 0) + // CHECK: {{#0 0x.* in f .*anon-struct.c:}}[[@LINE-3]] + printf("%i\n", s1p->i1); +} + +int main() { + s1 s = {.i1 = 1, .i1b = 5}; + f(&s, (s2 *)&s); +} + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation diff --git a/compiler-rt/test/tysan/basic.c b/compiler-rt/test/tysan/basic.c new file mode 100644 index 0000000000000..8e66e1a721383 --- /dev/null +++ b/compiler-rt/test/tysan/basic.c @@ -0,0 +1,65 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t 10 >%t.out.0 2>&1 +// RUN: FileCheck %s < %t.out.0 +// RUN: %clang_tysan -O2 %s -o %t && %run %t 10 >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include +#include +#include + +void __attribute__((noinline)) add_flt(float *a) { + *a += 2.0f; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: READ of size 4 at {{.*}} with type float accesses an existing object of type int + // CHECK: {{#0 0x.* in add_flt .*basic.c:}}[[@LINE-3]] + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type float accesses an existing object of type int + // CHECK: {{#0 0x.* in add_flt .*basic.c:}}[[@LINE-6]] + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: READ of size 4 at {{.*}} with type float accesses an existing object of type long + // CHECK: {{#0 0x.* in add_flt .*basic.c:}}[[@LINE-9]] + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type float accesses an existing object of type long + // CHECK: {{#0 0x.* in add_flt .*basic.c:}}[[@LINE-12]] + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: READ of size 4 at {{.*}} with type float accesses part of an existing object of type long that starts at offset -4 + // CHECK: {{#0 0x.* in add_flt .*basic.c:}}[[@LINE-15]] + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type float accesses part of an existing object of type long that starts at offset -4 + // CHECK: {{#0 0x.* in add_flt .*basic.c:}}[[@LINE-18]] + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: READ of size 4 at {{.*}} with type float partially accesses an object of type short that starts at offset 2 + // CHECK: {{#0 0x.* in add_flt .*basic.c:}}[[@LINE-21]] +} + +int main(int argc, char *argv[]) { + int x = atoi(argv[1]); + add_flt((float *)&x); + printf("x = %d\n", x); + + long y = x; + add_flt((float *)&y); + printf("y = %ld\n", y); + + add_flt(((float *)&y) + 1); + printf("y = %ld\n", y); + + char *mem = (char *)malloc(4 * sizeof(short)); + memset(mem, 0, 4 * sizeof(short)); + *(short *)(mem + 2) = x; + add_flt((float *)mem); + short s1 = *(short *)mem; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: READ of size 2 at {{.*}} with type short accesses an existing object of type float + // CHECK: {{#0 0x.* in main .*basic.c:}}[[@LINE-3]] + short s2 = *(short *)(mem + 2); + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: READ of size 2 at {{.*}} with type short accesses part of an existing object of type float that starts at offset -2 + // CHECK: {{#0 0x.* in main .*basic.c:}}[[@LINE-3]] + printf("m[0] = %d, m[1] = %d\n", s1, s2); + free(mem); + + return 0; +} + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation diff --git a/compiler-rt/test/tysan/char-memcpy.c b/compiler-rt/test/tysan/char-memcpy.c new file mode 100644 index 0000000000000..ebbb6b53d0f37 --- /dev/null +++ b/compiler-rt/test/tysan/char-memcpy.c @@ -0,0 +1,45 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out.0 2>&1 +// RUN: FileCheck %s < %t.out.0 +// RUN: %clang_tysan -O2 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include + +// There's no type-based-aliasing violation here: the memcpy is implemented +// using only char* or unsigned char* (both of which may alias anything). +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation + +void my_memcpy_uchar(void *dest, void *src, int n) { + unsigned char *p = dest, *q = src, *end = p + n; + while (p < end) + *p++ = *q++; +} + +void my_memcpy_char(void *dest, void *src, int n) { + char *p = dest, *q = src, *end = p + n; + while (p < end) + *p++ = *q++; +} + +void test_uchar() { + struct S { + short x; + short *r; + } s = {10, &s.x}, s2; + my_memcpy_uchar(&s2, &s, sizeof(struct S)); + printf("%d\n", *(s2.r)); +} + +void test_char() { + struct S { + short x; + short *r; + } s = {10, &s.x}, s2; + my_memcpy_char(&s2, &s, sizeof(struct S)); + printf("%d\n", *(s2.r)); +} + +int main() { + test_uchar(); + test_char(); +} diff --git a/compiler-rt/test/tysan/constexpr-subobject.cpp b/compiler-rt/test/tysan/constexpr-subobject.cpp new file mode 100644 index 0000000000000..9cae310554c9b --- /dev/null +++ b/compiler-rt/test/tysan/constexpr-subobject.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +// CHECK-NOT: TypeSanitizer + +int foo() { return 0; } + +struct Bar { + struct S2 { + int (*fnA)(); + int (*fnB)(); + }; + + static int x() { return 0; } + + static const S2 &get() { + static constexpr S2 Info = {&foo, &Bar::x}; + return Info; + } +}; + +int main() { + auto Info = Bar::get(); + return Info.fnB(); +} diff --git a/compiler-rt/test/tysan/global.c b/compiler-rt/test/tysan/global.c new file mode 100644 index 0000000000000..247ee768a8162 --- /dev/null +++ b/compiler-rt/test/tysan/global.c @@ -0,0 +1,31 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out +#include +#include + +float P; +long L; + +int main() { + *(int *)&P = 5; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type int accesses an existing object of type float + // CHECK: {{#0 0x.* in main .*global.c:}}[[@LINE-3]] + + void *mem = malloc(sizeof(long)); + *(int *)mem = 6; + memcpy(mem, &L, sizeof(L)); + *(int *)mem = 8; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type int accesses an existing object of type long + // CHECK: {{#0 0x.* in main .*global.c:}}[[@LINE-3]] + int r = *(((int *)mem) + 1); + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: READ of size 4 at {{.*}} with type int accesses part of an existing object of type long that starts at offset -4 + // CHECK: {{#0 0x.* in main .*global.c:}}[[@LINE-3]] + free(mem); + + return r; +} + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation diff --git a/compiler-rt/test/tysan/int-long.c b/compiler-rt/test/tysan/int-long.c new file mode 100644 index 0000000000000..b7956c07376e8 --- /dev/null +++ b/compiler-rt/test/tysan/int-long.c @@ -0,0 +1,21 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include + +long foo(int *x, long *y) { + *x = 0; + *y = 1; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 8 at {{.*}} with type long accesses an existing object of type int + // CHECK: {{#0 0x.* in foo .*int-long.c:}}[[@LINE-3]] + + return *x; +} + +int main(void) { + long l; + printf("%ld\n", foo((int *)&l, &l)); +} + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation diff --git a/compiler-rt/test/tysan/lit.cfg.py b/compiler-rt/test/tysan/lit.cfg.py new file mode 100644 index 0000000000000..05c8f0664d5e6 --- /dev/null +++ b/compiler-rt/test/tysan/lit.cfg.py @@ -0,0 +1,139 @@ +# -*- Python -*- + +import os +import platform +import re + +import lit.formats + +# Get shlex.quote if available (added in 3.3), and fall back to pipes.quote if +# it's not available. +try: + import shlex + sh_quote = shlex.quote +except: + import pipes + sh_quote = pipes.quote + +def get_required_attr(config, attr_name): + attr_value = getattr(config, attr_name, None) + if attr_value == None: + lit_config.fatal( + "No attribute %r in test configuration! You may need to run " + "tests from your build directory or add this attribute " + "to lit.site.cfg.py " % attr_name) + return attr_value + +def push_dynamic_library_lookup_path(config, new_path): + if platform.system() == 'Windows': + dynamic_library_lookup_var = 'PATH' + elif platform.system() == 'Darwin': + dynamic_library_lookup_var = 'DYLD_LIBRARY_PATH' + else: + dynamic_library_lookup_var = 'LD_LIBRARY_PATH' + + new_ld_library_path = os.path.pathsep.join( + (new_path, config.environment.get(dynamic_library_lookup_var, ''))) + config.environment[dynamic_library_lookup_var] = new_ld_library_path + + if platform.system() == 'FreeBSD': + dynamic_library_lookup_var = 'LD_32_LIBRARY_PATH' + new_ld_32_library_path = os.path.pathsep.join( + (new_path, config.environment.get(dynamic_library_lookup_var, ''))) + config.environment[dynamic_library_lookup_var] = new_ld_32_library_path + + if platform.system() == 'SunOS': + dynamic_library_lookup_var = 'LD_LIBRARY_PATH_32' + new_ld_library_path_32 = os.path.pathsep.join( + (new_path, config.environment.get(dynamic_library_lookup_var, ''))) + config.environment[dynamic_library_lookup_var] = new_ld_library_path_32 + + dynamic_library_lookup_var = 'LD_LIBRARY_PATH_64' + new_ld_library_path_64 = os.path.pathsep.join( + (new_path, config.environment.get(dynamic_library_lookup_var, ''))) + config.environment[dynamic_library_lookup_var] = new_ld_library_path_64 + +# Setup config name. +config.name = 'TypeSanitizer' + config.name_suffix + +# Platform-specific default TYSAN_OPTIONS for lit tests. +default_tysan_opts = list(config.default_sanitizer_opts) + +# On Darwin, leak checking is not enabled by default. Enable on macOS +# tests to prevent regressions +if config.host_os == 'Darwin' and config.apple_platform == 'osx': + default_tysan_opts += ['detect_leaks=1'] + +default_tysan_opts_str = ':'.join(default_tysan_opts) +if default_tysan_opts_str: + config.environment['TYSAN_OPTIONS'] = default_tysan_opts_str + default_tysan_opts_str += ':' +config.substitutions.append(('%env_tysan_opts=', + 'env TYSAN_OPTIONS=' + default_tysan_opts_str)) + +# Setup source root. +config.test_source_root = os.path.dirname(__file__) + +if config.host_os not in ['FreeBSD', 'NetBSD']: + libdl_flag = "-ldl" +else: + libdl_flag = "" + +# GCC-ASan doesn't link in all the necessary libraries automatically, so +# we have to do it ourselves. +if config.compiler_id == 'GNU': + extra_link_flags = ["-pthread", "-lstdc++", libdl_flag] +else: + extra_link_flags = [] + +# Setup default compiler flags used with -fsanitize=address option. +# FIXME: Review the set of required flags and check if it can be reduced. +target_cflags = [get_required_attr(config, "target_cflags")] + extra_link_flags +target_cxxflags = config.cxx_mode_flags + target_cflags +clang_tysan_static_cflags = (["-fsanitize=type", + "-mno-omit-leaf-frame-pointer", + "-fno-omit-frame-pointer", + "-fno-optimize-sibling-calls"] + + config.debug_info_flags + target_cflags) +if config.target_arch == 's390x': + clang_tysan_static_cflags.append("-mbackchain") +clang_tysan_static_cxxflags = config.cxx_mode_flags + clang_tysan_static_cflags + +clang_tysan_cflags = clang_tysan_static_cflags +clang_tysan_cxxflags = clang_tysan_static_cxxflags + +def build_invocation(compile_flags): + return " " + " ".join([config.clang] + compile_flags) + " " + +config.substitutions.append( ("%clang ", build_invocation(target_cflags)) ) +config.substitutions.append( ("%clangxx ", build_invocation(target_cxxflags)) ) +config.substitutions.append( ("%clang_tysan ", build_invocation(clang_tysan_cflags)) ) +config.substitutions.append( ("%clangxx_tysan ", build_invocation(clang_tysan_cxxflags)) ) + + +# FIXME: De-hardcode this path. +tysan_source_dir = os.path.join( + get_required_attr(config, "compiler_rt_src_root"), "lib", "tysan") +python_exec = sh_quote(get_required_attr(config, "python_executable")) + +# Set LD_LIBRARY_PATH to pick dynamic runtime up properly. +push_dynamic_library_lookup_path(config, config.compiler_rt_libdir) + +# Default test suffixes. +config.suffixes = ['.c', '.cpp'] + +if config.host_os == 'Darwin': + config.suffixes.append('.mm') + +if config.host_os == 'Windows': + config.substitutions.append(('%fPIC', '')) + config.substitutions.append(('%fPIE', '')) + config.substitutions.append(('%pie', '')) +else: + config.substitutions.append(('%fPIC', '-fPIC')) + config.substitutions.append(('%fPIE', '-fPIE')) + config.substitutions.append(('%pie', '-pie')) + +# Only run the tests on supported OSs. +if config.host_os not in ['Linux', 'Darwin',]: + config.unsupported = True diff --git a/compiler-rt/test/tysan/lit.site.cfg.py.in b/compiler-rt/test/tysan/lit.site.cfg.py.in new file mode 100644 index 0000000000000..b56dce4fed7a2 --- /dev/null +++ b/compiler-rt/test/tysan/lit.site.cfg.py.in @@ -0,0 +1,17 @@ +@LIT_SITE_CFG_IN_HEADER@ + +# Tool-specific config options. +config.name_suffix = "@TYSAN_TEST_CONFIG_SUFFIX@" +config.target_cflags = "@TYSAN_TEST_TARGET_CFLAGS@" +config.clang = "@TYSAN_TEST_TARGET_CC@" +config.bits = "@TYSAN_TEST_BITS@" +config.arm_thumb = "@COMPILER_RT_ARM_THUMB@" +config.apple_platform = "@TYSAN_TEST_APPLE_PLATFORM@" +config.apple_platform_min_deployment_target_flag = "@TYSAN_TEST_MIN_DEPLOYMENT_TARGET_FLAG@" +config.target_arch = "@TYSAN_TEST_TARGET_ARCH@" + +# Load common config for all compiler-rt lit tests. +lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured") + +# Load tool-specific config that would do the real work. +lit_config.load_config(config, "@TYSAN_LIT_SOURCE_DIR@/lit.cfg.py") diff --git a/compiler-rt/test/tysan/ptr-float.c b/compiler-rt/test/tysan/ptr-float.c new file mode 100644 index 0000000000000..61fa5f1afd70a --- /dev/null +++ b/compiler-rt/test/tysan/ptr-float.c @@ -0,0 +1,19 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +float *P; +void zero_array() { + int i; + for (i = 0; i < 1; ++i) + P[i] = 0.0f; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type float accesses an existing object of type any pointer + // CHECK: {{#0 0x.* in zero_array .*ptr-float.c:}}[[@LINE-3]] +} + +int main() { + P = (float *)&P; + zero_array(); +} + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation diff --git a/compiler-rt/test/tysan/struct-offset-multiple-compilation-units.cpp b/compiler-rt/test/tysan/struct-offset-multiple-compilation-units.cpp new file mode 100644 index 0000000000000..f7baa14d15aff --- /dev/null +++ b/compiler-rt/test/tysan/struct-offset-multiple-compilation-units.cpp @@ -0,0 +1,51 @@ +// RUN: %clangxx_tysan -O0 %s -c -o %t.o +// RUN: %clangxx_tysan -O0 %s -DPMAIN -c -o %tm.o +// RUN: %clangxx_tysan -O0 %s -DPINIT -c -o %tinit.o +// RUN: %clangxx_tysan -O0 %t.o %tm.o %tinit.o -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +#include +#include + +extern "C" { +typedef struct X { + int *start; + int *end; + int i; +} X; +}; + +#ifdef PMAIN +int foo(struct X *); +void bar(struct X *); +void init(struct X *); + +int main() { + struct X x; + init(&x); + printf("%d\n", foo(&x)); + free(x.start); + return 0; +} + +#elif PINIT + +void init(struct X *x) { + x->start = (int *)calloc(100, sizeof(int)); + x->end = x->start + 99; + x->i = 0; +} + +#else + +__attribute__((noinline)) int foo(struct X *x) { + if (x->start < x->end) + return 30; + return 10; +} + +void bar(struct X *x) { x->end = NULL; } + +#endif + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation diff --git a/compiler-rt/test/tysan/struct-offset.c b/compiler-rt/test/tysan/struct-offset.c new file mode 100644 index 0000000000000..7295e0ae121ed --- /dev/null +++ b/compiler-rt/test/tysan/struct-offset.c @@ -0,0 +1,26 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include +#include + +struct X { + int i; + int j; +}; + +int foo(struct X *p, struct X *q) { + q->j = 1; + p->i = 0; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type int (in X at offset 0) accesses an existing object of type int (in X at offset 4) + // CHECK: {{#0 0x.* in foo .*struct-offset.c:}}[[@LINE-3]] + return q->j; +} + +int main() { + unsigned char *p = malloc(3 * sizeof(int)); + printf("%i\n", foo((struct X *)(p + sizeof(int)), (struct X *)p)); +} + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation diff --git a/compiler-rt/test/tysan/struct.c b/compiler-rt/test/tysan/struct.c new file mode 100644 index 0000000000000..f7ecef5967624 --- /dev/null +++ b/compiler-rt/test/tysan/struct.c @@ -0,0 +1,39 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include + +typedef struct S1 { + int i1; +} s1; +typedef struct S2 { + int i2; +} s2; + +void g(int *i) { + *i = 5; + printf("%i\n", *i); +} + +void h(char *c) { + *c = 5; + printf("%i\n", (int)*c); +} + +void f(s1 *s1p, s2 *s2p) { + s1p->i1 = 2; + s2p->i2 = 3; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type int (in S2 at offset 0) accesses an existing object of type int (in S1 at offset 0) + // CHECK: {{#0 0x.* in f .*struct.c:}}[[@LINE-3]] + printf("%i\n", s1p->i1); +} + +int main() { + s1 s = {.i1 = 1}; + f(&s, (s2 *)&s); + g(&s.i1); + h((char *)&s.i1); +} + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation diff --git a/compiler-rt/test/tysan/union-wr-wr.c b/compiler-rt/test/tysan/union-wr-wr.c new file mode 100644 index 0000000000000..6414bbfcf9d95 --- /dev/null +++ b/compiler-rt/test/tysan/union-wr-wr.c @@ -0,0 +1,18 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation + +int main() { + union { + int i; + short s; + } u; + + u.i = 42; + u.s = 1; + + printf("%d\n", u.i); +} diff --git a/compiler-rt/test/tysan/violation-pr45282.c b/compiler-rt/test/tysan/violation-pr45282.c new file mode 100644 index 0000000000000..f3583d6be6f6a --- /dev/null +++ b/compiler-rt/test/tysan/violation-pr45282.c @@ -0,0 +1,32 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +// https://github.com/llvm/llvm-project/issues/45282 + +#include + +int main(void) { + + double a[29], b[20]; + int i, j; + + for (i = 0; i < 20; ++i) { + b[i] = 2.01f + 1.f; + ((float *)a)[i] = 2.01f * 2.0145f; + ((float *)a + 38)[i] = 2.01f * 1.0123f; + } + + // CHECK: TypeSanitizer: type-aliasing-violation on address + // CHECK-NEXT: WRITE of size 8 at {{.+}} with type double accesses an existing object of type float + // CHECK-NEXT: in main violation-pr45282.c:25 + + // loop of problems + for (j = 2; j <= 4; ++j) { + a[j - 1] = ((float *)a)[j] * ((float *)a + 38)[j - 1]; + ((float *)a + 38)[j - 1] = ((float *)a)[j - 1] + b[j - 1]; + } + + printf("((float *)a + 38)[2] = %f\n", ((float *)a + 38)[2]); + + return 0; +} diff --git a/compiler-rt/test/tysan/violation-pr47137.c b/compiler-rt/test/tysan/violation-pr47137.c new file mode 100644 index 0000000000000..3987128ff6fc6 --- /dev/null +++ b/compiler-rt/test/tysan/violation-pr47137.c @@ -0,0 +1,40 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +// https://github.com/llvm/llvm-project/issues/47137 +#include +#include + +void f(int m) { + int n = (4 * m + 2) / 3; + uint64_t *a = malloc(n * sizeof(uint64_t)); + uint64_t *b = malloc(n * sizeof(uint64_t)); + uint64_t aa[] = {0xffff3e0000000001, 0x22eaf0b680a88c16, 0x5a65d25ac40e20f3, + 0x34e7ac346236953e, 0x9dea3e0a26c6ba89, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000}; + uint64_t bb[] = {0x0000000024c0ffff, 0x000000004634d940, 0x00000000219d18ef, + 0x0000000000154519, 0x000000000000035f, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000}; + char l[20]; + l[0] = 0; + for (int i = 0; i < n; i++) { + a[i] = aa[i] + l[0] - '0'; + b[i] = bb[i] + l[0] - '0'; + } + + // CHECK: TypeSanitizer: type-aliasing-violation on address + // CHECK-NEXT: READ of size 2 at {{.+}} with type short accesses an existing object of type long long + // CHECK-NEXT: in f violation-pr47137.c:30 + for (int i = 0, j = 0; j < 4 * m; i += 4, j += 3) { + for (int k = 0; k < 3; k++) { + ((uint16_t *)a)[j + k] = ((uint16_t *)a)[i + k]; + ((uint16_t *)b)[j + k] = ((uint16_t *)b)[i + k]; + } + } + + printf("a: %016llx\n", a[0]); + free(a); + free(b); +} + +int main() { f(6); } diff --git a/compiler-rt/test/tysan/violation-pr51837.c b/compiler-rt/test/tysan/violation-pr51837.c new file mode 100644 index 0000000000000..d49a813933d65 --- /dev/null +++ b/compiler-rt/test/tysan/violation-pr51837.c @@ -0,0 +1,34 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include +#include + +// CHECK-NOT: TypeSanitizer + +union a { + int16_t b; + uint64_t c; +} d; + +uint64_t *e = &d.c; +static uint16_t f(int16_t a, int32_t b, uint64_t c); +static int64_t g(int32_t aa, uint8_t h, union a bb) { + int16_t *i = &d.b; + f(0, h, 0); + *i = h; + return 0; +} +uint16_t f(int16_t a, int32_t b, uint64_t c) { + for (d.c = 0; 0;) + ; + *e = 0; + return 0; +} + +int main() { + uint32_t j = 8; + g(1, j, d); + printf("%d\n", d.b); + return 0; +} diff --git a/compiler-rt/test/tysan/violation-pr62544.c b/compiler-rt/test/tysan/violation-pr62544.c new file mode 100644 index 0000000000000..30610925ba385 --- /dev/null +++ b/compiler-rt/test/tysan/violation-pr62544.c @@ -0,0 +1,24 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +// https://github.com/llvm/llvm-project/issues/62544 + +int printf(const char *, ...); +int a, b, c; +long d; +int main() { + short *e = &a; + int *f = &a; + *f = 0; + for (; b <= 9; b++) { + int **g = &f; + *f = d; + *g = &c; + } + + // CHECK: TypeSanitizer: type-aliasing-violation on address + // CHECK-NEXT: WRITE of size 2 at {{.+}} with type short accesses an existing object of type int + // CHECK-NEXT: in main violation-pr62544.c:22 + *e = 3; + printf("%d\n", a); +} diff --git a/compiler-rt/test/tysan/violation-pr62828.cpp b/compiler-rt/test/tysan/violation-pr62828.cpp new file mode 100644 index 0000000000000..33003df9761f5 --- /dev/null +++ b/compiler-rt/test/tysan/violation-pr62828.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +// https://github.com/llvm/llvm-project/issues/62828 +#include + +typedef int int_v8[8]; +typedef short short_v8[8]; +short *test1(int_v8 *cast_c_array, short_v8 *shuf_c_array1, int *ptr) { + int *input1 = reinterpret_cast(((int_v8 *)(cast_c_array))); + short *input2 = reinterpret_cast(reinterpret_cast(input1)); + + short *output1 = reinterpret_cast(((short_v8 *)(shuf_c_array1))); + short *output2 = + reinterpret_cast(reinterpret_cast(output1)); + + for (int r = 0; r < 8; ++r) { + int tmp = (int)((r * 4) + ptr[r]); + if ((ptr[r] / 4) == 0) { + int *input = reinterpret_cast(((int_v8 *)(cast_c_array))); + input[r] = tmp; + } + } + + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation on address + // CHECK-NEXT: READ of size 2 at {{.+}} with type short accesses an existing object of type int + // CHECK-NEXT: in test1(int (*) [8], short (*) [8], int*) violation-pr62828.cpp:29 + for (int i3 = 0; i3 < 4; ++i3) { + output2[i3] = input2[(i3 * 2)]; + } + return output2; +} + +int main() { + int_v8 in[4] = {{4, 4, 4, 4}}; + short_v8 out[4] = {{0}}; + int ptr[8] = {2}; + test1(in, out, ptr); + short *p = reinterpret_cast(out); + for (int i = 0; i < 32; i++) { + printf("%d ", p[i]); + } + return 0; +} diff --git a/compiler-rt/test/tysan/violation-pr68655.cpp b/compiler-rt/test/tysan/violation-pr68655.cpp new file mode 100644 index 0000000000000..ac20f8c94e1ff --- /dev/null +++ b/compiler-rt/test/tysan/violation-pr68655.cpp @@ -0,0 +1,40 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +// https://github.com/llvm/llvm-project/issues/68655 +struct S1 { + long long a; + long long b; +}; + +// CHECK: TypeSanitizer: type-aliasing-violation on address +// CHECK-NEXT: READ of size 4 at {{.+}} with type int accesses an existing object of type long long (in S1 at offset 0) +// CHECK-NEXT: in copyMem(S1*, S1*) violation-pr68655.cpp:19 + +void inline copyMem(S1 *dst, S1 *src) { + unsigned *d = reinterpret_cast(dst); + unsigned *s = reinterpret_cast(src); + + for (int i = 0; i < sizeof(S1) / sizeof(unsigned); i++) { + *d = *s; + d++; + s++; + } +} + +void math(S1 *dst, int *srcA, int idx_t) { + S1 zero[4]; + for (int i = 0; i < 2; i++) { + zero[i].a = i + idx_t; + zero[i].b = i * idx_t; + } + + copyMem(&dst[idx_t], &zero[srcA[idx_t]]); +} + +int main() { + S1 dst = {0}; + int Src[2] = {0, 0}; + math(&dst, &Src[0], 0); + return 0; +} diff --git a/compiler-rt/test/tysan/violation-pr86685.c b/compiler-rt/test/tysan/violation-pr86685.c new file mode 100644 index 0000000000000..fe4fd82af5fdd --- /dev/null +++ b/compiler-rt/test/tysan/violation-pr86685.c @@ -0,0 +1,29 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include +#include + +// Violation reported in https://github.com/llvm/llvm-project/issues/86685. +void foo(int *s, float *f, long n) { + for (long i = 0; i < n; ++i) { + *f = 2; + if (i == 1) + break; + + // CHECK: TypeSanitizer: type-aliasing-violation on address + // CHECK-NEXT: WRITE of size 4 at {{.+}} with type int accesses an existing object of type float + // CHECK-NEXT: #0 {{.+}} in foo violation-pr86685.c:17 + *s = 4; + } +} + +int main(void) { + union { + int s; + float f; + } u = {0}; + foo(&u.s, &u.f, 2); + printf("%.f\n", u.f); + return 0; +} From 6f48a28a75b65d46b8362a5703e27698fc09b598 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Fri, 6 Dec 2024 12:08:52 +0000 Subject: [PATCH 18/24] !fixup update tests --- compiler-rt/test/tysan/constexpr-subobject.cpp | 2 +- compiler-rt/test/tysan/ptr-float.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler-rt/test/tysan/constexpr-subobject.cpp b/compiler-rt/test/tysan/constexpr-subobject.cpp index 9cae310554c9b..c473ffe5e445b 100644 --- a/compiler-rt/test/tysan/constexpr-subobject.cpp +++ b/compiler-rt/test/tysan/constexpr-subobject.cpp @@ -1,5 +1,5 @@ // RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 -// RUN: FileCheck %s < %t.out +// RUN: FileCheck --allow-empty %s < %t.out // CHECK-NOT: TypeSanitizer diff --git a/compiler-rt/test/tysan/ptr-float.c b/compiler-rt/test/tysan/ptr-float.c index 61fa5f1afd70a..aaa9895986988 100644 --- a/compiler-rt/test/tysan/ptr-float.c +++ b/compiler-rt/test/tysan/ptr-float.c @@ -7,7 +7,7 @@ void zero_array() { for (i = 0; i < 1; ++i) P[i] = 0.0f; // CHECK: ERROR: TypeSanitizer: type-aliasing-violation - // CHECK: WRITE of size 4 at {{.*}} with type float accesses an existing object of type any pointer + // CHECK: WRITE of size 4 at {{.*}} with type float accesses an existing object of type p1 float // CHECK: {{#0 0x.* in zero_array .*ptr-float.c:}}[[@LINE-3]] } From f92088f81942a7fb60525eeaa0f9cea6da08e26c Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Thu, 12 Dec 2024 09:55:13 +0000 Subject: [PATCH 19/24] !fixup remove commented out code, thanks! --- compiler-rt/lib/tysan/tysan.h | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler-rt/lib/tysan/tysan.h b/compiler-rt/lib/tysan/tysan.h index ec6f9587e9ce5..97df28037b0d2 100644 --- a/compiler-rt/lib/tysan/tysan.h +++ b/compiler-rt/lib/tysan/tysan.h @@ -47,7 +47,6 @@ struct tysan_struct_type_descriptor { struct tysan_type_descriptor *Type; uptr Offset; } Members[1]; // Tail allocated. - // char Name[]; // Tail allocated. }; struct tysan_type_descriptor { From 758c99abb36139fe759b51bd70f9ffeac76f21fa Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Thu, 12 Dec 2024 15:43:25 +0000 Subject: [PATCH 20/24] !fixup update checks for linux. --- compiler-rt/test/tysan/violation-pr45282.c | 2 +- compiler-rt/test/tysan/violation-pr47137.c | 5 +++-- compiler-rt/test/tysan/violation-pr62544.c | 2 +- compiler-rt/test/tysan/violation-pr62828.cpp | 2 +- compiler-rt/test/tysan/violation-pr68655.cpp | 4 ++-- compiler-rt/test/tysan/violation-pr86685.c | 2 +- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/compiler-rt/test/tysan/violation-pr45282.c b/compiler-rt/test/tysan/violation-pr45282.c index f3583d6be6f6a..b3d8b0a6465fd 100644 --- a/compiler-rt/test/tysan/violation-pr45282.c +++ b/compiler-rt/test/tysan/violation-pr45282.c @@ -18,7 +18,7 @@ int main(void) { // CHECK: TypeSanitizer: type-aliasing-violation on address // CHECK-NEXT: WRITE of size 8 at {{.+}} with type double accesses an existing object of type float - // CHECK-NEXT: in main violation-pr45282.c:25 + // CHECK-NEXT: in main {{.*/?}}violation-pr45282.c:25 // loop of problems for (j = 2; j <= 4; ++j) { diff --git a/compiler-rt/test/tysan/violation-pr47137.c b/compiler-rt/test/tysan/violation-pr47137.c index 3987128ff6fc6..11c16cb735866 100644 --- a/compiler-rt/test/tysan/violation-pr47137.c +++ b/compiler-rt/test/tysan/violation-pr47137.c @@ -4,6 +4,7 @@ // https://github.com/llvm/llvm-project/issues/47137 #include #include +#include void f(int m) { int n = (4 * m + 2) / 3; @@ -23,8 +24,8 @@ void f(int m) { } // CHECK: TypeSanitizer: type-aliasing-violation on address - // CHECK-NEXT: READ of size 2 at {{.+}} with type short accesses an existing object of type long long - // CHECK-NEXT: in f violation-pr47137.c:30 + // CHECK-NEXT: READ of size 2 at {{.+}} with type short accesses an existing object of type long + // CHECK-NEXT: in f {{.*/?}}violation-pr47137.c:31 for (int i = 0, j = 0; j < 4 * m; i += 4, j += 3) { for (int k = 0; k < 3; k++) { ((uint16_t *)a)[j + k] = ((uint16_t *)a)[i + k]; diff --git a/compiler-rt/test/tysan/violation-pr62544.c b/compiler-rt/test/tysan/violation-pr62544.c index 30610925ba385..65dd333272116 100644 --- a/compiler-rt/test/tysan/violation-pr62544.c +++ b/compiler-rt/test/tysan/violation-pr62544.c @@ -18,7 +18,7 @@ int main() { // CHECK: TypeSanitizer: type-aliasing-violation on address // CHECK-NEXT: WRITE of size 2 at {{.+}} with type short accesses an existing object of type int - // CHECK-NEXT: in main violation-pr62544.c:22 + // CHECK-NEXT: in main {{.*/?}}violation-pr62544.c:22 *e = 3; printf("%d\n", a); } diff --git a/compiler-rt/test/tysan/violation-pr62828.cpp b/compiler-rt/test/tysan/violation-pr62828.cpp index 33003df9761f5..709132c4aba64 100644 --- a/compiler-rt/test/tysan/violation-pr62828.cpp +++ b/compiler-rt/test/tysan/violation-pr62828.cpp @@ -24,7 +24,7 @@ short *test1(int_v8 *cast_c_array, short_v8 *shuf_c_array1, int *ptr) { // CHECK: ERROR: TypeSanitizer: type-aliasing-violation on address // CHECK-NEXT: READ of size 2 at {{.+}} with type short accesses an existing object of type int - // CHECK-NEXT: in test1(int (*) [8], short (*) [8], int*) violation-pr62828.cpp:29 + // CHECK-NEXT: in test1(int (*) [8], short (*) [8], int*) {{.*/?}}violation-pr62828.cpp:29 for (int i3 = 0; i3 < 4; ++i3) { output2[i3] = input2[(i3 * 2)]; } diff --git a/compiler-rt/test/tysan/violation-pr68655.cpp b/compiler-rt/test/tysan/violation-pr68655.cpp index ac20f8c94e1ff..7be05c7a7d4f8 100644 --- a/compiler-rt/test/tysan/violation-pr68655.cpp +++ b/compiler-rt/test/tysan/violation-pr68655.cpp @@ -8,8 +8,8 @@ struct S1 { }; // CHECK: TypeSanitizer: type-aliasing-violation on address -// CHECK-NEXT: READ of size 4 at {{.+}} with type int accesses an existing object of type long long (in S1 at offset 0) -// CHECK-NEXT: in copyMem(S1*, S1*) violation-pr68655.cpp:19 +// CHECK-NEXT: READ of size 4 at {{.+}} with type int accesses an existing object of type long long (in {{.*}}S1 at offset 0) +// CHECK-NEXT: in copyMem(S1*, S1*) {{.*/?}}violation-pr68655.cpp:19 void inline copyMem(S1 *dst, S1 *src) { unsigned *d = reinterpret_cast(dst); diff --git a/compiler-rt/test/tysan/violation-pr86685.c b/compiler-rt/test/tysan/violation-pr86685.c index fe4fd82af5fdd..43b8d478e6851 100644 --- a/compiler-rt/test/tysan/violation-pr86685.c +++ b/compiler-rt/test/tysan/violation-pr86685.c @@ -13,7 +13,7 @@ void foo(int *s, float *f, long n) { // CHECK: TypeSanitizer: type-aliasing-violation on address // CHECK-NEXT: WRITE of size 4 at {{.+}} with type int accesses an existing object of type float - // CHECK-NEXT: #0 {{.+}} in foo violation-pr86685.c:17 + // CHECK-NEXT: #0 {{.+}} in foo {{.*/?}}violation-pr86685.c:17 *s = 4; } } From 43b62b9a12c47b653c95b3a16e4f627c520bd35f Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Thu, 12 Dec 2024 15:57:12 +0000 Subject: [PATCH 21/24] !fixup fix formatting in test --- compiler-rt/test/tysan/violation-pr47137.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler-rt/test/tysan/violation-pr47137.c b/compiler-rt/test/tysan/violation-pr47137.c index 11c16cb735866..fb895ff729de4 100644 --- a/compiler-rt/test/tysan/violation-pr47137.c +++ b/compiler-rt/test/tysan/violation-pr47137.c @@ -2,9 +2,9 @@ // RUN: FileCheck %s < %t.out // https://github.com/llvm/llvm-project/issues/47137 +#include #include #include -#include void f(int m) { int n = (4 * m + 2) / 3; From c3aa78ab1ec7ae809a17161d3cd27ec0ba7daab4 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Thu, 12 Dec 2024 22:31:22 +0000 Subject: [PATCH 22/24] !fixup fix python formatting --- compiler-rt/test/tysan/lit.cfg.py | 178 +++++++++++++++++------------- 1 file changed, 100 insertions(+), 78 deletions(-) diff --git a/compiler-rt/test/tysan/lit.cfg.py b/compiler-rt/test/tysan/lit.cfg.py index 05c8f0664d5e6..49b8665a9b871 100644 --- a/compiler-rt/test/tysan/lit.cfg.py +++ b/compiler-rt/test/tysan/lit.cfg.py @@ -9,131 +9,153 @@ # Get shlex.quote if available (added in 3.3), and fall back to pipes.quote if # it's not available. try: - import shlex - sh_quote = shlex.quote + import shlex + + sh_quote = shlex.quote except: - import pipes - sh_quote = pipes.quote + import pipes + + sh_quote = pipes.quote + def get_required_attr(config, attr_name): - attr_value = getattr(config, attr_name, None) - if attr_value == None: - lit_config.fatal( - "No attribute %r in test configuration! You may need to run " - "tests from your build directory or add this attribute " - "to lit.site.cfg.py " % attr_name) - return attr_value + attr_value = getattr(config, attr_name, None) + if attr_value == None: + lit_config.fatal( + "No attribute %r in test configuration! You may need to run " + "tests from your build directory or add this attribute " + "to lit.site.cfg.py " % attr_name + ) + return attr_value + def push_dynamic_library_lookup_path(config, new_path): - if platform.system() == 'Windows': - dynamic_library_lookup_var = 'PATH' - elif platform.system() == 'Darwin': - dynamic_library_lookup_var = 'DYLD_LIBRARY_PATH' - else: - dynamic_library_lookup_var = 'LD_LIBRARY_PATH' - - new_ld_library_path = os.path.pathsep.join( - (new_path, config.environment.get(dynamic_library_lookup_var, ''))) - config.environment[dynamic_library_lookup_var] = new_ld_library_path - - if platform.system() == 'FreeBSD': - dynamic_library_lookup_var = 'LD_32_LIBRARY_PATH' - new_ld_32_library_path = os.path.pathsep.join( - (new_path, config.environment.get(dynamic_library_lookup_var, ''))) - config.environment[dynamic_library_lookup_var] = new_ld_32_library_path - - if platform.system() == 'SunOS': - dynamic_library_lookup_var = 'LD_LIBRARY_PATH_32' - new_ld_library_path_32 = os.path.pathsep.join( - (new_path, config.environment.get(dynamic_library_lookup_var, ''))) - config.environment[dynamic_library_lookup_var] = new_ld_library_path_32 - - dynamic_library_lookup_var = 'LD_LIBRARY_PATH_64' - new_ld_library_path_64 = os.path.pathsep.join( - (new_path, config.environment.get(dynamic_library_lookup_var, ''))) - config.environment[dynamic_library_lookup_var] = new_ld_library_path_64 + if platform.system() == "Windows": + dynamic_library_lookup_var = "PATH" + elif platform.system() == "Darwin": + dynamic_library_lookup_var = "DYLD_LIBRARY_PATH" + else: + dynamic_library_lookup_var = "LD_LIBRARY_PATH" + + new_ld_library_path = os.path.pathsep.join( + (new_path, config.environment.get(dynamic_library_lookup_var, "")) + ) + config.environment[dynamic_library_lookup_var] = new_ld_library_path + + if platform.system() == "FreeBSD": + dynamic_library_lookup_var = "LD_32_LIBRARY_PATH" + new_ld_32_library_path = os.path.pathsep.join( + (new_path, config.environment.get(dynamic_library_lookup_var, "")) + ) + config.environment[dynamic_library_lookup_var] = new_ld_32_library_path + + if platform.system() == "SunOS": + dynamic_library_lookup_var = "LD_LIBRARY_PATH_32" + new_ld_library_path_32 = os.path.pathsep.join( + (new_path, config.environment.get(dynamic_library_lookup_var, "")) + ) + config.environment[dynamic_library_lookup_var] = new_ld_library_path_32 + + dynamic_library_lookup_var = "LD_LIBRARY_PATH_64" + new_ld_library_path_64 = os.path.pathsep.join( + (new_path, config.environment.get(dynamic_library_lookup_var, "")) + ) + config.environment[dynamic_library_lookup_var] = new_ld_library_path_64 + # Setup config name. -config.name = 'TypeSanitizer' + config.name_suffix +config.name = "TypeSanitizer" + config.name_suffix # Platform-specific default TYSAN_OPTIONS for lit tests. default_tysan_opts = list(config.default_sanitizer_opts) # On Darwin, leak checking is not enabled by default. Enable on macOS # tests to prevent regressions -if config.host_os == 'Darwin' and config.apple_platform == 'osx': - default_tysan_opts += ['detect_leaks=1'] +if config.host_os == "Darwin" and config.apple_platform == "osx": + default_tysan_opts += ["detect_leaks=1"] -default_tysan_opts_str = ':'.join(default_tysan_opts) +default_tysan_opts_str = ":".join(default_tysan_opts) if default_tysan_opts_str: - config.environment['TYSAN_OPTIONS'] = default_tysan_opts_str - default_tysan_opts_str += ':' -config.substitutions.append(('%env_tysan_opts=', - 'env TYSAN_OPTIONS=' + default_tysan_opts_str)) + config.environment["TYSAN_OPTIONS"] = default_tysan_opts_str + default_tysan_opts_str += ":" +config.substitutions.append( + ("%env_tysan_opts=", "env TYSAN_OPTIONS=" + default_tysan_opts_str) +) # Setup source root. config.test_source_root = os.path.dirname(__file__) -if config.host_os not in ['FreeBSD', 'NetBSD']: - libdl_flag = "-ldl" +if config.host_os not in ["FreeBSD", "NetBSD"]: + libdl_flag = "-ldl" else: - libdl_flag = "" + libdl_flag = "" # GCC-ASan doesn't link in all the necessary libraries automatically, so # we have to do it ourselves. -if config.compiler_id == 'GNU': - extra_link_flags = ["-pthread", "-lstdc++", libdl_flag] +if config.compiler_id == "GNU": + extra_link_flags = ["-pthread", "-lstdc++", libdl_flag] else: - extra_link_flags = [] + extra_link_flags = [] # Setup default compiler flags used with -fsanitize=address option. # FIXME: Review the set of required flags and check if it can be reduced. target_cflags = [get_required_attr(config, "target_cflags")] + extra_link_flags target_cxxflags = config.cxx_mode_flags + target_cflags -clang_tysan_static_cflags = (["-fsanitize=type", - "-mno-omit-leaf-frame-pointer", - "-fno-omit-frame-pointer", - "-fno-optimize-sibling-calls"] + - config.debug_info_flags + target_cflags) -if config.target_arch == 's390x': - clang_tysan_static_cflags.append("-mbackchain") +clang_tysan_static_cflags = ( + [ + "-fsanitize=type", + "-mno-omit-leaf-frame-pointer", + "-fno-omit-frame-pointer", + "-fno-optimize-sibling-calls", + ] + + config.debug_info_flags + + target_cflags +) +if config.target_arch == "s390x": + clang_tysan_static_cflags.append("-mbackchain") clang_tysan_static_cxxflags = config.cxx_mode_flags + clang_tysan_static_cflags -clang_tysan_cflags = clang_tysan_static_cflags +clang_tysan_cflags = clang_tysan_static_cflags clang_tysan_cxxflags = clang_tysan_static_cxxflags + def build_invocation(compile_flags): - return " " + " ".join([config.clang] + compile_flags) + " " + return " " + " ".join([config.clang] + compile_flags) + " " + -config.substitutions.append( ("%clang ", build_invocation(target_cflags)) ) -config.substitutions.append( ("%clangxx ", build_invocation(target_cxxflags)) ) -config.substitutions.append( ("%clang_tysan ", build_invocation(clang_tysan_cflags)) ) -config.substitutions.append( ("%clangxx_tysan ", build_invocation(clang_tysan_cxxflags)) ) +config.substitutions.append(("%clang ", build_invocation(target_cflags))) +config.substitutions.append(("%clangxx ", build_invocation(target_cxxflags))) +config.substitutions.append(("%clang_tysan ", build_invocation(clang_tysan_cflags))) +config.substitutions.append(("%clangxx_tysan ", build_invocation(clang_tysan_cxxflags))) # FIXME: De-hardcode this path. tysan_source_dir = os.path.join( - get_required_attr(config, "compiler_rt_src_root"), "lib", "tysan") + get_required_attr(config, "compiler_rt_src_root"), "lib", "tysan" +) python_exec = sh_quote(get_required_attr(config, "python_executable")) # Set LD_LIBRARY_PATH to pick dynamic runtime up properly. push_dynamic_library_lookup_path(config, config.compiler_rt_libdir) # Default test suffixes. -config.suffixes = ['.c', '.cpp'] +config.suffixes = [".c", ".cpp"] -if config.host_os == 'Darwin': - config.suffixes.append('.mm') +if config.host_os == "Darwin": + config.suffixes.append(".mm") -if config.host_os == 'Windows': - config.substitutions.append(('%fPIC', '')) - config.substitutions.append(('%fPIE', '')) - config.substitutions.append(('%pie', '')) +if config.host_os == "Windows": + config.substitutions.append(("%fPIC", "")) + config.substitutions.append(("%fPIE", "")) + config.substitutions.append(("%pie", "")) else: - config.substitutions.append(('%fPIC', '-fPIC')) - config.substitutions.append(('%fPIE', '-fPIE')) - config.substitutions.append(('%pie', '-pie')) + config.substitutions.append(("%fPIC", "-fPIC")) + config.substitutions.append(("%fPIE", "-fPIE")) + config.substitutions.append(("%pie", "-pie")) # Only run the tests on supported OSs. -if config.host_os not in ['Linux', 'Darwin',]: - config.unsupported = True +if config.host_os not in [ + "Linux", + "Darwin", +]: + config.unsupported = Tr From 17c457771023570f3b274ff61c6d426d2a801e68 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Mon, 16 Dec 2024 11:34:27 +0000 Subject: [PATCH 23/24] !fixup address latest comments, thanks! --- compiler-rt/lib/tysan/lit.cfg | 2 +- compiler-rt/lib/tysan/tysan.cpp | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/compiler-rt/lib/tysan/lit.cfg b/compiler-rt/lib/tysan/lit.cfg index bd2bbe855529a..e3ef6c9c97147 100644 --- a/compiler-rt/lib/tysan/lit.cfg +++ b/compiler-rt/lib/tysan/lit.cfg @@ -13,7 +13,7 @@ clang_tysan_cflags = (["-fsanitize=type", "-mno-omit-leaf-frame-pointer", "-fno-omit-frame-pointer", "-fno-optimize-sibling-calls"] + - [config.target_cflags] + + config.target_cflags + config.debug_info_flags) clang_tysan_cxxflags = config.cxx_mode_flags + clang_tysan_cflags diff --git a/compiler-rt/lib/tysan/tysan.cpp b/compiler-rt/lib/tysan/tysan.cpp index f1b6bdcf0d826..9a8ba2e1da390 100644 --- a/compiler-rt/lib/tysan/tysan.cpp +++ b/compiler-rt/lib/tysan/tysan.cpp @@ -22,6 +22,8 @@ #include "tysan/tysan.h" +#include + using namespace __sanitizer; using namespace __tysan; @@ -43,11 +45,12 @@ static const char *getDisplayName(const char *Name) { // Clang generates tags for C++ types that demangle as typeinfo. Remove the // prefix from the generated string. - const char TIPrefix[] = "typeinfo name for "; + const char *TIPrefix = "typeinfo name for "; + size_t TIPrefixLen = strlen(TIPrefix); const char *DName = Symbolizer::GetOrInit()->Demangle(Name); - if (!internal_strncmp(DName, TIPrefix, sizeof(TIPrefix) - 1)) - DName += sizeof(TIPrefix) - 1; + if (!internal_strncmp(DName, TIPrefix, TIPrefixLen)) + DName += TIPrefixLen; return DName; } @@ -91,7 +94,7 @@ static tysan_type_descriptor *getRootTD(tysan_type_descriptor *TD) { } else if (TD->Tag == TYSAN_MEMBER_TD) { TD = TD->Member.Access; } else { - DCHECK(0); + CHECK(false && "invalid enum value"); break; } } while (TD); From 975d1edc92471de60bfaca3d16665d8bc9046154 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Tue, 17 Dec 2024 11:50:43 +0000 Subject: [PATCH 24/24] !fixup address latest comments, thanks! --- compiler-rt/lib/tysan/tysan.cpp | 7 +++---- compiler-rt/test/tysan/lit.cfg.py | 34 +++++++++---------------------- 2 files changed, 13 insertions(+), 28 deletions(-) diff --git a/compiler-rt/lib/tysan/tysan.cpp b/compiler-rt/lib/tysan/tysan.cpp index 9a8ba2e1da390..39d78e7c95e0c 100644 --- a/compiler-rt/lib/tysan/tysan.cpp +++ b/compiler-rt/lib/tysan/tysan.cpp @@ -63,7 +63,7 @@ static void printTDName(tysan_type_descriptor *td) { switch (td->Tag) { default: - DCHECK(0); + CHECK(false && "invalid enum value"); break; case TYSAN_MEMBER_TD: printTDName(td->Member.Access); @@ -117,9 +117,8 @@ static bool isAliasingLegalUp(tysan_type_descriptor *TDA, } do { - if (TDA == TDB) { + if (TDA == TDB) return OffsetA == OffsetB; - } if (TDA->Tag == TYSAN_STRUCT_TD) { // Reached root type descriptor. @@ -135,7 +134,7 @@ static bool isAliasingLegalUp(tysan_type_descriptor *TDA, OffsetA -= TDA->Struct.Members[Idx].Offset; TDA = TDA->Struct.Members[Idx].Type; } else { - DCHECK(0); + CHECK(false && "invalid enum value"); break; } } while (TDA); diff --git a/compiler-rt/test/tysan/lit.cfg.py b/compiler-rt/test/tysan/lit.cfg.py index 49b8665a9b871..b53a3104fa05a 100644 --- a/compiler-rt/test/tysan/lit.cfg.py +++ b/compiler-rt/test/tysan/lit.cfg.py @@ -3,30 +3,21 @@ import os import platform import re +import shlex import lit.formats -# Get shlex.quote if available (added in 3.3), and fall back to pipes.quote if -# it's not available. -try: - import shlex - - sh_quote = shlex.quote -except: - import pipes - - sh_quote = pipes.quote - def get_required_attr(config, attr_name): attr_value = getattr(config, attr_name, None) - if attr_value == None: - lit_config.fatal( - "No attribute %r in test configuration! You may need to run " - "tests from your build directory or add this attribute " - "to lit.site.cfg.py " % attr_name - ) - return attr_value + if attr_value : + return attr_value + + lit_config.fatal( + "No attribute %r in test configuration! You may need to run " + "tests from your build directory or add this attribute " + "to lit.site.cfg.py " % attr_name + ) def push_dynamic_library_lookup_path(config, new_path): @@ -69,11 +60,6 @@ def push_dynamic_library_lookup_path(config, new_path): # Platform-specific default TYSAN_OPTIONS for lit tests. default_tysan_opts = list(config.default_sanitizer_opts) -# On Darwin, leak checking is not enabled by default. Enable on macOS -# tests to prevent regressions -if config.host_os == "Darwin" and config.apple_platform == "osx": - default_tysan_opts += ["detect_leaks=1"] - default_tysan_opts_str = ":".join(default_tysan_opts) if default_tysan_opts_str: config.environment["TYSAN_OPTIONS"] = default_tysan_opts_str @@ -133,7 +119,7 @@ def build_invocation(compile_flags): tysan_source_dir = os.path.join( get_required_attr(config, "compiler_rt_src_root"), "lib", "tysan" ) -python_exec = sh_quote(get_required_attr(config, "python_executable")) +python_exec = shlex.quote(get_required_attr(config, "python_executable")) # Set LD_LIBRARY_PATH to pick dynamic runtime up properly. push_dynamic_library_lookup_path(config, config.compiler_rt_libdir)