diff --git a/lib/Transforms/Instrumentation/SanitizerCoverage.cpp b/lib/Transforms/Instrumentation/SanitizerCoverage.cpp index 8600f9183e0..bf04bb17fc4 100644 --- a/lib/Transforms/Instrumentation/SanitizerCoverage.cpp +++ b/lib/Transforms/Instrumentation/SanitizerCoverage.cpp @@ -112,7 +112,7 @@ class SanitizerCoverageModule : public ModulePass { Type *IntptrTy; LLVMContext *C; - SmallVector Guards; + GlobalVariable *GuardArray; int CoverageLevel; }; @@ -137,7 +137,6 @@ bool SanitizerCoverageModule::runOnModule(Module &M) { Type *VoidTy = Type::getVoidTy(*C); IRBuilder<> IRB(*C); Type *Int32PtrTy = PointerType::getUnqual(IRB.getInt32Ty()); - Type *Int32PtrPtrTy = PointerType::getUnqual(Int32PtrTy); Function *CtorFunc = Function::Create(FunctionType::get(VoidTy, false), @@ -151,7 +150,7 @@ bool SanitizerCoverageModule::runOnModule(Module &M) { kSanCovIndirCallName, VoidTy, IntptrTy, IntptrTy, nullptr)); SanCovModuleInit = checkInterfaceFunction( M.getOrInsertFunction(kSanCovModuleInitName, Type::getVoidTy(*C), - Int32PtrPtrTy, IntptrTy, nullptr)); + Int32PtrTy, IntptrTy, nullptr)); SanCovModuleInit->setLinkage(Function::ExternalLinkage); // We insert an empty inline asm after cov callbacks to avoid callback merge. EmptyAsm = InlineAsm::get(FunctionType::get(IRB.getVoidTy(), false), @@ -165,18 +164,34 @@ bool SanitizerCoverageModule::runOnModule(Module &M) { M.getOrInsertFunction(kSanCovTraceBB, VoidTy, IntptrTy, nullptr)); } + // At this point we create a dummy array of guards because we don't + // know how many elements we will need. + Type *Int32Ty = IRB.getInt32Ty(); + GuardArray = + new GlobalVariable(M, Int32Ty, false, GlobalValue::ExternalLinkage, + nullptr, "__sancov_gen_cov_tmp"); + for (auto &F : M) runOnFunction(F); - ArrayType *ArrayOfInt32PtrTy = ArrayType::get(Int32PtrTy, Guards.size()); + // Now we know how many elements we need. Create an array of guards + // with one extra element at the beginning for the size. + Type *Int32ArrayNTy = + ArrayType::get(Int32Ty, SanCovFunction->getNumUses() + 1); + GlobalVariable *RealGuardArray = new GlobalVariable( + M, Int32ArrayNTy, false, GlobalValue::PrivateLinkage, + Constant::getNullValue(Int32ArrayNTy), "__sancov_gen_cov"); + + // Replace the dummy array with the real one. + GuardArray->replaceAllUsesWith( + IRB.CreatePointerCast(RealGuardArray, Int32PtrTy)); + GuardArray->eraseFromParent(); + + // Call __sanitizer_cov_module_init IRB.SetInsertPoint(CtorFunc->getEntryBlock().getTerminator()); - GlobalVariable *AllGuards = new GlobalVariable( - M, ArrayOfInt32PtrTy, false, GlobalVariable::InternalLinkage, - ConstantArray::get(ArrayOfInt32PtrTy, Guards), ""); - assert(SanCovFunction->getNumUses() == Guards.size()); IRB.CreateCall2(SanCovModuleInit, - IRB.CreatePointerCast(AllGuards, Int32PtrPtrTy), - ConstantInt::get(IntptrTy, Guards.size())); + IRB.CreatePointerCast(RealGuardArray, Int32PtrTy), + ConstantInt::get(IntptrTy, SanCovFunction->getNumUses())); return true; } @@ -282,24 +297,25 @@ void SanitizerCoverageModule::InjectCoverageAtBlock(Function &F, : IP->getDebugLoc(); IRBuilder<> IRB(IP); IRB.SetCurrentDebugLocation(EntryLoc); - Type *Int32Ty = IRB.getInt32Ty(); - GlobalVariable *Guard = new GlobalVariable( - *F.getParent(), Int32Ty, false, GlobalValue::PrivateLinkage, - Constant::getNullValue(Int32Ty), "__sancov_gen_cov_" + F.getName()); - LoadInst *Load = IRB.CreateLoad(Guard); + SmallVector Indices; + Value *GuardP = IRB.CreateAdd( + IRB.CreatePointerCast(GuardArray, IntptrTy), + ConstantInt::get(IntptrTy, (1 + SanCovFunction->getNumUses()) * 4)); + Type *Int32PtrTy = PointerType::getUnqual(IRB.getInt32Ty()); + GuardP = IRB.CreateIntToPtr(GuardP, Int32PtrTy); + LoadInst *Load = IRB.CreateLoad(GuardP); Load->setAtomic(Monotonic); Load->setAlignment(4); Load->setMetadata(F.getParent()->getMDKindID("nosanitize"), MDNode::get(*C, None)); - Value *Cmp = IRB.CreateICmpSGE(Constant::getNullValue(Int32Ty), Load); + Value *Cmp = IRB.CreateICmpSGE(Constant::getNullValue(Load->getType()), Load); Instruction *Ins = SplitBlockAndInsertIfThen( Cmp, IP, false, MDBuilder(*C).createBranchWeights(1, 100000)); IRB.SetInsertPoint(Ins); IRB.SetCurrentDebugLocation(EntryLoc); // __sanitizer_cov gets the PC of the instruction using GET_CALLER_PC. - IRB.CreateCall(SanCovFunction, Guard); + IRB.CreateCall(SanCovFunction, GuardP); IRB.CreateCall(EmptyAsm); // Avoids callback merge. - Guards.push_back(Guard); // Save the guard for later. } char SanitizerCoverageModule::ID = 0; diff --git a/test/Instrumentation/SanitizerCoverage/coverage.ll b/test/Instrumentation/SanitizerCoverage/coverage.ll index 9a05fa8c083..77e781e5474 100644 --- a/test/Instrumentation/SanitizerCoverage/coverage.ll +++ b/test/Instrumentation/SanitizerCoverage/coverage.ll @@ -33,7 +33,7 @@ entry: ; CHECK0-NOT: call void @__sanitizer_cov_module_init( ; CHECK1-LABEL: define void @foo -; CHECK1: %0 = load atomic i32* @__sancov_gen_cov_foo monotonic, align 4, !nosanitize +; CHECK1: %0 = load atomic i32* {{.*}} monotonic, align 4, !nosanitize ; CHECK1: %1 = icmp sge i32 0, %0 ; CHECK1: br i1 %1, label %2, label %3 ; CHECK1: call void @__sanitizer_cov(i32*{{.*}})