From 1ac6e55e75b951d5cf17dec31d9c637e63342d32 Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Wed, 30 Apr 2025 12:34:19 +0200 Subject: [PATCH] [sancov] add -sanitizer-coverage-drop-ctors Add a hidden flag to omit the @sancov.module_ctor* constructors. When building kernel modules with sanitizer coverage enabled, constructors may reference global symbols, creating unsupported relocations. Because the kernel does not strictly need these constructors in order for coverage to work, allow the user to omit them. Also apply clang-format to SanitizerCoverage.cpp. Fixes PR132393. --- .../Instrumentation/SanitizerCoverage.cpp | 116 +++++++++--------- .../SanitizerCoverage/trace-pc-guard.ll | 13 +- 2 files changed, 65 insertions(+), 64 deletions(-) diff --git a/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp b/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp index e52269637b92d..57d96353dd537 100644 --- a/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp +++ b/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp @@ -117,6 +117,11 @@ static cl::opt cl::desc("increments 8-bit counter for every edge"), cl::Hidden); +static cl::opt + ClSancovDropCtors("sanitizer-coverage-drop-ctors", + cl::desc("do not emit module ctors for global counters"), + cl::Hidden); + static cl::opt ClInlineBoolFlag("sanitizer-coverage-inline-bool-flag", cl::desc("sets a boolean flag for every edge"), @@ -288,11 +293,11 @@ class ModuleSanitizerCoverage { LLVMContext *C; const DataLayout *DL; - GlobalVariable *FunctionGuardArray; // for trace-pc-guard. - GlobalVariable *Function8bitCounterArray; // for inline-8bit-counters. - GlobalVariable *FunctionBoolArray; // for inline-bool-flag. - GlobalVariable *FunctionPCsArray; // for pc-table. - GlobalVariable *FunctionCFsArray; // for control flow table + GlobalVariable *FunctionGuardArray; // for trace-pc-guard. + GlobalVariable *Function8bitCounterArray; // for inline-8bit-counters. + GlobalVariable *FunctionBoolArray; // for inline-bool-flag. + GlobalVariable *FunctionPCsArray; // for pc-table. + GlobalVariable *FunctionCFsArray; // for control flow table SmallVector GlobalsToAppendToUsed; SmallVector GlobalsToAppendToCompilerUsed; @@ -336,13 +341,11 @@ ModuleSanitizerCoverage::CreateSecStartEnd(Module &M, const char *Section, GlobalValue::LinkageTypes Linkage = TargetTriple.isOSBinFormatCOFF() ? GlobalVariable::ExternalLinkage : GlobalVariable::ExternalWeakLinkage; - GlobalVariable *SecStart = - new GlobalVariable(M, Ty, false, Linkage, nullptr, - getSectionStart(Section)); + GlobalVariable *SecStart = new GlobalVariable(M, Ty, false, Linkage, nullptr, + getSectionStart(Section)); SecStart->setVisibility(GlobalValue::HiddenVisibility); - GlobalVariable *SecEnd = - new GlobalVariable(M, Ty, false, Linkage, nullptr, - getSectionEnd(Section)); + GlobalVariable *SecEnd = new GlobalVariable(M, Ty, false, Linkage, nullptr, + getSectionEnd(Section)); SecEnd->setVisibility(GlobalValue::HiddenVisibility); IRBuilder<> IRB(M.getContext()); if (!TargetTriple.isOSBinFormatCOFF()) @@ -358,6 +361,8 @@ ModuleSanitizerCoverage::CreateSecStartEnd(Module &M, const char *Section, Function *ModuleSanitizerCoverage::CreateInitCallsForSections( Module &M, const char *CtorName, const char *InitFunctionName, Type *Ty, const char *Section) { + if (ClSancovDropCtors) + return nullptr; auto SecStartEnd = CreateSecStartEnd(M, Section, Ty); auto SecStart = SecStartEnd.first; auto SecEnd = SecStartEnd.second; @@ -447,25 +452,16 @@ bool ModuleSanitizerCoverage::instrumentModule() { // Loads. SanCovLoadFunction[0] = M.getOrInsertFunction(SanCovLoad1, VoidTy, PtrTy); - SanCovLoadFunction[1] = - M.getOrInsertFunction(SanCovLoad2, VoidTy, PtrTy); - SanCovLoadFunction[2] = - M.getOrInsertFunction(SanCovLoad4, VoidTy, PtrTy); - SanCovLoadFunction[3] = - M.getOrInsertFunction(SanCovLoad8, VoidTy, PtrTy); - SanCovLoadFunction[4] = - M.getOrInsertFunction(SanCovLoad16, VoidTy, PtrTy); + SanCovLoadFunction[1] = M.getOrInsertFunction(SanCovLoad2, VoidTy, PtrTy); + SanCovLoadFunction[2] = M.getOrInsertFunction(SanCovLoad4, VoidTy, PtrTy); + SanCovLoadFunction[3] = M.getOrInsertFunction(SanCovLoad8, VoidTy, PtrTy); + SanCovLoadFunction[4] = M.getOrInsertFunction(SanCovLoad16, VoidTy, PtrTy); // Stores. - SanCovStoreFunction[0] = - M.getOrInsertFunction(SanCovStore1, VoidTy, PtrTy); - SanCovStoreFunction[1] = - M.getOrInsertFunction(SanCovStore2, VoidTy, PtrTy); - SanCovStoreFunction[2] = - M.getOrInsertFunction(SanCovStore4, VoidTy, PtrTy); - SanCovStoreFunction[3] = - M.getOrInsertFunction(SanCovStore8, VoidTy, PtrTy); - SanCovStoreFunction[4] = - M.getOrInsertFunction(SanCovStore16, VoidTy, PtrTy); + SanCovStoreFunction[0] = M.getOrInsertFunction(SanCovStore1, VoidTy, PtrTy); + SanCovStoreFunction[1] = M.getOrInsertFunction(SanCovStore2, VoidTy, PtrTy); + SanCovStoreFunction[2] = M.getOrInsertFunction(SanCovStore4, VoidTy, PtrTy); + SanCovStoreFunction[3] = M.getOrInsertFunction(SanCovStore8, VoidTy, PtrTy); + SanCovStoreFunction[4] = M.getOrInsertFunction(SanCovStore16, VoidTy, PtrTy); { AttributeList AL; @@ -534,16 +530,16 @@ bool ModuleSanitizerCoverage::instrumentModule() { } if (Ctor && Options.PCTable) { auto SecStartEnd = CreateSecStartEnd(M, SanCovPCsSectionName, IntptrTy); - FunctionCallee InitFunction = declareSanitizerInitFunction( - M, SanCovPCsInitName, {PtrTy, PtrTy}); + FunctionCallee InitFunction = + declareSanitizerInitFunction(M, SanCovPCsInitName, {PtrTy, PtrTy}); IRBuilder<> IRBCtor(Ctor->getEntryBlock().getTerminator()); IRBCtor.CreateCall(InitFunction, {SecStartEnd.first, SecStartEnd.second}); } if (Ctor && Options.CollectControlFlow) { auto SecStartEnd = CreateSecStartEnd(M, SanCovCFsSectionName, IntptrTy); - FunctionCallee InitFunction = declareSanitizerInitFunction( - M, SanCovCFsInitName, {PtrTy, PtrTy}); + FunctionCallee InitFunction = + declareSanitizerInitFunction(M, SanCovCFsInitName, {PtrTy, PtrTy}); IRBuilder<> IRBCtor(Ctor->getEntryBlock().getTerminator()); IRBCtor.CreateCall(InitFunction, {SecStartEnd.first, SecStartEnd.second}); } @@ -600,8 +596,8 @@ static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB, // Do not instrument full dominators, or full post-dominators with multiple // predecessors. - return !isFullDominator(BB, DT) - && !(isFullPostDominator(BB, PDT) && !BB->getSinglePredecessor()); + return !isFullDominator(BB, DT) && + !(isFullPostDominator(BB, PDT) && !BB->getSinglePredecessor()); } // Returns true iff From->To is a backedge. @@ -776,16 +772,16 @@ ModuleSanitizerCoverage::CreatePCArray(Function &F, for (size_t i = 0; i < N; i++) { if (&F.getEntryBlock() == AllBlocks[i]) { PCs.push_back((Constant *)IRB.CreatePointerCast(&F, PtrTy)); - PCs.push_back((Constant *)IRB.CreateIntToPtr( - ConstantInt::get(IntptrTy, 1), PtrTy)); + PCs.push_back( + (Constant *)IRB.CreateIntToPtr(ConstantInt::get(IntptrTy, 1), PtrTy)); } else { PCs.push_back((Constant *)IRB.CreatePointerCast( BlockAddress::get(AllBlocks[i]), PtrTy)); PCs.push_back(Constant::getNullValue(PtrTy)); } } - auto *PCArray = CreateFunctionLocalArrayInSection(N * 2, F, PtrTy, - SanCovPCsSectionName); + auto *PCArray = + CreateFunctionLocalArrayInSection(N * 2, F, PtrTy, SanCovPCsSectionName); PCArray->setInitializer( ConstantArray::get(ArrayType::get(PtrTy, N * 2), PCs)); PCArray->setConstant(true); @@ -840,7 +836,8 @@ bool ModuleSanitizerCoverage::InjectCoverage(Function &F, ArrayRef AllBlocks, Value *&FunctionGateCmp, bool IsLeafFunc) { - if (AllBlocks.empty()) return false; + if (AllBlocks.empty()) + return false; CreateFunctionLocalArrays(F, AllBlocks); for (size_t i = 0, N = AllBlocks.size(); i < N; i++) InjectCoverageAtBlock(F, *AllBlocks[i], i, FunctionGateCmp, IsLeafFunc); @@ -923,13 +920,14 @@ void ModuleSanitizerCoverage::InjectTraceForDiv( for (auto *BO : DivTraceTargets) { InstrumentationIRBuilder IRB(BO); Value *A1 = BO->getOperand(1); - if (isa(A1)) continue; + if (isa(A1)) + continue; if (!A1->getType()->isIntegerTy()) continue; uint64_t TypeSize = DL->getTypeStoreSizeInBits(A1->getType()); - int CallbackIdx = TypeSize == 32 ? 0 : - TypeSize == 64 ? 1 : -1; - if (CallbackIdx < 0) continue; + int CallbackIdx = TypeSize == 32 ? 0 : TypeSize == 64 ? 1 : -1; + if (CallbackIdx < 0) + continue; auto Ty = Type::getIntNTy(*C, TypeSize); IRB.CreateCall(SanCovTraceDivFunction[CallbackIdx], {IRB.CreateIntCast(A1, Ty, true)}); @@ -987,17 +985,20 @@ void ModuleSanitizerCoverage::InjectTraceForCmp( if (!A0->getType()->isIntegerTy()) continue; uint64_t TypeSize = DL->getTypeStoreSizeInBits(A0->getType()); - int CallbackIdx = TypeSize == 8 ? 0 : - TypeSize == 16 ? 1 : - TypeSize == 32 ? 2 : - TypeSize == 64 ? 3 : -1; - if (CallbackIdx < 0) continue; + int CallbackIdx = TypeSize == 8 ? 0 + : TypeSize == 16 ? 1 + : TypeSize == 32 ? 2 + : TypeSize == 64 ? 3 + : -1; + if (CallbackIdx < 0) + continue; // __sanitizer_cov_trace_cmp((type_size << 32) | predicate, A0, A1); auto CallbackFunc = SanCovTraceCmpFunction[CallbackIdx]; bool FirstIsConst = isa(A0); bool SecondIsConst = isa(A1); // If both are const, then we don't need such a comparison. - if (FirstIsConst && SecondIsConst) continue; + if (FirstIsConst && SecondIsConst) + continue; // If only one is const, then make it the first callback argument. if (FirstIsConst || SecondIsConst) { CallbackFunc = SanCovTraceConstCmpFunction[CallbackIdx]; @@ -1136,13 +1137,13 @@ void ModuleSanitizerCoverage::createFunctionControlFlow(Function &F) { if (&BB == &F.getEntryBlock()) CFs.push_back((Constant *)IRB.CreatePointerCast(&F, PtrTy)); else - CFs.push_back((Constant *)IRB.CreatePointerCast(BlockAddress::get(&BB), - PtrTy)); + CFs.push_back( + (Constant *)IRB.CreatePointerCast(BlockAddress::get(&BB), PtrTy)); for (auto SuccBB : successors(&BB)) { assert(SuccBB != &F.getEntryBlock()); - CFs.push_back((Constant *)IRB.CreatePointerCast(BlockAddress::get(SuccBB), - PtrTy)); + CFs.push_back( + (Constant *)IRB.CreatePointerCast(BlockAddress::get(SuccBB), PtrTy)); } CFs.push_back((Constant *)Constant::getNullValue(PtrTy)); @@ -1156,8 +1157,7 @@ void ModuleSanitizerCoverage::createFunctionControlFlow(Function &F) { } else { auto CalledF = CB->getCalledFunction(); if (CalledF && !CalledF->isIntrinsic()) - CFs.push_back( - (Constant *)IRB.CreatePointerCast(CalledF, PtrTy)); + CFs.push_back((Constant *)IRB.CreatePointerCast(CalledF, PtrTy)); } } } @@ -1165,8 +1165,8 @@ void ModuleSanitizerCoverage::createFunctionControlFlow(Function &F) { CFs.push_back((Constant *)Constant::getNullValue(PtrTy)); } - FunctionCFsArray = CreateFunctionLocalArrayInSection( - CFs.size(), F, PtrTy, SanCovCFsSectionName); + FunctionCFsArray = CreateFunctionLocalArrayInSection(CFs.size(), F, PtrTy, + SanCovCFsSectionName); FunctionCFsArray->setInitializer( ConstantArray::get(ArrayType::get(PtrTy, CFs.size()), CFs)); FunctionCFsArray->setConstant(true); diff --git a/llvm/test/Instrumentation/SanitizerCoverage/trace-pc-guard.ll b/llvm/test/Instrumentation/SanitizerCoverage/trace-pc-guard.ll index 5deb74eb8c6aa..5d46c23058b8e 100644 --- a/llvm/test/Instrumentation/SanitizerCoverage/trace-pc-guard.ll +++ b/llvm/test/Instrumentation/SanitizerCoverage/trace-pc-guard.ll @@ -1,8 +1,9 @@ -; RUN: opt < %s -passes='module(sancov-module)' -sanitizer-coverage-level=4 -sanitizer-coverage-trace-pc-guard -mtriple=x86_64 -S | FileCheck %s --check-prefixes=CHECK,COMDAT,ELF +; RUN: opt < %s -passes='module(sancov-module)' -sanitizer-coverage-level=4 -sanitizer-coverage-trace-pc-guard -mtriple=x86_64 -S | FileCheck %s --check-prefixes=CHECK,CHECK-CTOR,COMDAT,ELF,ELF-CTOR +; RUN: opt < %s -passes='module(sancov-module)' -sanitizer-coverage-level=4 -sanitizer-coverage-trace-pc-guard -sanitizer-coverage-drop-ctors=1 -mtriple=x86_64 -S | FileCheck %s --check-prefixes=CHECK,COMDAT,ELF -; RUN: opt < %s -passes='module(sancov-module)' -sanitizer-coverage-level=4 -sanitizer-coverage-trace-pc-guard -mtriple=aarch64-apple-darwin -S | FileCheck %s --check-prefixes=CHECK,MACHO +; RUN: opt < %s -passes='module(sancov-module)' -sanitizer-coverage-level=4 -sanitizer-coverage-trace-pc-guard -mtriple=aarch64-apple-darwin -S | FileCheck %s --check-prefixes=CHECK,CHECK-CTOR,MACHO -; RUN: opt < %s -passes='module(sancov-module)' -sanitizer-coverage-level=4 -sanitizer-coverage-trace-pc-guard -mtriple=x86_64-windows -S | FileCheck %s --check-prefixes=CHECK,COMDAT,WIN +; RUN: opt < %s -passes='module(sancov-module)' -sanitizer-coverage-level=4 -sanitizer-coverage-trace-pc-guard -mtriple=x86_64-windows -S | FileCheck %s --check-prefixes=CHECK,CHECK-CTOR,COMDAT,WIN ; COMDAT: $foo = comdat nodeduplicate ; COMDAT: $CallViaVptr = comdat nodeduplicate @@ -20,7 +21,7 @@ ; WIN-NEXT: @__sancov_gen_.1 = private global [1 x i32] zeroinitializer, section ".SCOV$GM", comdat($CallViaVptr), align 4{{$}} ; WIN-NEXT: @__sancov_gen_.2 = private global [1 x i32] zeroinitializer, section ".SCOV$GM", comdat($DirectBitcastCall), align 4{{$}} -; ELF: @llvm.used = appending global [1 x ptr] [ptr @sancov.module_ctor_trace_pc_guard] +; ELF-CTOR: @llvm.used = appending global [1 x ptr] [ptr @sancov.module_ctor_trace_pc_guard] ; ELF: @llvm.compiler.used = appending global [3 x ptr] [ptr @__sancov_gen_, ptr @__sancov_gen_.1, ptr @__sancov_gen_.2], section "llvm.metadata" ; MACHO: @llvm.used = appending global [4 x ptr] [ptr @sancov.module_ctor_trace_pc_guard, ptr @__sancov_gen_, ptr @__sancov_gen_.1, ptr @__sancov_gen_.2] ; MACHO-NOT: @llvm.compiler.used = @@ -73,7 +74,7 @@ define void @DirectBitcastCall() sanitize_address { ret void } -; ELF-LABEL: define internal void @sancov.module_ctor_trace_pc_guard() #2 comdat { +; ELF-CTOR-LABEL: define internal void @sancov.module_ctor_trace_pc_guard() #2 comdat { ; MACHO-LABEL: define internal void @sancov.module_ctor_trace_pc_guard() #2 { -; CHECK: attributes #2 = { nounwind } +; CHECK-CTOR: attributes #2 = { nounwind }