From 4e32edbff5d34dfc779797d73bb61d32ffa02953 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 7 Aug 2024 21:05:26 -0700 Subject: [PATCH] fuzzing: comptime assertions to protect the ABI compile errors are nice --- lib/fuzzer.zig | 7 +++++++ lib/std/Build/Fuzz/WebServer.zig | 6 ++++++ lib/std/Build/Fuzz/abi.zig | 9 ++++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/fuzzer.zig b/lib/fuzzer.zig index a5d8c9bbbf..6802d9dd69 100644 --- a/lib/fuzzer.zig +++ b/lib/fuzzer.zig @@ -214,6 +214,9 @@ const Fuzzer = struct { }); defer coverage_file.close(); const n_bitset_elems = (flagged_pcs.len + 7) / 8; + comptime assert(SeenPcsHeader.trailing[0] == .pc_addr); + comptime assert(SeenPcsHeader.trailing[1][0] == .pc_bits); + comptime assert(SeenPcsHeader.trailing[1][1] == u8); const bytes_len = @sizeOf(SeenPcsHeader) + flagged_pcs.len * @sizeOf(usize) + n_bitset_elems; const existing_len = coverage_file.getEndPos() catch |err| { fatal("unable to check len of coverage file: {s}", .{@errorName(err)}); @@ -301,6 +304,10 @@ const Fuzzer = struct { // Track code coverage from all runs. { + comptime assert(SeenPcsHeader.trailing[0] == .pc_addr); + comptime assert(SeenPcsHeader.trailing[1][0] == .pc_bits); + comptime assert(SeenPcsHeader.trailing[1][1] == u8); + const seen_pcs = f.seen_pcs.items[@sizeOf(SeenPcsHeader) + f.flagged_pcs.len * @sizeOf(usize) ..]; for (seen_pcs, 0..) |*elem, i| { const byte_i = i * 8; diff --git a/lib/std/Build/Fuzz/WebServer.zig b/lib/std/Build/Fuzz/WebServer.zig index 7b0c24c3e2..f0c9e8dfe3 100644 --- a/lib/std/Build/Fuzz/WebServer.zig +++ b/lib/std/Build/Fuzz/WebServer.zig @@ -7,6 +7,7 @@ const Step = std.Build.Step; const Coverage = std.debug.Coverage; const abi = std.Build.Fuzz.abi; const log = std.log; +const assert = std.debug.assert; const WebServer = @This(); @@ -383,7 +384,10 @@ fn sendCoverageContext( // TODO: make each events URL correspond to one coverage map const coverage_map = &coverage_maps[0]; const cov_header: *const abi.SeenPcsHeader = @ptrCast(coverage_map.mapped_memory[0..@sizeOf(abi.SeenPcsHeader)]); + comptime assert(abi.SeenPcsHeader.trailing[0] == .pc_addr); const seen_pcs = coverage_map.mapped_memory[@sizeOf(abi.SeenPcsHeader) + coverage_map.source_locations.len * @sizeOf(usize) ..]; + comptime assert(abi.SeenPcsHeader.trailing[1][0] == .pc_bits); + comptime assert(abi.SeenPcsHeader.trailing[1][1] == u8); const n_runs = @atomicLoad(usize, &cov_header.n_runs, .monotonic); const unique_runs = @atomicLoad(usize, &cov_header.unique_runs, .monotonic); const lowest_stack = @atomicLoad(usize, &cov_header.lowest_stack, .monotonic); @@ -630,6 +634,7 @@ fn prepareTables( gop.value_ptr.mapped_memory = mapped_memory; const header: *const abi.SeenPcsHeader = @ptrCast(mapped_memory[0..@sizeOf(abi.SeenPcsHeader)]); + comptime assert(abi.SeenPcsHeader.trailing[0] == .pc_addr); const pcs_bytes = mapped_memory[@sizeOf(abi.SeenPcsHeader)..][0 .. header.pcs_len * @sizeOf(usize)]; const pcs = std.mem.bytesAsSlice(usize, pcs_bytes); const source_locations = try gpa.alloc(Coverage.SourceLocation, pcs.len); @@ -649,6 +654,7 @@ fn addEntryPoint(ws: *WebServer, coverage_id: u64, addr: u64) error{ AlreadyRepo const coverage_map = ws.coverage_files.getPtr(coverage_id).?; const ptr = coverage_map.mapped_memory; + comptime assert(abi.SeenPcsHeader.trailing[0] == .pc_addr); const pcs_bytes = ptr[@sizeOf(abi.SeenPcsHeader)..][0 .. coverage_map.source_locations.len * @sizeOf(usize)]; const pcs: []const usize = @alignCast(std.mem.bytesAsSlice(usize, pcs_bytes)); const index = std.sort.upperBound(usize, pcs, addr, struct { diff --git a/lib/std/Build/Fuzz/abi.zig b/lib/std/Build/Fuzz/abi.zig index f385f9b08a..1d6585de7a 100644 --- a/lib/std/Build/Fuzz/abi.zig +++ b/lib/std/Build/Fuzz/abi.zig @@ -8,12 +8,19 @@ /// /// Trailing: /// * pc_addr: usize for each pcs_len -/// * 1 bit per pc_addr, usize elements +/// * 1 bit per pc_addr, u8 elements pub const SeenPcsHeader = extern struct { n_runs: usize, unique_runs: usize, pcs_len: usize, lowest_stack: usize, + + /// Used for comptime assertions. Provides a mechanism for strategically + /// causing compile errors. + pub const trailing = .{ + .pc_addr, + .{ .pc_bits, u8 }, + }; }; pub const ToClientTag = enum(u8) {