diff --git a/docs/SanitizerCoverage.rst b/docs/SanitizerCoverage.rst index 6d6e576e464506662f8bb9029b8238f35a386017..8ee2159ea31ac4f9cd8bfd96fa87548796c9b8e8 100644 --- a/docs/SanitizerCoverage.rst +++ b/docs/SanitizerCoverage.rst @@ -294,13 +294,14 @@ With ``-fsanitize-coverage=trace-bb`` the compiler will insert Tracing PCs =========== *Experimental* feature similar to tracing basic blocks, but with a different API. -With ``-fsanitize-coverage=[func,bb,edge],trace-pc`` the compiler will insert -``__sanitizer_cov_trace_pc()`` on every function/block/edge. -With and additional ``indirect-calls`` flag +With ``-fsanitize-coverage=trace-pc`` the compiler will insert +``__sanitizer_cov_trace_pc()`` on every edge. +With an additional ``...=trace-pc,indirect-calls`` flag ``__sanitizer_cov_trace_pc_indirect(void *callee)`` will be inserted on every indirect call. These callbacks are not implemented in the Sanitizer run-time and should be defined -by the user. -This mechanism is used for fuzzing the Linux kernel (https://github.com/google/syzkaller). +by the user. So, these flags do not require the other sanitizer to be used. +This mechanism is used for fuzzing the Linux kernel (https://github.com/google/syzkaller) +and can be used with `AFL <http://lcamtuf.coredump.cx/afl>`_. Tracing data flow ================= diff --git a/lib/Driver/SanitizerArgs.cpp b/lib/Driver/SanitizerArgs.cpp index 3e49989d866abd51b4fda93ce11c896031275c1d..10a506df713f5fb4e0e0e56f373e80cab33c1783 100644 --- a/lib/Driver/SanitizerArgs.cpp +++ b/lib/Driver/SanitizerArgs.cpp @@ -437,42 +437,45 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, // Parse -f(no-)?sanitize-coverage flags if coverage is supported by the // enabled sanitizers. - if (AllAddedKinds & SupportsCoverage) { - for (const auto *Arg : Args) { - if (Arg->getOption().matches(options::OPT_fsanitize_coverage)) { - Arg->claim(); - int LegacySanitizeCoverage; - if (Arg->getNumValues() == 1 && - !StringRef(Arg->getValue(0)) - .getAsInteger(0, LegacySanitizeCoverage) && - LegacySanitizeCoverage >= 0 && LegacySanitizeCoverage <= 4) { - D.Diag(diag::warn_drv_deprecated_arg) - << Arg->getAsString(Args) << "-fsanitize-coverage=[func,bb,edge]"; - // TODO: Add deprecation notice for this form. - switch (LegacySanitizeCoverage) { - case 0: - CoverageFeatures = 0; - break; - case 1: - CoverageFeatures = CoverageFunc; - break; - case 2: - CoverageFeatures = CoverageBB; - break; - case 3: - CoverageFeatures = CoverageEdge; - break; - case 4: - CoverageFeatures = CoverageEdge | CoverageIndirCall; - break; - } - continue; + for (const auto *Arg : Args) { + if (Arg->getOption().matches(options::OPT_fsanitize_coverage)) { + int LegacySanitizeCoverage; + if (Arg->getNumValues() == 1 && + !StringRef(Arg->getValue(0)) + .getAsInteger(0, LegacySanitizeCoverage) && + LegacySanitizeCoverage >= 0 && LegacySanitizeCoverage <= 4) { + D.Diag(diag::warn_drv_deprecated_arg) + << Arg->getAsString(Args) << "-fsanitize-coverage=[func,bb,edge]"; + // TODO: Add deprecation notice for this form. + switch (LegacySanitizeCoverage) { + case 0: + CoverageFeatures = 0; + break; + case 1: + CoverageFeatures = CoverageFunc; + break; + case 2: + CoverageFeatures = CoverageBB; + break; + case 3: + CoverageFeatures = CoverageEdge; + break; + case 4: + CoverageFeatures = CoverageEdge | CoverageIndirCall; + break; } - CoverageFeatures |= parseCoverageFeatures(D, Arg); - } else if (Arg->getOption().matches(options::OPT_fno_sanitize_coverage)) { + continue; + } + CoverageFeatures |= parseCoverageFeatures(D, Arg); + // If there is trace-pc, allow it w/o any of the sanitizers. + // Otherwise, require that one of the supported sanitizers is present. + if ((CoverageFeatures & CoverageTracePC) || + (AllAddedKinds & SupportsCoverage)) { Arg->claim(); - CoverageFeatures &= ~parseCoverageFeatures(D, Arg); } + } else if (Arg->getOption().matches(options::OPT_fno_sanitize_coverage)) { + Arg->claim(); + CoverageFeatures &= ~parseCoverageFeatures(D, Arg); } } // Choose at most one coverage type: function, bb, or edge. @@ -501,11 +504,10 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, D.Diag(clang::diag::err_drv_argument_only_allowed_with) << "-fsanitize-coverage=8bit-counters" << "-fsanitize-coverage=(func|bb|edge)"; + // trace-pc w/o func/bb/edge implies edge. if ((CoverageFeatures & CoverageTracePC) && !(CoverageFeatures & CoverageTypes)) - D.Diag(clang::diag::err_drv_argument_only_allowed_with) - << "-fsanitize-coverage=trace-pc" - << "-fsanitize-coverage=(func|bb|edge)"; + CoverageFeatures |= CoverageEdge; if (AllAddedKinds & Address) { AsanSharedRuntime = @@ -576,6 +578,23 @@ static void addIncludeLinkerOption(const ToolChain &TC, void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, types::ID InputType) const { + // Translate available CoverageFeatures to corresponding clang-cc1 flags. + // Do it even if Sanitizers.empty() since some forms of coverage don't require + // sanitizers. + std::pair<int, const char *> 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(Coverage8bitCounters, "-fsanitize-coverage-8bit-counters"), + std::make_pair(CoverageTracePC, "-fsanitize-coverage-trace-pc")}; + for (auto F : CoverageFlags) { + if (CoverageFeatures & F.first) + CmdArgs.push_back(Args.MakeArgString(F.second)); + } + if (Sanitizers.empty()) return; CmdArgs.push_back(Args.MakeArgString("-fsanitize=" + toString(Sanitizers))); @@ -615,21 +634,6 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, if (AsanFieldPadding) CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" + llvm::utostr(AsanFieldPadding))); - // Translate available CoverageFeatures to corresponding clang-cc1 flags. - std::pair<int, const char *> 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(Coverage8bitCounters, "-fsanitize-coverage-8bit-counters"), - std::make_pair(CoverageTracePC, "-fsanitize-coverage-trace-pc")}; - for (auto F : CoverageFlags) { - if (CoverageFeatures & F.first) - CmdArgs.push_back(Args.MakeArgString(F.second)); - } - // MSan: Workaround for PR16386. // ASan: This is mainly to help LSan with cases such as diff --git a/test/Driver/fsanitize-coverage.c b/test/Driver/fsanitize-coverage.c index 7aff3c270d3b7431b35ef06d733d5da842bf1b6e..2e12ff334f6c24806c9f8089475f6214b132c337 100644 --- a/test/Driver/fsanitize-coverage.c +++ b/test/Driver/fsanitize-coverage.c @@ -56,6 +56,14 @@ // RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=8bit-counters %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-MISSING-TYPE // CHECK-MISSING-TYPE: error: invalid argument '-fsanitize-coverage=8bit-counters' only allowed with '-fsanitize-coverage=(func|bb|edge)' +// RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=trace-pc %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TRACE_PC_EDGE +// RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=edge,trace-pc %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TRACE_PC_EDGE +// CHECK-TRACE_PC_EDGE: -fsanitize-coverage-type=3 +// CHECK-TRACE_PC_EDGE: -fsanitize-coverage-trace-pc +// RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=func,trace-pc %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TRACE_PC_FUNC +// CHECK-TRACE_PC_FUNC: -fsanitize-coverage-type=1 +// CHECK-TRACE_PC_FUNC: -fsanitize-coverage-trace-pc + // RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=trace-cmp,indirect-calls %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-TYPE-NECESSARY // CHECK-NO-TYPE-NECESSARY-NOT: error: // CHECK-NO-TYPE-NECESSARY: -fsanitize-coverage-indirect-calls @@ -70,5 +78,5 @@ // CLANG-CL-COVERAGE-NOT: warning: // CLANG-CL-COVERAGE-NOT: argument unused // CLANG-CL-COVERAGE-NOT: unknown argument -// CLANG-CL-COVERAGE: -fsanitize=address // CLANG-CL-COVERAGE: -fsanitize-coverage-type=1 +// CLANG-CL-COVERAGE: -fsanitize=address