From efa54824a36ac740618a6c0019911728bdf9633d Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Thu, 29 Sep 2016 17:43:24 +0000 Subject: [PATCH] [sanitizer-coverage/libFuzzer] make the guards for trace-pc 32-bit; create one array of guards per function, instead of one guard per BB. reorganize the code so that trace-pc-guard does not create unneeded globals git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@282735 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Fuzzer/FuzzerLoop.cpp | 3 +- lib/Fuzzer/FuzzerTracePC.cpp | 16 +- lib/Fuzzer/FuzzerTracePC.h | 6 +- .../Instrumentation/SanitizerCoverage.cpp | 155 ++++++++++-------- .../SanitizerCoverage/tracing-comdat.ll | 3 +- .../SanitizerCoverage/tracing.ll | 2 +- 6 files changed, 106 insertions(+), 79 deletions(-) diff --git a/lib/Fuzzer/FuzzerLoop.cpp b/lib/Fuzzer/FuzzerLoop.cpp index f7d4e4ef362..197b80e9473 100644 --- a/lib/Fuzzer/FuzzerLoop.cpp +++ b/lib/Fuzzer/FuzzerLoop.cpp @@ -500,7 +500,8 @@ void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) { UnitStartTime = system_clock::now(); ResetCounters(); // Reset coverage right before the callback. TPC.ResetMaps(); - TPC.ResetGuards(); + if (Options.UseCounters) + TPC.ResetGuards(); int Res = CB(DataCopy, Size); UnitStopTime = system_clock::now(); (void)Res; diff --git a/lib/Fuzzer/FuzzerTracePC.cpp b/lib/Fuzzer/FuzzerTracePC.cpp index 9789d5df852..44149922a15 100644 --- a/lib/Fuzzer/FuzzerTracePC.cpp +++ b/lib/Fuzzer/FuzzerTracePC.cpp @@ -20,8 +20,8 @@ namespace fuzzer { TracePC TPC; -void TracePC::HandleTrace(uintptr_t *Guard, uintptr_t PC) { - uintptr_t Idx = *Guard; +void TracePC::HandleTrace(uint32_t *Guard, uintptr_t PC) { + uint32_t Idx = *Guard; if (!Idx) return; uint8_t *CounterPtr = &Counters[Idx % kNumCounters]; uint8_t Counter = *CounterPtr; @@ -43,10 +43,10 @@ void TracePC::HandleTrace(uintptr_t *Guard, uintptr_t PC) { } } -void TracePC::HandleInit(uintptr_t *Start, uintptr_t *Stop) { +void TracePC::HandleInit(uint32_t *Start, uint32_t *Stop) { if (Start == Stop || *Start) return; assert(NumModules < sizeof(Modules) / sizeof(Modules[0])); - for (uintptr_t *P = Start; P < Stop; P++) + for (uint32_t *P = Start; P < Stop; P++) *P = ++NumGuards; Modules[NumModules].Start = Start; Modules[NumModules].Stop = Stop; @@ -61,9 +61,9 @@ void TracePC::PrintModuleInfo() { } void TracePC::ResetGuards() { - uintptr_t N = 0; + uint32_t N = 0; for (size_t M = 0; M < NumModules; M++) - for (uintptr_t *X = Modules[M].Start; X < Modules[M].Stop; X++) + for (uint32_t *X = Modules[M].Start; X < Modules[M].Stop; X++) *X = ++N; assert(N == NumGuards); } @@ -138,13 +138,13 @@ void TracePC::PrintFeatureSet() { extern "C" { __attribute__((visibility("default"))) -void __sanitizer_cov_trace_pc_guard(uintptr_t *Guard) { +void __sanitizer_cov_trace_pc_guard(uint32_t *Guard) { uintptr_t PC = (uintptr_t)__builtin_return_address(0); fuzzer::TPC.HandleTrace(Guard, PC); } __attribute__((visibility("default"))) -void __sanitizer_cov_trace_pc_guard_init(uintptr_t *Start, uintptr_t *Stop) { +void __sanitizer_cov_trace_pc_guard_init(uint32_t *Start, uint32_t *Stop) { fuzzer::TPC.HandleInit(Start, Stop); } diff --git a/lib/Fuzzer/FuzzerTracePC.h b/lib/Fuzzer/FuzzerTracePC.h index 0f2b6a878c4..3f4c7833540 100644 --- a/lib/Fuzzer/FuzzerTracePC.h +++ b/lib/Fuzzer/FuzzerTracePC.h @@ -19,8 +19,8 @@ namespace fuzzer { class TracePC { public: - void HandleTrace(uintptr_t *guard, uintptr_t PC); - void HandleInit(uintptr_t *start, uintptr_t *stop); + void HandleTrace(uint32_t *guard, uintptr_t PC); + void HandleInit(uint32_t *start, uint32_t *stop); void HandleCallerCallee(uintptr_t Caller, uintptr_t Callee); void HandleValueProfile(size_t Value) { ValueProfileMap.AddValue(Value); } size_t GetTotalPCCoverage() { return TotalPCCoverage; } @@ -71,7 +71,7 @@ private: } struct Module { - uintptr_t *Start, *Stop; + uint32_t *Start, *Stop; }; Module Modules[4096]; diff --git a/lib/Transforms/Instrumentation/SanitizerCoverage.cpp b/lib/Transforms/Instrumentation/SanitizerCoverage.cpp index e26fdb42c99..774fe2ff059 100644 --- a/lib/Transforms/Instrumentation/SanitizerCoverage.cpp +++ b/lib/Transforms/Instrumentation/SanitizerCoverage.cpp @@ -207,8 +207,10 @@ private: void InjectTraceForSwitch(Function &F, ArrayRef SwitchTraceTargets); bool InjectCoverage(Function &F, ArrayRef AllBlocks); + void CreateFunctionGuardArray(size_t NumGuards, Function &F); void SetNoSanitizeMetadata(Instruction *I); - void InjectCoverageAtBlock(Function &F, BasicBlock &BB, bool UseCalls); + void InjectCoverageAtBlock(Function &F, BasicBlock &BB, size_t Idx, + bool UseCalls); unsigned NumberOfInstrumentedBlocks() { return SanCovFunction->getNumUses() + SanCovWithCheckFunction->getNumUses() + SanCovTraceBB->getNumUses() + @@ -223,12 +225,13 @@ private: Function *SanCovTraceGepFunction; Function *SanCovTraceSwitchFunction; InlineAsm *EmptyAsm; - Type *IntptrTy, *IntptrPtrTy, *Int64Ty, *Int64PtrTy; + Type *IntptrTy, *IntptrPtrTy, *Int64Ty, *Int64PtrTy, *Int32Ty, *Int32PtrTy; Module *CurModule; LLVMContext *C; const DataLayout *DL; GlobalVariable *GuardArray; + GlobalVariable *FunctionGuardArray; // for trace-pc-guard. GlobalVariable *EightBitCounterArray; bool HasSancovGuardsSection; @@ -249,9 +252,10 @@ bool SanitizerCoverageModule::runOnModule(Module &M) { Type *VoidTy = Type::getVoidTy(*C); IRBuilder<> IRB(*C); Type *Int8PtrTy = PointerType::getUnqual(IRB.getInt8Ty()); - Type *Int32PtrTy = PointerType::getUnqual(IRB.getInt32Ty()); Int64PtrTy = PointerType::getUnqual(IRB.getInt64Ty()); + Int32PtrTy = PointerType::getUnqual(IRB.getInt32Ty()); Int64Ty = IRB.getInt64Ty(); + Int32Ty = IRB.getInt32Ty(); SanCovFunction = checkSanitizerInterfaceFunction( M.getOrInsertFunction(SanCovName, VoidTy, Int32PtrTy, nullptr)); @@ -296,7 +300,7 @@ bool SanitizerCoverageModule::runOnModule(Module &M) { SanCovTracePC = checkSanitizerInterfaceFunction( M.getOrInsertFunction(SanCovTracePCName, VoidTy, nullptr)); SanCovTracePCGuard = checkSanitizerInterfaceFunction(M.getOrInsertFunction( - SanCovTracePCGuardName, VoidTy, IntptrPtrTy, nullptr)); + SanCovTracePCGuardName, VoidTy, Int32PtrTy, nullptr)); SanCovTraceEnter = checkSanitizerInterfaceFunction( M.getOrInsertFunction(SanCovTraceEnterName, VoidTy, Int32PtrTy, nullptr)); SanCovTraceBB = checkSanitizerInterfaceFunction( @@ -307,9 +311,10 @@ bool SanitizerCoverageModule::runOnModule(Module &M) { Type *Int32Ty = IRB.getInt32Ty(); Type *Int8Ty = IRB.getInt8Ty(); - GuardArray = - new GlobalVariable(M, Int32Ty, false, GlobalValue::ExternalLinkage, - nullptr, "__sancov_gen_cov_tmp"); + if (!Options.TracePCGuard) + GuardArray = + new GlobalVariable(M, Int32Ty, false, GlobalValue::ExternalLinkage, + nullptr, "__sancov_gen_cov_tmp"); if (Options.Use8bitCounters) EightBitCounterArray = new GlobalVariable(M, Int8Ty, false, GlobalVariable::ExternalLinkage, @@ -320,17 +325,20 @@ bool SanitizerCoverageModule::runOnModule(Module &M) { auto N = NumberOfInstrumentedBlocks(); - // 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, N + 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(); + GlobalVariable *RealGuardArray = nullptr; + if (!Options.TracePCGuard) { + // 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, N + 1); + 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(); + } GlobalVariable *RealEightBitCounterArray; if (Options.Use8bitCounters) { @@ -359,16 +367,16 @@ bool SanitizerCoverageModule::runOnModule(Module &M) { GlobalVariable *Bounds[2]; const char *Prefix[2] = {"__start_", "__stop_"}; for (int i = 0; i < 2; i++) { - Bounds[i] = new GlobalVariable(M, IntptrPtrTy, false, + Bounds[i] = new GlobalVariable(M, Int32PtrTy, false, GlobalVariable::ExternalLinkage, nullptr, Prefix[i] + SectionName); Bounds[i]->setVisibility(GlobalValue::HiddenVisibility); } std::tie(CtorFunc, std::ignore) = createSanitizerCtorAndInitFunctions( M, SanCovModuleCtorName, SanCovTracePCGuardInitName, - {IntptrPtrTy, IntptrPtrTy}, - {IRB.CreatePointerCast(Bounds[0], IntptrPtrTy), - IRB.CreatePointerCast(Bounds[1], IntptrPtrTy)}); + {Int32PtrTy, Int32PtrTy}, + {IRB.CreatePointerCast(Bounds[0], Int32PtrTy), + IRB.CreatePointerCast(Bounds[1], Int32PtrTy)}); appendToGlobalCtors(M, CtorFunc, SanCtorAndDtorPriority); } @@ -419,6 +427,14 @@ static bool isFullPostDominator(const BasicBlock *BB, static bool shouldInstrumentBlock(const Function& F, const BasicBlock *BB, const DominatorTree *DT, const PostDominatorTree *PDT) { + // Don't insert coverage for unreachable blocks: we will never call + // __sanitizer_cov() for them, so counting them in + // NumberOfInstrumentedBlocks() might complicate calculation of code coverage + // percentage. Also, unreachable instructions frequently have no debug + // locations. + if (isa(BB->getTerminator())) + return false; + if (!ClPruneBlocks || &F.getEntryBlock() == BB) return true; @@ -486,19 +502,34 @@ bool SanitizerCoverageModule::runOnFunction(Function &F) { InjectTraceForGep(F, GepTraceTargets); return true; } +void SanitizerCoverageModule::CreateFunctionGuardArray(size_t NumGuards, Function &F) { + if (!Options.TracePCGuard) return; + HasSancovGuardsSection = true; + ArrayType *ArrayOfInt32Ty = ArrayType::get(Int32Ty, NumGuards); + FunctionGuardArray = new GlobalVariable( + *CurModule, ArrayOfInt32Ty, false, GlobalVariable::LinkOnceODRLinkage, + Constant::getNullValue(ArrayOfInt32Ty), "__sancov_guard." + F.getName()); + if (auto Comdat = F.getComdat()) + FunctionGuardArray->setComdat(Comdat); + FunctionGuardArray->setSection(SanCovTracePCGuardSection); + FunctionGuardArray->setVisibility(GlobalValue::HiddenVisibility); +} bool SanitizerCoverageModule::InjectCoverage(Function &F, ArrayRef AllBlocks) { + if (AllBlocks.empty()) return false; switch (Options.CoverageType) { case SanitizerCoverageOptions::SCK_None: return false; case SanitizerCoverageOptions::SCK_Function: - InjectCoverageAtBlock(F, F.getEntryBlock(), false); + CreateFunctionGuardArray(1, F); + InjectCoverageAtBlock(F, F.getEntryBlock(), 0, false); return true; default: { bool UseCalls = ClCoverageBlockThreshold < AllBlocks.size(); - for (auto BB : AllBlocks) - InjectCoverageAtBlock(F, *BB, UseCalls); + CreateFunctionGuardArray(AllBlocks.size(), F); + for (size_t i = 0, N = AllBlocks.size(); i < N; i++) + InjectCoverageAtBlock(F, *AllBlocks[i], i, UseCalls); return true; } } @@ -635,16 +666,8 @@ void SanitizerCoverageModule::SetNoSanitizeMetadata(Instruction *I) { } void SanitizerCoverageModule::InjectCoverageAtBlock(Function &F, BasicBlock &BB, - bool UseCalls) { - // Don't insert coverage for unreachable blocks: we will never call - // __sanitizer_cov() for them, so counting them in - // NumberOfInstrumentedBlocks() might complicate calculation of code coverage - // percentage. Also, unreachable instructions frequently have no debug - // locations. - if (isa(BB.getTerminator())) - return; + size_t Idx, bool UseCalls) { BasicBlock::iterator IP = BB.getFirstInsertionPt(); - bool IsEntryBB = &BB == &F.getEntryBlock(); DebugLoc EntryLoc; if (IsEntryBB) { @@ -660,24 +683,22 @@ void SanitizerCoverageModule::InjectCoverageAtBlock(Function &F, BasicBlock &BB, IRBuilder<> IRB(&*IP); IRB.SetCurrentDebugLocation(EntryLoc); - Value *GuardP = IRB.CreateAdd( - IRB.CreatePointerCast(GuardArray, IntptrTy), - ConstantInt::get(IntptrTy, (1 + NumberOfInstrumentedBlocks()) * 4)); - Type *Int32PtrTy = PointerType::getUnqual(IRB.getInt32Ty()); - GuardP = IRB.CreateIntToPtr(GuardP, Int32PtrTy); if (Options.TracePC) { IRB.CreateCall(SanCovTracePC); // gets the PC using GET_CALLER_PC. IRB.CreateCall(EmptyAsm, {}); // Avoids callback merge. } else if (Options.TracePCGuard) { - auto GuardVar = new GlobalVariable( - *F.getParent(), Int64Ty, false, GlobalVariable::LinkOnceODRLinkage, - Constant::getNullValue(Int64Ty), "__sancov_guard." + F.getName()); - if (auto Comdat = F.getComdat()) - GuardVar->setComdat(Comdat); + //auto GuardVar = new GlobalVariable( + // *F.getParent(), Int64Ty, false, GlobalVariable::LinkOnceODRLinkage, + // Constant::getNullValue(Int64Ty), "__sancov_guard." + F.getName()); + // if (auto Comdat = F.getComdat()) + // GuardVar->setComdat(Comdat); // TODO: add debug into to GuardVar. - GuardVar->setSection(SanCovTracePCGuardSection); - HasSancovGuardsSection = true; - auto GuardPtr = IRB.CreatePointerCast(GuardVar, IntptrPtrTy); + // GuardVar->setSection(SanCovTracePCGuardSection); + // auto GuardPtr = IRB.CreatePointerCast(GuardVar, IntptrPtrTy); + auto GuardPtr = IRB.CreateIntToPtr( + IRB.CreateAdd(IRB.CreatePointerCast(FunctionGuardArray, IntptrTy), + ConstantInt::get(IntptrTy, Idx * 4)), + Int32PtrTy); if (!UseCalls) { auto GuardLoad = IRB.CreateLoad(GuardPtr); GuardLoad->setAtomic(AtomicOrdering::Monotonic); @@ -692,24 +713,30 @@ void SanitizerCoverageModule::InjectCoverageAtBlock(Function &F, BasicBlock &BB, } IRB.CreateCall(SanCovTracePCGuard, GuardPtr); IRB.CreateCall(EmptyAsm, {}); // Avoids callback merge. - } else if (Options.TraceBB) { - IRB.CreateCall(IsEntryBB ? SanCovTraceEnter : SanCovTraceBB, GuardP); - } else if (UseCalls) { - IRB.CreateCall(SanCovWithCheckFunction, GuardP); } else { - LoadInst *Load = IRB.CreateLoad(GuardP); - Load->setAtomic(AtomicOrdering::Monotonic); - Load->setAlignment(4); - SetNoSanitizeMetadata(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, GuardP); - IRB.CreateCall(EmptyAsm, {}); // Avoids callback merge. + Value *GuardP = IRB.CreateAdd( + IRB.CreatePointerCast(GuardArray, IntptrTy), + ConstantInt::get(IntptrTy, (1 + NumberOfInstrumentedBlocks()) * 4)); + GuardP = IRB.CreateIntToPtr(GuardP, Int32PtrTy); + if (Options.TraceBB) { + IRB.CreateCall(IsEntryBB ? SanCovTraceEnter : SanCovTraceBB, GuardP); + } else if (UseCalls) { + IRB.CreateCall(SanCovWithCheckFunction, GuardP); + } else { + LoadInst *Load = IRB.CreateLoad(GuardP); + Load->setAtomic(AtomicOrdering::Monotonic); + Load->setAlignment(4); + SetNoSanitizeMetadata(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, GuardP); + IRB.CreateCall(EmptyAsm, {}); // Avoids callback merge. + } } if (Options.Use8bitCounters) { diff --git a/test/Instrumentation/SanitizerCoverage/tracing-comdat.ll b/test/Instrumentation/SanitizerCoverage/tracing-comdat.ll index f718af53644..9dc1a995f2a 100644 --- a/test/Instrumentation/SanitizerCoverage/tracing-comdat.ll +++ b/test/Instrumentation/SanitizerCoverage/tracing-comdat.ll @@ -9,5 +9,4 @@ entry: ret void } -; CHECK: @__sancov_guard.Foo = linkonce_odr global i64 0, section "__sancov_guards", comdat($Foo) - +; CHECK: @__sancov_guard.Foo = linkonce_odr hidden global [1 x i32] zeroinitializer, section "__sancov_guards", comdat($Foo) diff --git a/test/Instrumentation/SanitizerCoverage/tracing.ll b/test/Instrumentation/SanitizerCoverage/tracing.ll index df804f6f7e1..49c2a1a6352 100644 --- a/test/Instrumentation/SanitizerCoverage/tracing.ll +++ b/test/Instrumentation/SanitizerCoverage/tracing.ll @@ -46,4 +46,4 @@ entry: ; CHECK_PC_GUARD: call void @__sanitizer_cov_trace_pc_guard ; CHECK_PC_GUARD-NOT: call void @__sanitizer_cov_trace_pc ; CHECK_PC_GUARD: ret void -; CHECK_PC_GUARD: call void @__sanitizer_cov_trace_pc_guard_init(i64* bitcast (i64** @__start___sancov_guards to i64*), i64* bitcast (i64** @__stop___sancov_guards to i64*)) +; CHECK_PC_GUARD: call void @__sanitizer_cov_trace_pc_guard_init(i32* bitcast (i32** @__start___sancov_guards to i32*), i32* bitcast (i32** @__stop___sancov_guards to i32*)) -- 2.50.1