From 4c3ac21386c4032f10701f9fd9d2f37244514c99 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Fri, 22 Dec 2023 19:18:24 +0000 Subject: [PATCH 01/16] =?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/16] !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/16] !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/16] !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/16] !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/16] !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/16] !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/16] !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/16] !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/16] [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/16] !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/16] !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/16] !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/16] !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/16] !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/16] !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{{.*}} }