authorgravatar for xavierb@gmail.comXavier Bouchoux <xavierb@gmail.com> 2025-02-17 08:52:13+01:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-02-21 06:06:26+01:00
log84ece5624a153da44faca52ff622cd03b887d375
treea5d520b4f102b6dda9a145f7e4aa9a214894378b
parentaa5c6c027c3f69602f5bcd1ad0b4a89232c85ae1

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)

3 files changed, 19 insertions(+), 5 deletions(-)

lib/fuzzer.zig+12
...@@ -83,6 +83,18 @@ export fn __sanitizer_cov_trace_pc_indir(callee: usize) void {...@@ -83,6 +83,18 @@ export fn __sanitizer_cov_trace_pc_indir(callee: usize) void {
83 //fuzzer.traceValue(pc ^ callee);83 //fuzzer.traceValue(pc ^ callee);
84 //std.log.debug("0x{x}: indirect call to 0x{x}", .{ pc, callee });84 //std.log.debug("0x{x}: indirect call to 0x{x}", .{ pc, callee });
85}85}
86export fn __sanitizer_cov_8bit_counters_init(start: usize, end: usize) void {
87 // clang will emit a call to this function when compiling with code coverage instrumentation.
88 // however fuzzer_init() does not need this information, since it directly reads from the symbol table.
89 _ = start;
90 _ = end;
91}
92export fn __sanitizer_cov_pcs_init(start: usize, end: usize) void {
93 // clang will emit a call to this function when compiling with code coverage instrumentation.
94 // however fuzzer_init() does not need this information, since it directly reads from the symbol table.
95 _ = start;
96 _ = end;
97}
8698
87fn handleCmp(pc: usize, arg1: u64, arg2: u64) void {99fn handleCmp(pc: usize, arg1: u64, arg2: u64) void {
88 fuzzer.traceValue(pc ^ arg1 ^ arg2);100 fuzzer.traceValue(pc ^ arg1 ^ arg2);
src/Compilation.zig+3-3
...@@ -5922,10 +5922,10 @@ pub fn addCCArgs(...@@ -5922,10 +5922,10 @@ pub fn addCCArgs(
5922 // function was called.5922 // function was called.
5923 try argv.append("-fno-sanitize=function");5923 try argv.append("-fno-sanitize=function");
5924 }5924 }
5925 }
59255926
5926 if (comp.config.san_cov_trace_pc_guard) {5927 if (comp.config.san_cov_trace_pc_guard) {
5927 try argv.appendSlice(&.{ "-Xclang", "-fsanitize-coverage-trace-pc-guard" });5928 try argv.append("-fsanitize-coverage=trace-pc-guard");
5928 }
5929 }5929 }
5930 }5930 }
59315931
src/codegen/llvm.zig+4-2
...@@ -1333,7 +1333,6 @@ pub const Object = struct {...@@ -1333,7 +1333,6 @@ pub const Object = struct {
1333 .is_small = options.is_small,1333 .is_small = options.is_small,
1334 .time_report = options.time_report,1334 .time_report = options.time_report,
1335 .tsan = options.sanitize_thread,1335 .tsan = options.sanitize_thread,
1336 .sancov = options.fuzz,
1337 .lto = options.lto != .none,1336 .lto = options.lto != .none,
1338 // https://github.com/ziglang/zig/issues/212151337 // https://github.com/ziglang/zig/issues/21215
1339 .allow_fast_isel = !comp.root_mod.resolved_target.result.cpu.arch.isMIPS(),1338 .allow_fast_isel = !comp.root_mod.resolved_target.result.cpu.arch.isMIPS(),
...@@ -1341,6 +1340,9 @@ pub const Object = struct {...@@ -1341,6 +1340,9 @@ pub const Object = struct {
1341 .bin_filename = options.bin_path,1340 .bin_filename = options.bin_path,
1342 .llvm_ir_filename = options.post_ir_path,1341 .llvm_ir_filename = options.post_ir_path,
1343 .bitcode_filename = null,1342 .bitcode_filename = null,
1343
1344 // `.coverage` value is only used when `.sancov` is enabled.
1345 .sancov = options.fuzz or comp.config.san_cov_trace_pc_guard,
1344 .coverage = .{1346 .coverage = .{
1345 .CoverageType = .Edge,1347 .CoverageType = .Edge,
1346 // Works in tandem with Inline8bitCounters or InlineBoolFlag.1348 // Works in tandem with Inline8bitCounters or InlineBoolFlag.
...@@ -1348,7 +1350,7 @@ pub const Object = struct {...@@ -1348,7 +1350,7 @@ pub const Object = struct {
1348 // needs to for better fuzzing logic.1350 // needs to for better fuzzing logic.
1349 .IndirectCalls = false,1351 .IndirectCalls = false,
1350 .TraceBB = false,1352 .TraceBB = false,
1351 .TraceCmp = true,1353 .TraceCmp = options.fuzz,
1352 .TraceDiv = false,1354 .TraceDiv = false,
1353 .TraceGep = false,1355 .TraceGep = false,
1354 .Use8bitCounters = false,1356 .Use8bitCounters = false,