From: Kostya Serebryany Date: Thu, 22 Nov 2012 03:18:50 +0000 (+0000) Subject: [asan] rip off the creation of global redzones from the main AddressSanitizer class... X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=b9a12ea0fd92bfdb4c6eb5af333648a618f68686;p=oota-llvm.git [asan] rip off the creation of global redzones from the main AddressSanitizer class into a separate class. The intent is to make it a separate ModulePass in the following commmits git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@168484 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/lib/Transforms/Instrumentation/AddressSanitizer.cpp index 6e4cbe54240..61ddc08dd61 100644 --- a/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -174,6 +174,15 @@ class SetOfDynamicallyInitializedGlobals { SmallSet DynInitGlobals; }; +static int MappingScale() { + return ClMappingScale ? ClMappingScale : kDefaultShadowScale; +} + +static size_t RedzoneSize() { + // Redzone used for stack and globals is at least 32 bytes. + // For scales 6 and 7, the redzone has to be 64 and 128 bytes respectively. + return std::max(32U, 1U << MappingScale()); +} /// AddressSanitizer: instrument the code in module to find memory bugs. struct AddressSanitizer : public FunctionPass { @@ -198,7 +207,6 @@ struct AddressSanitizer : public FunctionPass { bool poisonStackInFunction(Function &F); virtual bool doInitialization(Module &M); virtual bool doFinalization(Module &M); - bool insertGlobalRedzones(Module &M); static char ID; // Pass identification, replacement for typeid private: @@ -208,15 +216,14 @@ struct AddressSanitizer : public FunctionPass { return SizeInBytes; } uint64_t getAlignedSize(uint64_t SizeInBytes) { - return ((SizeInBytes + RedzoneSize - 1) - / RedzoneSize) * RedzoneSize; + size_t RZ = RedzoneSize(); + return ((SizeInBytes + RZ - 1) / RZ) * RZ; } uint64_t getAlignedAllocaSize(AllocaInst *AI) { uint64_t SizeInBytes = getAllocaSizeInBytes(AI); return getAlignedSize(SizeInBytes); } - Function *checkInterfaceFunction(Constant *FuncOrBitcast); bool ShouldInstrumentGlobal(GlobalVariable *G); void PoisonStack(const ArrayRef &AllocaVec, IRBuilder<> IRB, Value *ShadowBase, bool DoPoison); @@ -226,8 +233,6 @@ struct AddressSanitizer : public FunctionPass { LLVMContext *C; DataLayout *TD; uint64_t MappingOffset; - int MappingScale; - size_t RedzoneSize; int LongSize; Type *IntptrTy; Type *IntptrPtrTy; @@ -235,7 +240,6 @@ struct AddressSanitizer : public FunctionPass { Function *AsanInitFunction; Function *AsanStackMallocFunc, *AsanStackFreeFunc; Function *AsanHandleNoReturnFunc; - Instruction *CtorInsertBefore; OwningPtr BL; // This array is indexed by AccessIsWrite and log2(AccessSize). Function *AsanErrorCallback[2][kNumberOfAccessSizes]; @@ -243,6 +247,22 @@ struct AddressSanitizer : public FunctionPass { SetOfDynamicallyInitializedGlobals DynamicallyInitializedGlobals; }; +// FIXME: inherit this from ModulePass and actually use it as a ModulePass. +class AddressSanitizerCreateGlobalRedzonesPass { + public: + bool runOnModule(Module &M, DataLayout *TD); + private: + bool ShouldInstrumentGlobal(GlobalVariable *G); + void createInitializerPoisonCalls(Module &M, Value *FirstAddr, + Value *LastAddr); + + static char ID; // Pass identification, replacement for typeid + OwningPtr BL; + SetOfDynamicallyInitializedGlobals DynamicallyInitializedGlobals; + Type *IntptrTy; + LLVMContext *C; +}; + } // namespace char AddressSanitizer::ID = 0; @@ -278,7 +298,7 @@ static bool GlobalWasGeneratedByAsan(GlobalVariable *G) { Value *AddressSanitizer::memToShadow(Value *Shadow, IRBuilder<> &IRB) { // Shadow >> scale - Shadow = IRB.CreateLShr(Shadow, MappingScale); + Shadow = IRB.CreateLShr(Shadow, MappingScale()); if (MappingOffset == 0) return Shadow; // (Shadow >> scale) | offset @@ -396,7 +416,7 @@ void AddressSanitizer::instrumentMop(Instruction *I) { // function of AddressSanitizer. If the instrumented module defines a function // with the same name, their prototypes must match, otherwise // getOrInsertFunction returns a bitcast. -Function *AddressSanitizer::checkInterfaceFunction(Constant *FuncOrBitcast) { +static Function *checkInterfaceFunction(Constant *FuncOrBitcast) { if (isa(FuncOrBitcast)) return cast(FuncOrBitcast); FuncOrBitcast->dump(); report_fatal_error("trying to redefine an AddressSanitizer " @@ -419,7 +439,7 @@ Instruction *AddressSanitizer::generateCrashCode( Value *AddressSanitizer::createSlowPathCmp(IRBuilder<> &IRB, Value *AddrLong, Value *ShadowValue, uint32_t TypeSize) { - size_t Granularity = 1 << MappingScale; + size_t Granularity = 1 << MappingScale(); // Addr & (Granularity - 1) Value *LastAccessedByte = IRB.CreateAnd( AddrLong, ConstantInt::get(IntptrTy, Granularity - 1)); @@ -440,7 +460,7 @@ void AddressSanitizer::instrumentAddress(Instruction *OrigIns, Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy); Type *ShadowTy = IntegerType::get( - *C, std::max(8U, TypeSize >> MappingScale)); + *C, std::max(8U, TypeSize >> MappingScale())); Type *ShadowPtrTy = PointerType::get(ShadowTy, 0); Value *ShadowPtr = memToShadow(AddrLong, IRB); Value *CmpVal = Constant::getNullValue(ShadowTy); @@ -449,7 +469,7 @@ void AddressSanitizer::instrumentAddress(Instruction *OrigIns, Value *Cmp = IRB.CreateICmpNE(ShadowValue, CmpVal); size_t AccessSizeIndex = TypeSizeToSizeIndex(TypeSize); - size_t Granularity = 1 << MappingScale; + size_t Granularity = 1 << MappingScale(); TerminatorInst *CrashTerm = 0; if (ClAlwaysSlowPath || (TypeSize < 8 * Granularity)) { @@ -473,9 +493,8 @@ void AddressSanitizer::instrumentAddress(Instruction *OrigIns, Crash->setDebugLoc(OrigIns->getDebugLoc()); } -void AddressSanitizer::createInitializerPoisonCalls(Module &M, - Value *FirstAddr, - Value *LastAddr) { +void AddressSanitizerCreateGlobalRedzonesPass::createInitializerPoisonCalls( + Module &M, Value *FirstAddr, Value *LastAddr) { // We do all of our poisoning and unpoisoning within _GLOBAL__I_a. Function *GlobalInit = M.getFunction("_GLOBAL__I_a"); // If that function is not present, this TU contains no globals, or they have @@ -506,7 +525,8 @@ void AddressSanitizer::createInitializerPoisonCalls(Module &M, } } -bool AddressSanitizer::ShouldInstrumentGlobal(GlobalVariable *G) { +bool AddressSanitizerCreateGlobalRedzonesPass::ShouldInstrumentGlobal( + GlobalVariable *G) { Type *Ty = cast(G->getType())->getElementType(); DEBUG(dbgs() << "GLOBAL: " << *G << "\n"); @@ -526,7 +546,7 @@ bool AddressSanitizer::ShouldInstrumentGlobal(GlobalVariable *G) { if (G->isThreadLocal()) return false; // For now, just ignore this Alloca if the alignment is large. - if (G->getAlignment() > RedzoneSize) return false; + if (G->getAlignment() > RedzoneSize()) return false; // Ignore all the globals with the names starting with "\01L_OBJC_". // Many of those are put into the .cstring section. The linker compresses @@ -568,7 +588,13 @@ bool AddressSanitizer::ShouldInstrumentGlobal(GlobalVariable *G) { // This function replaces all global variables with new variables that have // trailing redzones. It also creates a function that poisons // redzones and inserts this function into llvm.global_ctors. -bool AddressSanitizer::insertGlobalRedzones(Module &M) { +bool AddressSanitizerCreateGlobalRedzonesPass::runOnModule(Module &M, + DataLayout *TD) { + BL.reset(new BlackList(ClBlackListFile)); + DynamicallyInitializedGlobals.Init(M); + C = &(M.getContext()); + IntptrTy = Type::getIntNTy(*C, TD->getPointerSizeInBits()); + SmallVector GlobalsToChange; for (Module::GlobalListType::iterator G = M.global_begin(), @@ -592,7 +618,10 @@ bool AddressSanitizer::insertGlobalRedzones(Module &M) { IntptrTy, NULL); SmallVector Initializers(n), DynamicInit; - IRBuilder<> IRB(CtorInsertBefore); + + Function *CtorFunc = M.getFunction(kAsanModuleCtorName); + assert(CtorFunc); + IRBuilder<> IRB(CtorFunc->getEntryBlock().getTerminator()); // The addresses of the first and last dynamically initialized globals in // this TU. Used in initialization order checking. @@ -603,8 +632,8 @@ bool AddressSanitizer::insertGlobalRedzones(Module &M) { PointerType *PtrTy = cast(G->getType()); Type *Ty = PtrTy->getElementType(); uint64_t SizeInBytes = TD->getTypeAllocSize(Ty); - uint64_t RightRedzoneSize = RedzoneSize + - (RedzoneSize - (SizeInBytes % RedzoneSize)); + size_t RZ = RedzoneSize(); + uint64_t RightRedzoneSize = RZ + (RZ - (SizeInBytes % RZ)); Type *RightRedZoneTy = ArrayType::get(IRB.getInt8Ty(), RightRedzoneSize); // Determine whether this global should be poisoned in initialization. bool GlobalHasDynamicInitializer = @@ -628,7 +657,7 @@ bool AddressSanitizer::insertGlobalRedzones(Module &M) { M, NewTy, G->isConstant(), G->getLinkage(), NewInitializer, "", G, G->getThreadLocalMode()); NewGlobal->copyAttributesFrom(G); - NewGlobal->setAlignment(RedzoneSize); + NewGlobal->setAlignment(RZ); Value *Indices2[2]; Indices2[0] = IRB.getInt32(0); @@ -717,10 +746,8 @@ bool AddressSanitizer::doInitialization(Module &M) { FunctionType::get(Type::getVoidTy(*C), false), GlobalValue::InternalLinkage, kAsanModuleCtorName, &M); BasicBlock *AsanCtorBB = BasicBlock::Create(*C, "", AsanCtorFunction); - CtorInsertBefore = ReturnInst::Create(*C, AsanCtorBB); - // call __asan_init in the module ctor. - IRBuilder<> IRB(CtorInsertBefore); + IRBuilder<> IRB(ReturnInst::Create(*C, AsanCtorBB)); AsanInitFunction = checkInterfaceFunction( M.getOrInsertFunction(kAsanInitName, IRB.getVoidTy(), NULL)); AsanInitFunction->setLinkage(Function::ExternalLinkage); @@ -766,13 +793,6 @@ bool AddressSanitizer::doInitialization(Module &M) { MappingOffset = 1ULL << ClMappingOffsetLog; } } - MappingScale = kDefaultShadowScale; - if (ClMappingScale) { - MappingScale = ClMappingScale; - } - // Redzone used for stack and globals is at least 32 bytes. - // For scales 6 and 7, the redzone has to be 64 and 128 bytes respectively. - RedzoneSize = std::max(32, (int)(1 << MappingScale)); if (ClMappingOffsetLog >= 0) { @@ -787,7 +807,7 @@ bool AddressSanitizer::doInitialization(Module &M) { if (ClMappingScale) { GlobalValue *asan_mapping_scale = new GlobalVariable(M, IntptrTy, true, GlobalValue::LinkOnceODRLinkage, - ConstantInt::get(IntptrTy, MappingScale), + ConstantInt::get(IntptrTy, MappingScale()), kAsanMappingScaleName); // Read the global, otherwise it may be optimized away. IRB.CreateLoad(asan_mapping_scale, true); @@ -801,8 +821,11 @@ bool AddressSanitizer::doInitialization(Module &M) { bool AddressSanitizer::doFinalization(Module &M) { // We transform the globals at the very end so that the optimization analysis // works on the original globals. - if (ClGlobals) - return insertGlobalRedzones(M); + if (ClGlobals) { + // FIXME: instead of doFinalization, run this as a true ModulePass. + AddressSanitizerCreateGlobalRedzonesPass Pass; + return Pass.runOnModule(M, TD); + } return false; } @@ -915,10 +938,10 @@ static uint64_t ValueForPoison(uint64_t PoisonByte, size_t ShadowRedzoneSize) { static void PoisonShadowPartialRightRedzone(uint8_t *Shadow, size_t Size, - size_t RedzoneSize, + size_t RZSize, size_t ShadowGranularity, uint8_t Magic) { - for (size_t i = 0; i < RedzoneSize; + for (size_t i = 0; i < RZSize; i+= ShadowGranularity, Shadow++) { if (i + ShadowGranularity <= Size) { *Shadow = 0; // fully addressable @@ -933,7 +956,7 @@ static void PoisonShadowPartialRightRedzone(uint8_t *Shadow, void AddressSanitizer::PoisonStack(const ArrayRef &AllocaVec, IRBuilder<> IRB, Value *ShadowBase, bool DoPoison) { - size_t ShadowRZSize = RedzoneSize >> MappingScale; + size_t ShadowRZSize = RedzoneSize() >> MappingScale(); assert(ShadowRZSize >= 1 && ShadowRZSize <= 4); Type *RZTy = Type::getIntNTy(*C, ShadowRZSize * 8); Type *RZPtrTy = PointerType::get(RZTy, 0); @@ -949,12 +972,12 @@ void AddressSanitizer::PoisonStack(const ArrayRef &AllocaVec, IRB.CreateStore(PoisonLeft, IRB.CreateIntToPtr(ShadowBase, RZPtrTy)); // poison all other red zones. - uint64_t Pos = RedzoneSize; + uint64_t Pos = RedzoneSize(); for (size_t i = 0, n = AllocaVec.size(); i < n; i++) { AllocaInst *AI = AllocaVec[i]; uint64_t SizeInBytes = getAllocaSizeInBytes(AI); uint64_t AlignedSize = getAlignedAllocaSize(AI); - assert(AlignedSize - SizeInBytes < RedzoneSize); + assert(AlignedSize - SizeInBytes < RedzoneSize()); Value *Ptr = NULL; Pos += AlignedSize; @@ -964,13 +987,13 @@ void AddressSanitizer::PoisonStack(const ArrayRef &AllocaVec, // Poison the partial redzone at right Ptr = IRB.CreateAdd( ShadowBase, ConstantInt::get(IntptrTy, - (Pos >> MappingScale) - ShadowRZSize)); - size_t AddressableBytes = RedzoneSize - (AlignedSize - SizeInBytes); + (Pos >> MappingScale()) - ShadowRZSize)); + size_t AddressableBytes = RedzoneSize() - (AlignedSize - SizeInBytes); uint32_t Poison = 0; if (DoPoison) { PoisonShadowPartialRightRedzone((uint8_t*)&Poison, AddressableBytes, - RedzoneSize, - 1ULL << MappingScale, + RedzoneSize(), + 1ULL << MappingScale(), kAsanStackPartialRedzoneMagic); } Value *PartialPoison = ConstantInt::get(RZTy, Poison); @@ -979,11 +1002,11 @@ void AddressSanitizer::PoisonStack(const ArrayRef &AllocaVec, // Poison the full redzone at right. Ptr = IRB.CreateAdd(ShadowBase, - ConstantInt::get(IntptrTy, Pos >> MappingScale)); + ConstantInt::get(IntptrTy, Pos >> MappingScale())); Value *Poison = i == AllocaVec.size() - 1 ? PoisonRight : PoisonMid; IRB.CreateStore(Poison, IRB.CreateIntToPtr(Ptr, RZPtrTy)); - Pos += RedzoneSize; + Pos += RedzoneSize(); } } @@ -1035,7 +1058,7 @@ bool AddressSanitizer::poisonStackInFunction(Function &F) { if (AI->isArrayAllocation()) continue; if (!AI->isStaticAlloca()) continue; if (!AI->getAllocatedType()->isSized()) continue; - if (AI->getAlignment() > RedzoneSize) continue; + if (AI->getAlignment() > RedzoneSize()) continue; AllocaVec.push_back(AI); uint64_t AlignedSize = getAlignedAllocaSize(AI); TotalSize += AlignedSize; @@ -1044,7 +1067,7 @@ bool AddressSanitizer::poisonStackInFunction(Function &F) { if (AllocaVec.empty()) return false; - uint64_t LocalStackSize = TotalSize + (AllocaVec.size() + 1) * RedzoneSize; + uint64_t LocalStackSize = TotalSize + (AllocaVec.size() + 1) * RedzoneSize(); bool DoStackMalloc = ClUseAfterReturn && LocalStackSize <= kMaxStackMallocSize; @@ -1056,7 +1079,7 @@ bool AddressSanitizer::poisonStackInFunction(Function &F) { Type *ByteArrayTy = ArrayType::get(IRB.getInt8Ty(), LocalStackSize); AllocaInst *MyAlloca = new AllocaInst(ByteArrayTy, "MyAlloca", InsBefore); - MyAlloca->setAlignment(RedzoneSize); + MyAlloca->setAlignment(RedzoneSize()); assert(MyAlloca->isStaticAlloca()); Value *OrigStackBase = IRB.CreatePointerCast(MyAlloca, IntptrTy); Value *LocalStackBase = OrigStackBase; @@ -1071,7 +1094,7 @@ bool AddressSanitizer::poisonStackInFunction(Function &F) { raw_svector_ostream StackDescription(StackDescriptionStorage); StackDescription << F.getName() << " " << AllocaVec.size() << " "; - uint64_t Pos = RedzoneSize; + uint64_t Pos = RedzoneSize(); // Replace Alloca instructions with base+offset. for (size_t i = 0, n = AllocaVec.size(); i < n; i++) { AllocaInst *AI = AllocaVec[i]; @@ -1080,12 +1103,12 @@ bool AddressSanitizer::poisonStackInFunction(Function &F) { StackDescription << Pos << " " << SizeInBytes << " " << Name.size() << " " << Name << " "; uint64_t AlignedSize = getAlignedAllocaSize(AI); - assert((AlignedSize % RedzoneSize) == 0); + assert((AlignedSize % RedzoneSize()) == 0); AI->replaceAllUsesWith( IRB.CreateIntToPtr( IRB.CreateAdd(LocalStackBase, ConstantInt::get(IntptrTy, Pos)), AI->getType())); - Pos += AlignedSize + RedzoneSize; + Pos += AlignedSize + RedzoneSize(); } assert(Pos == LocalStackSize);