From 84ece5624a153da44faca52ff622cd03b887d375 Mon Sep 17 00:00:00 2001 From: Xavier Bouchoux Date: Mon, 17 Feb 2025 08:52:13 +0100 Subject: [PATCH] fix `-fsanitize-coverage-trace-pc-guard` and fuzzer support for C compile units - allow `-fsanitize-coverage-trace-pc-guard` to be used on its own without enabling the fuzzer. (note that previouly, while the flag was only active when fuzzing, the fuzzer itself doesn't use it, and the code will not link as is.) - add stub functions in the fuzzer to link with instrumented C code (previously fuzzed tests failed to link if they were calling into C): while the zig compile unit uses a custom `EmitOptions.Coverage` with features disabled, the C code is built calling into the clang driver with "-fsanitize=fuzzer-no-link" that automatically enables the default features. (see https://github.com/llvm/llvm-project/blob/de06978ebcff5f75913067b019d2d522d0be0872/clang/lib/Driver/SanitizerArgs.cpp#L587) - emit `-fsanitize-coverage=trace-pc-guard` instead of `-Xclang -fsanitize-coverage-trace-pc-guard` so that edge coverrage is enabled by clang driver. (previously, it was enabled only because the fuzzer was) --- lib/fuzzer.zig | 12 ++++++++++++ src/Compilation.zig | 6 +++--- src/codegen/llvm.zig | 6 ++++-- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/lib/fuzzer.zig b/lib/fuzzer.zig index 4c1f425a18849a0591d6decf575f227d090fd8a1..0c287c6afc14fef4db636f69aee0cc78891b2877 100644 --- a/lib/fuzzer.zig +++ b/lib/fuzzer.zig @@ -83,6 +83,18 @@ export fn __sanitizer_cov_trace_pc_indir(callee: usize) void { //fuzzer.traceValue(pc ^ callee); //std.log.debug("0x{x}: indirect call to 0x{x}", .{ pc, callee }); } +export fn __sanitizer_cov_8bit_counters_init(start: usize, end: usize) void { + // clang will emit a call to this function when compiling with code coverage instrumentation. + // however fuzzer_init() does not need this information, since it directly reads from the symbol table. + _ = start; + _ = end; +} +export fn __sanitizer_cov_pcs_init(start: usize, end: usize) void { + // clang will emit a call to this function when compiling with code coverage instrumentation. + // however fuzzer_init() does not need this information, since it directly reads from the symbol table. + _ = start; + _ = end; +} fn handleCmp(pc: usize, arg1: u64, arg2: u64) void { fuzzer.traceValue(pc ^ arg1 ^ arg2); diff --git a/src/Compilation.zig b/src/Compilation.zig index aafbc30fefd11a8cb6d422ecae0c90f5104cdf24..c2b72c6b0f3a0e8b8c0f527f158a5e7b8bd89e27 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -5922,10 +5922,10 @@ pub fn addCCArgs( // function was called. try argv.append("-fno-sanitize=function"); } + } - if (comp.config.san_cov_trace_pc_guard) { - try argv.appendSlice(&.{ "-Xclang", "-fsanitize-coverage-trace-pc-guard" }); - } + if (comp.config.san_cov_trace_pc_guard) { + try argv.append("-fsanitize-coverage=trace-pc-guard"); } } diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 41c817303c1dd82e133315beddc330a134201308..6970d0721a0fc586727ce5491e7db1ab212d5270 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1333,7 +1333,6 @@ pub const Object = struct { .is_small = options.is_small, .time_report = options.time_report, .tsan = options.sanitize_thread, - .sancov = options.fuzz, .lto = options.lto != .none, // https://github.com/ziglang/zig/issues/21215 .allow_fast_isel = !comp.root_mod.resolved_target.result.cpu.arch.isMIPS(), @@ -1341,6 +1340,9 @@ pub const Object = struct { .bin_filename = options.bin_path, .llvm_ir_filename = options.post_ir_path, .bitcode_filename = null, + + // `.coverage` value is only used when `.sancov` is enabled. + .sancov = options.fuzz or comp.config.san_cov_trace_pc_guard, .coverage = .{ .CoverageType = .Edge, // Works in tandem with Inline8bitCounters or InlineBoolFlag. @@ -1348,7 +1350,7 @@ pub const Object = struct { // needs to for better fuzzing logic. .IndirectCalls = false, .TraceBB = false, - .TraceCmp = true, + .TraceCmp = options.fuzz, .TraceDiv = false, .TraceGep = false, .Use8bitCounters = false, -- 2.54.0