diff --git a/clang/docs/SanitizerCoverage.rst b/clang/docs/SanitizerCoverage.rst --- a/clang/docs/SanitizerCoverage.rst +++ b/clang/docs/SanitizerCoverage.rst @@ -139,6 +139,28 @@ // Capture this array in order to read/modify the counters. } + +Inline bool-flag +================ + +**Experimental, may change or disappear in future** + +With ``-fsanitize-coverage=inline-bool-flag`` the compiler will insert +setting an inline boolean to true on every edge. +This is similar to ``-fsanitize-coverage=inline-8bit-counter`` but instead of +an increment of a counter, it just sets a boolean to true. + +Users need to implement a single function to capture the counters at startup. + +.. code-block:: c++ + + extern "C" + void __sanitizer_cov_bool_flag_init(bool *start, bool *end) { + // [start,end) is the array of boolean flags created for the current DSO. + // Capture this array in order to read/modify the flags. + } + + PC-Table ======== @@ -150,8 +172,8 @@ `Bug 34636 `_. With ``-fsanitize-coverage=pc-table`` the compiler will create a table of -instrumented PCs. Requires either ``-fsanitize-coverage=inline-8bit-counters`` or -``-fsanitize-coverage=trace-pc-guard``. +instrumented PCs. Requires either ``-fsanitize-coverage=inline-8bit-counters``, +or ``-fsanitize-coverage=inline-bool-flag``, or ``-fsanitize-coverage=trace-pc-guard``. Users need to implement a single function to capture the PC table at startup: @@ -164,8 +186,9 @@ // pairs [PC,PCFlags] for every instrumented block in the current DSO. // Capture this array in order to read the PCs and their Flags. // The number of PCs and PCFlags for a given DSO is the same as the number - // of 8-bit counters (-fsanitize-coverage=inline-8bit-counters) or - // trace_pc_guard callbacks (-fsanitize-coverage=trace-pc-guard) + // of 8-bit counters (-fsanitize-coverage=inline-8bit-counters), or + // boolean flags (-fsanitize-coverage=inline=bool-flags), or trace_pc_guard + // callbacks (-fsanitize-coverage=trace-pc-guard). // A PCFlags describes the basic block: // * bit0: 1 if the block is the function entry block, 0 otherwise. } diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -232,6 +232,7 @@ CODEGENOPT(SanitizeCoverageTracePCGuard, 1, 0) ///< Enable PC tracing with guard ///< in sanitizer coverage. CODEGENOPT(SanitizeCoverageInline8bitCounters, 1, 0) ///< Use inline 8bit counters. +CODEGENOPT(SanitizeCoverageInlineBoolFlag, 1, 0) ///< Use inline bool flag. CODEGENOPT(SanitizeCoveragePCTable, 1, 0) ///< Create a PC Table. CODEGENOPT(SanitizeCoverageNoPrune, 1, 0) ///< Disable coverage pruning. CODEGENOPT(SanitizeCoverageStackDepth, 1, 0) ///< Enable max stack depth tracing diff --git a/clang/include/clang/Driver/CC1Options.td b/clang/include/clang/Driver/CC1Options.td --- a/clang/include/clang/Driver/CC1Options.td +++ b/clang/include/clang/Driver/CC1Options.td @@ -355,6 +355,9 @@ def fsanitize_coverage_inline_8bit_counters : Flag<["-"], "fsanitize-coverage-inline-8bit-counters">, HelpText<"Enable inline 8-bit counters in sanitizer coverage">; +def fsanitize_coverage_inline_bool_flag + : Flag<["-"], "fsanitize-coverage-inline-bool-flag">, + HelpText<"Enable inline bool flag in sanitizer coverage">; def fsanitize_coverage_pc_table : Flag<["-"], "fsanitize-coverage-pc-table">, HelpText<"Create a table of coverage-instrumented PCs">; diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -901,7 +901,7 @@ def fdiagnostics_show_option : Flag<["-"], "fdiagnostics-show-option">, Group, HelpText<"Print option name with mappable diagnostics">; def fdiagnostics_show_note_include_stack : Flag<["-"], "fdiagnostics-show-note-include-stack">, - Group, Flags<[CC1Option]>, HelpText<"Display include stacks for diagnostic notes">; + Group, Flags<[CC1Option]>, HelpText<"Display include stacks for diagnostic notes">; def fdiagnostics_format_EQ : Joined<["-"], "fdiagnostics-format=">, Group; def fdiagnostics_show_category_EQ : Joined<["-"], "fdiagnostics-show-category=">, Group; def fdiagnostics_show_template_tree : Flag<["-"], "fdiagnostics-show-template-tree">, @@ -1019,7 +1019,7 @@ : CommaJoined<["-"], "fno-sanitize-coverage=">, Group, Flags<[CoreOption, DriverOption]>, HelpText<"Disable specified features of coverage instrumentation for " - "Sanitizers">, Values<"func,bb,edge,indirect-calls,trace-bb,trace-cmp,trace-div,trace-gep,8bit-counters,trace-pc,trace-pc-guard,no-prune,inline-8bit-counters">; + "Sanitizers">, Values<"func,bb,edge,indirect-calls,trace-bb,trace-cmp,trace-div,trace-gep,8bit-counters,trace-pc,trace-pc-guard,no-prune,inline-8bit-counters,inline-bool-flag">; def fsanitize_memory_track_origins_EQ : Joined<["-"], "fsanitize-memory-track-origins=">, Group, HelpText<"Enable origins tracking in MemorySanitizer">; diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -222,6 +222,7 @@ Opts.TracePCGuard = CGOpts.SanitizeCoverageTracePCGuard; Opts.NoPrune = CGOpts.SanitizeCoverageNoPrune; Opts.Inline8bitCounters = CGOpts.SanitizeCoverageInline8bitCounters; + Opts.InlineBoolFlag = CGOpts.SanitizeCoverageInlineBoolFlag; Opts.PCTable = CGOpts.SanitizeCoveragePCTable; Opts.StackDepth = CGOpts.SanitizeCoverageStackDepth; return Opts; diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -77,17 +77,18 @@ CoverageBB = 1 << 1, CoverageEdge = 1 << 2, CoverageIndirCall = 1 << 3, - CoverageTraceBB = 1 << 4, // Deprecated. + CoverageTraceBB = 1 << 4, // Deprecated. CoverageTraceCmp = 1 << 5, CoverageTraceDiv = 1 << 6, CoverageTraceGep = 1 << 7, - Coverage8bitCounters = 1 << 8, // Deprecated. + Coverage8bitCounters = 1 << 8, // Deprecated. CoverageTracePC = 1 << 9, CoverageTracePCGuard = 1 << 10, CoverageNoPrune = 1 << 11, CoverageInline8bitCounters = 1 << 12, CoveragePCTable = 1 << 13, CoverageStackDepth = 1 << 14, + CoverageInlineBoolFlag = 1 << 15, }; /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any @@ -380,7 +381,8 @@ // Enable coverage if the fuzzing flag is set. if (Add & SanitizerKind::FuzzerNoLink) { - CoverageFeatures |= CoverageInline8bitCounters | CoverageIndirCall | + CoverageFeatures |= CoverageInline8bitCounters | + CoverageInlineBoolFlag | CoverageIndirCall | CoverageTraceCmp | CoveragePCTable; // Due to TLS differences, stack depth tracking is only enabled on Linux if (TC.getTriple().isOSLinux()) @@ -723,8 +725,9 @@ << "-fsanitize-coverage=trace-pc-guard"; int InsertionPointTypes = CoverageFunc | CoverageBB | CoverageEdge; - int InstrumentationTypes = - CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters; + int InstrumentationTypes = CoverageTracePC | CoverageTracePCGuard | + CoverageInline8bitCounters | + CoverageInlineBoolFlag; if ((CoverageFeatures & InsertionPointTypes) && !(CoverageFeatures & InstrumentationTypes)) { D.Diag(clang::diag::warn_drv_deprecated_arg) @@ -735,7 +738,8 @@ // trace-pc w/o func/bb/edge implies edge. if (!(CoverageFeatures & InsertionPointTypes)) { if (CoverageFeatures & - (CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters)) + (CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters | + CoverageInlineBoolFlag)) CoverageFeatures |= CoverageEdge; if (CoverageFeatures & CoverageStackDepth) @@ -907,21 +911,25 @@ // Do it even if Sanitizers.empty() since some forms of coverage don't require // sanitizers. std::pair CoverageFlags[] = { - std::make_pair(CoverageFunc, "-fsanitize-coverage-type=1"), - std::make_pair(CoverageBB, "-fsanitize-coverage-type=2"), - std::make_pair(CoverageEdge, "-fsanitize-coverage-type=3"), - std::make_pair(CoverageIndirCall, "-fsanitize-coverage-indirect-calls"), - std::make_pair(CoverageTraceBB, "-fsanitize-coverage-trace-bb"), - std::make_pair(CoverageTraceCmp, "-fsanitize-coverage-trace-cmp"), - std::make_pair(CoverageTraceDiv, "-fsanitize-coverage-trace-div"), - std::make_pair(CoverageTraceGep, "-fsanitize-coverage-trace-gep"), - std::make_pair(Coverage8bitCounters, "-fsanitize-coverage-8bit-counters"), - std::make_pair(CoverageTracePC, "-fsanitize-coverage-trace-pc"), - std::make_pair(CoverageTracePCGuard, "-fsanitize-coverage-trace-pc-guard"), - std::make_pair(CoverageInline8bitCounters, "-fsanitize-coverage-inline-8bit-counters"), - std::make_pair(CoveragePCTable, "-fsanitize-coverage-pc-table"), - std::make_pair(CoverageNoPrune, "-fsanitize-coverage-no-prune"), - std::make_pair(CoverageStackDepth, "-fsanitize-coverage-stack-depth")}; + std::make_pair(CoverageFunc, "-fsanitize-coverage-type=1"), + std::make_pair(CoverageBB, "-fsanitize-coverage-type=2"), + std::make_pair(CoverageEdge, "-fsanitize-coverage-type=3"), + std::make_pair(CoverageIndirCall, "-fsanitize-coverage-indirect-calls"), + std::make_pair(CoverageTraceBB, "-fsanitize-coverage-trace-bb"), + std::make_pair(CoverageTraceCmp, "-fsanitize-coverage-trace-cmp"), + std::make_pair(CoverageTraceDiv, "-fsanitize-coverage-trace-div"), + std::make_pair(CoverageTraceGep, "-fsanitize-coverage-trace-gep"), + std::make_pair(Coverage8bitCounters, "-fsanitize-coverage-8bit-counters"), + std::make_pair(CoverageTracePC, "-fsanitize-coverage-trace-pc"), + std::make_pair(CoverageTracePCGuard, + "-fsanitize-coverage-trace-pc-guard"), + std::make_pair(CoverageInline8bitCounters, + "-fsanitize-coverage-inline-8bit-counters"), + std::make_pair(CoverageInlineBoolFlag, + "-fsanitize-coverage-inline-bool-flag"), + std::make_pair(CoveragePCTable, "-fsanitize-coverage-pc-table"), + std::make_pair(CoverageNoPrune, "-fsanitize-coverage-no-prune"), + std::make_pair(CoverageStackDepth, "-fsanitize-coverage-stack-depth")}; for (auto F : CoverageFlags) { if (CoverageFeatures & F.first) CmdArgs.push_back(F.second); @@ -1105,22 +1113,23 @@ for (int i = 0, n = A->getNumValues(); i != n; ++i) { const char *Value = A->getValue(i); int F = llvm::StringSwitch(Value) - .Case("func", CoverageFunc) - .Case("bb", CoverageBB) - .Case("edge", CoverageEdge) - .Case("indirect-calls", CoverageIndirCall) - .Case("trace-bb", CoverageTraceBB) - .Case("trace-cmp", CoverageTraceCmp) - .Case("trace-div", CoverageTraceDiv) - .Case("trace-gep", CoverageTraceGep) - .Case("8bit-counters", Coverage8bitCounters) - .Case("trace-pc", CoverageTracePC) - .Case("trace-pc-guard", CoverageTracePCGuard) - .Case("no-prune", CoverageNoPrune) - .Case("inline-8bit-counters", CoverageInline8bitCounters) - .Case("pc-table", CoveragePCTable) - .Case("stack-depth", CoverageStackDepth) - .Default(0); + .Case("func", CoverageFunc) + .Case("bb", CoverageBB) + .Case("edge", CoverageEdge) + .Case("indirect-calls", CoverageIndirCall) + .Case("trace-bb", CoverageTraceBB) + .Case("trace-cmp", CoverageTraceCmp) + .Case("trace-div", CoverageTraceDiv) + .Case("trace-gep", CoverageTraceGep) + .Case("8bit-counters", Coverage8bitCounters) + .Case("trace-pc", CoverageTracePC) + .Case("trace-pc-guard", CoverageTracePCGuard) + .Case("no-prune", CoverageNoPrune) + .Case("inline-8bit-counters", CoverageInline8bitCounters) + .Case("inline-bool-flag", CoverageInlineBoolFlag) + .Case("pc-table", CoveragePCTable) + .Case("stack-depth", CoverageStackDepth) + .Default(0); if (F == 0) D.Diag(clang::diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Value; diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1175,6 +1175,8 @@ Opts.SanitizeCoverageNoPrune = Args.hasArg(OPT_fsanitize_coverage_no_prune); Opts.SanitizeCoverageInline8bitCounters = Args.hasArg(OPT_fsanitize_coverage_inline_8bit_counters); + Opts.SanitizeCoverageInlineBoolFlag = + Args.hasArg(OPT_fsanitize_coverage_inline_bool_flag); Opts.SanitizeCoveragePCTable = Args.hasArg(OPT_fsanitize_coverage_pc_table); Opts.SanitizeCoverageStackDepth = Args.hasArg(OPT_fsanitize_coverage_stack_depth); diff --git a/clang/test/Driver/autocomplete.c b/clang/test/Driver/autocomplete.c --- a/clang/test/Driver/autocomplete.c +++ b/clang/test/Driver/autocomplete.c @@ -54,6 +54,7 @@ // FNOSANICOVERALL-NEXT: func // FNOSANICOVERALL-NEXT: indirect-calls // FNOSANICOVERALL-NEXT: inline-8bit-counters +// FNOSANICOVERALL-NEXT: inline-bool-flag // FNOSANICOVERALL-NEXT: no-prune // FNOSANICOVERALL-NEXT: trace-bb // FNOSANICOVERALL-NEXT: trace-cmp diff --git a/clang/test/Driver/fsanitize-coverage.c b/clang/test/Driver/fsanitize-coverage.c --- a/clang/test/Driver/fsanitize-coverage.c +++ b/clang/test/Driver/fsanitize-coverage.c @@ -105,9 +105,18 @@ // CHECK_INLINE8BIT-NOT: warning // CHECK_INLINE8BIT: -fsanitize-coverage-inline-8bit-counters -// RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=inline-8bit-counters,pc-table %s -### 2>&1 | FileCheck %s --check-prefix=CHECK_PC_TABLE -// RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=trace-pc-guard,pc-table %s -### 2>&1 | FileCheck %s --check-prefix=CHECK_PC_TABLE -// CHECK_PC_TABLE: -fsanitize-coverage-pc-table +// RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=inline-bool-flag %s-### 2>&1 | FileCheck %s --check-prefix=CHECK_INLINE_BOOL_FLAG +// RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=bb,inline-bool-flag %s -### 2>&1 | FileCheck %s --check-prefix=CHECK_INLINE_BOOL_FLAG +// CHECK_INLINE_BOOL_FLAG-NOT: warning +// CHECK_INLINE_BOOL_FLAG: -fsanitize-coverage-inline-bool-flag + +// RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=inline-8bit-counters,pc-table %s -### 2>&1 | FileCheck %s --check-prefix=CHECK_PC_TABLE_FOR_INLINE8BIT +// RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=trace-pc-guard,pc-table %s -### 2>&1 | FileCheck %s --check-prefix=CHECK_PC_TABLE_FOR_INLINE8BIT +// CHECK_PC_TABLE_FOR_INLINE8BIT: -fsanitize-coverage-pc-table + +// RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=inline-bool-flag,pc-table %s -### 2>&1 | FileCheck %s --check-prefix=CHECK_PC_TABLE_FOR_INLINEBOOL +// RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=trace-pc-guard,pc-table %s -### 2>&1 | FileCheck %s --check-prefix=CHECK_PC_TABLE_FOR_INLINEBOOL +// CHECK_PC_TABLE_FOR_INLINEBOOL: -fsanitize-coverage-pc-table // RUN: %clang_cl --target=i386-pc-win32 -fsanitize=address -fsanitize-coverage=func,trace-pc-guard -c -### -- %s 2>&1 | FileCheck %s -check-prefix=CLANG-CL-COVERAGE // CLANG-CL-COVERAGE-NOT: error: diff --git a/compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_inline_bool_flag.cpp b/compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_inline_bool_flag.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_inline_bool_flag.cpp @@ -0,0 +1,42 @@ +// Tests -fsanitize-coverage=inline-bool-flag,pc-table +// +// REQUIRES: has_sancovcc,stable-runtime +// UNSUPPORTED: i386-darwin +// +// RUN: %clangxx -O0 %s -fsanitize-coverage=inline-bool-flag,pc-table -o %t +// RUN: %run %t 2>&1 | FileCheck %s +// XFAIL: tsan + +#include +#include +#include + +const bool *first_flag; + +extern "C" void __sanitizer_cov_bool_flag_init(const bool *start, + const bool *end) { + printf("INIT: %p %p\n", start, end); + assert(end - start > 1); + first_flag = start; +} + +uintptr_t FirstPC; +uintptr_t FirstPCFlag; + +extern "C" void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg, + const uintptr_t *pcs_end) { + const uintptr_t *B = (const uintptr_t *)pcs_beg; + const uintptr_t *E = (const uintptr_t *)pcs_end; + assert(B + 1 < E); + FirstPC = B[0]; + FirstPCFlag = B[1]; +} + +int main() { + assert(first_flag); + assert(*first_flag); + assert(FirstPC == (uintptr_t)&main); + assert(FirstPCFlag == 1); + fprintf(stderr, "PASS\n"); + // CHECK: PASS +} diff --git a/llvm/include/llvm/Transforms/Instrumentation.h b/llvm/include/llvm/Transforms/Instrumentation.h --- a/llvm/include/llvm/Transforms/Instrumentation.h +++ b/llvm/include/llvm/Transforms/Instrumentation.h @@ -174,6 +174,7 @@ bool TracePC = false; bool TracePCGuard = false; bool Inline8bitCounters = false; + bool InlineBoolFlag = false; bool PCTable = false; bool NoPrune = false; bool StackDepth = false; diff --git a/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp b/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp --- a/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp +++ b/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp @@ -67,6 +67,8 @@ "sancov.module_ctor_trace_pc_guard"; static const char *const SanCovModuleCtor8bitCountersName = "sancov.module_ctor_8bit_counters"; +static const char *const SanCovModuleCtorBoolFlagName = + "sancov.module_ctor_bool_flag"; static const uint64_t SanCtorAndDtorPriority = 2; static const char *const SanCovTracePCGuardName = @@ -75,10 +77,13 @@ "__sanitizer_cov_trace_pc_guard_init"; static const char *const SanCov8bitCountersInitName = "__sanitizer_cov_8bit_counters_init"; +static const char *const SanCovBoolFlagInitName = + "__sanitizer_cov_bool_flag_init"; static const char *const SanCovPCsInitName = "__sanitizer_cov_pcs_init"; static const char *const SanCovGuardsSectionName = "sancov_guards"; static const char *const SanCovCountersSectionName = "sancov_cntrs"; +static const char *const SanCovBoolFlagSectionName = "sancov_bool_flag"; static const char *const SanCovPCsSectionName = "sancov_pcs"; static const char *const SanCovLowestStackName = "__sancov_lowest_stack"; @@ -101,7 +106,8 @@ // BBs, put this global into a named section, and pass this section's bounds // to __sanitizer_cov_pcs_init. // This way the coverage instrumentation does not need to acquire the PCs -// at run-time. Works with trace-pc-guard and inline-8bit-counters. +// at run-time. Works with trace-pc-guard, inline-8bit-counters, and +// inline-bool-flag. static cl::opt ClCreatePCTable("sanitizer-coverage-pc-table", cl::desc("create a static PC table"), cl::Hidden, cl::init(false)); @@ -111,6 +117,11 @@ cl::desc("increments 8-bit counter for every edge"), cl::Hidden, cl::init(false)); +static cl::opt + ClInlineBoolFlag("sanitizer-coverage-inline-bool-flag", + cl::desc("sets a boolean flag for every edge"), cl::Hidden, + cl::init(false)); + static cl::opt ClCMPTracing("sanitizer-coverage-trace-compares", cl::desc("Tracing of CMP and similar instructions"), @@ -169,11 +180,13 @@ Options.TracePC |= ClTracePC; Options.TracePCGuard |= ClTracePCGuard; Options.Inline8bitCounters |= ClInline8bitCounters; + Options.InlineBoolFlag |= ClInlineBoolFlag; Options.PCTable |= ClCreatePCTable; Options.NoPrune |= !ClPruneBlocks; Options.StackDepth |= ClStackDepth; if (!Options.TracePCGuard && !Options.TracePC && - !Options.Inline8bitCounters && !Options.StackDepth) + !Options.Inline8bitCounters && !Options.StackDepth && + !Options.InlineBoolFlag) Options.TracePCGuard = true; // TracePCGuard is default. return Options; } @@ -235,7 +248,7 @@ GlobalVariable *SanCovLowestStack; InlineAsm *EmptyAsm; Type *IntptrTy, *IntptrPtrTy, *Int64Ty, *Int64PtrTy, *Int32Ty, *Int32PtrTy, - *Int16Ty, *Int8Ty, *Int8PtrTy; + *Int16Ty, *Int8Ty, *Int8PtrTy, *Int1Ty, *Int1PtrTy; Module *CurModule; std::string CurModuleUniqueId; Triple TargetTriple; @@ -244,6 +257,7 @@ GlobalVariable *FunctionGuardArray; // for trace-pc-guard. GlobalVariable *Function8bitCounterArray; // for inline-8bit-counters. + GlobalVariable *FunctionBoolArray; // for inline-bool-flag. GlobalVariable *FunctionPCsArray; // for pc-table. SmallVector GlobalsToAppendToUsed; SmallVector GlobalsToAppendToCompilerUsed; @@ -367,6 +381,7 @@ TargetTriple = Triple(M.getTargetTriple()); FunctionGuardArray = nullptr; Function8bitCounterArray = nullptr; + FunctionBoolArray = nullptr; FunctionPCsArray = nullptr; IntptrTy = Type::getIntNTy(*C, DL->getPointerSizeInBits()); IntptrPtrTy = PointerType::getUnqual(IntptrTy); @@ -375,10 +390,12 @@ Int64PtrTy = PointerType::getUnqual(IRB.getInt64Ty()); Int32PtrTy = PointerType::getUnqual(IRB.getInt32Ty()); Int8PtrTy = PointerType::getUnqual(IRB.getInt8Ty()); + Int1PtrTy = PointerType::getUnqual(IRB.getInt1Ty()); Int64Ty = IRB.getInt64Ty(); Int32Ty = IRB.getInt32Ty(); Int16Ty = IRB.getInt16Ty(); Int8Ty = IRB.getInt8Ty(); + Int1Ty = IRB.getInt1Ty(); SanCovTracePCIndir = M.getOrInsertFunction(SanCovTracePCIndirName, VoidTy, IntptrTy); @@ -462,6 +479,11 @@ Ctor = CreateInitCallsForSections(M, SanCovModuleCtor8bitCountersName, SanCov8bitCountersInitName, Int8PtrTy, SanCovCountersSectionName); + if (FunctionBoolArray) { + Ctor = CreateInitCallsForSections(M, SanCovModuleCtorBoolFlagName, + SanCovBoolFlagInitName, Int1PtrTy, + SanCovBoolFlagSectionName); + } if (Ctor && Options.PCTable) { auto SecStartEnd = CreateSecStartEnd(M, SanCovPCsSectionName, IntptrPtrTy); FunctionCallee InitFunction = declareSanitizerInitFunction( @@ -701,6 +723,9 @@ if (Options.Inline8bitCounters) Function8bitCounterArray = CreateFunctionLocalArrayInSection( AllBlocks.size(), F, Int8Ty, SanCovCountersSectionName); + if (Options.InlineBoolFlag) + FunctionBoolArray = CreateFunctionLocalArrayInSection( + AllBlocks.size(), F, Int1Ty, SanCovBoolFlagSectionName); if (Options.PCTable) FunctionPCsArray = CreatePCArray(F, AllBlocks); @@ -727,7 +752,8 @@ Function &F, ArrayRef IndirCalls) { if (IndirCalls.empty()) return; - assert(Options.TracePC || Options.TracePCGuard || Options.Inline8bitCounters); + assert(Options.TracePC || Options.TracePCGuard || + Options.Inline8bitCounters || Options.InlineBoolFlag); for (auto I : IndirCalls) { IRBuilder<> IRB(I); CallSite CS(I); @@ -886,6 +912,15 @@ SetNoSanitizeMetadata(Load); SetNoSanitizeMetadata(Store); } + if (Options.InlineBoolFlag) { + auto FlagPtr = IRB.CreateGEP( + FunctionBoolArray->getValueType(), FunctionBoolArray, + {ConstantInt::get(IntptrTy, 0), ConstantInt::get(IntptrTy, Idx)}); + auto Store = IRB.CreateStore(ConstantInt::getTrue(Int1Ty), FlagPtr); + Store->setAtomic(AtomicOrdering::NotAtomic); + Store->setAlignment(llvm::MaybeAlign(FunctionBoolArray->getAlign())); + SetNoSanitizeMetadata(Store); + } if (Options.StackDepth && IsEntryBB && !IsLeafFunc) { // Check stack depth. If it's the deepest so far, record it. Module *M = F.getParent(); @@ -910,6 +945,8 @@ if (TargetTriple.isOSBinFormatCOFF()) { if (Section == SanCovCountersSectionName) return ".SCOV$CM"; + if (Section == SanCovBoolFlagSectionName) + return ".SCOV$BM"; if (Section == SanCovPCsSectionName) return ".SCOVP$M"; return ".SCOV$GM"; // For SanCovGuardsSectionName. diff --git a/llvm/test/Instrumentation/SanitizerCoverage/coff-pc-table-inline-bool-flag.ll b/llvm/test/Instrumentation/SanitizerCoverage/coff-pc-table-inline-bool-flag.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Instrumentation/SanitizerCoverage/coff-pc-table-inline-bool-flag.ll @@ -0,0 +1,13 @@ +; Checks that the PC and 8-bit Counter Arrays are placed in their own sections in COFF binaries. +; RUN: opt < %s -sancov -sanitizer-coverage-level=1 -sanitizer-coverage-inline-bool-flag=1 -sanitizer-coverage-pc-table=1 -S | FileCheck %s +; RUN: opt < %s -passes='module(sancov-module)' -sanitizer-coverage-level=1 -sanitizer-coverage-inline-bool-flag=1 -sanitizer-coverage-pc-table=1 -S | FileCheck %s +target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc19.14.26433" + +define void @foo() { +entry: + ret void +} + +; CHECK-DAG: section ".SCOV{{\$}}BM", +; CHECK-DAG: section ".SCOVP{{\$}}M", diff --git a/llvm/test/Instrumentation/SanitizerCoverage/inline-bool-flag.ll b/llvm/test/Instrumentation/SanitizerCoverage/inline-bool-flag.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Instrumentation/SanitizerCoverage/inline-bool-flag.ll @@ -0,0 +1,13 @@ +; Test -sanitizer-coverage-inline-bool-flag=1 +; RUN: opt < %s -sancov -sanitizer-coverage-level=1 -sanitizer-coverage-inline-bool-flag=1 -S | FileCheck %s +; RUN: opt < %s -passes='module(sancov-module)' -sanitizer-coverage-level=1 -sanitizer-coverage-inline-bool-flag=1 -S | FileCheck %s + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" +target triple = "x86_64-unknown-linux-gnu" +define void @foo() { +entry: +; CHECK: section "__sancov_bool_flag", comdat($foo), !associated !0 +; CHECK: store i1 true, i1* getelementptr inbounds ([1 x i1], [1 x i1]* @__sancov_gen_, i64 0, i64 0), !nosanitize !1 + ret void +} +; CHECK: call void @__sanitizer_cov_bool_flag_init(i1* bitcast (i1** @__start___sancov_bool_flag to i1*), i1* bitcast (i1** @__stop___sancov_bool_flag to i1*)) diff --git a/llvm/test/Instrumentation/SanitizerCoverage/pc-table.ll b/llvm/test/Instrumentation/SanitizerCoverage/pc-table.ll --- a/llvm/test/Instrumentation/SanitizerCoverage/pc-table.ll +++ b/llvm/test/Instrumentation/SanitizerCoverage/pc-table.ll @@ -1,8 +1,10 @@ ; Test -sanitizer-coverage-pc-table=1 ; RUN: opt < %s -sancov -sanitizer-coverage-level=3 -sanitizer-coverage-trace-pc-guard -sanitizer-coverage-pc-table=1 -S | FileCheck %s ; RUN: opt < %s -sancov -sanitizer-coverage-level=3 -sanitizer-coverage-inline-8bit-counters -sanitizer-coverage-pc-table=1 -S | FileCheck %s +; RUN: opt < %s -sancov -sanitizer-coverage-level=3 -sanitizer-coverage-inline-bool-flag -sanitizer-coverage-pc-table=1 -S | FileCheck %s ; RUN: opt < %s -passes='module(sancov-module)' -sanitizer-coverage-level=3 -sanitizer-coverage-trace-pc-guard -sanitizer-coverage-pc-table=1 -S | FileCheck %s ; RUN: opt < %s -passes='module(sancov-module)' -sanitizer-coverage-level=3 -sanitizer-coverage-inline-8bit-counters -sanitizer-coverage-pc-table=1 -S | FileCheck %s +; RUN: opt < %s -passes='module(sancov-module)' -sanitizer-coverage-level=3 -sanitizer-coverage-inline-bool-flag -sanitizer-coverage-pc-table=1 -S | FileCheck %s target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" target triple = "x86_64-unknown-linux-gnu" diff --git a/llvm/test/Instrumentation/SanitizerCoverage/trace-pc-guard-inline-bool-flag.ll b/llvm/test/Instrumentation/SanitizerCoverage/trace-pc-guard-inline-bool-flag.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Instrumentation/SanitizerCoverage/trace-pc-guard-inline-bool-flag.ll @@ -0,0 +1,14 @@ +; RUN: opt < %s -sancov -sanitizer-coverage-level=1 -sanitizer-coverage-trace-pc-guard -sanitizer-coverage-inline-bool-flag -S | FileCheck %s +; RUN: opt < %s -passes='module(sancov-module)' -sanitizer-coverage-level=1 -sanitizer-coverage-trace-pc-guard -sanitizer-coverage-inline-bool-flag -S | FileCheck %s + +; Module ctors should have stable names across modules, not something like +; @sancov.module_ctor.3 that may cause duplicate ctors after linked together. + +; CHECK: define internal void @sancov.module_ctor_trace_pc_guard() comdat { +; CHECK: define internal void @sancov.module_ctor_bool_flag() comdat { + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" +target triple = "x86_64-unknown-linux-gnu" +define void @foo() { + ret void +}