From eb11fae6d08f479c0799db45860a98af528fa6e7 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Sat, 28 Jul 2018 10:51:19 +0000 Subject: Vendor import of llvm trunk r338150: https://llvm.org/svn/llvm-project/llvm/trunk@338150 --- .../Instrumentation/AddressSanitizer.cpp | 139 ++-- lib/Transforms/Instrumentation/BoundsChecking.cpp | 44 +- lib/Transforms/Instrumentation/CFGMST.h | 16 +- lib/Transforms/Instrumentation/CGProfile.cpp | 100 +++ lib/Transforms/Instrumentation/CMakeLists.txt | 1 + .../Instrumentation/DataFlowSanitizer.cpp | 137 +++- .../Instrumentation/EfficiencySanitizer.cpp | 4 +- lib/Transforms/Instrumentation/GCOVProfiling.cpp | 303 ++++++-- .../Instrumentation/HWAddressSanitizer.cpp | 511 +++++++++++-- .../Instrumentation/IndirectCallPromotion.cpp | 30 +- lib/Transforms/Instrumentation/InstrProfiling.cpp | 46 +- lib/Transforms/Instrumentation/MemorySanitizer.cpp | 851 +++++++++++++-------- .../Instrumentation/PGOInstrumentation.cpp | 83 +- lib/Transforms/Instrumentation/PGOMemOPSizeOpt.cpp | 74 +- .../Instrumentation/SanitizerCoverage.cpp | 23 +- lib/Transforms/Instrumentation/ThreadSanitizer.cpp | 8 +- 16 files changed, 1747 insertions(+), 623 deletions(-) create mode 100644 lib/Transforms/Instrumentation/CGProfile.cpp (limited to 'lib/Transforms/Instrumentation') diff --git a/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/lib/Transforms/Instrumentation/AddressSanitizer.cpp index 8e39f24d819c..b3f659194558 100644 --- a/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -16,7 +16,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DepthFirstIterator.h" -#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringExtras.h" @@ -25,6 +25,7 @@ #include "llvm/ADT/Twine.h" #include "llvm/Analysis/MemoryBuiltins.h" #include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/Transforms/Utils/Local.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/BinaryFormat/MachO.h" #include "llvm/IR/Argument.h" @@ -71,7 +72,6 @@ #include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/Utils/ASanStackFrameLayout.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" -#include "llvm/Transforms/Utils/Local.h" #include "llvm/Transforms/Utils/ModuleUtils.h" #include "llvm/Transforms/Utils/PromoteMemToReg.h" #include @@ -107,10 +107,18 @@ static const uint64_t kMIPS64_ShadowOffset64 = 1ULL << 37; static const uint64_t kAArch64_ShadowOffset64 = 1ULL << 36; static const uint64_t kFreeBSD_ShadowOffset32 = 1ULL << 30; static const uint64_t kFreeBSD_ShadowOffset64 = 1ULL << 46; +static const uint64_t kNetBSD_ShadowOffset32 = 1ULL << 30; static const uint64_t kNetBSD_ShadowOffset64 = 1ULL << 46; static const uint64_t kPS4CPU_ShadowOffset64 = 1ULL << 40; static const uint64_t kWindowsShadowOffset32 = 3ULL << 28; +static const uint64_t kMyriadShadowScale = 5; +static const uint64_t kMyriadMemoryOffset32 = 0x80000000ULL; +static const uint64_t kMyriadMemorySize32 = 0x20000000ULL; +static const uint64_t kMyriadTagShift = 29; +static const uint64_t kMyriadDDRTag = 4; +static const uint64_t kMyriadCacheBitMask32 = 0x40000000ULL; + // The shadow memory space is dynamically allocated. static const uint64_t kWindowsShadowOffset64 = kDynamicShadowSentinel; @@ -145,7 +153,7 @@ static const char *const kAsanHandleNoReturnName = "__asan_handle_no_return"; static const int kMaxAsanStackMallocSizeClass = 10; static const char *const kAsanStackMallocNameTemplate = "__asan_stack_malloc_"; static const char *const kAsanStackFreeNameTemplate = "__asan_stack_free_"; -static const char *const kAsanGenPrefix = "__asan_gen_"; +static const char *const kAsanGenPrefix = "___asan_gen_"; static const char *const kODRGenPrefix = "__odr_asan_gen_"; static const char *const kSanCovGenPrefix = "__sancov_gen_"; static const char *const kAsanSetShadowPrefix = "__asan_set_shadow_"; @@ -485,18 +493,17 @@ static ShadowMapping getShadowMapping(Triple &TargetTriple, int LongSize, bool IsSystemZ = TargetTriple.getArch() == Triple::systemz; bool IsX86 = TargetTriple.getArch() == Triple::x86; bool IsX86_64 = TargetTriple.getArch() == Triple::x86_64; - bool IsMIPS32 = TargetTriple.getArch() == Triple::mips || - TargetTriple.getArch() == Triple::mipsel; - bool IsMIPS64 = TargetTriple.getArch() == Triple::mips64 || - TargetTriple.getArch() == Triple::mips64el; + bool IsMIPS32 = TargetTriple.isMIPS32(); + bool IsMIPS64 = TargetTriple.isMIPS64(); bool IsArmOrThumb = TargetTriple.isARM() || TargetTriple.isThumb(); bool IsAArch64 = TargetTriple.getArch() == Triple::aarch64; bool IsWindows = TargetTriple.isOSWindows(); bool IsFuchsia = TargetTriple.isOSFuchsia(); + bool IsMyriad = TargetTriple.getVendor() == llvm::Triple::Myriad; ShadowMapping Mapping; - Mapping.Scale = kDefaultShadowScale; + Mapping.Scale = IsMyriad ? kMyriadShadowScale : kDefaultShadowScale; if (ClMappingScale.getNumOccurrences() > 0) { Mapping.Scale = ClMappingScale; } @@ -508,11 +515,18 @@ static ShadowMapping getShadowMapping(Triple &TargetTriple, int LongSize, Mapping.Offset = kMIPS32_ShadowOffset32; else if (IsFreeBSD) Mapping.Offset = kFreeBSD_ShadowOffset32; + else if (IsNetBSD) + Mapping.Offset = kNetBSD_ShadowOffset32; else if (IsIOS) // If we're targeting iOS and x86, the binary is built for iOS simulator. Mapping.Offset = IsX86 ? kIOSSimShadowOffset32 : kIOSShadowOffset32; else if (IsWindows) Mapping.Offset = kWindowsShadowOffset32; + else if (IsMyriad) { + uint64_t ShadowOffset = (kMyriadMemoryOffset32 + kMyriadMemorySize32 - + (kMyriadMemorySize32 >> Mapping.Scale)); + Mapping.Offset = ShadowOffset - (kMyriadMemoryOffset32 >> Mapping.Scale); + } else Mapping.Offset = kDefaultShadowOffset32; } else { // LongSize == 64 @@ -589,9 +603,10 @@ struct AddressSanitizer : public FunctionPass { explicit AddressSanitizer(bool CompileKernel = false, bool Recover = false, bool UseAfterScope = false) - : FunctionPass(ID), CompileKernel(CompileKernel || ClEnableKasan), - Recover(Recover || ClRecover), - UseAfterScope(UseAfterScope || ClUseAfterScope) { + : FunctionPass(ID), UseAfterScope(UseAfterScope || ClUseAfterScope) { + this->Recover = ClRecover.getNumOccurrences() > 0 ? ClRecover : Recover; + this->CompileKernel = ClEnableKasan.getNumOccurrences() > 0 ? + ClEnableKasan : CompileKernel; initializeAddressSanitizerPass(*PassRegistry::getPassRegistry()); } @@ -717,8 +732,7 @@ public: explicit AddressSanitizerModule(bool CompileKernel = false, bool Recover = false, bool UseGlobalsGC = true) - : ModulePass(ID), CompileKernel(CompileKernel || ClEnableKasan), - Recover(Recover || ClRecover), + : ModulePass(ID), UseGlobalsGC(UseGlobalsGC && ClUseGlobalsGC), // Not a typo: ClWithComdat is almost completely pointless without // ClUseGlobalsGC (because then it only works on modules without @@ -727,7 +741,12 @@ public: // argument is designed as workaround. Therefore, disable both // ClWithComdat and ClUseGlobalsGC unless the frontend says it's ok to // do globals-gc. - UseCtorComdat(UseGlobalsGC && ClWithComdat) {} + UseCtorComdat(UseGlobalsGC && ClWithComdat) { + this->Recover = ClRecover.getNumOccurrences() > 0 ? + ClRecover : Recover; + this->CompileKernel = ClEnableKasan.getNumOccurrences() > 0 ? + ClEnableKasan : CompileKernel; + } bool runOnModule(Module &M) override; StringRef getPassName() const override { return "AddressSanitizerModule"; } @@ -869,7 +888,7 @@ struct FunctionStackPoisoner : public InstVisitor { processStaticAllocas(); if (ClDebugStack) { - DEBUG(dbgs() << F); + LLVM_DEBUG(dbgs() << F); } return true; } @@ -888,13 +907,13 @@ struct FunctionStackPoisoner : public InstVisitor { void createDynamicAllocasInitStorage(); // ----------------------- Visitors. - /// \brief Collect all Ret instructions. + /// Collect all Ret instructions. void visitReturnInst(ReturnInst &RI) { RetVec.push_back(&RI); } - /// \brief Collect all Resume instructions. + /// Collect all Resume instructions. void visitResumeInst(ResumeInst &RI) { RetVec.push_back(&RI); } - /// \brief Collect all CatchReturnInst instructions. + /// Collect all CatchReturnInst instructions. void visitCleanupReturnInst(CleanupReturnInst &CRI) { RetVec.push_back(&CRI); } void unpoisonDynamicAllocasBeforeInst(Instruction *InstBefore, @@ -942,7 +961,7 @@ struct FunctionStackPoisoner : public InstVisitor { // requested memory, but also left, partial and right redzones. void handleDynamicAllocaCall(AllocaInst *AI); - /// \brief Collect Alloca instructions we want (and can) handle. + /// Collect Alloca instructions we want (and can) handle. void visitAllocaInst(AllocaInst &AI) { if (!ASan.isInterestingAlloca(AI)) { if (AI.isStaticAlloca()) { @@ -963,7 +982,7 @@ struct FunctionStackPoisoner : public InstVisitor { AllocaVec.push_back(&AI); } - /// \brief Collect lifetime intrinsic calls to check for use-after-scope + /// Collect lifetime intrinsic calls to check for use-after-scope /// errors. void visitIntrinsicInst(IntrinsicInst &II) { Intrinsic::ID ID = II.getIntrinsicID(); @@ -1081,7 +1100,7 @@ static size_t TypeSizeToSizeIndex(uint32_t TypeSize) { return Res; } -// \brief Create a constant for Str so that we can pass it to the run-time lib. +// Create a constant for Str so that we can pass it to the run-time lib. static GlobalVariable *createPrivateGlobalForString(Module &M, StringRef Str, bool AllowMerging) { Constant *StrConst = ConstantDataArray::getString(M.getContext(), Str); @@ -1095,7 +1114,7 @@ static GlobalVariable *createPrivateGlobalForString(Module &M, StringRef Str, return GV; } -/// \brief Create a global describing a source location. +/// Create a global describing a source location. static GlobalVariable *createPrivateGlobalForSourceLoc(Module &M, LocationMetadata MD) { Constant *LocData[] = { @@ -1111,7 +1130,7 @@ static GlobalVariable *createPrivateGlobalForSourceLoc(Module &M, return GV; } -/// \brief Check if \p G has been created by a trusted compiler pass. +/// Check if \p G has been created by a trusted compiler pass. static bool GlobalWasGeneratedByCompiler(GlobalVariable *G) { // Do not instrument asan globals. if (G->getName().startswith(kAsanGenPrefix) || @@ -1487,6 +1506,8 @@ void AddressSanitizer::instrumentAddress(Instruction *OrigIns, uint32_t TypeSize, bool IsWrite, Value *SizeArgument, bool UseCalls, uint32_t Exp) { + bool IsMyriad = TargetTriple.getVendor() == llvm::Triple::Myriad; + IRBuilder<> IRB(InsertBefore); Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy); size_t AccessSizeIndex = TypeSizeToSizeIndex(TypeSize); @@ -1501,6 +1522,23 @@ void AddressSanitizer::instrumentAddress(Instruction *OrigIns, return; } + if (IsMyriad) { + // Strip the cache bit and do range check. + // AddrLong &= ~kMyriadCacheBitMask32 + AddrLong = IRB.CreateAnd(AddrLong, ~kMyriadCacheBitMask32); + // Tag = AddrLong >> kMyriadTagShift + Value *Tag = IRB.CreateLShr(AddrLong, kMyriadTagShift); + // Tag == kMyriadDDRTag + Value *TagCheck = + IRB.CreateICmpEQ(Tag, ConstantInt::get(IntptrTy, kMyriadDDRTag)); + + TerminatorInst *TagCheckTerm = SplitBlockAndInsertIfThen( + TagCheck, InsertBefore, false, MDBuilder(*C).createBranchWeights(1, 100000)); + assert(cast(TagCheckTerm)->isUnconditional()); + IRB.SetInsertPoint(TagCheckTerm); + InsertBefore = TagCheckTerm; + } + Type *ShadowTy = IntegerType::get(*C, std::max(8U, TypeSize >> Mapping.Scale)); Type *ShadowPtrTy = PointerType::get(ShadowTy, 0); @@ -1609,7 +1647,7 @@ void AddressSanitizerModule::createInitializerPoisonCalls( bool AddressSanitizerModule::ShouldInstrumentGlobal(GlobalVariable *G) { Type *Ty = G->getValueType(); - DEBUG(dbgs() << "GLOBAL: " << *G << "\n"); + LLVM_DEBUG(dbgs() << "GLOBAL: " << *G << "\n"); if (GlobalsMD.get(G).IsBlacklisted) return false; if (!Ty->isSized()) return false; @@ -1646,12 +1684,17 @@ bool AddressSanitizerModule::ShouldInstrumentGlobal(GlobalVariable *G) { return false; } - // Callbacks put into the CRT initializer/terminator sections - // should not be instrumented. + // On COFF, if the section name contains '$', it is highly likely that the + // user is using section sorting to create an array of globals similar to + // the way initialization callbacks are registered in .init_array and + // .CRT$XCU. The ATL also registers things in .ATL$__[azm]. Adding redzones + // to such globals is counterproductive, because the intent is that they + // will form an array, and out-of-bounds accesses are expected. // See https://github.com/google/sanitizers/issues/305 // and http://msdn.microsoft.com/en-US/en-en/library/bb918180(v=vs.120).aspx - if (Section.startswith(".CRT")) { - DEBUG(dbgs() << "Ignoring a global initializer callback: " << *G << "\n"); + if (TargetTriple.isOSBinFormatCOFF() && Section.contains('$')) { + LLVM_DEBUG(dbgs() << "Ignoring global in sorted section (contains '$'): " + << *G << "\n"); return false; } @@ -1668,7 +1711,7 @@ bool AddressSanitizerModule::ShouldInstrumentGlobal(GlobalVariable *G) { // them. if (ParsedSegment == "__OBJC" || (ParsedSegment == "__DATA" && ParsedSection.startswith("__objc_"))) { - DEBUG(dbgs() << "Ignoring ObjC runtime global: " << *G << "\n"); + LLVM_DEBUG(dbgs() << "Ignoring ObjC runtime global: " << *G << "\n"); return false; } // See https://github.com/google/sanitizers/issues/32 @@ -1680,13 +1723,13 @@ bool AddressSanitizerModule::ShouldInstrumentGlobal(GlobalVariable *G) { // Therefore there's no point in placing redzones into __DATA,__cfstring. // Moreover, it causes the linker to crash on OS X 10.7 if (ParsedSegment == "__DATA" && ParsedSection == "__cfstring") { - DEBUG(dbgs() << "Ignoring CFString: " << *G << "\n"); + LLVM_DEBUG(dbgs() << "Ignoring CFString: " << *G << "\n"); return false; } // The linker merges the contents of cstring_literals and removes the // trailing zeroes. if (ParsedSegment == "__TEXT" && (TAA & MachO::S_CSTRING_LITERALS)) { - DEBUG(dbgs() << "Ignoring a cstring literal: " << *G << "\n"); + LLVM_DEBUG(dbgs() << "Ignoring a cstring literal: " << *G << "\n"); return false; } } @@ -2153,11 +2196,21 @@ bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M, bool if (ClInitializers && MD.IsDynInit) HasDynamicallyInitializedGlobals = true; - DEBUG(dbgs() << "NEW GLOBAL: " << *NewGlobal << "\n"); + LLVM_DEBUG(dbgs() << "NEW GLOBAL: " << *NewGlobal << "\n"); Initializers[i] = Initializer; } + // Add instrumented globals to llvm.compiler.used list to avoid LTO from + // ConstantMerge'ing them. + SmallVector GlobalsToAddToUsedList; + for (size_t i = 0; i < n; i++) { + GlobalVariable *G = NewGlobals[i]; + if (G->getName().empty()) continue; + GlobalsToAddToUsedList.push_back(G); + } + appendToCompilerUsed(M, ArrayRef(GlobalsToAddToUsedList)); + std::string ELFUniqueModuleId = (UseGlobalsGC && TargetTriple.isOSBinFormatELF()) ? getUniqueModuleId(&M) : ""; @@ -2177,7 +2230,7 @@ bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M, bool if (HasDynamicallyInitializedGlobals) createInitializerPoisonCalls(M, ModuleName); - DEBUG(dbgs() << M); + LLVM_DEBUG(dbgs() << M); return true; } @@ -2247,7 +2300,6 @@ void AddressSanitizer::initializeCallbacks(Module &M) { for (size_t AccessIsWrite = 0; AccessIsWrite <= 1; AccessIsWrite++) { const std::string TypeStr = AccessIsWrite ? "store" : "load"; const std::string ExpStr = Exp ? "exp_" : ""; - const std::string SuffixStr = CompileKernel ? "N" : "_n"; const std::string EndingStr = Recover ? "_noabort" : ""; SmallVector Args2 = {IntptrTy, IntptrTy}; @@ -2259,8 +2311,7 @@ void AddressSanitizer::initializeCallbacks(Module &M) { } AsanErrorCallbackSized[AccessIsWrite][Exp] = checkSanitizerInterfaceFunction(M.getOrInsertFunction( - kAsanReportErrorTemplate + ExpStr + TypeStr + SuffixStr + - EndingStr, + kAsanReportErrorTemplate + ExpStr + TypeStr + "_n" + EndingStr, FunctionType::get(IRB.getVoidTy(), Args2, false))); AsanMemoryAccessCallbackSized[AccessIsWrite][Exp] = @@ -2420,7 +2471,7 @@ bool AddressSanitizer::runOnFunction(Function &F) { // Leave if the function doesn't need instrumentation. if (!F.hasFnAttribute(Attribute::SanitizeAddress)) return FunctionModified; - DEBUG(dbgs() << "ASAN instrumenting:\n" << F << "\n"); + LLVM_DEBUG(dbgs() << "ASAN instrumenting:\n" << F << "\n"); initializeCallbacks(*F.getParent()); DT = &getAnalysis().getDomTree(); @@ -2435,7 +2486,7 @@ bool AddressSanitizer::runOnFunction(Function &F) { // We want to instrument every address only once per basic block (unless there // are calls between uses). - SmallSet TempsToInstrument; + SmallPtrSet TempsToInstrument; SmallVector ToInstrument; SmallVector NoReturnCalls; SmallVector AllBlocks; @@ -2494,7 +2545,6 @@ bool AddressSanitizer::runOnFunction(Function &F) { } bool UseCalls = - CompileKernel || (ClInstrumentationWithCallsThreshold >= 0 && ToInstrument.size() > (unsigned)ClInstrumentationWithCallsThreshold); const DataLayout &DL = F.getParent()->getDataLayout(); @@ -2534,8 +2584,8 @@ bool AddressSanitizer::runOnFunction(Function &F) { if (NumInstrumented > 0 || ChangedStack || !NoReturnCalls.empty()) FunctionModified = true; - DEBUG(dbgs() << "ASAN done instrumenting: " << FunctionModified << " " - << F << "\n"); + LLVM_DEBUG(dbgs() << "ASAN done instrumenting: " << FunctionModified << " " + << F << "\n"); return FunctionModified; } @@ -2710,7 +2760,7 @@ void FunctionStackPoisoner::copyArgsPassedByValToAllocas() { Arg.replaceAllUsesWith(AI); uint64_t AllocSize = DL.getTypeAllocSize(Ty); - IRB.CreateMemCpy(AI, &Arg, AllocSize, Align); + IRB.CreateMemCpy(AI, Align, &Arg, Align, AllocSize); } } } @@ -2851,7 +2901,7 @@ void FunctionStackPoisoner::processStaticAllocas() { } auto DescriptionString = ComputeASanStackFrameDescription(SVD); - DEBUG(dbgs() << DescriptionString << " --- " << L.FrameSize << "\n"); + LLVM_DEBUG(dbgs() << DescriptionString << " --- " << L.FrameSize << "\n"); uint64_t LocalStackSize = L.FrameSize; bool DoStackMalloc = ClUseAfterReturn && !ASan.CompileKernel && LocalStackSize <= kMaxStackMallocSize; @@ -3086,7 +3136,8 @@ AllocaInst *FunctionStackPoisoner::findAllocaForValue(Value *V) { } else if (GetElementPtrInst *EP = dyn_cast(V)) { Res = findAllocaForValue(EP->getPointerOperand()); } else { - DEBUG(dbgs() << "Alloca search canceled on unknown instruction: " << *V << "\n"); + LLVM_DEBUG(dbgs() << "Alloca search canceled on unknown instruction: " << *V + << "\n"); } if (Res) AllocaForValue[V] = Res; return Res; diff --git a/lib/Transforms/Instrumentation/BoundsChecking.cpp b/lib/Transforms/Instrumentation/BoundsChecking.cpp index be9a22a8681b..e13db08e263c 100644 --- a/lib/Transforms/Instrumentation/BoundsChecking.cpp +++ b/lib/Transforms/Instrumentation/BoundsChecking.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/Statistic.h" #include "llvm/ADT/Twine.h" #include "llvm/Analysis/MemoryBuiltins.h" +#include "llvm/Analysis/ScalarEvolution.h" #include "llvm/Analysis/TargetFolder.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/IR/BasicBlock.h" @@ -59,11 +60,11 @@ template static bool instrumentMemAccess(Value *Ptr, Value *InstVal, const DataLayout &DL, TargetLibraryInfo &TLI, ObjectSizeOffsetEvaluator &ObjSizeEval, - BuilderTy &IRB, - GetTrapBBT GetTrapBB) { + BuilderTy &IRB, GetTrapBBT GetTrapBB, + ScalarEvolution &SE) { uint64_t NeededSize = DL.getTypeStoreSize(InstVal->getType()); - DEBUG(dbgs() << "Instrument " << *Ptr << " for " << Twine(NeededSize) - << " bytes\n"); + LLVM_DEBUG(dbgs() << "Instrument " << *Ptr << " for " << Twine(NeededSize) + << " bytes\n"); SizeOffsetEvalType SizeOffset = ObjSizeEval.compute(Ptr); @@ -79,6 +80,10 @@ static bool instrumentMemAccess(Value *Ptr, Value *InstVal, Type *IntTy = DL.getIntPtrType(Ptr->getType()); Value *NeededSizeVal = ConstantInt::get(IntTy, NeededSize); + auto SizeRange = SE.getUnsignedRange(SE.getSCEV(Size)); + auto OffsetRange = SE.getUnsignedRange(SE.getSCEV(Offset)); + auto NeededSizeRange = SE.getUnsignedRange(SE.getSCEV(NeededSizeVal)); + // three checks are required to ensure safety: // . Offset >= 0 (since the offset is given from the base ptr) // . Size >= Offset (unsigned) @@ -87,10 +92,17 @@ static bool instrumentMemAccess(Value *Ptr, Value *InstVal, // optimization: if Size >= 0 (signed), skip 1st check // FIXME: add NSW/NUW here? -- we dont care if the subtraction overflows Value *ObjSize = IRB.CreateSub(Size, Offset); - Value *Cmp2 = IRB.CreateICmpULT(Size, Offset); - Value *Cmp3 = IRB.CreateICmpULT(ObjSize, NeededSizeVal); + Value *Cmp2 = SizeRange.getUnsignedMin().uge(OffsetRange.getUnsignedMax()) + ? ConstantInt::getFalse(Ptr->getContext()) + : IRB.CreateICmpULT(Size, Offset); + Value *Cmp3 = SizeRange.sub(OffsetRange) + .getUnsignedMin() + .uge(NeededSizeRange.getUnsignedMax()) + ? ConstantInt::getFalse(Ptr->getContext()) + : IRB.CreateICmpULT(ObjSize, NeededSizeVal); Value *Or = IRB.CreateOr(Cmp2, Cmp3); - if (!SizeCI || SizeCI->getValue().slt(0)) { + if ((!SizeCI || SizeCI->getValue().slt(0)) && + !SizeRange.getSignedMin().isNonNegative()) { Value *Cmp1 = IRB.CreateICmpSLT(Offset, ConstantInt::get(IntTy, 0)); Or = IRB.CreateOr(Cmp1, Or); } @@ -123,7 +135,8 @@ static bool instrumentMemAccess(Value *Ptr, Value *InstVal, return true; } -static bool addBoundsChecking(Function &F, TargetLibraryInfo &TLI) { +static bool addBoundsChecking(Function &F, TargetLibraryInfo &TLI, + ScalarEvolution &SE) { const DataLayout &DL = F.getParent()->getDataLayout(); ObjectSizeOffsetEvaluator ObjSizeEval(DL, &TLI, F.getContext(), /*RoundToAlign=*/true); @@ -168,19 +181,19 @@ static bool addBoundsChecking(Function &F, TargetLibraryInfo &TLI) { BuilderTy IRB(Inst->getParent(), BasicBlock::iterator(Inst), TargetFolder(DL)); if (LoadInst *LI = dyn_cast(Inst)) { MadeChange |= instrumentMemAccess(LI->getPointerOperand(), LI, DL, TLI, - ObjSizeEval, IRB, GetTrapBB); + ObjSizeEval, IRB, GetTrapBB, SE); } else if (StoreInst *SI = dyn_cast(Inst)) { MadeChange |= instrumentMemAccess(SI->getPointerOperand(), SI->getValueOperand(), - DL, TLI, ObjSizeEval, IRB, GetTrapBB); + DL, TLI, ObjSizeEval, IRB, GetTrapBB, SE); } else if (AtomicCmpXchgInst *AI = dyn_cast(Inst)) { MadeChange |= instrumentMemAccess(AI->getPointerOperand(), AI->getCompareOperand(), - DL, TLI, ObjSizeEval, IRB, GetTrapBB); + DL, TLI, ObjSizeEval, IRB, GetTrapBB, SE); } else if (AtomicRMWInst *AI = dyn_cast(Inst)) { MadeChange |= instrumentMemAccess(AI->getPointerOperand(), AI->getValOperand(), DL, - TLI, ObjSizeEval, IRB, GetTrapBB); + TLI, ObjSizeEval, IRB, GetTrapBB, SE); } else { llvm_unreachable("unknown Instruction type"); } @@ -190,8 +203,9 @@ static bool addBoundsChecking(Function &F, TargetLibraryInfo &TLI) { PreservedAnalyses BoundsCheckingPass::run(Function &F, FunctionAnalysisManager &AM) { auto &TLI = AM.getResult(F); + auto &SE = AM.getResult(F); - if (!addBoundsChecking(F, TLI)) + if (!addBoundsChecking(F, TLI, SE)) return PreservedAnalyses::all(); return PreservedAnalyses::none(); @@ -207,11 +221,13 @@ struct BoundsCheckingLegacyPass : public FunctionPass { bool runOnFunction(Function &F) override { auto &TLI = getAnalysis().getTLI(); - return addBoundsChecking(F, TLI); + auto &SE = getAnalysis().getSE(); + return addBoundsChecking(F, TLI, SE); } void getAnalysisUsage(AnalysisUsage &AU) const override { AU.addRequired(); + AU.addRequired(); } }; } // namespace diff --git a/lib/Transforms/Instrumentation/CFGMST.h b/lib/Transforms/Instrumentation/CFGMST.h index 075e5672cff8..cc9b149d0b6a 100644 --- a/lib/Transforms/Instrumentation/CFGMST.h +++ b/lib/Transforms/Instrumentation/CFGMST.h @@ -31,7 +31,7 @@ namespace llvm { -/// \brief An union-find based Minimum Spanning Tree for CFG +/// An union-find based Minimum Spanning Tree for CFG /// /// Implements a Union-find algorithm to compute Minimum Spanning Tree /// for a given CFG. @@ -97,7 +97,7 @@ public: // Edges with large weight will be put into MST first so they are less likely // to be instrumented. void buildEdges() { - DEBUG(dbgs() << "Build Edge on " << F.getName() << "\n"); + LLVM_DEBUG(dbgs() << "Build Edge on " << F.getName() << "\n"); const BasicBlock *Entry = &(F.getEntryBlock()); uint64_t EntryWeight = (BFI != nullptr ? BFI->getEntryFreq() : 2); @@ -107,8 +107,8 @@ public: // Add a fake edge to the entry. EntryIncoming = &addEdge(nullptr, Entry, EntryWeight); - DEBUG(dbgs() << " Edge: from fake node to " << Entry->getName() - << " w = " << EntryWeight << "\n"); + LLVM_DEBUG(dbgs() << " Edge: from fake node to " << Entry->getName() + << " w = " << EntryWeight << "\n"); // Special handling for single BB functions. if (succ_empty(Entry)) { @@ -138,8 +138,8 @@ public: Weight = BPI->getEdgeProbability(&*BB, TargetBB).scale(scaleFactor); auto *E = &addEdge(&*BB, TargetBB, Weight); E->IsCritical = Critical; - DEBUG(dbgs() << " Edge: from " << BB->getName() << " to " - << TargetBB->getName() << " w=" << Weight << "\n"); + LLVM_DEBUG(dbgs() << " Edge: from " << BB->getName() << " to " + << TargetBB->getName() << " w=" << Weight << "\n"); // Keep track of entry/exit edges: if (&*BB == Entry) { @@ -164,8 +164,8 @@ public: MaxExitOutWeight = BBWeight; ExitOutgoing = ExitO; } - DEBUG(dbgs() << " Edge: from " << BB->getName() << " to fake exit" - << " w = " << BBWeight << "\n"); + LLVM_DEBUG(dbgs() << " Edge: from " << BB->getName() << " to fake exit" + << " w = " << BBWeight << "\n"); } } diff --git a/lib/Transforms/Instrumentation/CGProfile.cpp b/lib/Transforms/Instrumentation/CGProfile.cpp new file mode 100644 index 000000000000..9606b3da2475 --- /dev/null +++ b/lib/Transforms/Instrumentation/CGProfile.cpp @@ -0,0 +1,100 @@ +//===-- CGProfile.cpp -----------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Instrumentation/CGProfile.h" + +#include "llvm/ADT/MapVector.h" +#include "llvm/Analysis/BlockFrequencyInfo.h" +#include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/IR/CallSite.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/MDBuilder.h" +#include "llvm/IR/PassManager.h" +#include "llvm/ProfileData/InstrProf.h" +#include "llvm/Transforms/Instrumentation.h" + +#include + +using namespace llvm; + +PreservedAnalyses CGProfilePass::run(Module &M, ModuleAnalysisManager &MAM) { + MapVector, uint64_t> Counts; + FunctionAnalysisManager &FAM = + MAM.getResult(M).getManager(); + InstrProfSymtab Symtab; + auto UpdateCounts = [&](TargetTransformInfo &TTI, Function *F, + Function *CalledF, uint64_t NewCount) { + if (!CalledF || !TTI.isLoweredToCall(CalledF)) + return; + uint64_t &Count = Counts[std::make_pair(F, CalledF)]; + Count = SaturatingAdd(Count, NewCount); + }; + // Ignore error here. Indirect calls are ignored if this fails. + (void)(bool)Symtab.create(M); + for (auto &F : M) { + if (F.isDeclaration()) + continue; + auto &BFI = FAM.getResult(F); + if (BFI.getEntryFreq() == 0) + continue; + TargetTransformInfo &TTI = FAM.getResult(F); + for (auto &BB : F) { + Optional BBCount = BFI.getBlockProfileCount(&BB); + if (!BBCount) + continue; + for (auto &I : BB) { + CallSite CS(&I); + if (!CS) + continue; + if (CS.isIndirectCall()) { + InstrProfValueData ValueData[8]; + uint32_t ActualNumValueData; + uint64_t TotalC; + if (!getValueProfDataFromInst(*CS.getInstruction(), + IPVK_IndirectCallTarget, 8, ValueData, + ActualNumValueData, TotalC)) + continue; + for (const auto &VD : + ArrayRef(ValueData, ActualNumValueData)) { + UpdateCounts(TTI, &F, Symtab.getFunction(VD.Value), VD.Count); + } + continue; + } + UpdateCounts(TTI, &F, CS.getCalledFunction(), *BBCount); + } + } + } + + addModuleFlags(M, Counts); + + return PreservedAnalyses::all(); +} + +void CGProfilePass::addModuleFlags( + Module &M, + MapVector, uint64_t> &Counts) const { + if (Counts.empty()) + return; + + LLVMContext &Context = M.getContext(); + MDBuilder MDB(Context); + std::vector Nodes; + + for (auto E : Counts) { + SmallVector Vals; + Vals.push_back(ValueAsMetadata::get(E.first.first)); + Vals.push_back(ValueAsMetadata::get(E.first.second)); + Vals.push_back(MDB.createConstant( + ConstantInt::get(Type::getInt64Ty(Context), E.second))); + Nodes.push_back(MDNode::get(Context, Vals)); + } + + M.addModuleFlag(Module::Append, "CG Profile", MDNode::get(Context, Nodes)); +} diff --git a/lib/Transforms/Instrumentation/CMakeLists.txt b/lib/Transforms/Instrumentation/CMakeLists.txt index 66fdcb3ccc49..5d0084823190 100644 --- a/lib/Transforms/Instrumentation/CMakeLists.txt +++ b/lib/Transforms/Instrumentation/CMakeLists.txt @@ -1,6 +1,7 @@ add_llvm_library(LLVMInstrumentation AddressSanitizer.cpp BoundsChecking.cpp + CGProfile.cpp DataFlowSanitizer.cpp GCOVProfiling.cpp MemorySanitizer.cpp diff --git a/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp b/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp index 09bcbb282653..bb0e4379d1a8 100644 --- a/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp +++ b/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp @@ -56,6 +56,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" +#include "llvm/Transforms/Utils/Local.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/Argument.h" #include "llvm/IR/Attributes.h" @@ -90,7 +91,6 @@ #include "llvm/Support/SpecialCaseList.h" #include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" -#include "llvm/Transforms/Utils/Local.h" #include #include #include @@ -211,6 +211,72 @@ class DFSanABIList { } }; +/// TransformedFunction is used to express the result of transforming one +/// function type into another. This struct is immutable. It holds metadata +/// useful for updating calls of the old function to the new type. +struct TransformedFunction { + TransformedFunction(FunctionType* OriginalType, + FunctionType* TransformedType, + std::vector ArgumentIndexMapping) + : OriginalType(OriginalType), + TransformedType(TransformedType), + ArgumentIndexMapping(ArgumentIndexMapping) {} + + // Disallow copies. + TransformedFunction(const TransformedFunction&) = delete; + TransformedFunction& operator=(const TransformedFunction&) = delete; + + // Allow moves. + TransformedFunction(TransformedFunction&&) = default; + TransformedFunction& operator=(TransformedFunction&&) = default; + + /// Type of the function before the transformation. + FunctionType* const OriginalType; + + /// Type of the function after the transformation. + FunctionType* const TransformedType; + + /// Transforming a function may change the position of arguments. This + /// member records the mapping from each argument's old position to its new + /// position. Argument positions are zero-indexed. If the transformation + /// from F to F' made the first argument of F into the third argument of F', + /// then ArgumentIndexMapping[0] will equal 2. + const std::vector ArgumentIndexMapping; +}; + +/// Given function attributes from a call site for the original function, +/// return function attributes appropriate for a call to the transformed +/// function. +AttributeList TransformFunctionAttributes( + const TransformedFunction& TransformedFunction, + LLVMContext& Ctx, AttributeList CallSiteAttrs) { + + // Construct a vector of AttributeSet for each function argument. + std::vector ArgumentAttributes( + TransformedFunction.TransformedType->getNumParams()); + + // Copy attributes from the parameter of the original function to the + // transformed version. 'ArgumentIndexMapping' holds the mapping from + // old argument position to new. + for (unsigned i=0, ie = TransformedFunction.ArgumentIndexMapping.size(); + i < ie; ++i) { + unsigned TransformedIndex = TransformedFunction.ArgumentIndexMapping[i]; + ArgumentAttributes[TransformedIndex] = CallSiteAttrs.getParamAttributes(i); + } + + // Copy annotations on varargs arguments. + for (unsigned i = TransformedFunction.OriginalType->getNumParams(), + ie = CallSiteAttrs.getNumAttrSets(); igetReturnType(), ArgTypes, false); } -FunctionType *DataFlowSanitizer::getCustomFunctionType(FunctionType *T) { +TransformedFunction DataFlowSanitizer::getCustomFunctionType(FunctionType *T) { SmallVector ArgTypes; - for (FunctionType::param_iterator i = T->param_begin(), e = T->param_end(); - i != e; ++i) { + + // Some parameters of the custom function being constructed are + // parameters of T. Record the mapping from parameters of T to + // parameters of the custom function, so that parameter attributes + // at call sites can be updated. + std::vector ArgumentIndexMapping; + for (unsigned i = 0, ie = T->getNumParams(); i != ie; ++i) { + Type* param_type = T->getParamType(i); FunctionType *FT; - if (isa(*i) && (FT = dyn_cast(cast( - *i)->getElementType()))) { + if (isa(param_type) && (FT = dyn_cast( + cast(param_type)->getElementType()))) { + ArgumentIndexMapping.push_back(ArgTypes.size()); ArgTypes.push_back(getTrampolineFunctionType(FT)->getPointerTo()); ArgTypes.push_back(Type::getInt8PtrTy(*Ctx)); } else { - ArgTypes.push_back(*i); + ArgumentIndexMapping.push_back(ArgTypes.size()); + ArgTypes.push_back(param_type); } } for (unsigned i = 0, e = T->getNumParams(); i != e; ++i) @@ -457,14 +531,15 @@ FunctionType *DataFlowSanitizer::getCustomFunctionType(FunctionType *T) { Type *RetType = T->getReturnType(); if (!RetType->isVoidTy()) ArgTypes.push_back(ShadowPtrTy); - return FunctionType::get(T->getReturnType(), ArgTypes, T->isVarArg()); + return TransformedFunction( + T, FunctionType::get(T->getReturnType(), ArgTypes, T->isVarArg()), + ArgumentIndexMapping); } bool DataFlowSanitizer::doInitialization(Module &M) { Triple TargetTriple(M.getTargetTriple()); bool IsX86_64 = TargetTriple.getArch() == Triple::x86_64; - bool IsMIPS64 = TargetTriple.getArch() == Triple::mips64 || - TargetTriple.getArch() == Triple::mips64el; + bool IsMIPS64 = TargetTriple.isMIPS64(); bool IsAArch64 = TargetTriple.getArch() == Triple::aarch64 || TargetTriple.getArch() == Triple::aarch64_be; @@ -783,9 +858,17 @@ bool DataFlowSanitizer::runOnModule(Module &M) { FunctionType *NewFT = getInstrumentedABI() == IA_Args ? getArgsFunctionType(FT) : FT; + + // If the function being wrapped has local linkage, then preserve the + // function's linkage in the wrapper function. + GlobalValue::LinkageTypes wrapperLinkage = + F.hasLocalLinkage() + ? F.getLinkage() + : GlobalValue::LinkOnceODRLinkage; + Function *NewF = buildWrapperFunction( &F, std::string("dfsw$") + std::string(F.getName()), - GlobalValue::LinkOnceODRLinkage, NewFT); + wrapperLinkage, NewFT); if (getInstrumentedABI() == IA_TLS) NewF->removeAttributes(AttributeList::FunctionIndex, ReadOnlyNoneAttrs); @@ -1382,20 +1465,19 @@ void DFSanVisitor::visitMemTransferInst(MemTransferInst &I) { Value *LenShadow = IRB.CreateMul( I.getLength(), ConstantInt::get(I.getLength()->getType(), DFSF.DFS.ShadowWidth / 8)); - Value *AlignShadow; - if (ClPreserveAlignment) { - AlignShadow = IRB.CreateMul(I.getAlignmentCst(), - ConstantInt::get(I.getAlignmentCst()->getType(), - DFSF.DFS.ShadowWidth / 8)); - } else { - AlignShadow = ConstantInt::get(I.getAlignmentCst()->getType(), - DFSF.DFS.ShadowWidth / 8); - } Type *Int8Ptr = Type::getInt8PtrTy(*DFSF.DFS.Ctx); DestShadow = IRB.CreateBitCast(DestShadow, Int8Ptr); SrcShadow = IRB.CreateBitCast(SrcShadow, Int8Ptr); - IRB.CreateCall(I.getCalledValue(), {DestShadow, SrcShadow, LenShadow, - AlignShadow, I.getVolatileCst()}); + auto *MTI = cast( + IRB.CreateCall(I.getCalledValue(), + {DestShadow, SrcShadow, LenShadow, I.getVolatileCst()})); + if (ClPreserveAlignment) { + MTI->setDestAlignment(I.getDestAlignment() * (DFSF.DFS.ShadowWidth / 8)); + MTI->setSourceAlignment(I.getSourceAlignment() * (DFSF.DFS.ShadowWidth / 8)); + } else { + MTI->setDestAlignment(DFSF.DFS.ShadowWidth / 8); + MTI->setSourceAlignment(DFSF.DFS.ShadowWidth / 8); + } } void DFSanVisitor::visitReturnInst(ReturnInst &RI) { @@ -1460,11 +1542,11 @@ void DFSanVisitor::visitCallSite(CallSite CS) { // wrapper. if (CallInst *CI = dyn_cast(CS.getInstruction())) { FunctionType *FT = F->getFunctionType(); - FunctionType *CustomFT = DFSF.DFS.getCustomFunctionType(FT); + TransformedFunction CustomFn = DFSF.DFS.getCustomFunctionType(FT); std::string CustomFName = "__dfsw_"; CustomFName += F->getName(); - Constant *CustomF = - DFSF.DFS.Mod->getOrInsertFunction(CustomFName, CustomFT); + Constant *CustomF = DFSF.DFS.Mod->getOrInsertFunction( + CustomFName, CustomFn.TransformedType); if (Function *CustomFn = dyn_cast(CustomF)) { CustomFn->copyAttributesFrom(F); @@ -1532,7 +1614,8 @@ void DFSanVisitor::visitCallSite(CallSite CS) { CallInst *CustomCI = IRB.CreateCall(CustomF, Args); CustomCI->setCallingConv(CI->getCallingConv()); - CustomCI->setAttributes(CI->getAttributes()); + CustomCI->setAttributes(TransformFunctionAttributes(CustomFn, + CI->getContext(), CI->getAttributes())); // Update the parameter attributes of the custom call instruction to // zero extend the shadow parameters. This is required for targets diff --git a/lib/Transforms/Instrumentation/EfficiencySanitizer.cpp b/lib/Transforms/Instrumentation/EfficiencySanitizer.cpp index 6864d295525c..33f220a893df 100644 --- a/lib/Transforms/Instrumentation/EfficiencySanitizer.cpp +++ b/lib/Transforms/Instrumentation/EfficiencySanitizer.cpp @@ -23,6 +23,7 @@ #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/Transforms/Utils/Local.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/IntrinsicInst.h" @@ -33,7 +34,6 @@ #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" using namespace llvm; @@ -537,7 +537,7 @@ void EfficiencySanitizer::createDestructor(Module &M, Constant *ToolInfoArg) { bool EfficiencySanitizer::initOnModule(Module &M) { Triple TargetTriple(M.getTargetTriple()); - if (TargetTriple.getArch() == Triple::mips64 || TargetTriple.getArch() == Triple::mips64el) + if (TargetTriple.isMIPS64()) ShadowParams = ShadowParams40; else ShadowParams = ShadowParams47; diff --git a/lib/Transforms/Instrumentation/GCOVProfiling.cpp b/lib/Transforms/Instrumentation/GCOVProfiling.cpp index 67ca8172b0d5..acd27c2e226f 100644 --- a/lib/Transforms/Instrumentation/GCOVProfiling.cpp +++ b/lib/Transforms/Instrumentation/GCOVProfiling.cpp @@ -17,11 +17,13 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Sequence.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/UniqueVector.h" #include "llvm/Analysis/EHPersonalities.h" +#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DebugLoc.h" #include "llvm/IR/IRBuilder.h" @@ -35,8 +37,8 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Transforms/GCOVProfiler.h" #include "llvm/Transforms/Instrumentation.h" +#include "llvm/Transforms/Instrumentation/GCOVProfiler.h" #include "llvm/Transforms/Utils/ModuleUtils.h" #include #include @@ -84,7 +86,7 @@ public: ReversedVersion[3] = Options.Version[0]; ReversedVersion[4] = '\0'; } - bool runOnModule(Module &M); + bool runOnModule(Module &M, const TargetLibraryInfo &TLI); private: // Create the .gcno files for the Module based on DebugInfo. @@ -130,6 +132,7 @@ private: SmallVector FileChecksums; Module *M; + const TargetLibraryInfo *TLI; LLVMContext *Ctx; SmallVector, 16> Funcs; }; @@ -145,7 +148,14 @@ public: } StringRef getPassName() const override { return "GCOV Profiler"; } - bool runOnModule(Module &M) override { return Profiler.runOnModule(M); } + bool runOnModule(Module &M) override { + auto &TLI = getAnalysis().getTLI(); + return Profiler.runOnModule(M, TLI); + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); + } private: GCOVProfiler Profiler; @@ -153,8 +163,13 @@ private: } char GCOVProfilerLegacyPass::ID = 0; -INITIALIZE_PASS(GCOVProfilerLegacyPass, "insert-gcov-profiling", - "Insert instrumentation for GCOV profiling", false, false) +INITIALIZE_PASS_BEGIN( + GCOVProfilerLegacyPass, "insert-gcov-profiling", + "Insert instrumentation for GCOV profiling", false, false) +INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) +INITIALIZE_PASS_END( + GCOVProfilerLegacyPass, "insert-gcov-profiling", + "Insert instrumentation for GCOV profiling", false, false) ModulePass *llvm::createGCOVProfilerPass(const GCOVOptions &Options) { return new GCOVProfilerLegacyPass(Options); @@ -272,7 +287,7 @@ namespace { write(Len); write(Number); - std::sort( + llvm::sort( SortedLinesByFile.begin(), SortedLinesByFile.end(), [](StringMapEntry *LHS, StringMapEntry *RHS) { return LHS->getKey() < RHS->getKey(); @@ -315,7 +330,7 @@ namespace { ReturnBlock(1, os) { this->os = os; - DEBUG(dbgs() << "Function: " << getFunctionName(SP) << "\n"); + LLVM_DEBUG(dbgs() << "Function: " << getFunctionName(SP) << "\n"); uint32_t i = 0; for (auto &BB : *F) { @@ -383,7 +398,7 @@ namespace { for (int i = 0, e = Blocks.size() + 1; i != e; ++i) { write(0); // No flags on our blocks. } - DEBUG(dbgs() << Blocks.size() << " blocks.\n"); + LLVM_DEBUG(dbgs() << Blocks.size() << " blocks.\n"); // Emit edges between blocks. if (Blocks.empty()) return; @@ -396,8 +411,8 @@ namespace { write(Block.OutEdges.size() * 2 + 1); write(Block.Number); for (int i = 0, e = Block.OutEdges.size(); i != e; ++i) { - DEBUG(dbgs() << Block.Number << " -> " << Block.OutEdges[i]->Number - << "\n"); + LLVM_DEBUG(dbgs() << Block.Number << " -> " + << Block.OutEdges[i]->Number << "\n"); write(Block.OutEdges[i]->Number); write(0); // no flags } @@ -461,8 +476,9 @@ std::string GCOVProfiler::mangleName(const DICompileUnit *CU, return CurPath.str(); } -bool GCOVProfiler::runOnModule(Module &M) { +bool GCOVProfiler::runOnModule(Module &M, const TargetLibraryInfo &TLI) { this->M = &M; + this->TLI = &TLI; Ctx = &M.getContext(); if (Options.EmitNotes) emitProfileNotes(); @@ -475,7 +491,8 @@ PreservedAnalyses GCOVProfilerPass::run(Module &M, GCOVProfiler Profiler(GCOVOpts); - if (!Profiler.runOnModule(M)) + auto &TLI = AM.getResult(M); + if (!Profiler.runOnModule(M, TLI)) return PreservedAnalyses::all(); return PreservedAnalyses::none(); @@ -503,11 +520,11 @@ static bool functionHasLines(Function &F) { return false; } -static bool isUsingFuncletBasedEH(Function &F) { +static bool isUsingScopeBasedEH(Function &F) { if (!F.hasPersonalityFn()) return false; EHPersonality Personality = classifyEHPersonality(F.getPersonalityFn()); - return isFuncletEHPersonality(Personality); + return isScopedEHPersonality(Personality); } static bool shouldKeepInEntry(BasicBlock::iterator It) { @@ -550,8 +567,8 @@ void GCOVProfiler::emitProfileNotes() { DISubprogram *SP = F.getSubprogram(); if (!SP) continue; if (!functionHasLines(F)) continue; - // TODO: Functions using funclet-based EH are currently not supported. - if (isUsingFuncletBasedEH(F)) continue; + // TODO: Functions using scope-based EH are currently not supported. + if (isUsingScopeBasedEH(F)) continue; // gcov expects every function to start with an entry block that has a // single successor, so split the entry block to make sure of that. @@ -629,8 +646,8 @@ bool GCOVProfiler::emitProfileArcs() { DISubprogram *SP = F.getSubprogram(); if (!SP) continue; if (!functionHasLines(F)) continue; - // TODO: Functions using funclet-based EH are currently not supported. - if (isUsingFuncletBasedEH(F)) continue; + // TODO: Functions using scope-based EH are currently not supported. + if (isUsingScopeBasedEH(F)) continue; if (!Result) Result = true; unsigned Edges = 0; @@ -807,7 +824,12 @@ Constant *GCOVProfiler::getStartFileFunc() { Type::getInt32Ty(*Ctx), // uint32_t checksum }; FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false); - return M->getOrInsertFunction("llvm_gcda_start_file", FTy); + auto *Res = M->getOrInsertFunction("llvm_gcda_start_file", FTy); + if (Function *FunRes = dyn_cast(Res)) + if (auto AK = TLI->getExtAttrForI32Param(false)) + FunRes->addParamAttr(2, AK); + return Res; + } Constant *GCOVProfiler::getIncrementIndirectCounterFunc() { @@ -830,7 +852,15 @@ Constant *GCOVProfiler::getEmitFunctionFunc() { Type::getInt32Ty(*Ctx), // uint32_t cfg_checksum }; FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false); - return M->getOrInsertFunction("llvm_gcda_emit_function", FTy); + auto *Res = M->getOrInsertFunction("llvm_gcda_emit_function", FTy); + if (Function *FunRes = dyn_cast(Res)) + if (auto AK = TLI->getExtAttrForI32Param(false)) { + FunRes->addParamAttr(0, AK); + FunRes->addParamAttr(2, AK); + FunRes->addParamAttr(3, AK); + FunRes->addParamAttr(4, AK); + } + return Res; } Constant *GCOVProfiler::getEmitArcsFunc() { @@ -839,7 +869,11 @@ Constant *GCOVProfiler::getEmitArcsFunc() { Type::getInt64PtrTy(*Ctx), // uint64_t *counters }; FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false); - return M->getOrInsertFunction("llvm_gcda_emit_arcs", FTy); + auto *Res = M->getOrInsertFunction("llvm_gcda_emit_arcs", FTy); + if (Function *FunRes = dyn_cast(Res)) + if (auto AK = TLI->getExtAttrForI32Param(false)) + FunRes->addParamAttr(0, AK); + return Res; } Constant *GCOVProfiler::getSummaryInfoFunc() { @@ -886,46 +920,205 @@ Function *GCOVProfiler::insertCounterWriteout( Constant *SummaryInfo = getSummaryInfoFunc(); Constant *EndFile = getEndFileFunc(); - NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu"); - if (CU_Nodes) { - for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) { - auto *CU = cast(CU_Nodes->getOperand(i)); + NamedMDNode *CUNodes = M->getNamedMetadata("llvm.dbg.cu"); + if (!CUNodes) { + Builder.CreateRetVoid(); + return WriteoutF; + } - // Skip module skeleton (and module) CUs. - if (CU->getDWOId()) - continue; + // Collect the relevant data into a large constant data structure that we can + // walk to write out everything. + StructType *StartFileCallArgsTy = StructType::create( + {Builder.getInt8PtrTy(), Builder.getInt8PtrTy(), Builder.getInt32Ty()}); + StructType *EmitFunctionCallArgsTy = StructType::create( + {Builder.getInt32Ty(), Builder.getInt8PtrTy(), Builder.getInt32Ty(), + Builder.getInt8Ty(), Builder.getInt32Ty()}); + StructType *EmitArcsCallArgsTy = StructType::create( + {Builder.getInt32Ty(), Builder.getInt64Ty()->getPointerTo()}); + StructType *FileInfoTy = + StructType::create({StartFileCallArgsTy, Builder.getInt32Ty(), + EmitFunctionCallArgsTy->getPointerTo(), + EmitArcsCallArgsTy->getPointerTo()}); + + Constant *Zero32 = Builder.getInt32(0); + // Build an explicit array of two zeros for use in ConstantExpr GEP building. + Constant *TwoZero32s[] = {Zero32, Zero32}; + + SmallVector FileInfos; + for (int i : llvm::seq(0, CUNodes->getNumOperands())) { + auto *CU = cast(CUNodes->getOperand(i)); - std::string FilenameGcda = mangleName(CU, GCovFileType::GCDA); - uint32_t CfgChecksum = FileChecksums.empty() ? 0 : FileChecksums[i]; - Builder.CreateCall(StartFile, - {Builder.CreateGlobalStringPtr(FilenameGcda), - Builder.CreateGlobalStringPtr(ReversedVersion), - Builder.getInt32(CfgChecksum)}); - for (unsigned j = 0, e = CountersBySP.size(); j != e; ++j) { - auto *SP = cast_or_null(CountersBySP[j].second); - uint32_t FuncChecksum = Funcs.empty() ? 0 : Funcs[j]->getFuncChecksum(); - Builder.CreateCall( - EmitFunction, - {Builder.getInt32(j), - Options.FunctionNamesInData - ? Builder.CreateGlobalStringPtr(getFunctionName(SP)) - : Constant::getNullValue(Builder.getInt8PtrTy()), - Builder.getInt32(FuncChecksum), - Builder.getInt8(Options.UseCfgChecksum), - Builder.getInt32(CfgChecksum)}); - - GlobalVariable *GV = CountersBySP[j].first; - unsigned Arcs = - cast(GV->getValueType())->getNumElements(); - Builder.CreateCall(EmitArcs, {Builder.getInt32(Arcs), - Builder.CreateConstGEP2_64(GV, 0, 0)}); - } - Builder.CreateCall(SummaryInfo, {}); - Builder.CreateCall(EndFile, {}); + // Skip module skeleton (and module) CUs. + if (CU->getDWOId()) + continue; + + std::string FilenameGcda = mangleName(CU, GCovFileType::GCDA); + uint32_t CfgChecksum = FileChecksums.empty() ? 0 : FileChecksums[i]; + auto *StartFileCallArgs = ConstantStruct::get( + StartFileCallArgsTy, {Builder.CreateGlobalStringPtr(FilenameGcda), + Builder.CreateGlobalStringPtr(ReversedVersion), + Builder.getInt32(CfgChecksum)}); + + SmallVector EmitFunctionCallArgsArray; + SmallVector EmitArcsCallArgsArray; + for (int j : llvm::seq(0, CountersBySP.size())) { + auto *SP = cast_or_null(CountersBySP[j].second); + uint32_t FuncChecksum = Funcs.empty() ? 0 : Funcs[j]->getFuncChecksum(); + EmitFunctionCallArgsArray.push_back(ConstantStruct::get( + EmitFunctionCallArgsTy, + {Builder.getInt32(j), + Options.FunctionNamesInData + ? Builder.CreateGlobalStringPtr(getFunctionName(SP)) + : Constant::getNullValue(Builder.getInt8PtrTy()), + Builder.getInt32(FuncChecksum), + Builder.getInt8(Options.UseCfgChecksum), + Builder.getInt32(CfgChecksum)})); + + GlobalVariable *GV = CountersBySP[j].first; + unsigned Arcs = cast(GV->getValueType())->getNumElements(); + EmitArcsCallArgsArray.push_back(ConstantStruct::get( + EmitArcsCallArgsTy, + {Builder.getInt32(Arcs), ConstantExpr::getInBoundsGetElementPtr( + GV->getValueType(), GV, TwoZero32s)})); } + // Create global arrays for the two emit calls. + int CountersSize = CountersBySP.size(); + assert(CountersSize == (int)EmitFunctionCallArgsArray.size() && + "Mismatched array size!"); + assert(CountersSize == (int)EmitArcsCallArgsArray.size() && + "Mismatched array size!"); + auto *EmitFunctionCallArgsArrayTy = + ArrayType::get(EmitFunctionCallArgsTy, CountersSize); + auto *EmitFunctionCallArgsArrayGV = new GlobalVariable( + *M, EmitFunctionCallArgsArrayTy, /*isConstant*/ true, + GlobalValue::InternalLinkage, + ConstantArray::get(EmitFunctionCallArgsArrayTy, + EmitFunctionCallArgsArray), + Twine("__llvm_internal_gcov_emit_function_args.") + Twine(i)); + auto *EmitArcsCallArgsArrayTy = + ArrayType::get(EmitArcsCallArgsTy, CountersSize); + EmitFunctionCallArgsArrayGV->setUnnamedAddr( + GlobalValue::UnnamedAddr::Global); + auto *EmitArcsCallArgsArrayGV = new GlobalVariable( + *M, EmitArcsCallArgsArrayTy, /*isConstant*/ true, + GlobalValue::InternalLinkage, + ConstantArray::get(EmitArcsCallArgsArrayTy, EmitArcsCallArgsArray), + Twine("__llvm_internal_gcov_emit_arcs_args.") + Twine(i)); + EmitArcsCallArgsArrayGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); + + FileInfos.push_back(ConstantStruct::get( + FileInfoTy, + {StartFileCallArgs, Builder.getInt32(CountersSize), + ConstantExpr::getInBoundsGetElementPtr(EmitFunctionCallArgsArrayTy, + EmitFunctionCallArgsArrayGV, + TwoZero32s), + ConstantExpr::getInBoundsGetElementPtr( + EmitArcsCallArgsArrayTy, EmitArcsCallArgsArrayGV, TwoZero32s)})); } + // If we didn't find anything to actually emit, bail on out. + if (FileInfos.empty()) { + Builder.CreateRetVoid(); + return WriteoutF; + } + + // To simplify code, we cap the number of file infos we write out to fit + // easily in a 32-bit signed integer. This gives consistent behavior between + // 32-bit and 64-bit systems without requiring (potentially very slow) 64-bit + // operations on 32-bit systems. It also seems unreasonable to try to handle + // more than 2 billion files. + if ((int64_t)FileInfos.size() > (int64_t)INT_MAX) + FileInfos.resize(INT_MAX); + + // Create a global for the entire data structure so we can walk it more + // easily. + auto *FileInfoArrayTy = ArrayType::get(FileInfoTy, FileInfos.size()); + auto *FileInfoArrayGV = new GlobalVariable( + *M, FileInfoArrayTy, /*isConstant*/ true, GlobalValue::InternalLinkage, + ConstantArray::get(FileInfoArrayTy, FileInfos), + "__llvm_internal_gcov_emit_file_info"); + FileInfoArrayGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); + + // Create the CFG for walking this data structure. + auto *FileLoopHeader = + BasicBlock::Create(*Ctx, "file.loop.header", WriteoutF); + auto *CounterLoopHeader = + BasicBlock::Create(*Ctx, "counter.loop.header", WriteoutF); + auto *FileLoopLatch = BasicBlock::Create(*Ctx, "file.loop.latch", WriteoutF); + auto *ExitBB = BasicBlock::Create(*Ctx, "exit", WriteoutF); + + // We always have at least one file, so just branch to the header. + Builder.CreateBr(FileLoopHeader); + + // The index into the files structure is our loop induction variable. + Builder.SetInsertPoint(FileLoopHeader); + PHINode *IV = + Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2); + IV->addIncoming(Builder.getInt32(0), BB); + auto *FileInfoPtr = + Builder.CreateInBoundsGEP(FileInfoArrayGV, {Builder.getInt32(0), IV}); + auto *StartFileCallArgsPtr = Builder.CreateStructGEP(FileInfoPtr, 0); + auto *StartFileCall = Builder.CreateCall( + StartFile, + {Builder.CreateLoad(Builder.CreateStructGEP(StartFileCallArgsPtr, 0)), + Builder.CreateLoad(Builder.CreateStructGEP(StartFileCallArgsPtr, 1)), + Builder.CreateLoad(Builder.CreateStructGEP(StartFileCallArgsPtr, 2))}); + if (auto AK = TLI->getExtAttrForI32Param(false)) + StartFileCall->addParamAttr(2, AK); + auto *NumCounters = + Builder.CreateLoad(Builder.CreateStructGEP(FileInfoPtr, 1)); + auto *EmitFunctionCallArgsArray = + Builder.CreateLoad(Builder.CreateStructGEP(FileInfoPtr, 2)); + auto *EmitArcsCallArgsArray = + Builder.CreateLoad(Builder.CreateStructGEP(FileInfoPtr, 3)); + auto *EnterCounterLoopCond = + Builder.CreateICmpSLT(Builder.getInt32(0), NumCounters); + Builder.CreateCondBr(EnterCounterLoopCond, CounterLoopHeader, FileLoopLatch); + + Builder.SetInsertPoint(CounterLoopHeader); + auto *JV = Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2); + JV->addIncoming(Builder.getInt32(0), FileLoopHeader); + auto *EmitFunctionCallArgsPtr = + Builder.CreateInBoundsGEP(EmitFunctionCallArgsArray, {JV}); + auto *EmitFunctionCall = Builder.CreateCall( + EmitFunction, + {Builder.CreateLoad(Builder.CreateStructGEP(EmitFunctionCallArgsPtr, 0)), + Builder.CreateLoad(Builder.CreateStructGEP(EmitFunctionCallArgsPtr, 1)), + Builder.CreateLoad(Builder.CreateStructGEP(EmitFunctionCallArgsPtr, 2)), + Builder.CreateLoad(Builder.CreateStructGEP(EmitFunctionCallArgsPtr, 3)), + Builder.CreateLoad( + Builder.CreateStructGEP(EmitFunctionCallArgsPtr, 4))}); + if (auto AK = TLI->getExtAttrForI32Param(false)) { + EmitFunctionCall->addParamAttr(0, AK); + EmitFunctionCall->addParamAttr(2, AK); + EmitFunctionCall->addParamAttr(3, AK); + EmitFunctionCall->addParamAttr(4, AK); + } + auto *EmitArcsCallArgsPtr = + Builder.CreateInBoundsGEP(EmitArcsCallArgsArray, {JV}); + auto *EmitArcsCall = Builder.CreateCall( + EmitArcs, + {Builder.CreateLoad(Builder.CreateStructGEP(EmitArcsCallArgsPtr, 0)), + Builder.CreateLoad(Builder.CreateStructGEP(EmitArcsCallArgsPtr, 1))}); + if (auto AK = TLI->getExtAttrForI32Param(false)) + EmitArcsCall->addParamAttr(0, AK); + auto *NextJV = Builder.CreateAdd(JV, Builder.getInt32(1)); + auto *CounterLoopCond = Builder.CreateICmpSLT(NextJV, NumCounters); + Builder.CreateCondBr(CounterLoopCond, CounterLoopHeader, FileLoopLatch); + JV->addIncoming(NextJV, CounterLoopHeader); + + Builder.SetInsertPoint(FileLoopLatch); + Builder.CreateCall(SummaryInfo, {}); + Builder.CreateCall(EndFile, {}); + auto *NextIV = Builder.CreateAdd(IV, Builder.getInt32(1)); + auto *FileLoopCond = + Builder.CreateICmpSLT(NextIV, Builder.getInt32(FileInfos.size())); + Builder.CreateCondBr(FileLoopCond, FileLoopHeader, ExitBB); + IV->addIncoming(NextIV, FileLoopLatch); + + Builder.SetInsertPoint(ExitBB); Builder.CreateRetVoid(); + return WriteoutF; } diff --git a/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp b/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp index 8e2833d22032..d62598bb5d4f 100644 --- a/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp +++ b/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp @@ -22,10 +22,7 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/MDBuilder.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/IR/Function.h" -#include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/InstVisitor.h" @@ -34,6 +31,7 @@ #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/MDBuilder.h" #include "llvm/IR/Module.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" @@ -41,8 +39,11 @@ #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Instrumentation.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/ModuleUtils.h" +#include "llvm/Transforms/Utils/PromoteMemToReg.h" using namespace llvm; @@ -51,10 +52,15 @@ using namespace llvm; static const char *const kHwasanModuleCtorName = "hwasan.module_ctor"; static const char *const kHwasanInitName = "__hwasan_init"; +static const char *const kHwasanShadowMemoryDynamicAddress = + "__hwasan_shadow_memory_dynamic_address"; + // Accesses sizes are powers of two: 1, 2, 4, 8, 16. static const size_t kNumberOfAccessSizes = 5; -static const size_t kShadowScale = 4; +static const size_t kDefaultShadowScale = 4; +static const uint64_t kDynamicShadowSentinel = + std::numeric_limits::max(); static const unsigned kPointerTagShift = 56; static cl::opt ClMemoryAccessCallbackPrefix( @@ -85,17 +91,57 @@ static cl::opt ClRecover( cl::desc("Enable recovery mode (continue-after-error)."), cl::Hidden, cl::init(false)); +static cl::opt ClInstrumentStack("hwasan-instrument-stack", + cl::desc("instrument stack (allocas)"), + cl::Hidden, cl::init(true)); + +static cl::opt ClUARRetagToZero( + "hwasan-uar-retag-to-zero", + cl::desc("Clear alloca tags before returning from the function to allow " + "non-instrumented and instrumented function calls mix. When set " + "to false, allocas are retagged before returning from the " + "function to detect use after return."), + cl::Hidden, cl::init(true)); + +static cl::opt ClGenerateTagsWithCalls( + "hwasan-generate-tags-with-calls", + cl::desc("generate new tags with runtime library calls"), cl::Hidden, + cl::init(false)); + +static cl::opt ClMatchAllTag( + "hwasan-match-all-tag", + cl::desc("don't report bad accesses via pointers with this tag"), + cl::Hidden, cl::init(-1)); + +static cl::opt ClEnableKhwasan( + "hwasan-kernel", + cl::desc("Enable KernelHWAddressSanitizer instrumentation"), + cl::Hidden, cl::init(false)); + +// These flags allow to change the shadow mapping and control how shadow memory +// is accessed. The shadow mapping looks like: +// Shadow = (Mem >> scale) + offset + +static cl::opt ClMappingOffset( + "hwasan-mapping-offset", + cl::desc("HWASan shadow mapping offset [EXPERIMENTAL]"), cl::Hidden, + cl::init(0)); + namespace { -/// \brief An instrumentation pass implementing detection of addressability bugs +/// An instrumentation pass implementing detection of addressability bugs /// using tagged pointers. class HWAddressSanitizer : public FunctionPass { public: // Pass identification, replacement for typeid. static char ID; - HWAddressSanitizer(bool Recover = false) - : FunctionPass(ID), Recover(Recover || ClRecover) {} + explicit HWAddressSanitizer(bool CompileKernel = false, bool Recover = false) + : FunctionPass(ID) { + this->Recover = ClRecover.getNumOccurrences() > 0 ? ClRecover : Recover; + this->CompileKernel = ClEnableKhwasan.getNumOccurrences() > 0 ? + ClEnableKhwasan : CompileKernel; + } StringRef getPassName() const override { return "HWAddressSanitizer"; } @@ -103,6 +149,11 @@ public: bool doInitialization(Module &M) override; void initializeCallbacks(Module &M); + + void maybeInsertDynamicShadowAtFunctionEntry(Function &F); + + void untagPointerOperand(Instruction *I, Value *Addr); + Value *memToShadow(Value *Shadow, Type *Ty, IRBuilder<> &IRB); void instrumentMemAccessInline(Value *PtrLong, bool IsWrite, unsigned AccessSizeIndex, Instruction *InsertBefore); @@ -111,16 +162,54 @@ public: uint64_t *TypeSize, unsigned *Alignment, Value **MaybeMask); + bool isInterestingAlloca(const AllocaInst &AI); + bool tagAlloca(IRBuilder<> &IRB, AllocaInst *AI, Value *Tag); + Value *tagPointer(IRBuilder<> &IRB, Type *Ty, Value *PtrLong, Value *Tag); + Value *untagPointer(IRBuilder<> &IRB, Value *PtrLong); + bool instrumentStack(SmallVectorImpl &Allocas, + SmallVectorImpl &RetVec); + Value *getNextTagWithCall(IRBuilder<> &IRB); + Value *getStackBaseTag(IRBuilder<> &IRB); + Value *getAllocaTag(IRBuilder<> &IRB, Value *StackTag, AllocaInst *AI, + unsigned AllocaNo); + Value *getUARTag(IRBuilder<> &IRB, Value *StackTag); + private: LLVMContext *C; + Triple TargetTriple; + + /// This struct defines the shadow mapping using the rule: + /// shadow = (mem >> Scale) + Offset. + /// If InGlobal is true, then + /// extern char __hwasan_shadow[]; + /// shadow = (mem >> Scale) + &__hwasan_shadow + struct ShadowMapping { + int Scale; + uint64_t Offset; + bool InGlobal; + + void init(Triple &TargetTriple); + unsigned getAllocaAlignment() const { return 1U << Scale; } + }; + ShadowMapping Mapping; + Type *IntptrTy; + Type *Int8Ty; + bool CompileKernel; bool Recover; Function *HwasanCtorFunction; Function *HwasanMemoryAccessCallback[2][kNumberOfAccessSizes]; Function *HwasanMemoryAccessCallbackSized[2]; + + Function *HwasanTagMemoryFunc; + Function *HwasanGenerateTagFunc; + + Constant *ShadowGlobal; + + Value *LocalDynamicShadow = nullptr; }; } // end anonymous namespace @@ -129,34 +218,44 @@ char HWAddressSanitizer::ID = 0; INITIALIZE_PASS_BEGIN( HWAddressSanitizer, "hwasan", - "HWAddressSanitizer: detect memory bugs using tagged addressing.", false, false) + "HWAddressSanitizer: detect memory bugs using tagged addressing.", false, + false) INITIALIZE_PASS_END( HWAddressSanitizer, "hwasan", - "HWAddressSanitizer: detect memory bugs using tagged addressing.", false, false) + "HWAddressSanitizer: detect memory bugs using tagged addressing.", false, + false) -FunctionPass *llvm::createHWAddressSanitizerPass(bool Recover) { - return new HWAddressSanitizer(Recover); +FunctionPass *llvm::createHWAddressSanitizerPass(bool CompileKernel, + bool Recover) { + assert(!CompileKernel || Recover); + return new HWAddressSanitizer(CompileKernel, Recover); } -/// \brief Module-level initialization. +/// Module-level initialization. /// /// inserts a call to __hwasan_init to the module's constructor list. bool HWAddressSanitizer::doInitialization(Module &M) { - DEBUG(dbgs() << "Init " << M.getName() << "\n"); + LLVM_DEBUG(dbgs() << "Init " << M.getName() << "\n"); auto &DL = M.getDataLayout(); - Triple TargetTriple(M.getTargetTriple()); + TargetTriple = Triple(M.getTargetTriple()); + + Mapping.init(TargetTriple); C = &(M.getContext()); IRBuilder<> IRB(*C); IntptrTy = IRB.getIntPtrTy(DL); - - std::tie(HwasanCtorFunction, std::ignore) = - createSanitizerCtorAndInitFunctions(M, kHwasanModuleCtorName, - kHwasanInitName, - /*InitArgTypes=*/{}, - /*InitArgs=*/{}); - appendToGlobalCtors(M, HwasanCtorFunction, 0); + Int8Ty = IRB.getInt8Ty(); + + HwasanCtorFunction = nullptr; + if (!CompileKernel) { + std::tie(HwasanCtorFunction, std::ignore) = + createSanitizerCtorAndInitFunctions(M, kHwasanModuleCtorName, + kHwasanInitName, + /*InitArgTypes=*/{}, + /*InitArgs=*/{}); + appendToGlobalCtors(M, HwasanCtorFunction, 0); + } return true; } @@ -168,7 +267,7 @@ void HWAddressSanitizer::initializeCallbacks(Module &M) { HwasanMemoryAccessCallbackSized[AccessIsWrite] = checkSanitizerInterfaceFunction(M.getOrInsertFunction( - ClMemoryAccessCallbackPrefix + TypeStr + EndingStr, + ClMemoryAccessCallbackPrefix + TypeStr + "N" + EndingStr, FunctionType::get(IRB.getVoidTy(), {IntptrTy, IntptrTy}, false))); for (size_t AccessSizeIndex = 0; AccessSizeIndex < kNumberOfAccessSizes; @@ -180,16 +279,50 @@ void HWAddressSanitizer::initializeCallbacks(Module &M) { FunctionType::get(IRB.getVoidTy(), {IntptrTy}, false))); } } + + HwasanTagMemoryFunc = checkSanitizerInterfaceFunction(M.getOrInsertFunction( + "__hwasan_tag_memory", IRB.getVoidTy(), IntptrTy, Int8Ty, IntptrTy)); + HwasanGenerateTagFunc = checkSanitizerInterfaceFunction( + M.getOrInsertFunction("__hwasan_generate_tag", Int8Ty)); + + if (Mapping.InGlobal) + ShadowGlobal = M.getOrInsertGlobal("__hwasan_shadow", + ArrayType::get(IRB.getInt8Ty(), 0)); +} + +void HWAddressSanitizer::maybeInsertDynamicShadowAtFunctionEntry(Function &F) { + // Generate code only when dynamic addressing is needed. + if (Mapping.Offset != kDynamicShadowSentinel) + return; + + IRBuilder<> IRB(&F.front().front()); + if (Mapping.InGlobal) { + // An empty inline asm with input reg == output reg. + // An opaque pointer-to-int cast, basically. + InlineAsm *Asm = InlineAsm::get( + FunctionType::get(IntptrTy, {ShadowGlobal->getType()}, false), + StringRef(""), StringRef("=r,0"), + /*hasSideEffects=*/false); + LocalDynamicShadow = IRB.CreateCall(Asm, {ShadowGlobal}, ".hwasan.shadow"); + } else { + Value *GlobalDynamicAddress = F.getParent()->getOrInsertGlobal( + kHwasanShadowMemoryDynamicAddress, IntptrTy); + LocalDynamicShadow = IRB.CreateLoad(GlobalDynamicAddress); + } } Value *HWAddressSanitizer::isInterestingMemoryAccess(Instruction *I, - bool *IsWrite, - uint64_t *TypeSize, - unsigned *Alignment, - Value **MaybeMask) { + bool *IsWrite, + uint64_t *TypeSize, + unsigned *Alignment, + Value **MaybeMask) { // Skip memory accesses inserted by another instrumentation. if (I->getMetadata("nosanitize")) return nullptr; + // Do not instrument the load fetching the dynamic shadow address. + if (LocalDynamicShadow == I) + return nullptr; + Value *PtrOperand = nullptr; const DataLayout &DL = I->getModule()->getDataLayout(); if (LoadInst *LI = dyn_cast(I)) { @@ -219,7 +352,7 @@ Value *HWAddressSanitizer::isInterestingMemoryAccess(Instruction *I, } if (PtrOperand) { - // Do not instrument acesses from different address spaces; we cannot deal + // Do not instrument accesses from different address spaces; we cannot deal // with them. Type *PtrTy = cast(PtrOperand->getType()->getScalarType()); if (PtrTy->getPointerAddressSpace() != 0) @@ -236,41 +369,103 @@ Value *HWAddressSanitizer::isInterestingMemoryAccess(Instruction *I, return PtrOperand; } +static unsigned getPointerOperandIndex(Instruction *I) { + if (LoadInst *LI = dyn_cast(I)) + return LI->getPointerOperandIndex(); + if (StoreInst *SI = dyn_cast(I)) + return SI->getPointerOperandIndex(); + if (AtomicRMWInst *RMW = dyn_cast(I)) + return RMW->getPointerOperandIndex(); + if (AtomicCmpXchgInst *XCHG = dyn_cast(I)) + return XCHG->getPointerOperandIndex(); + report_fatal_error("Unexpected instruction"); + return -1; +} + static size_t TypeSizeToSizeIndex(uint32_t TypeSize) { size_t Res = countTrailingZeros(TypeSize / 8); assert(Res < kNumberOfAccessSizes); return Res; } +void HWAddressSanitizer::untagPointerOperand(Instruction *I, Value *Addr) { + if (TargetTriple.isAArch64()) + return; + + IRBuilder<> IRB(I); + Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy); + Value *UntaggedPtr = + IRB.CreateIntToPtr(untagPointer(IRB, AddrLong), Addr->getType()); + I->setOperand(getPointerOperandIndex(I), UntaggedPtr); +} + +Value *HWAddressSanitizer::memToShadow(Value *Mem, Type *Ty, IRBuilder<> &IRB) { + // Mem >> Scale + Value *Shadow = IRB.CreateLShr(Mem, Mapping.Scale); + if (Mapping.Offset == 0) + return Shadow; + // (Mem >> Scale) + Offset + Value *ShadowBase; + if (LocalDynamicShadow) + ShadowBase = LocalDynamicShadow; + else + ShadowBase = ConstantInt::get(Ty, Mapping.Offset); + return IRB.CreateAdd(Shadow, ShadowBase); +} + void HWAddressSanitizer::instrumentMemAccessInline(Value *PtrLong, bool IsWrite, unsigned AccessSizeIndex, Instruction *InsertBefore) { IRBuilder<> IRB(InsertBefore); - Value *PtrTag = IRB.CreateTrunc(IRB.CreateLShr(PtrLong, kPointerTagShift), IRB.getInt8Ty()); - Value *AddrLong = - IRB.CreateAnd(PtrLong, ConstantInt::get(PtrLong->getType(), - ~(0xFFULL << kPointerTagShift))); - Value *ShadowLong = IRB.CreateLShr(AddrLong, kShadowScale); - Value *MemTag = IRB.CreateLoad(IRB.CreateIntToPtr(ShadowLong, IRB.getInt8PtrTy())); + Value *PtrTag = IRB.CreateTrunc(IRB.CreateLShr(PtrLong, kPointerTagShift), + IRB.getInt8Ty()); + Value *AddrLong = untagPointer(IRB, PtrLong); + Value *ShadowLong = memToShadow(AddrLong, PtrLong->getType(), IRB); + Value *MemTag = + IRB.CreateLoad(IRB.CreateIntToPtr(ShadowLong, IRB.getInt8PtrTy())); Value *TagMismatch = IRB.CreateICmpNE(PtrTag, MemTag); + int matchAllTag = ClMatchAllTag.getNumOccurrences() > 0 ? + ClMatchAllTag : (CompileKernel ? 0xFF : -1); + if (matchAllTag != -1) { + Value *TagNotIgnored = IRB.CreateICmpNE(PtrTag, + ConstantInt::get(PtrTag->getType(), matchAllTag)); + TagMismatch = IRB.CreateAnd(TagMismatch, TagNotIgnored); + } + TerminatorInst *CheckTerm = SplitBlockAndInsertIfThen(TagMismatch, InsertBefore, !Recover, MDBuilder(*C).createBranchWeights(1, 100000)); IRB.SetInsertPoint(CheckTerm); - // The signal handler will find the data address in x0. - InlineAsm *Asm = InlineAsm::get( - FunctionType::get(IRB.getVoidTy(), {PtrLong->getType()}, false), - "hlt #" + - itostr(0x100 + Recover * 0x20 + IsWrite * 0x10 + AccessSizeIndex), - "{x0}", - /*hasSideEffects=*/true); + const int64_t AccessInfo = Recover * 0x20 + IsWrite * 0x10 + AccessSizeIndex; + InlineAsm *Asm; + switch (TargetTriple.getArch()) { + case Triple::x86_64: + // The signal handler will find the data address in rdi. + Asm = InlineAsm::get( + FunctionType::get(IRB.getVoidTy(), {PtrLong->getType()}, false), + "int3\nnopl " + itostr(0x40 + AccessInfo) + "(%rax)", + "{rdi}", + /*hasSideEffects=*/true); + break; + case Triple::aarch64: + case Triple::aarch64_be: + // The signal handler will find the data address in x0. + Asm = InlineAsm::get( + FunctionType::get(IRB.getVoidTy(), {PtrLong->getType()}, false), + "brk #" + itostr(0x900 + AccessInfo), + "{x0}", + /*hasSideEffects=*/true); + break; + default: + report_fatal_error("unsupported architecture"); + } IRB.CreateCall(Asm, PtrLong); } bool HWAddressSanitizer::instrumentMemAccess(Instruction *I) { - DEBUG(dbgs() << "Instrumenting: " << *I << "\n"); + LLVM_DEBUG(dbgs() << "Instrumenting: " << *I << "\n"); bool IsWrite = false; unsigned Alignment = 0; uint64_t TypeSize = 0; @@ -288,7 +483,7 @@ bool HWAddressSanitizer::instrumentMemAccess(Instruction *I) { Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy); if (isPowerOf2_64(TypeSize) && (TypeSize / 8 <= (1UL << (kNumberOfAccessSizes - 1))) && - (Alignment >= (1UL << kShadowScale) || Alignment == 0 || + (Alignment >= (1UL << Mapping.Scale) || Alignment == 0 || Alignment >= TypeSize / 8)) { size_t AccessSizeIndex = TypeSizeToSizeIndex(TypeSize); if (ClInstrumentWithCalls) { @@ -301,10 +496,197 @@ bool HWAddressSanitizer::instrumentMemAccess(Instruction *I) { IRB.CreateCall(HwasanMemoryAccessCallbackSized[IsWrite], {AddrLong, ConstantInt::get(IntptrTy, TypeSize / 8)}); } + untagPointerOperand(I, Addr); return true; } +static uint64_t getAllocaSizeInBytes(const AllocaInst &AI) { + uint64_t ArraySize = 1; + if (AI.isArrayAllocation()) { + const ConstantInt *CI = dyn_cast(AI.getArraySize()); + assert(CI && "non-constant array size"); + ArraySize = CI->getZExtValue(); + } + Type *Ty = AI.getAllocatedType(); + uint64_t SizeInBytes = AI.getModule()->getDataLayout().getTypeAllocSize(Ty); + return SizeInBytes * ArraySize; +} + +bool HWAddressSanitizer::tagAlloca(IRBuilder<> &IRB, AllocaInst *AI, + Value *Tag) { + size_t Size = (getAllocaSizeInBytes(*AI) + Mapping.getAllocaAlignment() - 1) & + ~(Mapping.getAllocaAlignment() - 1); + + Value *JustTag = IRB.CreateTrunc(Tag, IRB.getInt8Ty()); + if (ClInstrumentWithCalls) { + IRB.CreateCall(HwasanTagMemoryFunc, + {IRB.CreatePointerCast(AI, IntptrTy), JustTag, + ConstantInt::get(IntptrTy, Size)}); + } else { + size_t ShadowSize = Size >> Mapping.Scale; + Value *ShadowPtr = IRB.CreateIntToPtr( + memToShadow(IRB.CreatePointerCast(AI, IntptrTy), AI->getType(), IRB), + IRB.getInt8PtrTy()); + // If this memset is not inlined, it will be intercepted in the hwasan + // runtime library. That's OK, because the interceptor skips the checks if + // the address is in the shadow region. + // FIXME: the interceptor is not as fast as real memset. Consider lowering + // llvm.memset right here into either a sequence of stores, or a call to + // hwasan_tag_memory. + IRB.CreateMemSet(ShadowPtr, JustTag, ShadowSize, /*Align=*/1); + } + return true; +} + +static unsigned RetagMask(unsigned AllocaNo) { + // A list of 8-bit numbers that have at most one run of non-zero bits. + // x = x ^ (mask << 56) can be encoded as a single armv8 instruction for these + // masks. + // The list does not include the value 255, which is used for UAR. + static unsigned FastMasks[] = { + 0, 1, 2, 3, 4, 6, 7, 8, 12, 14, 15, 16, 24, + 28, 30, 31, 32, 48, 56, 60, 62, 63, 64, 96, 112, 120, + 124, 126, 127, 128, 192, 224, 240, 248, 252, 254}; + return FastMasks[AllocaNo % (sizeof(FastMasks) / sizeof(FastMasks[0]))]; +} + +Value *HWAddressSanitizer::getNextTagWithCall(IRBuilder<> &IRB) { + return IRB.CreateZExt(IRB.CreateCall(HwasanGenerateTagFunc), IntptrTy); +} + +Value *HWAddressSanitizer::getStackBaseTag(IRBuilder<> &IRB) { + if (ClGenerateTagsWithCalls) + return nullptr; + // FIXME: use addressofreturnaddress (but implement it in aarch64 backend + // first). + Module *M = IRB.GetInsertBlock()->getParent()->getParent(); + auto GetStackPointerFn = + Intrinsic::getDeclaration(M, Intrinsic::frameaddress); + Value *StackPointer = IRB.CreateCall( + GetStackPointerFn, {Constant::getNullValue(IRB.getInt32Ty())}); + + // Extract some entropy from the stack pointer for the tags. + // Take bits 20..28 (ASLR entropy) and xor with bits 0..8 (these differ + // between functions). + Value *StackPointerLong = IRB.CreatePointerCast(StackPointer, IntptrTy); + Value *StackTag = + IRB.CreateXor(StackPointerLong, IRB.CreateLShr(StackPointerLong, 20), + "hwasan.stack.base.tag"); + return StackTag; +} + +Value *HWAddressSanitizer::getAllocaTag(IRBuilder<> &IRB, Value *StackTag, + AllocaInst *AI, unsigned AllocaNo) { + if (ClGenerateTagsWithCalls) + return getNextTagWithCall(IRB); + return IRB.CreateXor(StackTag, + ConstantInt::get(IntptrTy, RetagMask(AllocaNo))); +} + +Value *HWAddressSanitizer::getUARTag(IRBuilder<> &IRB, Value *StackTag) { + if (ClUARRetagToZero) + return ConstantInt::get(IntptrTy, 0); + if (ClGenerateTagsWithCalls) + return getNextTagWithCall(IRB); + return IRB.CreateXor(StackTag, ConstantInt::get(IntptrTy, 0xFFU)); +} + +// Add a tag to an address. +Value *HWAddressSanitizer::tagPointer(IRBuilder<> &IRB, Type *Ty, + Value *PtrLong, Value *Tag) { + Value *TaggedPtrLong; + if (CompileKernel) { + // Kernel addresses have 0xFF in the most significant byte. + Value *ShiftedTag = IRB.CreateOr( + IRB.CreateShl(Tag, kPointerTagShift), + ConstantInt::get(IntptrTy, (1ULL << kPointerTagShift) - 1)); + TaggedPtrLong = IRB.CreateAnd(PtrLong, ShiftedTag); + } else { + // Userspace can simply do OR (tag << 56); + Value *ShiftedTag = IRB.CreateShl(Tag, kPointerTagShift); + TaggedPtrLong = IRB.CreateOr(PtrLong, ShiftedTag); + } + return IRB.CreateIntToPtr(TaggedPtrLong, Ty); +} + +// Remove tag from an address. +Value *HWAddressSanitizer::untagPointer(IRBuilder<> &IRB, Value *PtrLong) { + Value *UntaggedPtrLong; + if (CompileKernel) { + // Kernel addresses have 0xFF in the most significant byte. + UntaggedPtrLong = IRB.CreateOr(PtrLong, + ConstantInt::get(PtrLong->getType(), 0xFFULL << kPointerTagShift)); + } else { + // Userspace addresses have 0x00. + UntaggedPtrLong = IRB.CreateAnd(PtrLong, + ConstantInt::get(PtrLong->getType(), ~(0xFFULL << kPointerTagShift))); + } + return UntaggedPtrLong; +} + +bool HWAddressSanitizer::instrumentStack( + SmallVectorImpl &Allocas, + SmallVectorImpl &RetVec) { + Function *F = Allocas[0]->getParent()->getParent(); + Instruction *InsertPt = &*F->getEntryBlock().begin(); + IRBuilder<> IRB(InsertPt); + + Value *StackTag = getStackBaseTag(IRB); + + // Ideally, we want to calculate tagged stack base pointer, and rewrite all + // alloca addresses using that. Unfortunately, offsets are not known yet + // (unless we use ASan-style mega-alloca). Instead we keep the base tag in a + // temp, shift-OR it into each alloca address and xor with the retag mask. + // This generates one extra instruction per alloca use. + for (unsigned N = 0; N < Allocas.size(); ++N) { + auto *AI = Allocas[N]; + IRB.SetInsertPoint(AI->getNextNode()); + + // Replace uses of the alloca with tagged address. + Value *Tag = getAllocaTag(IRB, StackTag, AI, N); + Value *AILong = IRB.CreatePointerCast(AI, IntptrTy); + Value *Replacement = tagPointer(IRB, AI->getType(), AILong, Tag); + std::string Name = + AI->hasName() ? AI->getName().str() : "alloca." + itostr(N); + Replacement->setName(Name + ".hwasan"); + + for (auto UI = AI->use_begin(), UE = AI->use_end(); UI != UE;) { + Use &U = *UI++; + if (U.getUser() != AILong) + U.set(Replacement); + } + + tagAlloca(IRB, AI, Tag); + + for (auto RI : RetVec) { + IRB.SetInsertPoint(RI); + + // Re-tag alloca memory with the special UAR tag. + Value *Tag = getUARTag(IRB, StackTag); + tagAlloca(IRB, AI, Tag); + } + } + + return true; +} + +bool HWAddressSanitizer::isInterestingAlloca(const AllocaInst &AI) { + return (AI.getAllocatedType()->isSized() && + // FIXME: instrument dynamic allocas, too + AI.isStaticAlloca() && + // alloca() may be called with 0 size, ignore it. + getAllocaSizeInBytes(AI) > 0 && + // We are only interested in allocas not promotable to registers. + // Promotable allocas are common under -O0. + !isAllocaPromotable(&AI) && + // inalloca allocas are not treated as static, and we don't want + // dynamic alloca instrumentation for them as well. + !AI.isUsedWithInAlloca() && + // swifterror allocas are register promoted by ISel + !AI.isSwiftError()); +} + bool HWAddressSanitizer::runOnFunction(Function &F) { if (&F == HwasanCtorFunction) return false; @@ -312,14 +694,35 @@ bool HWAddressSanitizer::runOnFunction(Function &F) { if (!F.hasFnAttribute(Attribute::SanitizeHWAddress)) return false; - DEBUG(dbgs() << "Function: " << F.getName() << "\n"); + LLVM_DEBUG(dbgs() << "Function: " << F.getName() << "\n"); initializeCallbacks(*F.getParent()); + assert(!LocalDynamicShadow); + maybeInsertDynamicShadowAtFunctionEntry(F); + bool Changed = false; SmallVector ToInstrument; + SmallVector AllocasToInstrument; + SmallVector RetVec; for (auto &BB : F) { for (auto &Inst : BB) { + if (ClInstrumentStack) + if (AllocaInst *AI = dyn_cast(&Inst)) { + // Realign all allocas. We don't want small uninteresting allocas to + // hide in instrumented alloca's padding. + if (AI->getAlignment() < Mapping.getAllocaAlignment()) + AI->setAlignment(Mapping.getAllocaAlignment()); + // Instrument some of them. + if (isInterestingAlloca(*AI)) + AllocasToInstrument.push_back(AI); + continue; + } + + if (isa(Inst) || isa(Inst) || + isa(Inst)) + RetVec.push_back(&Inst); + Value *MaybeMask = nullptr; bool IsWrite; unsigned Alignment; @@ -331,8 +734,30 @@ bool HWAddressSanitizer::runOnFunction(Function &F) { } } + if (!AllocasToInstrument.empty()) + Changed |= instrumentStack(AllocasToInstrument, RetVec); + for (auto Inst : ToInstrument) Changed |= instrumentMemAccess(Inst); + LocalDynamicShadow = nullptr; + return Changed; } + +void HWAddressSanitizer::ShadowMapping::init(Triple &TargetTriple) { + const bool IsAndroid = TargetTriple.isAndroid(); + const bool IsAndroidWithIfuncSupport = + IsAndroid && !TargetTriple.isAndroidVersionLT(21); + + Scale = kDefaultShadowScale; + + if (ClEnableKhwasan || ClInstrumentWithCalls || !IsAndroidWithIfuncSupport) + Offset = 0; + else + Offset = kDynamicShadowSentinel; + if (ClMappingOffset.getNumOccurrences() > 0) + Offset = ClMappingOffset; + + InGlobal = IsAndroidWithIfuncSupport; +} diff --git a/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp b/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp index 49b8a67a6c14..27fb0e4393af 100644 --- a/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp +++ b/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp @@ -45,7 +45,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Instrumentation.h" -#include "llvm/Transforms/PGOInstrumentation.h" +#include "llvm/Transforms/Instrumentation/PGOInstrumentation.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/CallPromotionUtils.h" #include @@ -223,12 +223,12 @@ ICallPromotionFunc::getPromotionCandidatesForCallSite( uint64_t TotalCount, uint32_t NumCandidates) { std::vector Ret; - DEBUG(dbgs() << " \nWork on callsite #" << NumOfPGOICallsites << *Inst - << " Num_targets: " << ValueDataRef.size() - << " Num_candidates: " << NumCandidates << "\n"); + LLVM_DEBUG(dbgs() << " \nWork on callsite #" << NumOfPGOICallsites << *Inst + << " Num_targets: " << ValueDataRef.size() + << " Num_candidates: " << NumCandidates << "\n"); NumOfPGOICallsites++; if (ICPCSSkip != 0 && NumOfPGOICallsites <= ICPCSSkip) { - DEBUG(dbgs() << " Skip: User options.\n"); + LLVM_DEBUG(dbgs() << " Skip: User options.\n"); return Ret; } @@ -236,11 +236,11 @@ ICallPromotionFunc::getPromotionCandidatesForCallSite( uint64_t Count = ValueDataRef[I].Count; assert(Count <= TotalCount); uint64_t Target = ValueDataRef[I].Value; - DEBUG(dbgs() << " Candidate " << I << " Count=" << Count - << " Target_func: " << Target << "\n"); + LLVM_DEBUG(dbgs() << " Candidate " << I << " Count=" << Count + << " Target_func: " << Target << "\n"); if (ICPInvokeOnly && dyn_cast(Inst)) { - DEBUG(dbgs() << " Not promote: User options.\n"); + LLVM_DEBUG(dbgs() << " Not promote: User options.\n"); ORE.emit([&]() { return OptimizationRemarkMissed(DEBUG_TYPE, "UserOptions", Inst) << " Not promote: User options"; @@ -248,7 +248,7 @@ ICallPromotionFunc::getPromotionCandidatesForCallSite( break; } if (ICPCallOnly && dyn_cast(Inst)) { - DEBUG(dbgs() << " Not promote: User option.\n"); + LLVM_DEBUG(dbgs() << " Not promote: User option.\n"); ORE.emit([&]() { return OptimizationRemarkMissed(DEBUG_TYPE, "UserOptions", Inst) << " Not promote: User options"; @@ -256,7 +256,7 @@ ICallPromotionFunc::getPromotionCandidatesForCallSite( break; } if (ICPCutOff != 0 && NumOfPGOICallPromotion >= ICPCutOff) { - DEBUG(dbgs() << " Not promote: Cutoff reached.\n"); + LLVM_DEBUG(dbgs() << " Not promote: Cutoff reached.\n"); ORE.emit([&]() { return OptimizationRemarkMissed(DEBUG_TYPE, "CutOffReached", Inst) << " Not promote: Cutoff reached"; @@ -266,7 +266,7 @@ ICallPromotionFunc::getPromotionCandidatesForCallSite( Function *TargetFunction = Symtab->getFunction(Target); if (TargetFunction == nullptr) { - DEBUG(dbgs() << " Not promote: Cannot find the target\n"); + LLVM_DEBUG(dbgs() << " Not promote: Cannot find the target\n"); ORE.emit([&]() { return OptimizationRemarkMissed(DEBUG_TYPE, "UnableToFindTarget", Inst) << "Cannot promote indirect call: target not found"; @@ -387,7 +387,7 @@ static bool promoteIndirectCalls(Module &M, ProfileSummaryInfo *PSI, InstrProfSymtab Symtab; if (Error E = Symtab.create(M, InLTO)) { std::string SymtabFailure = toString(std::move(E)); - DEBUG(dbgs() << "Failed to create symtab: " << SymtabFailure << "\n"); + LLVM_DEBUG(dbgs() << "Failed to create symtab: " << SymtabFailure << "\n"); (void)SymtabFailure; return false; } @@ -412,12 +412,12 @@ static bool promoteIndirectCalls(Module &M, ProfileSummaryInfo *PSI, ICallPromotionFunc ICallPromotion(F, &M, &Symtab, SamplePGO, *ORE); bool FuncChanged = ICallPromotion.processFunction(PSI); if (ICPDUMPAFTER && FuncChanged) { - DEBUG(dbgs() << "\n== IR Dump After =="; F.print(dbgs())); - DEBUG(dbgs() << "\n"); + LLVM_DEBUG(dbgs() << "\n== IR Dump After =="; F.print(dbgs())); + LLVM_DEBUG(dbgs() << "\n"); } Changed |= FuncChanged; if (ICPCutOff != 0 && NumOfPGOICallPromotion >= ICPCutOff) { - DEBUG(dbgs() << " Stop: Cutoff reached.\n"); + LLVM_DEBUG(dbgs() << " Stop: Cutoff reached.\n"); break; } } diff --git a/lib/Transforms/Instrumentation/InstrProfiling.cpp b/lib/Transforms/Instrumentation/InstrProfiling.cpp index 9b70f95480e4..22076f04d6ad 100644 --- a/lib/Transforms/Instrumentation/InstrProfiling.cpp +++ b/lib/Transforms/Instrumentation/InstrProfiling.cpp @@ -13,7 +13,7 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Transforms/InstrProfiling.h" +#include "llvm/Transforms/Instrumentation/InstrProfiling.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -271,8 +271,8 @@ public: break; } - DEBUG(dbgs() << Promoted << " counters promoted for loop (depth=" - << L.getLoopDepth() << ")\n"); + LLVM_DEBUG(dbgs() << Promoted << " counters promoted for loop (depth=" + << L.getLoopDepth() << ")\n"); return Promoted != 0; } @@ -430,9 +430,24 @@ void InstrProfiling::promoteCounterLoadStores(Function *F) { } } -bool InstrProfiling::run(Module &M, const TargetLibraryInfo &TLI) { - bool MadeChange = false; +/// Check if the module contains uses of any profiling intrinsics. +static bool containsProfilingIntrinsics(Module &M) { + if (auto *F = M.getFunction( + Intrinsic::getName(llvm::Intrinsic::instrprof_increment))) + if (!F->use_empty()) + return true; + if (auto *F = M.getFunction( + Intrinsic::getName(llvm::Intrinsic::instrprof_increment_step))) + if (!F->use_empty()) + return true; + if (auto *F = M.getFunction( + Intrinsic::getName(llvm::Intrinsic::instrprof_value_profile))) + if (!F->use_empty()) + return true; + return false; +} +bool InstrProfiling::run(Module &M, const TargetLibraryInfo &TLI) { this->M = &M; this->TLI = &TLI; NamesVar = nullptr; @@ -443,6 +458,15 @@ bool InstrProfiling::run(Module &M, const TargetLibraryInfo &TLI) { MemOPSizeRangeLast); TT = Triple(M.getTargetTriple()); + // Emit the runtime hook even if no counters are present. + bool MadeChange = emitRuntimeHook(); + + // Improve compile time by avoiding linear scans when there is no work. + GlobalVariable *CoverageNamesVar = + M.getNamedGlobal(getCoverageUnusedNamesVarName()); + if (!containsProfilingIntrinsics(M) && !CoverageNamesVar) + return MadeChange; + // We did not know how many value sites there would be inside // the instrumented function. This is counting the number of instrumented // target value sites to enter it as field in the profile data variable. @@ -464,8 +488,7 @@ bool InstrProfiling::run(Module &M, const TargetLibraryInfo &TLI) { for (Function &F : M) MadeChange |= lowerIntrinsics(&F); - if (GlobalVariable *CoverageNamesVar = - M.getNamedGlobal(getCoverageUnusedNamesVarName())) { + if (CoverageNamesVar) { lowerCoverageData(CoverageNamesVar); MadeChange = true; } @@ -476,7 +499,6 @@ bool InstrProfiling::run(Module &M, const TargetLibraryInfo &TLI) { emitVNodes(); emitNameData(); emitRegistration(); - emitRuntimeHook(); emitUses(); emitInitialization(); return true; @@ -669,6 +691,7 @@ static bool needsRuntimeRegistrationOfSectionRange(const Module &M) { // Use linker script magic to get data/cnts/name start/end. if (Triple(M.getTargetTriple()).isOSLinux() || Triple(M.getTargetTriple()).isOSFreeBSD() || + Triple(M.getTargetTriple()).isOSFuchsia() || Triple(M.getTargetTriple()).isPS4CPU()) return false; @@ -892,15 +915,15 @@ void InstrProfiling::emitRegistration() { IRB.CreateRetVoid(); } -void InstrProfiling::emitRuntimeHook() { +bool InstrProfiling::emitRuntimeHook() { // We expect the linker to be invoked with -u flag for linux, // for which case there is no need to emit the user function. if (Triple(M->getTargetTriple()).isOSLinux()) - return; + return false; // If the module's provided its own runtime, we don't need to do anything. if (M->getGlobalVariable(getInstrProfRuntimeHookVarName())) - return; + return false; // Declare an external variable that will pull in the runtime initialization. auto *Int32Ty = Type::getInt32Ty(M->getContext()); @@ -925,6 +948,7 @@ void InstrProfiling::emitRuntimeHook() { // Mark the user variable as used so that it isn't stripped out. UsedVars.push_back(User); + return true; } void InstrProfiling::emitUses() { diff --git a/lib/Transforms/Instrumentation/MemorySanitizer.cpp b/lib/Transforms/Instrumentation/MemorySanitizer.cpp index b3c39b5b1665..4bcef6972786 100644 --- a/lib/Transforms/Instrumentation/MemorySanitizer.cpp +++ b/lib/Transforms/Instrumentation/MemorySanitizer.cpp @@ -101,6 +101,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/Transforms/Utils/Local.h" #include "llvm/IR/Argument.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/BasicBlock.h" @@ -138,7 +139,6 @@ #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 #include @@ -163,7 +163,7 @@ static const unsigned kRetvalTLSSize = 800; // Accesses sizes are powers of two: 1, 2, 4, 8. static const size_t kNumberOfAccessSizes = 4; -/// \brief Track origins of uninitialized values. +/// Track origins of uninitialized values. /// /// Adds a section to MemorySanitizer report that points to the allocation /// (stack or heap) the uninitialized bits came from originally. @@ -199,6 +199,18 @@ static cl::opt ClHandleICmpExact("msan-handle-icmp-exact", cl::desc("exact handling of relational integer ICmp"), cl::Hidden, cl::init(false)); +// When compiling the Linux kernel, we sometimes see false positives related to +// MSan being unable to understand that inline assembly calls may initialize +// local variables. +// This flag makes the compiler conservatively unpoison every memory location +// passed into an assembly call. Note that this may cause false positives. +// Because it's impossible to figure out the array sizes, we can only unpoison +// the first sizeof(type) bytes for each type* pointer. +static cl::opt ClHandleAsmConservative( + "msan-handle-asm-conservative", + cl::desc("conservative handling of inline assembly"), cl::Hidden, + cl::init(false)); + // This flag controls whether we check the shadow of the address // operand of load or store. Such bugs are very rare, since load from // a garbage address typically results in SEGV, but still happen @@ -234,6 +246,24 @@ static cl::opt ClWithComdat("msan-with-comdat", cl::desc("Place MSan constructors in comdat sections"), cl::Hidden, cl::init(false)); +// These options allow to specify custom memory map parameters +// See MemoryMapParams for details. +static cl::opt ClAndMask("msan-and-mask", + cl::desc("Define custom MSan AndMask"), + cl::Hidden, cl::init(0)); + +static cl::opt ClXorMask("msan-xor-mask", + cl::desc("Define custom MSan XorMask"), + cl::Hidden, cl::init(0)); + +static cl::opt ClShadowBase("msan-shadow-base", + cl::desc("Define custom MSan ShadowBase"), + cl::Hidden, cl::init(0)); + +static cl::opt ClOriginBase("msan-origin-base", + cl::desc("Define custom MSan OriginBase"), + cl::Hidden, cl::init(0)); + static const char *const kMsanModuleCtorName = "msan.module_ctor"; static const char *const kMsanInitName = "__msan_init"; @@ -360,7 +390,7 @@ static const PlatformMemoryMapParams NetBSD_X86_MemoryMapParams = { namespace { -/// \brief An instrumentation pass implementing detection of uninitialized +/// An instrumentation pass implementing detection of uninitialized /// reads. /// /// MemorySanitizer: instrument the code in module to find @@ -368,7 +398,7 @@ namespace { class MemorySanitizer : public FunctionPass { public: // Pass identification, replacement for typeid. - static char ID; + static char ID; MemorySanitizer(int TrackOrigins = 0, bool Recover = false) : FunctionPass(ID), @@ -392,8 +422,9 @@ private: friend struct VarArgPowerPC64Helper; void initializeCallbacks(Module &M); + void createUserspaceApi(Module &M); - /// \brief Track origins (allocation points) of uninitialized values. + /// Track origins (allocation points) of uninitialized values. int TrackOrigins; bool Recover; @@ -401,60 +432,67 @@ private: Type *IntptrTy; Type *OriginTy; - /// \brief Thread-local shadow storage for function parameters. + /// Thread-local shadow storage for function parameters. GlobalVariable *ParamTLS; - /// \brief Thread-local origin storage for function parameters. + /// Thread-local origin storage for function parameters. GlobalVariable *ParamOriginTLS; - /// \brief Thread-local shadow storage for function return value. + /// Thread-local shadow storage for function return value. GlobalVariable *RetvalTLS; - /// \brief Thread-local origin storage for function return value. + /// Thread-local origin storage for function return value. GlobalVariable *RetvalOriginTLS; - /// \brief Thread-local shadow storage for in-register va_arg function + /// Thread-local shadow storage for in-register va_arg function /// parameters (x86_64-specific). GlobalVariable *VAArgTLS; - /// \brief Thread-local shadow storage for va_arg overflow area + /// Thread-local shadow storage for va_arg overflow area /// (x86_64-specific). GlobalVariable *VAArgOverflowSizeTLS; - /// \brief Thread-local space used to pass origin value to the UMR reporting + /// Thread-local space used to pass origin value to the UMR reporting /// function. GlobalVariable *OriginTLS; - /// \brief The run-time callback to print a warning. - Value *WarningFn = nullptr; + /// Are the instrumentation callbacks set up? + bool CallbacksInitialized = false; + + /// The run-time callback to print a warning. + Value *WarningFn; // These arrays are indexed by log2(AccessSize). Value *MaybeWarningFn[kNumberOfAccessSizes]; Value *MaybeStoreOriginFn[kNumberOfAccessSizes]; - /// \brief Run-time helper that generates a new origin value for a stack + /// Run-time helper that generates a new origin value for a stack /// allocation. Value *MsanSetAllocaOrigin4Fn; - /// \brief Run-time helper that poisons stack on function entry. + /// Run-time helper that poisons stack on function entry. Value *MsanPoisonStackFn; - /// \brief Run-time helper that records a store (or any event) of an + /// Run-time helper that records a store (or any event) of an /// uninitialized value and returns an updated origin id encoding this info. Value *MsanChainOriginFn; - /// \brief MSan runtime replacements for memmove, memcpy and memset. + /// MSan runtime replacements for memmove, memcpy and memset. Value *MemmoveFn, *MemcpyFn, *MemsetFn; - /// \brief Memory map parameters used in application-to-shadow calculation. + /// Memory map parameters used in application-to-shadow calculation. const MemoryMapParams *MapParams; + /// Custom memory map parameters used when -msan-shadow-base or + // -msan-origin-base is provided. + MemoryMapParams CustomMapParams; + MDNode *ColdCallWeights; - /// \brief Branch weights for origin store. + /// Branch weights for origin store. MDNode *OriginStoreWeights; - /// \brief An empty volatile inline asm that prevents callback merge. + /// An empty volatile inline asm that prevents callback merge. InlineAsm *EmptyAsm; Function *MsanCtorFunction; @@ -476,7 +514,7 @@ FunctionPass *llvm::createMemorySanitizerPass(int TrackOrigins, bool Recover) { return new MemorySanitizer(TrackOrigins, Recover); } -/// \brief Create a non-const global initialized with the given string. +/// Create a non-const global initialized with the given string. /// /// Creates a writable global for Str so that we can pass it to the /// run-time lib. Runtime uses first 4 bytes of the string to store the @@ -488,12 +526,8 @@ static GlobalVariable *createPrivateNonConstGlobalForString(Module &M, GlobalValue::PrivateLinkage, StrConst, ""); } -/// \brief Insert extern declaration of runtime-provided functions and globals. -void MemorySanitizer::initializeCallbacks(Module &M) { - // Only do this once. - if (WarningFn) - return; - +/// Insert declarations for userspace-specific functions and globals. +void MemorySanitizer::createUserspaceApi(Module &M) { IRBuilder<> IRB(*C); // Create the callback. // FIXME: this function should have "Cold" calling conv, @@ -502,6 +536,38 @@ void MemorySanitizer::initializeCallbacks(Module &M) { : "__msan_warning_noreturn"; WarningFn = M.getOrInsertFunction(WarningFnName, IRB.getVoidTy()); + // Create the global TLS variables. + RetvalTLS = new GlobalVariable( + M, ArrayType::get(IRB.getInt64Ty(), kRetvalTLSSize / 8), false, + GlobalVariable::ExternalLinkage, nullptr, "__msan_retval_tls", nullptr, + GlobalVariable::InitialExecTLSModel); + + RetvalOriginTLS = new GlobalVariable( + M, OriginTy, false, GlobalVariable::ExternalLinkage, nullptr, + "__msan_retval_origin_tls", nullptr, GlobalVariable::InitialExecTLSModel); + + ParamTLS = new GlobalVariable( + M, ArrayType::get(IRB.getInt64Ty(), kParamTLSSize / 8), false, + GlobalVariable::ExternalLinkage, nullptr, "__msan_param_tls", nullptr, + GlobalVariable::InitialExecTLSModel); + + ParamOriginTLS = new GlobalVariable( + M, ArrayType::get(OriginTy, kParamTLSSize / 4), false, + GlobalVariable::ExternalLinkage, nullptr, "__msan_param_origin_tls", + nullptr, GlobalVariable::InitialExecTLSModel); + + VAArgTLS = new GlobalVariable( + M, ArrayType::get(IRB.getInt64Ty(), kParamTLSSize / 8), false, + GlobalVariable::ExternalLinkage, nullptr, "__msan_va_arg_tls", nullptr, + GlobalVariable::InitialExecTLSModel); + VAArgOverflowSizeTLS = new GlobalVariable( + M, IRB.getInt64Ty(), false, GlobalVariable::ExternalLinkage, nullptr, + "__msan_va_arg_overflow_size_tls", nullptr, + GlobalVariable::InitialExecTLSModel); + OriginTLS = new GlobalVariable( + M, IRB.getInt32Ty(), false, GlobalVariable::ExternalLinkage, nullptr, + "__msan_origin_tls", nullptr, GlobalVariable::InitialExecTLSModel); + for (size_t AccessSizeIndex = 0; AccessSizeIndex < kNumberOfAccessSizes; AccessSizeIndex++) { unsigned AccessSize = 1 << AccessSizeIndex; @@ -522,6 +588,17 @@ void MemorySanitizer::initializeCallbacks(Module &M) { MsanPoisonStackFn = M.getOrInsertFunction("__msan_poison_stack", IRB.getVoidTy(), IRB.getInt8PtrTy(), IntptrTy); +} + +/// Insert extern declaration of runtime-provided functions and globals. +void MemorySanitizer::initializeCallbacks(Module &M) { + // Only do this once. + if (CallbacksInitialized) + return; + + IRBuilder<> IRB(*C); + // Initialize callbacks that are common for kernel and userspace + // instrumentation. MsanChainOriginFn = M.getOrInsertFunction( "__msan_chain_origin", IRB.getInt32Ty(), IRB.getInt32Ty()); MemmoveFn = M.getOrInsertFunction( @@ -533,98 +610,81 @@ void MemorySanitizer::initializeCallbacks(Module &M) { MemsetFn = M.getOrInsertFunction( "__msan_memset", IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), IRB.getInt32Ty(), IntptrTy); - - // Create globals. - RetvalTLS = new GlobalVariable( - M, ArrayType::get(IRB.getInt64Ty(), kRetvalTLSSize / 8), false, - GlobalVariable::ExternalLinkage, nullptr, "__msan_retval_tls", nullptr, - GlobalVariable::InitialExecTLSModel); - RetvalOriginTLS = new GlobalVariable( - M, OriginTy, false, GlobalVariable::ExternalLinkage, nullptr, - "__msan_retval_origin_tls", nullptr, GlobalVariable::InitialExecTLSModel); - - ParamTLS = new GlobalVariable( - M, ArrayType::get(IRB.getInt64Ty(), kParamTLSSize / 8), false, - GlobalVariable::ExternalLinkage, nullptr, "__msan_param_tls", nullptr, - GlobalVariable::InitialExecTLSModel); - ParamOriginTLS = new GlobalVariable( - M, ArrayType::get(OriginTy, kParamTLSSize / 4), false, - GlobalVariable::ExternalLinkage, nullptr, "__msan_param_origin_tls", - nullptr, GlobalVariable::InitialExecTLSModel); - - VAArgTLS = new GlobalVariable( - M, ArrayType::get(IRB.getInt64Ty(), kParamTLSSize / 8), false, - GlobalVariable::ExternalLinkage, nullptr, "__msan_va_arg_tls", nullptr, - GlobalVariable::InitialExecTLSModel); - VAArgOverflowSizeTLS = new GlobalVariable( - M, IRB.getInt64Ty(), false, GlobalVariable::ExternalLinkage, nullptr, - "__msan_va_arg_overflow_size_tls", nullptr, - GlobalVariable::InitialExecTLSModel); - OriginTLS = new GlobalVariable( - M, IRB.getInt32Ty(), false, GlobalVariable::ExternalLinkage, nullptr, - "__msan_origin_tls", nullptr, GlobalVariable::InitialExecTLSModel); - // We insert an empty inline asm after __msan_report* to avoid callback merge. EmptyAsm = InlineAsm::get(FunctionType::get(IRB.getVoidTy(), false), StringRef(""), StringRef(""), /*hasSideEffects=*/true); + + createUserspaceApi(M); + CallbacksInitialized = true; } -/// \brief Module-level initialization. +/// Module-level initialization. /// /// inserts a call to __msan_init to the module's constructor list. bool MemorySanitizer::doInitialization(Module &M) { auto &DL = M.getDataLayout(); - Triple TargetTriple(M.getTargetTriple()); - switch (TargetTriple.getOS()) { - case Triple::FreeBSD: - switch (TargetTriple.getArch()) { - case Triple::x86_64: - MapParams = FreeBSD_X86_MemoryMapParams.bits64; - break; - case Triple::x86: - MapParams = FreeBSD_X86_MemoryMapParams.bits32; - break; - default: - report_fatal_error("unsupported architecture"); - } - break; - case Triple::NetBSD: - switch (TargetTriple.getArch()) { - case Triple::x86_64: - MapParams = NetBSD_X86_MemoryMapParams.bits64; - break; - default: - report_fatal_error("unsupported architecture"); - } - break; - case Triple::Linux: - switch (TargetTriple.getArch()) { - case Triple::x86_64: - MapParams = Linux_X86_MemoryMapParams.bits64; - break; - case Triple::x86: - MapParams = Linux_X86_MemoryMapParams.bits32; - break; - case Triple::mips64: - case Triple::mips64el: - MapParams = Linux_MIPS_MemoryMapParams.bits64; - break; - case Triple::ppc64: - case Triple::ppc64le: - MapParams = Linux_PowerPC_MemoryMapParams.bits64; - break; - case Triple::aarch64: - case Triple::aarch64_be: - MapParams = Linux_ARM_MemoryMapParams.bits64; - break; - default: - report_fatal_error("unsupported architecture"); - } - break; - default: - report_fatal_error("unsupported operating system"); + bool ShadowPassed = ClShadowBase.getNumOccurrences() > 0; + bool OriginPassed = ClOriginBase.getNumOccurrences() > 0; + // Check the overrides first + if (ShadowPassed || OriginPassed) { + CustomMapParams.AndMask = ClAndMask; + CustomMapParams.XorMask = ClXorMask; + CustomMapParams.ShadowBase = ClShadowBase; + CustomMapParams.OriginBase = ClOriginBase; + MapParams = &CustomMapParams; + } else { + Triple TargetTriple(M.getTargetTriple()); + switch (TargetTriple.getOS()) { + case Triple::FreeBSD: + switch (TargetTriple.getArch()) { + case Triple::x86_64: + MapParams = FreeBSD_X86_MemoryMapParams.bits64; + break; + case Triple::x86: + MapParams = FreeBSD_X86_MemoryMapParams.bits32; + break; + default: + report_fatal_error("unsupported architecture"); + } + break; + case Triple::NetBSD: + switch (TargetTriple.getArch()) { + case Triple::x86_64: + MapParams = NetBSD_X86_MemoryMapParams.bits64; + break; + default: + report_fatal_error("unsupported architecture"); + } + break; + case Triple::Linux: + switch (TargetTriple.getArch()) { + case Triple::x86_64: + MapParams = Linux_X86_MemoryMapParams.bits64; + break; + case Triple::x86: + MapParams = Linux_X86_MemoryMapParams.bits32; + break; + case Triple::mips64: + case Triple::mips64el: + MapParams = Linux_MIPS_MemoryMapParams.bits64; + break; + case Triple::ppc64: + case Triple::ppc64le: + MapParams = Linux_PowerPC_MemoryMapParams.bits64; + break; + case Triple::aarch64: + case Triple::aarch64_be: + MapParams = Linux_ARM_MemoryMapParams.bits64; + break; + default: + report_fatal_error("unsupported architecture"); + } + break; + default: + report_fatal_error("unsupported operating system"); + } } C = &(M.getContext()); @@ -661,7 +721,7 @@ bool MemorySanitizer::doInitialization(Module &M) { namespace { -/// \brief A helper class that handles instrumentation of VarArg +/// A helper class that handles instrumentation of VarArg /// functions on a particular platform. /// /// Implementations are expected to insert the instrumentation @@ -672,16 +732,16 @@ namespace { struct VarArgHelper { virtual ~VarArgHelper() = default; - /// \brief Visit a CallSite. + /// Visit a CallSite. virtual void visitCallSite(CallSite &CS, IRBuilder<> &IRB) = 0; - /// \brief Visit a va_start call. + /// Visit a va_start call. virtual void visitVAStartInst(VAStartInst &I) = 0; - /// \brief Visit a va_copy call. + /// Visit a va_copy call. virtual void visitVACopyInst(VACopyInst &I) = 0; - /// \brief Finalize function instrumentation. + /// Finalize function instrumentation. /// /// This method is called after visiting all interesting (see above) /// instructions in a function. @@ -715,6 +775,7 @@ struct MemorySanitizerVisitor : public InstVisitor { ValueMap ShadowMap, OriginMap; std::unique_ptr VAHelper; const TargetLibraryInfo *TLI; + BasicBlock *ActualFnStart; // The following flags disable parts of MSan instrumentation based on // blacklist contents and command-line options. @@ -747,9 +808,12 @@ struct MemorySanitizerVisitor : public InstVisitor { CheckReturnValue = SanitizeFunction && (F.getName() == "main"); TLI = &MS.getAnalysis().getTLI(); - DEBUG(if (!InsertChecks) - dbgs() << "MemorySanitizer is not inserting checks into '" - << F.getName() << "'\n"); + MS.initializeCallbacks(*F.getParent()); + ActualFnStart = &F.getEntryBlock(); + + LLVM_DEBUG(if (!InsertChecks) dbgs() + << "MemorySanitizer is not inserting checks into '" + << F.getName() << "'\n"); } Value *updateOrigin(Value *V, IRBuilder<> &IRB) { @@ -766,7 +830,7 @@ struct MemorySanitizerVisitor : public InstVisitor { return IRB.CreateOr(Origin, IRB.CreateShl(Origin, kOriginSize * 8)); } - /// \brief Fill memory range with the given origin value. + /// Fill memory range with the given origin value. void paintOrigin(IRBuilder<> &IRB, Value *Origin, Value *OriginPtr, unsigned Size, unsigned Alignment) { const DataLayout &DL = F.getParent()->getDataLayout(); @@ -849,13 +913,11 @@ struct MemorySanitizerVisitor : public InstVisitor { unsigned Alignment = SI->getAlignment(); unsigned OriginAlignment = std::max(kMinOriginAlignment, Alignment); std::tie(ShadowPtr, OriginPtr) = - getShadowOriginPtr(Addr, IRB, ShadowTy, Alignment); + getShadowOriginPtr(Addr, IRB, ShadowTy, Alignment, /*isStore*/ true); StoreInst *NewSI = IRB.CreateAlignedStore(Shadow, ShadowPtr, Alignment); - DEBUG(dbgs() << " STORE: " << *NewSI << "\n"); - - if (ClCheckAccessAddress) - insertShadowCheck(Addr, NewSI); + LLVM_DEBUG(dbgs() << " STORE: " << *NewSI << "\n"); + (void)NewSI; if (SI->isAtomic()) SI->setOrdering(addReleaseOrdering(SI->getOrdering())); @@ -866,25 +928,31 @@ struct MemorySanitizerVisitor : public InstVisitor { } } + /// Helper function to insert a warning at IRB's current insert point. + void insertWarningFn(IRBuilder<> &IRB, Value *Origin) { + if (!Origin) + Origin = (Value *)IRB.getInt32(0); + if (MS.TrackOrigins) { + IRB.CreateStore(Origin, MS.OriginTLS); + } + IRB.CreateCall(MS.WarningFn, {}); + IRB.CreateCall(MS.EmptyAsm, {}); + // FIXME: Insert UnreachableInst if !MS.Recover? + // This may invalidate some of the following checks and needs to be done + // at the very end. + } + void materializeOneCheck(Instruction *OrigIns, Value *Shadow, Value *Origin, bool AsCall) { IRBuilder<> IRB(OrigIns); - DEBUG(dbgs() << " SHAD0 : " << *Shadow << "\n"); + LLVM_DEBUG(dbgs() << " SHAD0 : " << *Shadow << "\n"); Value *ConvertedShadow = convertToShadowTyNoVec(Shadow, IRB); - DEBUG(dbgs() << " SHAD1 : " << *ConvertedShadow << "\n"); + LLVM_DEBUG(dbgs() << " SHAD1 : " << *ConvertedShadow << "\n"); Constant *ConstantShadow = dyn_cast_or_null(ConvertedShadow); if (ConstantShadow) { if (ClCheckConstantShadow && !ConstantShadow->isZeroValue()) { - if (MS.TrackOrigins) { - IRB.CreateStore(Origin ? (Value *)Origin : (Value *)IRB.getInt32(0), - MS.OriginTLS); - } - IRB.CreateCall(MS.WarningFn, {}); - IRB.CreateCall(MS.EmptyAsm, {}); - // FIXME: Insert UnreachableInst if !MS.Recover? - // This may invalidate some of the following checks and needs to be done - // at the very end. + insertWarningFn(IRB, Origin); } return; } @@ -908,13 +976,8 @@ struct MemorySanitizerVisitor : public InstVisitor { /* Unreachable */ !MS.Recover, MS.ColdCallWeights); IRB.SetInsertPoint(CheckTerm); - if (MS.TrackOrigins) { - IRB.CreateStore(Origin ? (Value *)Origin : (Value *)IRB.getInt32(0), - MS.OriginTLS); - } - IRB.CreateCall(MS.WarningFn, {}); - IRB.CreateCall(MS.EmptyAsm, {}); - DEBUG(dbgs() << " CHECK: " << *Cmp << "\n"); + insertWarningFn(IRB, Origin); + LLVM_DEBUG(dbgs() << " CHECK: " << *Cmp << "\n"); } } @@ -925,13 +988,11 @@ struct MemorySanitizerVisitor : public InstVisitor { Value *Origin = ShadowData.Origin; materializeOneCheck(OrigIns, Shadow, Origin, InstrumentWithCalls); } - DEBUG(dbgs() << "DONE:\n" << F); + LLVM_DEBUG(dbgs() << "DONE:\n" << F); } - /// \brief Add MemorySanitizer instrumentation to a function. + /// Add MemorySanitizer instrumentation to a function. bool runOnFunction() { - MS.initializeCallbacks(*F.getParent()); - // In the presence of unreachable blocks, we may see Phi nodes with // incoming nodes from such blocks. Since InstVisitor skips unreachable // blocks, such nodes will not have any shadow value associated with them. @@ -941,7 +1002,7 @@ struct MemorySanitizerVisitor : public InstVisitor { // Iterate all BBs in depth-first order and create shadow instructions // for all instructions (where applicable). // For PHI nodes we create dummy shadow PHIs which will be finalized later. - for (BasicBlock *BB : depth_first(&F.getEntryBlock())) + for (BasicBlock *BB : depth_first(ActualFnStart)) visit(*BB); // Finalize PHI nodes. @@ -961,22 +1022,22 @@ struct MemorySanitizerVisitor : public InstVisitor { InstrumentationList.size() + StoreList.size() > (unsigned)ClInstrumentationWithCallThreshold; - // Delayed instrumentation of StoreInst. - // This may add new checks to be inserted later. - materializeStores(InstrumentWithCalls); - // Insert shadow value checks. materializeChecks(InstrumentWithCalls); + // Delayed instrumentation of StoreInst. + // This may not add new address checks. + materializeStores(InstrumentWithCalls); + return true; } - /// \brief Compute the shadow type that corresponds to a given Value. + /// Compute the shadow type that corresponds to a given Value. Type *getShadowTy(Value *V) { return getShadowTy(V->getType()); } - /// \brief Compute the shadow type that corresponds to a given Type. + /// Compute the shadow type that corresponds to a given Type. Type *getShadowTy(Type *OrigTy) { if (!OrigTy->isSized()) { return nullptr; @@ -1000,21 +1061,21 @@ struct MemorySanitizerVisitor : public InstVisitor { for (unsigned i = 0, n = ST->getNumElements(); i < n; i++) Elements.push_back(getShadowTy(ST->getElementType(i))); StructType *Res = StructType::get(*MS.C, Elements, ST->isPacked()); - DEBUG(dbgs() << "getShadowTy: " << *ST << " ===> " << *Res << "\n"); + LLVM_DEBUG(dbgs() << "getShadowTy: " << *ST << " ===> " << *Res << "\n"); return Res; } uint32_t TypeSize = DL.getTypeSizeInBits(OrigTy); return IntegerType::get(*MS.C, TypeSize); } - /// \brief Flatten a vector type. + /// Flatten a vector type. Type *getShadowTyNoVec(Type *ty) { if (VectorType *vt = dyn_cast(ty)) return IntegerType::get(*MS.C, vt->getBitWidth()); return ty; } - /// \brief Convert a shadow value to it's flattened variant. + /// Convert a shadow value to it's flattened variant. Value *convertToShadowTyNoVec(Value *V, IRBuilder<> &IRB) { Type *Ty = V->getType(); Type *NoVecTy = getShadowTyNoVec(Ty); @@ -1022,7 +1083,7 @@ struct MemorySanitizerVisitor : public InstVisitor { return IRB.CreateBitCast(V, NoVecTy); } - /// \brief Compute the integer shadow offset that corresponds to a given + /// Compute the integer shadow offset that corresponds to a given /// application address. /// /// Offset = (Addr & ~AndMask) ^ XorMask @@ -1041,18 +1102,18 @@ struct MemorySanitizerVisitor : public InstVisitor { return OffsetLong; } - /// \brief Compute the shadow and origin addresses corresponding to a given + /// Compute the shadow and origin addresses corresponding to a given /// application address. /// /// Shadow = ShadowBase + Offset /// Origin = (OriginBase + Offset) & ~3ULL - std::pair getShadowOriginPtrUserspace( - Value *Addr, IRBuilder<> &IRB, Type *ShadowTy, unsigned Alignment, - Instruction **FirstInsn) { + std::pair getShadowOriginPtrUserspace(Value *Addr, + IRBuilder<> &IRB, + Type *ShadowTy, + unsigned Alignment) { Value *ShadowOffset = getShadowPtrOffset(Addr, IRB); Value *ShadowLong = ShadowOffset; uint64_t ShadowBase = MS.MapParams->ShadowBase; - *FirstInsn = dyn_cast(ShadowLong); if (ShadowBase != 0) { ShadowLong = IRB.CreateAdd(ShadowLong, @@ -1080,58 +1141,60 @@ struct MemorySanitizerVisitor : public InstVisitor { std::pair getShadowOriginPtr(Value *Addr, IRBuilder<> &IRB, Type *ShadowTy, - unsigned Alignment) { - Instruction *FirstInsn = nullptr; + unsigned Alignment, + bool isStore) { std::pair ret = - getShadowOriginPtrUserspace(Addr, IRB, ShadowTy, Alignment, &FirstInsn); + getShadowOriginPtrUserspace(Addr, IRB, ShadowTy, Alignment); return ret; } - /// \brief Compute the shadow address for a given function argument. + /// Compute the shadow address for a given function argument. /// /// Shadow = ParamTLS+ArgOffset. Value *getShadowPtrForArgument(Value *A, IRBuilder<> &IRB, int ArgOffset) { Value *Base = IRB.CreatePointerCast(MS.ParamTLS, MS.IntptrTy); - Base = IRB.CreateAdd(Base, ConstantInt::get(MS.IntptrTy, ArgOffset)); + if (ArgOffset) + Base = IRB.CreateAdd(Base, ConstantInt::get(MS.IntptrTy, ArgOffset)); return IRB.CreateIntToPtr(Base, PointerType::get(getShadowTy(A), 0), "_msarg"); } - /// \brief Compute the origin address for a given function argument. + /// Compute the origin address for a given function argument. Value *getOriginPtrForArgument(Value *A, IRBuilder<> &IRB, int ArgOffset) { if (!MS.TrackOrigins) return nullptr; Value *Base = IRB.CreatePointerCast(MS.ParamOriginTLS, MS.IntptrTy); - Base = IRB.CreateAdd(Base, ConstantInt::get(MS.IntptrTy, ArgOffset)); + if (ArgOffset) + Base = IRB.CreateAdd(Base, ConstantInt::get(MS.IntptrTy, ArgOffset)); return IRB.CreateIntToPtr(Base, PointerType::get(MS.OriginTy, 0), "_msarg_o"); } - /// \brief Compute the shadow address for a retval. + /// Compute the shadow address for a retval. Value *getShadowPtrForRetval(Value *A, IRBuilder<> &IRB) { return IRB.CreatePointerCast(MS.RetvalTLS, PointerType::get(getShadowTy(A), 0), "_msret"); } - /// \brief Compute the origin address for a retval. + /// Compute the origin address for a retval. Value *getOriginPtrForRetval(IRBuilder<> &IRB) { // We keep a single origin for the entire retval. Might be too optimistic. return MS.RetvalOriginTLS; } - /// \brief Set SV to be the shadow value for V. + /// Set SV to be the shadow value for V. void setShadow(Value *V, Value *SV) { assert(!ShadowMap.count(V) && "Values may only have one shadow"); ShadowMap[V] = PropagateShadow ? SV : getCleanShadow(V); } - /// \brief Set Origin to be the origin value for V. + /// Set Origin to be the origin value for V. void setOrigin(Value *V, Value *Origin) { if (!MS.TrackOrigins) return; assert(!OriginMap.count(V) && "Values may only have one origin"); - DEBUG(dbgs() << "ORIGIN: " << *V << " ==> " << *Origin << "\n"); + LLVM_DEBUG(dbgs() << "ORIGIN: " << *V << " ==> " << *Origin << "\n"); OriginMap[V] = Origin; } @@ -1142,7 +1205,7 @@ struct MemorySanitizerVisitor : public InstVisitor { return Constant::getNullValue(ShadowTy); } - /// \brief Create a clean shadow value for a given value. + /// Create a clean shadow value for a given value. /// /// Clean shadow (all zeroes) means all bits of the value are defined /// (initialized). @@ -1150,7 +1213,7 @@ struct MemorySanitizerVisitor : public InstVisitor { return getCleanShadow(V->getType()); } - /// \brief Create a dirty shadow of a given shadow type. + /// Create a dirty shadow of a given shadow type. Constant *getPoisonedShadow(Type *ShadowTy) { assert(ShadowTy); if (isa(ShadowTy) || isa(ShadowTy)) @@ -1169,7 +1232,7 @@ struct MemorySanitizerVisitor : public InstVisitor { llvm_unreachable("Unexpected shadow type"); } - /// \brief Create a dirty shadow for a given value. + /// Create a dirty shadow for a given value. Constant *getPoisonedShadow(Value *V) { Type *ShadowTy = getShadowTy(V); if (!ShadowTy) @@ -1177,12 +1240,12 @@ struct MemorySanitizerVisitor : public InstVisitor { return getPoisonedShadow(ShadowTy); } - /// \brief Create a clean (zero) origin. + /// Create a clean (zero) origin. Value *getCleanOrigin() { return Constant::getNullValue(MS.OriginTy); } - /// \brief Get the shadow value for a given Value. + /// Get the shadow value for a given Value. /// /// This function either returns the value set earlier with setShadow, /// or extracts if from ParamTLS (for function arguments). @@ -1194,7 +1257,7 @@ struct MemorySanitizerVisitor : public InstVisitor { // For instructions the shadow is already stored in the map. Value *Shadow = ShadowMap[V]; if (!Shadow) { - DEBUG(dbgs() << "No shadow: " << *V << "\n" << *(I->getParent())); + LLVM_DEBUG(dbgs() << "No shadow: " << *V << "\n" << *(I->getParent())); (void)I; assert(Shadow && "No shadow for a value"); } @@ -1202,7 +1265,7 @@ struct MemorySanitizerVisitor : public InstVisitor { } if (UndefValue *U = dyn_cast(V)) { Value *AllOnes = PoisonUndef ? getPoisonedShadow(V) : getCleanShadow(V); - DEBUG(dbgs() << "Undef: " << *U << " ==> " << *AllOnes << "\n"); + LLVM_DEBUG(dbgs() << "Undef: " << *U << " ==> " << *AllOnes << "\n"); (void)U; return AllOnes; } @@ -1212,12 +1275,12 @@ struct MemorySanitizerVisitor : public InstVisitor { if (*ShadowPtr) return *ShadowPtr; Function *F = A->getParent(); - IRBuilder<> EntryIRB(F->getEntryBlock().getFirstNonPHI()); + IRBuilder<> EntryIRB(ActualFnStart->getFirstNonPHI()); unsigned ArgOffset = 0; const DataLayout &DL = F->getParent()->getDataLayout(); for (auto &FArg : F->args()) { if (!FArg.getType()->isSized()) { - DEBUG(dbgs() << "Arg is not sized\n"); + LLVM_DEBUG(dbgs() << "Arg is not sized\n"); continue; } unsigned Size = @@ -1237,7 +1300,8 @@ struct MemorySanitizerVisitor : public InstVisitor { ArgAlign = DL.getABITypeAlignment(EltType); } Value *CpShadowPtr = - getShadowOriginPtr(V, EntryIRB, EntryIRB.getInt8Ty(), ArgAlign) + getShadowOriginPtr(V, EntryIRB, EntryIRB.getInt8Ty(), ArgAlign, + /*isStore*/ true) .first; if (Overflow) { // ParamTLS overflow. @@ -1246,9 +1310,9 @@ struct MemorySanitizerVisitor : public InstVisitor { Size, ArgAlign); } else { unsigned CopyAlign = std::min(ArgAlign, kShadowTLSAlignment); - Value *Cpy = - EntryIRB.CreateMemCpy(CpShadowPtr, Base, Size, CopyAlign); - DEBUG(dbgs() << " ByValCpy: " << *Cpy << "\n"); + Value *Cpy = EntryIRB.CreateMemCpy(CpShadowPtr, CopyAlign, Base, + CopyAlign, Size); + LLVM_DEBUG(dbgs() << " ByValCpy: " << *Cpy << "\n"); (void)Cpy; } *ShadowPtr = getCleanShadow(V); @@ -1261,8 +1325,8 @@ struct MemorySanitizerVisitor : public InstVisitor { EntryIRB.CreateAlignedLoad(Base, kShadowTLSAlignment); } } - DEBUG(dbgs() << " ARG: " << FArg << " ==> " << - **ShadowPtr << "\n"); + LLVM_DEBUG(dbgs() + << " ARG: " << FArg << " ==> " << **ShadowPtr << "\n"); if (MS.TrackOrigins && !Overflow) { Value *OriginPtr = getOriginPtrForArgument(&FArg, EntryIRB, ArgOffset); @@ -1280,12 +1344,12 @@ struct MemorySanitizerVisitor : public InstVisitor { return getCleanShadow(V); } - /// \brief Get the shadow for i-th argument of the instruction I. + /// Get the shadow for i-th argument of the instruction I. Value *getShadow(Instruction *I, int i) { return getShadow(I->getOperand(i)); } - /// \brief Get the origin for a value. + /// Get the origin for a value. Value *getOrigin(Value *V) { if (!MS.TrackOrigins) return nullptr; if (!PropagateShadow) return getCleanOrigin(); @@ -1301,12 +1365,12 @@ struct MemorySanitizerVisitor : public InstVisitor { return Origin; } - /// \brief Get the origin for i-th argument of the instruction I. + /// Get the origin for i-th argument of the instruction I. Value *getOrigin(Instruction *I, int i) { return getOrigin(I->getOperand(i)); } - /// \brief Remember the place where a shadow check should be inserted. + /// Remember the place where a shadow check should be inserted. /// /// This location will be later instrumented with a check that will print a /// UMR warning in runtime if the shadow value is not 0. @@ -1322,7 +1386,7 @@ struct MemorySanitizerVisitor : public InstVisitor { ShadowOriginAndInsertPoint(Shadow, Origin, OrigIns)); } - /// \brief Remember the place where a shadow check should be inserted. + /// Remember the place where a shadow check should be inserted. /// /// This location will be later instrumented with a check that will print a /// UMR warning in runtime if the value is not fully defined. @@ -1382,7 +1446,7 @@ struct MemorySanitizerVisitor : public InstVisitor { InstVisitor::visit(I); } - /// \brief Instrument LoadInst + /// Instrument LoadInst /// /// Loads the corresponding shadow and (optionally) origin. /// Optionally, checks that the load address is fully defined. @@ -1396,7 +1460,7 @@ struct MemorySanitizerVisitor : public InstVisitor { unsigned Alignment = I.getAlignment(); if (PropagateShadow) { std::tie(ShadowPtr, OriginPtr) = - getShadowOriginPtr(Addr, IRB, ShadowTy, Alignment); + getShadowOriginPtr(Addr, IRB, ShadowTy, Alignment, /*isStore*/ false); setShadow(&I, IRB.CreateAlignedLoad(ShadowPtr, Alignment, "_msld")); } else { setShadow(&I, getCleanShadow(&I)); @@ -1418,12 +1482,14 @@ struct MemorySanitizerVisitor : public InstVisitor { } } - /// \brief Instrument StoreInst + /// Instrument StoreInst /// /// Stores the corresponding shadow and (optionally) origin. /// Optionally, checks that the store address is fully defined. void visitStoreInst(StoreInst &I) { StoreList.push_back(&I); + if (ClCheckAccessAddress) + insertShadowCheck(I.getPointerOperand(), &I); } void handleCASOrRMW(Instruction &I) { @@ -1431,8 +1497,9 @@ struct MemorySanitizerVisitor : public InstVisitor { IRBuilder<> IRB(&I); Value *Addr = I.getOperand(0); - Value *ShadowPtr = - getShadowOriginPtr(Addr, IRB, I.getType(), /*Alignment*/ 1).first; + Value *ShadowPtr = getShadowOriginPtr(Addr, IRB, I.getType(), + /*Alignment*/ 1, /*isStore*/ true) + .first; if (ClCheckAccessAddress) insertShadowCheck(Addr, &I); @@ -1536,7 +1603,7 @@ struct MemorySanitizerVisitor : public InstVisitor { void visitFPExtInst(CastInst& I) { handleShadowOr(I); } void visitFPTruncInst(CastInst& I) { handleShadowOr(I); } - /// \brief Propagate shadow for bitwise AND. + /// Propagate shadow for bitwise AND. /// /// This code is exact, i.e. if, for example, a bit in the left argument /// is defined and 0, then neither the value not definedness of the @@ -1585,7 +1652,7 @@ struct MemorySanitizerVisitor : public InstVisitor { setOriginForNaryOp(I); } - /// \brief Default propagation of shadow and/or origin. + /// Default propagation of shadow and/or origin. /// /// This class implements the general case of shadow propagation, used in all /// cases where we don't know and/or don't care about what the operation @@ -1611,7 +1678,7 @@ struct MemorySanitizerVisitor : public InstVisitor { Combiner(MemorySanitizerVisitor *MSV, IRBuilder<> &IRB) : IRB(IRB), MSV(MSV) {} - /// \brief Add a pair of shadow and origin values to the mix. + /// Add a pair of shadow and origin values to the mix. Combiner &Add(Value *OpShadow, Value *OpOrigin) { if (CombineShadow) { assert(OpShadow); @@ -1641,14 +1708,14 @@ struct MemorySanitizerVisitor : public InstVisitor { return *this; } - /// \brief Add an application value to the mix. + /// Add an application value to the mix. Combiner &Add(Value *V) { Value *OpShadow = MSV->getShadow(V); Value *OpOrigin = MSV->MS.TrackOrigins ? MSV->getOrigin(V) : nullptr; return Add(OpShadow, OpOrigin); } - /// \brief Set the current combined values as the given instruction's shadow + /// Set the current combined values as the given instruction's shadow /// and origin. void Done(Instruction *I) { if (CombineShadow) { @@ -1666,7 +1733,7 @@ struct MemorySanitizerVisitor : public InstVisitor { using ShadowAndOriginCombiner = Combiner; using OriginCombiner = Combiner; - /// \brief Propagate origin for arbitrary operation. + /// Propagate origin for arbitrary operation. void setOriginForNaryOp(Instruction &I) { if (!MS.TrackOrigins) return; IRBuilder<> IRB(&I); @@ -1684,7 +1751,7 @@ struct MemorySanitizerVisitor : public InstVisitor { Ty->getPrimitiveSizeInBits(); } - /// \brief Cast between two shadow types, extending or truncating as + /// Cast between two shadow types, extending or truncating as /// necessary. Value *CreateShadowCast(IRBuilder<> &IRB, Value *V, Type *dstTy, bool Signed = false) { @@ -1706,7 +1773,7 @@ struct MemorySanitizerVisitor : public InstVisitor { // TODO: handle struct types. } - /// \brief Cast an application value to the type of its own shadow. + /// Cast an application value to the type of its own shadow. Value *CreateAppToShadowCast(IRBuilder<> &IRB, Value *V) { Type *ShadowTy = getShadowTy(V); if (V->getType() == ShadowTy) @@ -1717,7 +1784,7 @@ struct MemorySanitizerVisitor : public InstVisitor { return IRB.CreateBitCast(V, ShadowTy); } - /// \brief Propagate shadow for arbitrary operation. + /// Propagate shadow for arbitrary operation. void handleShadowOr(Instruction &I) { IRBuilder<> IRB(&I); ShadowAndOriginCombiner SC(this, IRB); @@ -1726,7 +1793,7 @@ struct MemorySanitizerVisitor : public InstVisitor { SC.Done(&I); } - // \brief Handle multiplication by constant. + // Handle multiplication by constant. // // Handle a special case of multiplication by constant that may have one or // more zeros in the lower bits. This makes corresponding number of lower bits @@ -1788,7 +1855,7 @@ struct MemorySanitizerVisitor : public InstVisitor { void visitSub(BinaryOperator &I) { handleShadowOr(I); } void visitXor(BinaryOperator &I) { handleShadowOr(I); } - void handleDiv(Instruction &I) { + void handleIntegerDiv(Instruction &I) { IRBuilder<> IRB(&I); // Strict on the second argument. insertShadowCheck(I.getOperand(1), &I); @@ -1796,14 +1863,17 @@ struct MemorySanitizerVisitor : public InstVisitor { setOrigin(&I, getOrigin(&I, 0)); } - void visitUDiv(BinaryOperator &I) { handleDiv(I); } - void visitSDiv(BinaryOperator &I) { handleDiv(I); } - void visitFDiv(BinaryOperator &I) { handleDiv(I); } - void visitURem(BinaryOperator &I) { handleDiv(I); } - void visitSRem(BinaryOperator &I) { handleDiv(I); } - void visitFRem(BinaryOperator &I) { handleDiv(I); } + void visitUDiv(BinaryOperator &I) { handleIntegerDiv(I); } + void visitSDiv(BinaryOperator &I) { handleIntegerDiv(I); } + void visitURem(BinaryOperator &I) { handleIntegerDiv(I); } + void visitSRem(BinaryOperator &I) { handleIntegerDiv(I); } + + // Floating point division is side-effect free. We can not require that the + // divisor is fully initialized and must propagate shadow. See PR37523. + void visitFDiv(BinaryOperator &I) { handleShadowOr(I); } + void visitFRem(BinaryOperator &I) { handleShadowOr(I); } - /// \brief Instrument == and != comparisons. + /// Instrument == and != comparisons. /// /// Sometimes the comparison result is known even if some of the bits of the /// arguments are not. @@ -1841,7 +1911,7 @@ struct MemorySanitizerVisitor : public InstVisitor { setOriginForNaryOp(I); } - /// \brief Build the lowest possible value of V, taking into account V's + /// Build the lowest possible value of V, taking into account V's /// uninitialized bits. Value *getLowestPossibleValue(IRBuilder<> &IRB, Value *A, Value *Sa, bool isSigned) { @@ -1858,7 +1928,7 @@ struct MemorySanitizerVisitor : public InstVisitor { } } - /// \brief Build the highest possible value of V, taking into account V's + /// Build the highest possible value of V, taking into account V's /// uninitialized bits. Value *getHighestPossibleValue(IRBuilder<> &IRB, Value *A, Value *Sa, bool isSigned) { @@ -1875,7 +1945,7 @@ struct MemorySanitizerVisitor : public InstVisitor { } } - /// \brief Instrument relational comparisons. + /// Instrument relational comparisons. /// /// This function does exact shadow propagation for all relational /// comparisons of integers, pointers and vectors of those. @@ -1908,7 +1978,7 @@ struct MemorySanitizerVisitor : public InstVisitor { setOriginForNaryOp(I); } - /// \brief Instrument signed relational comparisons. + /// Instrument signed relational comparisons. /// /// Handle sign bit tests: x<0, x>=0, x<=-1, x>-1 by propagating the highest /// bit of the shadow. Everything else is delegated to handleShadowOr(). @@ -1992,7 +2062,7 @@ struct MemorySanitizerVisitor : public InstVisitor { void visitAShr(BinaryOperator &I) { handleShift(I); } void visitLShr(BinaryOperator &I) { handleShift(I); } - /// \brief Instrument llvm.memmove + /// Instrument llvm.memmove /// /// At this point we don't know if llvm.memmove will be inlined or not. /// If we don't instrument it and it gets inlined, @@ -2045,7 +2115,7 @@ struct MemorySanitizerVisitor : public InstVisitor { VAHelper->visitVACopyInst(I); } - /// \brief Handle vector store-like intrinsics. + /// Handle vector store-like intrinsics. /// /// Instrument intrinsics that look like a simple SIMD store: writes memory, /// has 1 pointer argument and 1 vector argument, returns void. @@ -2057,8 +2127,8 @@ struct MemorySanitizerVisitor : public InstVisitor { // We don't know the pointer alignment (could be unaligned SSE store!). // Have to assume to worst case. - std::tie(ShadowPtr, OriginPtr) = - getShadowOriginPtr(Addr, IRB, Shadow->getType(), /*Alignment*/ 1); + std::tie(ShadowPtr, OriginPtr) = getShadowOriginPtr( + Addr, IRB, Shadow->getType(), /*Alignment*/ 1, /*isStore*/ true); IRB.CreateAlignedStore(Shadow, ShadowPtr, 1); if (ClCheckAccessAddress) @@ -2069,7 +2139,7 @@ struct MemorySanitizerVisitor : public InstVisitor { return true; } - /// \brief Handle vector load-like intrinsics. + /// Handle vector load-like intrinsics. /// /// Instrument intrinsics that look like a simple SIMD load: reads memory, /// has 1 pointer argument, returns a vector. @@ -2084,7 +2154,7 @@ struct MemorySanitizerVisitor : public InstVisitor { // Have to assume to worst case. unsigned Alignment = 1; std::tie(ShadowPtr, OriginPtr) = - getShadowOriginPtr(Addr, IRB, ShadowTy, Alignment); + getShadowOriginPtr(Addr, IRB, ShadowTy, Alignment, /*isStore*/ false); setShadow(&I, IRB.CreateAlignedLoad(ShadowPtr, Alignment, "_msld")); } else { setShadow(&I, getCleanShadow(&I)); @@ -2102,7 +2172,7 @@ struct MemorySanitizerVisitor : public InstVisitor { return true; } - /// \brief Handle (SIMD arithmetic)-like intrinsics. + /// Handle (SIMD arithmetic)-like intrinsics. /// /// Instrument intrinsics with any number of arguments of the same type, /// equal to the return type. The type should be simple (no aggregates or @@ -2132,7 +2202,7 @@ struct MemorySanitizerVisitor : public InstVisitor { return true; } - /// \brief Heuristically instrument unknown intrinsics. + /// Heuristically instrument unknown intrinsics. /// /// The main purpose of this code is to do something reasonable with all /// random intrinsics we might encounter, most importantly - SIMD intrinsics. @@ -2182,7 +2252,7 @@ struct MemorySanitizerVisitor : public InstVisitor { setOrigin(&I, getOrigin(Op)); } - // \brief Instrument vector convert instrinsic. + // Instrument vector convert instrinsic. // // This function instruments intrinsics like cvtsi2ss: // %Out = int_xxx_cvtyyy(%ConvertOp) @@ -2285,7 +2355,7 @@ struct MemorySanitizerVisitor : public InstVisitor { return IRB.CreateSExt(S2, T); } - // \brief Instrument vector shift instrinsic. + // Instrument vector shift instrinsic. // // This function instruments intrinsics like int_x86_avx2_psll_w. // Intrinsic shifts %In by %ShiftSize bits. @@ -2310,14 +2380,14 @@ struct MemorySanitizerVisitor : public InstVisitor { setOriginForNaryOp(I); } - // \brief Get an X86_MMX-sized vector type. + // Get an X86_MMX-sized vector type. Type *getMMXVectorTy(unsigned EltSizeInBits) { const unsigned X86_MMXSizeInBits = 64; return VectorType::get(IntegerType::get(*MS.C, EltSizeInBits), X86_MMXSizeInBits / EltSizeInBits); } - // \brief Returns a signed counterpart for an (un)signed-saturate-and-pack + // Returns a signed counterpart for an (un)signed-saturate-and-pack // intrinsic. Intrinsic::ID getSignedPackIntrinsic(Intrinsic::ID id) { switch (id) { @@ -2348,7 +2418,7 @@ struct MemorySanitizerVisitor : public InstVisitor { } } - // \brief Instrument vector pack instrinsic. + // Instrument vector pack instrinsic. // // This function instruments intrinsics like x86_mmx_packsswb, that // packs elements of 2 input vectors into half as many bits with saturation. @@ -2391,7 +2461,7 @@ struct MemorySanitizerVisitor : public InstVisitor { setOriginForNaryOp(I); } - // \brief Instrument sum-of-absolute-differencies intrinsic. + // Instrument sum-of-absolute-differencies intrinsic. void handleVectorSadIntrinsic(IntrinsicInst &I) { const unsigned SignificantBitsPerResultElement = 16; bool isX86_MMX = I.getOperand(0)->getType()->isX86_MMXTy(); @@ -2410,7 +2480,7 @@ struct MemorySanitizerVisitor : public InstVisitor { setOriginForNaryOp(I); } - // \brief Instrument multiply-add intrinsic. + // Instrument multiply-add intrinsic. void handleVectorPmaddIntrinsic(IntrinsicInst &I, unsigned EltSizeInBits = 0) { bool isX86_MMX = I.getOperand(0)->getType()->isX86_MMXTy(); @@ -2425,7 +2495,7 @@ struct MemorySanitizerVisitor : public InstVisitor { setOriginForNaryOp(I); } - // \brief Instrument compare-packed intrinsic. + // Instrument compare-packed intrinsic. // Basically, an or followed by sext(icmp ne 0) to end up with all-zeros or // all-ones shadow. void handleVectorComparePackedIntrinsic(IntrinsicInst &I) { @@ -2438,7 +2508,7 @@ struct MemorySanitizerVisitor : public InstVisitor { setOriginForNaryOp(I); } - // \brief Instrument compare-scalar intrinsic. + // Instrument compare-scalar intrinsic. // This handles both cmp* intrinsics which return the result in the first // element of a vector, and comi* which return the result as i32. void handleVectorCompareScalarIntrinsic(IntrinsicInst &I) { @@ -2453,7 +2523,9 @@ struct MemorySanitizerVisitor : public InstVisitor { IRBuilder<> IRB(&I); Value* Addr = I.getArgOperand(0); Type *Ty = IRB.getInt32Ty(); - Value *ShadowPtr = getShadowOriginPtr(Addr, IRB, Ty, /*Alignment*/ 1).first; + Value *ShadowPtr = + getShadowOriginPtr(Addr, IRB, Ty, /*Alignment*/ 1, /*isStore*/ true) + .first; IRB.CreateStore(getCleanShadow(Ty), IRB.CreatePointerCast(ShadowPtr, Ty->getPointerTo())); @@ -2471,7 +2543,7 @@ struct MemorySanitizerVisitor : public InstVisitor { unsigned Alignment = 1; Value *ShadowPtr, *OriginPtr; std::tie(ShadowPtr, OriginPtr) = - getShadowOriginPtr(Addr, IRB, Ty, Alignment); + getShadowOriginPtr(Addr, IRB, Ty, Alignment, /*isStore*/ false); if (ClCheckAccessAddress) insertShadowCheck(Addr, &I); @@ -2482,11 +2554,98 @@ struct MemorySanitizerVisitor : public InstVisitor { insertShadowCheck(Shadow, Origin, &I); } + void handleMaskedStore(IntrinsicInst &I) { + IRBuilder<> IRB(&I); + Value *V = I.getArgOperand(0); + Value *Addr = I.getArgOperand(1); + unsigned Align = cast(I.getArgOperand(2))->getZExtValue(); + Value *Mask = I.getArgOperand(3); + Value *Shadow = getShadow(V); + + Value *ShadowPtr; + Value *OriginPtr; + std::tie(ShadowPtr, OriginPtr) = getShadowOriginPtr( + Addr, IRB, Shadow->getType(), Align, /*isStore*/ true); + + if (ClCheckAccessAddress) { + insertShadowCheck(Addr, &I); + // Uninitialized mask is kind of like uninitialized address, but not as + // scary. + insertShadowCheck(Mask, &I); + } + + IRB.CreateMaskedStore(Shadow, ShadowPtr, Align, Mask); + + if (MS.TrackOrigins) { + auto &DL = F.getParent()->getDataLayout(); + paintOrigin(IRB, getOrigin(V), OriginPtr, + DL.getTypeStoreSize(Shadow->getType()), + std::max(Align, kMinOriginAlignment)); + } + } + + bool handleMaskedLoad(IntrinsicInst &I) { + IRBuilder<> IRB(&I); + Value *Addr = I.getArgOperand(0); + unsigned Align = cast(I.getArgOperand(1))->getZExtValue(); + Value *Mask = I.getArgOperand(2); + Value *PassThru = I.getArgOperand(3); + + Type *ShadowTy = getShadowTy(&I); + Value *ShadowPtr, *OriginPtr; + if (PropagateShadow) { + std::tie(ShadowPtr, OriginPtr) = + getShadowOriginPtr(Addr, IRB, ShadowTy, Align, /*isStore*/ false); + setShadow(&I, IRB.CreateMaskedLoad(ShadowPtr, Align, Mask, + getShadow(PassThru), "_msmaskedld")); + } else { + setShadow(&I, getCleanShadow(&I)); + } + + if (ClCheckAccessAddress) { + insertShadowCheck(Addr, &I); + insertShadowCheck(Mask, &I); + } + + if (MS.TrackOrigins) { + if (PropagateShadow) { + // Choose between PassThru's and the loaded value's origins. + Value *MaskedPassThruShadow = IRB.CreateAnd( + getShadow(PassThru), IRB.CreateSExt(IRB.CreateNeg(Mask), ShadowTy)); + + Value *Acc = IRB.CreateExtractElement( + MaskedPassThruShadow, ConstantInt::get(IRB.getInt32Ty(), 0)); + for (int i = 1, N = PassThru->getType()->getVectorNumElements(); i < N; + ++i) { + Value *More = IRB.CreateExtractElement( + MaskedPassThruShadow, ConstantInt::get(IRB.getInt32Ty(), i)); + Acc = IRB.CreateOr(Acc, More); + } + + Value *Origin = IRB.CreateSelect( + IRB.CreateICmpNE(Acc, Constant::getNullValue(Acc->getType())), + getOrigin(PassThru), IRB.CreateLoad(OriginPtr)); + + setOrigin(&I, Origin); + } else { + setOrigin(&I, getCleanOrigin()); + } + } + return true; + } + + void visitIntrinsicInst(IntrinsicInst &I) { switch (I.getIntrinsicID()) { case Intrinsic::bswap: handleBswap(I); break; + case Intrinsic::masked_store: + handleMaskedStore(I); + break; + case Intrinsic::masked_load: + handleMaskedLoad(I); + break; case Intrinsic::x86_sse_stmxcsr: handleStmxcsr(I); break; @@ -2501,20 +2660,14 @@ struct MemorySanitizerVisitor : public InstVisitor { case Intrinsic::x86_avx512_cvttss2usi: case Intrinsic::x86_avx512_cvttsd2usi64: case Intrinsic::x86_avx512_cvttsd2usi: - case Intrinsic::x86_avx512_cvtusi2sd: case Intrinsic::x86_avx512_cvtusi2ss: case Intrinsic::x86_avx512_cvtusi642sd: case Intrinsic::x86_avx512_cvtusi642ss: case Intrinsic::x86_sse2_cvtsd2si64: case Intrinsic::x86_sse2_cvtsd2si: case Intrinsic::x86_sse2_cvtsd2ss: - case Intrinsic::x86_sse2_cvtsi2sd: - case Intrinsic::x86_sse2_cvtsi642sd: - case Intrinsic::x86_sse2_cvtss2sd: case Intrinsic::x86_sse2_cvttsd2si64: case Intrinsic::x86_sse2_cvttsd2si: - case Intrinsic::x86_sse_cvtsi2ss: - case Intrinsic::x86_sse_cvtsi642ss: case Intrinsic::x86_sse_cvtss2si64: case Intrinsic::x86_sse_cvtss2si: case Intrinsic::x86_sse_cvttss2si64: @@ -2715,7 +2868,10 @@ struct MemorySanitizerVisitor : public InstVisitor { // outputs as clean. Note that any side effects of the inline asm that are // not immediately visible in its constraints are not handled. if (Call->isInlineAsm()) { - visitInstruction(I); + if (ClHandleAsmConservative) + visitAsmInstruction(I); + else + visitInstruction(I); return; } @@ -2738,13 +2894,13 @@ struct MemorySanitizerVisitor : public InstVisitor { IRBuilder<> IRB(&I); unsigned ArgOffset = 0; - DEBUG(dbgs() << " CallSite: " << I << "\n"); + LLVM_DEBUG(dbgs() << " CallSite: " << I << "\n"); for (CallSite::arg_iterator ArgIt = CS.arg_begin(), End = CS.arg_end(); ArgIt != End; ++ArgIt) { Value *A = *ArgIt; unsigned i = ArgIt - CS.arg_begin(); if (!A->getType()->isSized()) { - DEBUG(dbgs() << "Arg " << i << " is not sized: " << I << "\n"); + LLVM_DEBUG(dbgs() << "Arg " << i << " is not sized: " << I << "\n"); continue; } unsigned Size = 0; @@ -2754,8 +2910,8 @@ struct MemorySanitizerVisitor : public InstVisitor { // __msan_param_tls. Value *ArgShadow = getShadow(A); Value *ArgShadowBase = getShadowPtrForArgument(A, IRB, ArgOffset); - DEBUG(dbgs() << " Arg#" << i << ": " << *A << - " Shadow: " << *ArgShadow << "\n"); + LLVM_DEBUG(dbgs() << " Arg#" << i << ": " << *A + << " Shadow: " << *ArgShadow << "\n"); bool ArgIsInitialized = false; const DataLayout &DL = F.getParent()->getDataLayout(); if (CS.paramHasAttr(i, Attribute::ByVal)) { @@ -2765,10 +2921,12 @@ struct MemorySanitizerVisitor : public InstVisitor { if (ArgOffset + Size > kParamTLSSize) break; unsigned ParamAlignment = CS.getParamAlignment(i); unsigned Alignment = std::min(ParamAlignment, kShadowTLSAlignment); - Value *AShadowPtr = - getShadowOriginPtr(A, IRB, IRB.getInt8Ty(), Alignment).first; + Value *AShadowPtr = getShadowOriginPtr(A, IRB, IRB.getInt8Ty(), + Alignment, /*isStore*/ false) + .first; - Store = IRB.CreateMemCpy(ArgShadowBase, AShadowPtr, Size, Alignment); + Store = IRB.CreateMemCpy(ArgShadowBase, Alignment, AShadowPtr, + Alignment, Size); } else { Size = DL.getTypeAllocSize(A->getType()); if (ArgOffset + Size > kParamTLSSize) break; @@ -2782,10 +2940,10 @@ struct MemorySanitizerVisitor : public InstVisitor { getOriginPtrForArgument(A, IRB, ArgOffset)); (void)Store; assert(Size != 0 && Store != nullptr); - DEBUG(dbgs() << " Param:" << *Store << "\n"); + LLVM_DEBUG(dbgs() << " Param:" << *Store << "\n"); ArgOffset += alignTo(Size, 8); } - DEBUG(dbgs() << " done with call args\n"); + LLVM_DEBUG(dbgs() << " done with call args\n"); FunctionType *FT = cast(CS.getCalledValue()->getType()->getContainedType(0)); @@ -2888,8 +3046,9 @@ struct MemorySanitizerVisitor : public InstVisitor { IRB.CreateCall(MS.MsanPoisonStackFn, {IRB.CreatePointerCast(&I, IRB.getInt8PtrTy()), Len}); } else { - Value *ShadowBase = - getShadowOriginPtr(&I, IRB, IRB.getInt8Ty(), I.getAlignment()).first; + Value *ShadowBase = getShadowOriginPtr(&I, IRB, IRB.getInt8Ty(), + I.getAlignment(), /*isStore*/ true) + .first; Value *PoisonValue = IRB.getInt8(PoisonStack ? ClPoisonStackPattern : 0); IRB.CreateMemSet(ShadowBase, PoisonValue, Len, I.getAlignment()); @@ -2991,24 +3150,24 @@ struct MemorySanitizerVisitor : public InstVisitor { void visitExtractValueInst(ExtractValueInst &I) { IRBuilder<> IRB(&I); Value *Agg = I.getAggregateOperand(); - DEBUG(dbgs() << "ExtractValue: " << I << "\n"); + LLVM_DEBUG(dbgs() << "ExtractValue: " << I << "\n"); Value *AggShadow = getShadow(Agg); - DEBUG(dbgs() << " AggShadow: " << *AggShadow << "\n"); + LLVM_DEBUG(dbgs() << " AggShadow: " << *AggShadow << "\n"); Value *ResShadow = IRB.CreateExtractValue(AggShadow, I.getIndices()); - DEBUG(dbgs() << " ResShadow: " << *ResShadow << "\n"); + LLVM_DEBUG(dbgs() << " ResShadow: " << *ResShadow << "\n"); setShadow(&I, ResShadow); setOriginForNaryOp(I); } void visitInsertValueInst(InsertValueInst &I) { IRBuilder<> IRB(&I); - DEBUG(dbgs() << "InsertValue: " << I << "\n"); + LLVM_DEBUG(dbgs() << "InsertValue: " << I << "\n"); Value *AggShadow = getShadow(I.getAggregateOperand()); Value *InsShadow = getShadow(I.getInsertedValueOperand()); - DEBUG(dbgs() << " AggShadow: " << *AggShadow << "\n"); - DEBUG(dbgs() << " InsShadow: " << *InsShadow << "\n"); + LLVM_DEBUG(dbgs() << " AggShadow: " << *AggShadow << "\n"); + LLVM_DEBUG(dbgs() << " InsShadow: " << *InsShadow << "\n"); Value *Res = IRB.CreateInsertValue(AggShadow, InsShadow, I.getIndices()); - DEBUG(dbgs() << " Res: " << *Res << "\n"); + LLVM_DEBUG(dbgs() << " Res: " << *Res << "\n"); setShadow(&I, Res); setOriginForNaryOp(I); } @@ -3023,25 +3182,58 @@ struct MemorySanitizerVisitor : public InstVisitor { } void visitResumeInst(ResumeInst &I) { - DEBUG(dbgs() << "Resume: " << I << "\n"); + LLVM_DEBUG(dbgs() << "Resume: " << I << "\n"); // Nothing to do here. } void visitCleanupReturnInst(CleanupReturnInst &CRI) { - DEBUG(dbgs() << "CleanupReturn: " << CRI << "\n"); + LLVM_DEBUG(dbgs() << "CleanupReturn: " << CRI << "\n"); // Nothing to do here. } void visitCatchReturnInst(CatchReturnInst &CRI) { - DEBUG(dbgs() << "CatchReturn: " << CRI << "\n"); + LLVM_DEBUG(dbgs() << "CatchReturn: " << CRI << "\n"); // Nothing to do here. } + void visitAsmInstruction(Instruction &I) { + // Conservative inline assembly handling: check for poisoned shadow of + // asm() arguments, then unpoison the result and all the memory locations + // pointed to by those arguments. + CallInst *CI = dyn_cast(&I); + + for (size_t i = 0, n = CI->getNumOperands(); i < n; i++) { + Value *Operand = CI->getOperand(i); + if (Operand->getType()->isSized()) + insertShadowCheck(Operand, &I); + } + setShadow(&I, getCleanShadow(&I)); + setOrigin(&I, getCleanOrigin()); + IRBuilder<> IRB(&I); + IRB.SetInsertPoint(I.getNextNode()); + for (size_t i = 0, n = CI->getNumOperands(); i < n; i++) { + Value *Operand = CI->getOperand(i); + Type *OpType = Operand->getType(); + if (!OpType->isPointerTy()) + continue; + Type *ElType = OpType->getPointerElementType(); + if (!ElType->isSized()) + continue; + Value *ShadowPtr, *OriginPtr; + std::tie(ShadowPtr, OriginPtr) = getShadowOriginPtr( + Operand, IRB, ElType, /*Alignment*/ 1, /*isStore*/ true); + Value *CShadow = getCleanShadow(ElType); + IRB.CreateStore( + CShadow, + IRB.CreatePointerCast(ShadowPtr, CShadow->getType()->getPointerTo())); + } + } + void visitInstruction(Instruction &I) { // Everything else: stop propagating and check for poisoned shadow. if (ClDumpStrictInstructions) dumpInst(I); - DEBUG(dbgs() << "DEFAULT: " << I << "\n"); + LLVM_DEBUG(dbgs() << "DEFAULT: " << I << "\n"); for (size_t i = 0, n = I.getNumOperands(); i < n; i++) { Value *Operand = I.getOperand(i); if (Operand->getType()->isSized()) @@ -3052,7 +3244,7 @@ struct MemorySanitizerVisitor : public InstVisitor { } }; -/// \brief AMD64-specific implementation of VarArgHelper. +/// AMD64-specific implementation of VarArgHelper. struct VarArgAMD64Helper : public VarArgHelper { // An unfortunate workaround for asymmetric lowering of va_arg stuff. // See a comment in visitCallSite for more details. @@ -3116,10 +3308,12 @@ struct VarArgAMD64Helper : public VarArgHelper { getShadowPtrForVAArgument(RealTy, IRB, OverflowOffset); OverflowOffset += alignTo(ArgSize, 8); Value *ShadowPtr, *OriginPtr; - std::tie(ShadowPtr, OriginPtr) = MSV.getShadowOriginPtr( - A, IRB, IRB.getInt8Ty(), kShadowTLSAlignment); + std::tie(ShadowPtr, OriginPtr) = + MSV.getShadowOriginPtr(A, IRB, IRB.getInt8Ty(), kShadowTLSAlignment, + /*isStore*/ false); - IRB.CreateMemCpy(ShadowBase, ShadowPtr, ArgSize, kShadowTLSAlignment); + IRB.CreateMemCpy(ShadowBase, kShadowTLSAlignment, ShadowPtr, + kShadowTLSAlignment, ArgSize); } else { ArgKind AK = classifyArgument(A); if (AK == AK_GeneralPurpose && GpOffset >= AMD64GpEndOffset) @@ -3157,7 +3351,7 @@ struct VarArgAMD64Helper : public VarArgHelper { IRB.CreateStore(OverflowSize, MS.VAArgOverflowSizeTLS); } - /// \brief Compute the shadow address for a given va_arg. + /// Compute the shadow address for a given va_arg. Value *getShadowPtrForVAArgument(Type *Ty, IRBuilder<> &IRB, int ArgOffset) { Value *Base = IRB.CreatePointerCast(MS.VAArgTLS, MS.IntptrTy); @@ -3172,7 +3366,8 @@ struct VarArgAMD64Helper : public VarArgHelper { Value *ShadowPtr, *OriginPtr; unsigned Alignment = 8; std::tie(ShadowPtr, OriginPtr) = - MSV.getShadowOriginPtr(VAListTag, IRB, IRB.getInt8Ty(), Alignment); + MSV.getShadowOriginPtr(VAListTag, IRB, IRB.getInt8Ty(), Alignment, + /*isStore*/ true); // Unpoison the whole __va_list_tag. // FIXME: magic ABI constants. @@ -3200,13 +3395,13 @@ struct VarArgAMD64Helper : public VarArgHelper { if (!VAStartInstrumentationList.empty()) { // If there is a va_start in this function, make a backup copy of // va_arg_tls somewhere in the function entry block. - IRBuilder<> IRB(F.getEntryBlock().getFirstNonPHI()); + IRBuilder<> IRB(MSV.ActualFnStart->getFirstNonPHI()); VAArgOverflowSize = IRB.CreateLoad(MS.VAArgOverflowSizeTLS); Value *CopySize = IRB.CreateAdd(ConstantInt::get(MS.IntptrTy, AMD64FpEndOffset), VAArgOverflowSize); VAArgTLSCopy = IRB.CreateAlloca(Type::getInt8Ty(*MS.C), CopySize); - IRB.CreateMemCpy(VAArgTLSCopy, MS.VAArgTLS, CopySize, 8); + IRB.CreateMemCpy(VAArgTLSCopy, 8, MS.VAArgTLS, 8, CopySize); } // Instrument va_start. @@ -3219,33 +3414,33 @@ struct VarArgAMD64Helper : public VarArgHelper { Value *RegSaveAreaPtrPtr = IRB.CreateIntToPtr( IRB.CreateAdd(IRB.CreatePtrToInt(VAListTag, MS.IntptrTy), ConstantInt::get(MS.IntptrTy, 16)), - Type::getInt64PtrTy(*MS.C)); + PointerType::get(Type::getInt64PtrTy(*MS.C), 0)); Value *RegSaveAreaPtr = IRB.CreateLoad(RegSaveAreaPtrPtr); Value *RegSaveAreaShadowPtr, *RegSaveAreaOriginPtr; unsigned Alignment = 16; std::tie(RegSaveAreaShadowPtr, RegSaveAreaOriginPtr) = MSV.getShadowOriginPtr(RegSaveAreaPtr, IRB, IRB.getInt8Ty(), - Alignment); - IRB.CreateMemCpy(RegSaveAreaShadowPtr, VAArgTLSCopy, AMD64FpEndOffset, - Alignment); + Alignment, /*isStore*/ true); + IRB.CreateMemCpy(RegSaveAreaShadowPtr, Alignment, VAArgTLSCopy, Alignment, + AMD64FpEndOffset); Value *OverflowArgAreaPtrPtr = IRB.CreateIntToPtr( IRB.CreateAdd(IRB.CreatePtrToInt(VAListTag, MS.IntptrTy), ConstantInt::get(MS.IntptrTy, 8)), - Type::getInt64PtrTy(*MS.C)); + PointerType::get(Type::getInt64PtrTy(*MS.C), 0)); Value *OverflowArgAreaPtr = IRB.CreateLoad(OverflowArgAreaPtrPtr); Value *OverflowArgAreaShadowPtr, *OverflowArgAreaOriginPtr; std::tie(OverflowArgAreaShadowPtr, OverflowArgAreaOriginPtr) = MSV.getShadowOriginPtr(OverflowArgAreaPtr, IRB, IRB.getInt8Ty(), - Alignment); + Alignment, /*isStore*/ true); Value *SrcPtr = IRB.CreateConstGEP1_32(IRB.getInt8Ty(), VAArgTLSCopy, AMD64FpEndOffset); - IRB.CreateMemCpy(OverflowArgAreaShadowPtr, SrcPtr, VAArgOverflowSize, - Alignment); + IRB.CreateMemCpy(OverflowArgAreaShadowPtr, Alignment, SrcPtr, Alignment, + VAArgOverflowSize); } } }; -/// \brief MIPS64-specific implementation of VarArgHelper. +/// MIPS64-specific implementation of VarArgHelper. struct VarArgMIPS64Helper : public VarArgHelper { Function &F; MemorySanitizer &MS; @@ -3286,7 +3481,7 @@ struct VarArgMIPS64Helper : public VarArgHelper { IRB.CreateStore(TotalVAArgSize, MS.VAArgOverflowSizeTLS); } - /// \brief Compute the shadow address for a given va_arg. + /// Compute the shadow address for a given va_arg. Value *getShadowPtrForVAArgument(Type *Ty, IRBuilder<> &IRB, int ArgOffset) { Value *Base = IRB.CreatePointerCast(MS.VAArgTLS, MS.IntptrTy); @@ -3301,8 +3496,8 @@ struct VarArgMIPS64Helper : public VarArgHelper { Value *VAListTag = I.getArgOperand(0); Value *ShadowPtr, *OriginPtr; unsigned Alignment = 8; - std::tie(ShadowPtr, OriginPtr) = - MSV.getShadowOriginPtr(VAListTag, IRB, IRB.getInt8Ty(), Alignment); + std::tie(ShadowPtr, OriginPtr) = MSV.getShadowOriginPtr( + VAListTag, IRB, IRB.getInt8Ty(), Alignment, /*isStore*/ true); IRB.CreateMemSet(ShadowPtr, Constant::getNullValue(IRB.getInt8Ty()), /* size */ 8, Alignment, false); } @@ -3313,8 +3508,8 @@ struct VarArgMIPS64Helper : public VarArgHelper { Value *VAListTag = I.getArgOperand(0); Value *ShadowPtr, *OriginPtr; unsigned Alignment = 8; - std::tie(ShadowPtr, OriginPtr) = - MSV.getShadowOriginPtr(VAListTag, IRB, IRB.getInt8Ty(), Alignment); + std::tie(ShadowPtr, OriginPtr) = MSV.getShadowOriginPtr( + VAListTag, IRB, IRB.getInt8Ty(), Alignment, /*isStore*/ true); IRB.CreateMemSet(ShadowPtr, Constant::getNullValue(IRB.getInt8Ty()), /* size */ 8, Alignment, false); } @@ -3322,7 +3517,7 @@ struct VarArgMIPS64Helper : public VarArgHelper { void finalizeInstrumentation() override { assert(!VAArgSize && !VAArgTLSCopy && "finalizeInstrumentation called twice"); - IRBuilder<> IRB(F.getEntryBlock().getFirstNonPHI()); + IRBuilder<> IRB(MSV.ActualFnStart->getFirstNonPHI()); VAArgSize = IRB.CreateLoad(MS.VAArgOverflowSizeTLS); Value *CopySize = IRB.CreateAdd(ConstantInt::get(MS.IntptrTy, 0), VAArgSize); @@ -3331,7 +3526,7 @@ struct VarArgMIPS64Helper : public VarArgHelper { // If there is a va_start in this function, make a backup copy of // va_arg_tls somewhere in the function entry block. VAArgTLSCopy = IRB.CreateAlloca(Type::getInt8Ty(*MS.C), CopySize); - IRB.CreateMemCpy(VAArgTLSCopy, MS.VAArgTLS, CopySize, 8); + IRB.CreateMemCpy(VAArgTLSCopy, 8, MS.VAArgTLS, 8, CopySize); } // Instrument va_start. @@ -3341,20 +3536,21 @@ struct VarArgMIPS64Helper : public VarArgHelper { IRBuilder<> IRB(OrigInst->getNextNode()); Value *VAListTag = OrigInst->getArgOperand(0); Value *RegSaveAreaPtrPtr = - IRB.CreateIntToPtr(IRB.CreatePtrToInt(VAListTag, MS.IntptrTy), - Type::getInt64PtrTy(*MS.C)); + IRB.CreateIntToPtr(IRB.CreatePtrToInt(VAListTag, MS.IntptrTy), + PointerType::get(Type::getInt64PtrTy(*MS.C), 0)); Value *RegSaveAreaPtr = IRB.CreateLoad(RegSaveAreaPtrPtr); Value *RegSaveAreaShadowPtr, *RegSaveAreaOriginPtr; unsigned Alignment = 8; std::tie(RegSaveAreaShadowPtr, RegSaveAreaOriginPtr) = MSV.getShadowOriginPtr(RegSaveAreaPtr, IRB, IRB.getInt8Ty(), - Alignment); - IRB.CreateMemCpy(RegSaveAreaShadowPtr, VAArgTLSCopy, CopySize, Alignment); + Alignment, /*isStore*/ true); + IRB.CreateMemCpy(RegSaveAreaShadowPtr, Alignment, VAArgTLSCopy, Alignment, + CopySize); } } }; -/// \brief AArch64-specific implementation of VarArgHelper. +/// AArch64-specific implementation of VarArgHelper. struct VarArgAArch64Helper : public VarArgHelper { static const unsigned kAArch64GrArgSize = 64; static const unsigned kAArch64VrArgSize = 128; @@ -3461,8 +3657,8 @@ struct VarArgAArch64Helper : public VarArgHelper { Value *VAListTag = I.getArgOperand(0); Value *ShadowPtr, *OriginPtr; unsigned Alignment = 8; - std::tie(ShadowPtr, OriginPtr) = - MSV.getShadowOriginPtr(VAListTag, IRB, IRB.getInt8Ty(), Alignment); + std::tie(ShadowPtr, OriginPtr) = MSV.getShadowOriginPtr( + VAListTag, IRB, IRB.getInt8Ty(), Alignment, /*isStore*/ true); IRB.CreateMemSet(ShadowPtr, Constant::getNullValue(IRB.getInt8Ty()), /* size */ 32, Alignment, false); } @@ -3473,8 +3669,8 @@ struct VarArgAArch64Helper : public VarArgHelper { Value *VAListTag = I.getArgOperand(0); Value *ShadowPtr, *OriginPtr; unsigned Alignment = 8; - std::tie(ShadowPtr, OriginPtr) = - MSV.getShadowOriginPtr(VAListTag, IRB, IRB.getInt8Ty(), Alignment); + std::tie(ShadowPtr, OriginPtr) = MSV.getShadowOriginPtr( + VAListTag, IRB, IRB.getInt8Ty(), Alignment, /*isStore*/ true); IRB.CreateMemSet(ShadowPtr, Constant::getNullValue(IRB.getInt8Ty()), /* size */ 32, Alignment, false); } @@ -3506,13 +3702,13 @@ struct VarArgAArch64Helper : public VarArgHelper { if (!VAStartInstrumentationList.empty()) { // If there is a va_start in this function, make a backup copy of // va_arg_tls somewhere in the function entry block. - IRBuilder<> IRB(F.getEntryBlock().getFirstNonPHI()); + IRBuilder<> IRB(MSV.ActualFnStart->getFirstNonPHI()); VAArgOverflowSize = IRB.CreateLoad(MS.VAArgOverflowSizeTLS); Value *CopySize = IRB.CreateAdd(ConstantInt::get(MS.IntptrTy, AArch64VAEndOffset), VAArgOverflowSize); VAArgTLSCopy = IRB.CreateAlloca(Type::getInt8Ty(*MS.C), CopySize); - IRB.CreateMemCpy(VAArgTLSCopy, MS.VAArgTLS, CopySize, 8); + IRB.CreateMemCpy(VAArgTLSCopy, 8, MS.VAArgTLS, 8, CopySize); } Value *GrArgSize = ConstantInt::get(MS.IntptrTy, kAArch64GrArgSize); @@ -3563,14 +3759,14 @@ struct VarArgAArch64Helper : public VarArgHelper { Value *GrRegSaveAreaShadowPtr = MSV.getShadowOriginPtr(GrRegSaveAreaPtr, IRB, IRB.getInt8Ty(), - /*Alignment*/ 8) + /*Alignment*/ 8, /*isStore*/ true) .first; Value *GrSrcPtr = IRB.CreateInBoundsGEP(IRB.getInt8Ty(), VAArgTLSCopy, GrRegSaveAreaShadowPtrOff); Value *GrCopySize = IRB.CreateSub(GrArgSize, GrRegSaveAreaShadowPtrOff); - IRB.CreateMemCpy(GrRegSaveAreaShadowPtr, GrSrcPtr, GrCopySize, 8); + IRB.CreateMemCpy(GrRegSaveAreaShadowPtr, 8, GrSrcPtr, 8, GrCopySize); // Again, but for FP/SIMD values. Value *VrRegSaveAreaShadowPtrOff = @@ -3578,7 +3774,7 @@ struct VarArgAArch64Helper : public VarArgHelper { Value *VrRegSaveAreaShadowPtr = MSV.getShadowOriginPtr(VrRegSaveAreaPtr, IRB, IRB.getInt8Ty(), - /*Alignment*/ 8) + /*Alignment*/ 8, /*isStore*/ true) .first; Value *VrSrcPtr = IRB.CreateInBoundsGEP( @@ -3588,25 +3784,25 @@ struct VarArgAArch64Helper : public VarArgHelper { VrRegSaveAreaShadowPtrOff); Value *VrCopySize = IRB.CreateSub(VrArgSize, VrRegSaveAreaShadowPtrOff); - IRB.CreateMemCpy(VrRegSaveAreaShadowPtr, VrSrcPtr, VrCopySize, 8); + IRB.CreateMemCpy(VrRegSaveAreaShadowPtr, 8, VrSrcPtr, 8, VrCopySize); // And finally for remaining arguments. Value *StackSaveAreaShadowPtr = MSV.getShadowOriginPtr(StackSaveAreaPtr, IRB, IRB.getInt8Ty(), - /*Alignment*/ 16) + /*Alignment*/ 16, /*isStore*/ true) .first; Value *StackSrcPtr = IRB.CreateInBoundsGEP(IRB.getInt8Ty(), VAArgTLSCopy, IRB.getInt32(AArch64VAEndOffset)); - IRB.CreateMemCpy(StackSaveAreaShadowPtr, StackSrcPtr, - VAArgOverflowSize, 16); + IRB.CreateMemCpy(StackSaveAreaShadowPtr, 16, StackSrcPtr, 16, + VAArgOverflowSize); } } }; -/// \brief PowerPC64-specific implementation of VarArgHelper. +/// PowerPC64-specific implementation of VarArgHelper. struct VarArgPowerPC64Helper : public VarArgHelper { Function &F; MemorySanitizer &MS; @@ -3657,9 +3853,10 @@ struct VarArgPowerPC64Helper : public VarArgHelper { VAArgOffset - VAArgBase); Value *AShadowPtr, *AOriginPtr; std::tie(AShadowPtr, AOriginPtr) = MSV.getShadowOriginPtr( - A, IRB, IRB.getInt8Ty(), kShadowTLSAlignment); + A, IRB, IRB.getInt8Ty(), kShadowTLSAlignment, /*isStore*/ false); - IRB.CreateMemCpy(Base, AShadowPtr, ArgSize, kShadowTLSAlignment); + IRB.CreateMemCpy(Base, kShadowTLSAlignment, AShadowPtr, + kShadowTLSAlignment, ArgSize); } VAArgOffset += alignTo(ArgSize, 8); } else { @@ -3704,7 +3901,7 @@ struct VarArgPowerPC64Helper : public VarArgHelper { IRB.CreateStore(TotalVAArgSize, MS.VAArgOverflowSizeTLS); } - /// \brief Compute the shadow address for a given va_arg. + /// Compute the shadow address for a given va_arg. Value *getShadowPtrForVAArgument(Type *Ty, IRBuilder<> &IRB, int ArgOffset) { Value *Base = IRB.CreatePointerCast(MS.VAArgTLS, MS.IntptrTy); @@ -3719,8 +3916,8 @@ struct VarArgPowerPC64Helper : public VarArgHelper { Value *VAListTag = I.getArgOperand(0); Value *ShadowPtr, *OriginPtr; unsigned Alignment = 8; - std::tie(ShadowPtr, OriginPtr) = - MSV.getShadowOriginPtr(VAListTag, IRB, IRB.getInt8Ty(), Alignment); + std::tie(ShadowPtr, OriginPtr) = MSV.getShadowOriginPtr( + VAListTag, IRB, IRB.getInt8Ty(), Alignment, /*isStore*/ true); IRB.CreateMemSet(ShadowPtr, Constant::getNullValue(IRB.getInt8Ty()), /* size */ 8, Alignment, false); } @@ -3730,8 +3927,8 @@ struct VarArgPowerPC64Helper : public VarArgHelper { Value *VAListTag = I.getArgOperand(0); Value *ShadowPtr, *OriginPtr; unsigned Alignment = 8; - std::tie(ShadowPtr, OriginPtr) = - MSV.getShadowOriginPtr(VAListTag, IRB, IRB.getInt8Ty(), Alignment); + std::tie(ShadowPtr, OriginPtr) = MSV.getShadowOriginPtr( + VAListTag, IRB, IRB.getInt8Ty(), Alignment, /*isStore*/ true); // Unpoison the whole __va_list_tag. // FIXME: magic ABI constants. IRB.CreateMemSet(ShadowPtr, Constant::getNullValue(IRB.getInt8Ty()), @@ -3741,7 +3938,7 @@ struct VarArgPowerPC64Helper : public VarArgHelper { void finalizeInstrumentation() override { assert(!VAArgSize && !VAArgTLSCopy && "finalizeInstrumentation called twice"); - IRBuilder<> IRB(F.getEntryBlock().getFirstNonPHI()); + IRBuilder<> IRB(MSV.ActualFnStart->getFirstNonPHI()); VAArgSize = IRB.CreateLoad(MS.VAArgOverflowSizeTLS); Value *CopySize = IRB.CreateAdd(ConstantInt::get(MS.IntptrTy, 0), VAArgSize); @@ -3750,7 +3947,7 @@ struct VarArgPowerPC64Helper : public VarArgHelper { // If there is a va_start in this function, make a backup copy of // va_arg_tls somewhere in the function entry block. VAArgTLSCopy = IRB.CreateAlloca(Type::getInt8Ty(*MS.C), CopySize); - IRB.CreateMemCpy(VAArgTLSCopy, MS.VAArgTLS, CopySize, 8); + IRB.CreateMemCpy(VAArgTLSCopy, 8, MS.VAArgTLS, 8, CopySize); } // Instrument va_start. @@ -3760,20 +3957,21 @@ struct VarArgPowerPC64Helper : public VarArgHelper { IRBuilder<> IRB(OrigInst->getNextNode()); Value *VAListTag = OrigInst->getArgOperand(0); Value *RegSaveAreaPtrPtr = - IRB.CreateIntToPtr(IRB.CreatePtrToInt(VAListTag, MS.IntptrTy), - Type::getInt64PtrTy(*MS.C)); + IRB.CreateIntToPtr(IRB.CreatePtrToInt(VAListTag, MS.IntptrTy), + PointerType::get(Type::getInt64PtrTy(*MS.C), 0)); Value *RegSaveAreaPtr = IRB.CreateLoad(RegSaveAreaPtrPtr); Value *RegSaveAreaShadowPtr, *RegSaveAreaOriginPtr; unsigned Alignment = 8; std::tie(RegSaveAreaShadowPtr, RegSaveAreaOriginPtr) = MSV.getShadowOriginPtr(RegSaveAreaPtr, IRB, IRB.getInt8Ty(), - Alignment); - IRB.CreateMemCpy(RegSaveAreaShadowPtr, VAArgTLSCopy, CopySize, Alignment); + Alignment, /*isStore*/ true); + IRB.CreateMemCpy(RegSaveAreaShadowPtr, Alignment, VAArgTLSCopy, Alignment, + CopySize); } } }; -/// \brief A no-op implementation of VarArgHelper. +/// A no-op implementation of VarArgHelper. struct VarArgNoOpHelper : public VarArgHelper { VarArgNoOpHelper(Function &F, MemorySanitizer &MS, MemorySanitizerVisitor &MSV) {} @@ -3796,8 +3994,7 @@ static VarArgHelper *CreateVarArgHelper(Function &Func, MemorySanitizer &Msan, Triple TargetTriple(Func.getParent()->getTargetTriple()); if (TargetTriple.getArch() == Triple::x86_64) return new VarArgAMD64Helper(Func, Msan, Visitor); - else if (TargetTriple.getArch() == Triple::mips64 || - TargetTriple.getArch() == Triple::mips64el) + else if (TargetTriple.isMIPS64()) return new VarArgMIPS64Helper(Func, Msan, Visitor); else if (TargetTriple.getArch() == Triple::aarch64) return new VarArgAArch64Helper(Func, Msan, Visitor); diff --git a/lib/Transforms/Instrumentation/PGOInstrumentation.cpp b/lib/Transforms/Instrumentation/PGOInstrumentation.cpp index cb4b3a9c2545..307b7eaa2196 100644 --- a/lib/Transforms/Instrumentation/PGOInstrumentation.cpp +++ b/lib/Transforms/Instrumentation/PGOInstrumentation.cpp @@ -48,7 +48,7 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Transforms/PGOInstrumentation.h" +#include "llvm/Transforms/Instrumentation/PGOInstrumentation.h" #include "CFGMST.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/ArrayRef.h" @@ -119,6 +119,7 @@ #include using namespace llvm; +using ProfileCount = Function::ProfileCount; #define DEBUG_TYPE "pgo-instrumentation" @@ -223,8 +224,8 @@ static cl::opt EmitBranchProbability("pgo-emit-branch-prob", cl::init(false), cl::Hidden, cl::desc("When this option is on, the annotated " "branch probability will be emitted as " - " optimization remarks: -Rpass-analysis=" - "pgo-instr-use")); + "optimization remarks: -{Rpass|" + "pass-remarks}=pgo-instrumentation")); // Command line option to turn on CFG dot dump after profile annotation. // Defined in Analysis/BlockFrequencyInfo.cpp: -pgo-view-counts @@ -448,7 +449,7 @@ ModulePass *llvm::createPGOInstrumentationUseLegacyPass(StringRef Filename) { namespace { -/// \brief An MST based instrumentation for PGO +/// An MST based instrumentation for PGO /// /// Implements a Minimum Spanning Tree (MST) based instrumentation for PGO /// in the function level. @@ -545,7 +546,7 @@ public: computeCFGHash(); if (!ComdatMembers.empty()) renameComdatFunction(); - DEBUG(dumpInfo("after CFGMST")); + LLVM_DEBUG(dumpInfo("after CFGMST")); NumOfPGOBB += MST.BBInfos.size(); for (auto &E : MST.AllEdges) { @@ -595,12 +596,12 @@ void FuncPGOInstrumentation::computeCFGHash() { FunctionHash = (uint64_t)SIVisitor.getNumOfSelectInsts() << 56 | (uint64_t)ValueSites[IPVK_IndirectCallTarget].size() << 48 | (uint64_t)MST.AllEdges.size() << 32 | JC.getCRC(); - DEBUG(dbgs() << "Function Hash Computation for " << F.getName() << ":\n" - << " CRC = " << JC.getCRC() - << ", Selects = " << SIVisitor.getNumOfSelectInsts() - << ", Edges = " << MST.AllEdges.size() - << ", ICSites = " << ValueSites[IPVK_IndirectCallTarget].size() - << ", Hash = " << FunctionHash << "\n";); + LLVM_DEBUG(dbgs() << "Function Hash Computation for " << F.getName() << ":\n" + << " CRC = " << JC.getCRC() + << ", Selects = " << SIVisitor.getNumOfSelectInsts() + << ", Edges = " << MST.AllEdges.size() << ", ICSites = " + << ValueSites[IPVK_IndirectCallTarget].size() + << ", Hash = " << FunctionHash << "\n";); } // Check if we can safely rename this Comdat function. @@ -701,8 +702,8 @@ BasicBlock *FuncPGOInstrumentation::getInstrBB(Edge *E) { // For a critical edge, we have to split. Instrument the newly // created BB. NumOfPGOSplit++; - DEBUG(dbgs() << "Split critical edge: " << getBBInfo(SrcBB).Index << " --> " - << getBBInfo(DestBB).Index << "\n"); + LLVM_DEBUG(dbgs() << "Split critical edge: " << getBBInfo(SrcBB).Index + << " --> " << getBBInfo(DestBB).Index << "\n"); unsigned SuccNum = GetSuccessorNumber(SrcBB, DestBB); BasicBlock *InstrBB = SplitCriticalEdge(TI, SuccNum); assert(InstrBB && "Critical edge is not split"); @@ -752,8 +753,8 @@ static void instrumentOneFunc( for (auto &I : FuncInfo.ValueSites[IPVK_IndirectCallTarget]) { CallSite CS(I); Value *Callee = CS.getCalledValue(); - DEBUG(dbgs() << "Instrument one indirect call: CallSite Index = " - << NumIndirectCallSites << "\n"); + LLVM_DEBUG(dbgs() << "Instrument one indirect call: CallSite Index = " + << NumIndirectCallSites << "\n"); IRBuilder<> Builder(I); assert(Builder.GetInsertPoint() != I->getParent()->end() && "Cannot get the Instrumentation point"); @@ -861,7 +862,7 @@ public: // Set the branch weights based on the count values. void setBranchWeights(); - // Annotate the value profile call sites all all value kind. + // Annotate the value profile call sites for all value kind. void annotateValueSites(); // Annotate the value profile call sites for one value kind. @@ -1041,14 +1042,14 @@ bool PGOUseFunc::readCounters(IndexedInstrProfReader *PGOReader) { std::vector &CountFromProfile = ProfileRecord.Counts; NumOfPGOFunc++; - DEBUG(dbgs() << CountFromProfile.size() << " counts\n"); + LLVM_DEBUG(dbgs() << CountFromProfile.size() << " counts\n"); uint64_t ValueSum = 0; for (unsigned I = 0, S = CountFromProfile.size(); I < S; I++) { - DEBUG(dbgs() << " " << I << ": " << CountFromProfile[I] << "\n"); + LLVM_DEBUG(dbgs() << " " << I << ": " << CountFromProfile[I] << "\n"); ValueSum += CountFromProfile[I]; } - DEBUG(dbgs() << "SUM = " << ValueSum << "\n"); + LLVM_DEBUG(dbgs() << "SUM = " << ValueSum << "\n"); getBBInfo(nullptr).UnknownCountOutEdge = 2; getBBInfo(nullptr).UnknownCountInEdge = 2; @@ -1128,7 +1129,7 @@ void PGOUseFunc::populateCounters() { } } - DEBUG(dbgs() << "Populate counts in " << NumPasses << " passes.\n"); + LLVM_DEBUG(dbgs() << "Populate counts in " << NumPasses << " passes.\n"); #ifndef NDEBUG // Assert every BB has a valid counter. for (auto &BB : F) { @@ -1139,7 +1140,7 @@ void PGOUseFunc::populateCounters() { } #endif uint64_t FuncEntryCount = getBBInfo(&*F.begin()).CountValue; - F.setEntryCount(FuncEntryCount); + F.setEntryCount(ProfileCount(FuncEntryCount, Function::PCT_Real)); uint64_t FuncMaxCount = FuncEntryCount; for (auto &BB : F) { auto BI = findBBInfo(&BB); @@ -1153,13 +1154,13 @@ void PGOUseFunc::populateCounters() { FuncInfo.SIVisitor.annotateSelects(F, this, &CountPosition); assert(CountPosition == ProfileCountSize); - DEBUG(FuncInfo.dumpInfo("after reading profile.")); + LLVM_DEBUG(FuncInfo.dumpInfo("after reading profile.")); } // Assign the scaled count values to the BB with multiple out edges. void PGOUseFunc::setBranchWeights() { // Generate MD_prof metadata for every branch instruction. - DEBUG(dbgs() << "\nSetting branch weights.\n"); + LLVM_DEBUG(dbgs() << "\nSetting branch weights.\n"); for (auto &BB : F) { TerminatorInst *TI = BB.getTerminator(); if (TI->getNumSuccessors() < 2) @@ -1200,7 +1201,7 @@ static bool isIndirectBrTarget(BasicBlock *BB) { } void PGOUseFunc::annotateIrrLoopHeaderWeights() { - DEBUG(dbgs() << "\nAnnotating irreducible loop header weights.\n"); + LLVM_DEBUG(dbgs() << "\nAnnotating irreducible loop header weights.\n"); // Find irr loop headers for (auto &BB : F) { // As a heuristic also annotate indrectbr targets as they have a high chance @@ -1333,9 +1334,9 @@ void PGOUseFunc::annotateValueSites(uint32_t Kind) { } for (auto &I : ValueSites) { - DEBUG(dbgs() << "Read one value site profile (kind = " << Kind - << "): Index = " << ValueSiteIndex << " out of " - << NumValueSites << "\n"); + LLVM_DEBUG(dbgs() << "Read one value site profile (kind = " << Kind + << "): Index = " << ValueSiteIndex << " out of " + << NumValueSites << "\n"); annotateValueSite(*M, *I, ProfileRecord, static_cast(Kind), ValueSiteIndex, Kind == IPVK_MemOPSize ? MaxNumMemOPAnnotations @@ -1431,7 +1432,7 @@ static bool annotateAllFunctions( Module &M, StringRef ProfileFileName, function_ref LookupBPI, function_ref LookupBFI) { - DEBUG(dbgs() << "Read in profile counters: "); + LLVM_DEBUG(dbgs() << "Read in profile counters: "); auto &Ctx = M.getContext(); // Read the counter array from file. auto ReaderOrErr = IndexedInstrProfReader::create(ProfileFileName); @@ -1517,12 +1518,13 @@ static bool annotateAllFunctions( // inconsistent MST between prof-gen and prof-use. for (auto &F : HotFunctions) { F->addFnAttr(Attribute::InlineHint); - DEBUG(dbgs() << "Set inline attribute to function: " << F->getName() - << "\n"); + LLVM_DEBUG(dbgs() << "Set inline attribute to function: " << F->getName() + << "\n"); } for (auto &F : ColdFunctions) { F->addFnAttr(Attribute::Cold); - DEBUG(dbgs() << "Set cold attribute to function: " << F->getName() << "\n"); + LLVM_DEBUG(dbgs() << "Set cold attribute to function: " << F->getName() + << "\n"); } return true; } @@ -1585,22 +1587,25 @@ void llvm::setProfMetadata(Module *M, Instruction *TI, for (const auto &ECI : EdgeCounts) Weights.push_back(scaleBranchCount(ECI, Scale)); - DEBUG(dbgs() << "Weight is: "; - for (const auto &W : Weights) { dbgs() << W << " "; } - dbgs() << "\n";); + LLVM_DEBUG(dbgs() << "Weight is: "; for (const auto &W + : Weights) { + dbgs() << W << " "; + } dbgs() << "\n";); TI->setMetadata(LLVMContext::MD_prof, MDB.createBranchWeights(Weights)); if (EmitBranchProbability) { std::string BrCondStr = getBranchCondString(TI); if (BrCondStr.empty()) return; - unsigned WSum = - std::accumulate(Weights.begin(), Weights.end(), 0, - [](unsigned w1, unsigned w2) { return w1 + w2; }); + uint64_t WSum = + std::accumulate(Weights.begin(), Weights.end(), (uint64_t)0, + [](uint64_t w1, uint64_t w2) { return w1 + w2; }); uint64_t TotalCount = - std::accumulate(EdgeCounts.begin(), EdgeCounts.end(), 0, + std::accumulate(EdgeCounts.begin(), EdgeCounts.end(), (uint64_t)0, [](uint64_t c1, uint64_t c2) { return c1 + c2; }); - BranchProbability BP(Weights[0], WSum); + Scale = calculateCountScale(WSum); + BranchProbability BP(scaleBranchCount(Weights[0], Scale), + scaleBranchCount(WSum, Scale)); std::string BranchProbStr; raw_string_ostream OS(BranchProbStr); OS << BP; diff --git a/lib/Transforms/Instrumentation/PGOMemOPSizeOpt.cpp b/lib/Transforms/Instrumentation/PGOMemOPSizeOpt.cpp index 95eb3680403a..2c71e75dadcc 100644 --- a/lib/Transforms/Instrumentation/PGOMemOPSizeOpt.cpp +++ b/lib/Transforms/Instrumentation/PGOMemOPSizeOpt.cpp @@ -25,6 +25,8 @@ #include "llvm/IR/BasicBlock.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/DomTreeUpdater.h" +#include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/InstVisitor.h" @@ -44,7 +46,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include "llvm/Transforms/Instrumentation.h" -#include "llvm/Transforms/PGOInstrumentation.h" +#include "llvm/Transforms/Instrumentation/PGOInstrumentation.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include #include @@ -112,6 +114,7 @@ private: AU.addRequired(); AU.addRequired(); AU.addPreserved(); + AU.addPreserved(); } }; } // end anonymous namespace @@ -133,8 +136,8 @@ namespace { class MemOPSizeOpt : public InstVisitor { public: MemOPSizeOpt(Function &Func, BlockFrequencyInfo &BFI, - OptimizationRemarkEmitter &ORE) - : Func(Func), BFI(BFI), ORE(ORE), Changed(false) { + OptimizationRemarkEmitter &ORE, DominatorTree *DT) + : Func(Func), BFI(BFI), ORE(ORE), DT(DT), Changed(false) { ValueDataArray = llvm::make_unique(MemOPMaxVersion + 2); // Get the MemOPSize range information from option MemOPSizeRange, @@ -151,8 +154,9 @@ public: if (perform(MI)) { Changed = true; ++NumOfPGOMemOPOpt; - DEBUG(dbgs() << "MemOP call: " << MI->getCalledFunction()->getName() - << "is Transformed.\n"); + LLVM_DEBUG(dbgs() << "MemOP call: " + << MI->getCalledFunction()->getName() + << "is Transformed.\n"); } } } @@ -169,6 +173,7 @@ private: Function &Func; BlockFrequencyInfo &BFI; OptimizationRemarkEmitter &ORE; + DominatorTree *DT; bool Changed; std::vector WorkList; // Start of the previse range. @@ -245,9 +250,9 @@ bool MemOPSizeOpt::perform(MemIntrinsic *MI) { } ArrayRef VDs(ValueDataArray.get(), NumVals); - DEBUG(dbgs() << "Read one memory intrinsic profile with count " << ActualCount - << "\n"); - DEBUG( + LLVM_DEBUG(dbgs() << "Read one memory intrinsic profile with count " + << ActualCount << "\n"); + LLVM_DEBUG( for (auto &VD : VDs) { dbgs() << " (" << VD.Value << "," << VD.Count << ")\n"; }); @@ -260,8 +265,8 @@ bool MemOPSizeOpt::perform(MemIntrinsic *MI) { TotalCount = ActualCount; if (MemOPScaleCount) - DEBUG(dbgs() << "Scale counts: numerator = " << ActualCount - << " denominator = " << SavedTotalCount << "\n"); + LLVM_DEBUG(dbgs() << "Scale counts: numerator = " << ActualCount + << " denominator = " << SavedTotalCount << "\n"); // Keeping track of the count of the default case: uint64_t RemainCount = TotalCount; @@ -310,9 +315,9 @@ bool MemOPSizeOpt::perform(MemIntrinsic *MI) { uint64_t SumForOpt = TotalCount - RemainCount; - DEBUG(dbgs() << "Optimize one memory intrinsic call to " << Version - << " Versions (covering " << SumForOpt << " out of " - << TotalCount << ")\n"); + LLVM_DEBUG(dbgs() << "Optimize one memory intrinsic call to " << Version + << " Versions (covering " << SumForOpt << " out of " + << TotalCount << ")\n"); // mem_op(..., size) // ==> @@ -331,19 +336,20 @@ bool MemOPSizeOpt::perform(MemIntrinsic *MI) { // merge_bb: BasicBlock *BB = MI->getParent(); - DEBUG(dbgs() << "\n\n== Basic Block Before ==\n"); - DEBUG(dbgs() << *BB << "\n"); + LLVM_DEBUG(dbgs() << "\n\n== Basic Block Before ==\n"); + LLVM_DEBUG(dbgs() << *BB << "\n"); auto OrigBBFreq = BFI.getBlockFreq(BB); - BasicBlock *DefaultBB = SplitBlock(BB, MI); + BasicBlock *DefaultBB = SplitBlock(BB, MI, DT); BasicBlock::iterator It(*MI); ++It; assert(It != DefaultBB->end()); - BasicBlock *MergeBB = SplitBlock(DefaultBB, &(*It)); + BasicBlock *MergeBB = SplitBlock(DefaultBB, &(*It), DT); MergeBB->setName("MemOP.Merge"); BFI.setBlockFreq(MergeBB, OrigBBFreq.getFrequency()); DefaultBB->setName("MemOP.Default"); + DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager); auto &Ctx = Func.getContext(); IRBuilder<> IRB(BB); BB->getTerminator()->eraseFromParent(); @@ -358,7 +364,11 @@ bool MemOPSizeOpt::perform(MemIntrinsic *MI) { annotateValueSite(*Func.getParent(), *MI, VDs.slice(Version), SavedRemainCount, IPVK_MemOPSize, NumVals); - DEBUG(dbgs() << "\n\n== Basic Block After==\n"); + LLVM_DEBUG(dbgs() << "\n\n== Basic Block After==\n"); + + std::vector Updates; + if (DT) + Updates.reserve(2 * SizeIds.size()); for (uint64_t SizeId : SizeIds) { BasicBlock *CaseBB = BasicBlock::Create( @@ -374,13 +384,20 @@ bool MemOPSizeOpt::perform(MemIntrinsic *MI) { IRBuilder<> IRBCase(CaseBB); IRBCase.CreateBr(MergeBB); SI->addCase(CaseSizeId, CaseBB); - DEBUG(dbgs() << *CaseBB << "\n"); + if (DT) { + Updates.push_back({DominatorTree::Insert, CaseBB, MergeBB}); + Updates.push_back({DominatorTree::Insert, BB, CaseBB}); + } + LLVM_DEBUG(dbgs() << *CaseBB << "\n"); } + DTU.applyUpdates(Updates); + Updates.clear(); + setProfMetadata(Func.getParent(), SI, CaseCounts, MaxCount); - DEBUG(dbgs() << *BB << "\n"); - DEBUG(dbgs() << *DefaultBB << "\n"); - DEBUG(dbgs() << *MergeBB << "\n"); + LLVM_DEBUG(dbgs() << *BB << "\n"); + LLVM_DEBUG(dbgs() << *DefaultBB << "\n"); + LLVM_DEBUG(dbgs() << *MergeBB << "\n"); ORE.emit([&]() { using namespace ore; @@ -396,13 +413,14 @@ bool MemOPSizeOpt::perform(MemIntrinsic *MI) { } // namespace static bool PGOMemOPSizeOptImpl(Function &F, BlockFrequencyInfo &BFI, - OptimizationRemarkEmitter &ORE) { + OptimizationRemarkEmitter &ORE, + DominatorTree *DT) { if (DisableMemOPOPT) return false; if (F.hasFnAttribute(Attribute::OptimizeForSize)) return false; - MemOPSizeOpt MemOPSizeOpt(F, BFI, ORE); + MemOPSizeOpt MemOPSizeOpt(F, BFI, ORE, DT); MemOPSizeOpt.perform(); return MemOPSizeOpt.isChanged(); } @@ -411,7 +429,9 @@ bool PGOMemOPSizeOptLegacyPass::runOnFunction(Function &F) { BlockFrequencyInfo &BFI = getAnalysis().getBFI(); auto &ORE = getAnalysis().getORE(); - return PGOMemOPSizeOptImpl(F, BFI, ORE); + auto *DTWP = getAnalysisIfAvailable(); + DominatorTree *DT = DTWP ? &DTWP->getDomTree() : nullptr; + return PGOMemOPSizeOptImpl(F, BFI, ORE, DT); } namespace llvm { @@ -421,11 +441,13 @@ PreservedAnalyses PGOMemOPSizeOpt::run(Function &F, FunctionAnalysisManager &FAM) { auto &BFI = FAM.getResult(F); auto &ORE = FAM.getResult(F); - bool Changed = PGOMemOPSizeOptImpl(F, BFI, ORE); + auto *DT = FAM.getCachedResult(F); + bool Changed = PGOMemOPSizeOptImpl(F, BFI, ORE, DT); if (!Changed) return PreservedAnalyses::all(); auto PA = PreservedAnalyses(); PA.preserve(); + PA.preserve(); return PA; } } // namespace llvm diff --git a/lib/Transforms/Instrumentation/SanitizerCoverage.cpp b/lib/Transforms/Instrumentation/SanitizerCoverage.cpp index d950e2e730f2..a4dd48c8dd6a 100644 --- a/lib/Transforms/Instrumentation/SanitizerCoverage.cpp +++ b/lib/Transforms/Instrumentation/SanitizerCoverage.cpp @@ -35,7 +35,6 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Instrumentation.h" -#include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/ModuleUtils.h" @@ -243,6 +242,7 @@ private: GlobalVariable *Function8bitCounterArray; // for inline-8bit-counters. GlobalVariable *FunctionPCsArray; // for pc-table. SmallVector GlobalsToAppendToUsed; + SmallVector GlobalsToAppendToCompilerUsed; SanitizerCoverageOptions Options; }; @@ -405,6 +405,7 @@ bool SanitizerCoverageModule::runOnModule(Module &M) { // so we need to prevent them from being dead stripped. if (TargetTriple.isOSBinFormatMachO()) appendToUsed(M, GlobalsToAppendToUsed); + appendToCompilerUsed(M, GlobalsToAppendToCompilerUsed); return true; } @@ -480,6 +481,8 @@ bool SanitizerCoverageModule::runOnFunction(Function &F) { if (F.getName() == "__local_stdio_printf_options" || F.getName() == "__local_stdio_scanf_options") return false; + if (isa(F.getEntryBlock().getTerminator())) + return false; // Don't instrument functions using SEH for now. Splitting basic blocks like // we do for coverage breaks WinEHPrepare. // FIXME: Remove this when SEH no longer uses landingpad pattern matching. @@ -592,11 +595,15 @@ void SanitizerCoverageModule::CreateFunctionLocalArrays( if (Options.Inline8bitCounters) { Function8bitCounterArray = CreateFunctionLocalArrayInSection( AllBlocks.size(), F, Int8Ty, SanCovCountersSectionName); - GlobalsToAppendToUsed.push_back(Function8bitCounterArray); + GlobalsToAppendToCompilerUsed.push_back(Function8bitCounterArray); + MDNode *MD = MDNode::get(F.getContext(), ValueAsMetadata::get(&F)); + Function8bitCounterArray->addMetadata(LLVMContext::MD_associated, *MD); } if (Options.PCTable) { FunctionPCsArray = CreatePCArray(F, AllBlocks); - GlobalsToAppendToUsed.push_back(FunctionPCsArray); + GlobalsToAppendToCompilerUsed.push_back(FunctionPCsArray); + MDNode *MD = MDNode::get(F.getContext(), ValueAsMetadata::get(&F)); + FunctionPCsArray->addMetadata(LLVMContext::MD_associated, *MD); } } @@ -659,11 +666,11 @@ void SanitizerCoverageModule::InjectTraceForSwitch( C = ConstantExpr::getCast(CastInst::ZExt, It.getCaseValue(), Int64Ty); Initializers.push_back(C); } - std::sort(Initializers.begin() + 2, Initializers.end(), - [](const Constant *A, const Constant *B) { - return cast(A)->getLimitedValue() < - cast(B)->getLimitedValue(); - }); + llvm::sort(Initializers.begin() + 2, Initializers.end(), + [](const Constant *A, const Constant *B) { + return cast(A)->getLimitedValue() < + cast(B)->getLimitedValue(); + }); ArrayType *ArrayOfInt64Ty = ArrayType::get(Int64Ty, Initializers.size()); GlobalVariable *GV = new GlobalVariable( *CurModule, ArrayOfInt64Ty, false, GlobalVariable::InternalLinkage, diff --git a/lib/Transforms/Instrumentation/ThreadSanitizer.cpp b/lib/Transforms/Instrumentation/ThreadSanitizer.cpp index ec6904486e10..fa1e5a157a0f 100644 --- a/lib/Transforms/Instrumentation/ThreadSanitizer.cpp +++ b/lib/Transforms/Instrumentation/ThreadSanitizer.cpp @@ -19,13 +19,14 @@ // The rest is handled by the run-time library. //===----------------------------------------------------------------------===// -#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Analysis/CaptureTracking.h" #include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/Transforms/Utils/Local.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Function.h" @@ -44,7 +45,6 @@ #include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/EscapeEnumerator.h" -#include "llvm/Transforms/Utils/Local.h" #include "llvm/Transforms/Utils/ModuleUtils.h" using namespace llvm; @@ -339,7 +339,7 @@ bool ThreadSanitizer::addrPointsToConstantData(Value *Addr) { void ThreadSanitizer::chooseInstructionsToInstrument( SmallVectorImpl &Local, SmallVectorImpl &All, const DataLayout &DL) { - SmallSet WriteTargets; + SmallPtrSet WriteTargets; // Iterate from the end. for (Instruction *I : reverse(Local)) { if (StoreInst *Store = dyn_cast(I)) { @@ -502,7 +502,7 @@ bool ThreadSanitizer::instrumentLoadOrStore(Instruction *I, if (Idx < 0) return false; if (IsWrite && isVtableAccess(I)) { - DEBUG(dbgs() << " VPTR : " << *I << "\n"); + LLVM_DEBUG(dbgs() << " VPTR : " << *I << "\n"); Value *StoredValue = cast(I)->getValueOperand(); // StoredValue may be a vector type if we are storing several vptrs at once. // In this case, just take the first element of the vector since this is -- cgit v1.3