authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-08-07 21:05:26-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-08-08 21:46:36-07:00
log4e32edbff5d34dfc779797d73bb61d32ffa02953
tree6641a92b99f5488d1891bfb7ef52f3104cc52053
parent2cfad202045632945b5007e1d42c2f8a326be44a

fuzzing: comptime assertions to protect the ABI

compile errors are nice

3 files changed, 21 insertions(+), 1 deletions(-)

lib/fuzzer.zig+7
...@@ -214,6 +214,9 @@ const Fuzzer = struct {...@@ -214,6 +214,9 @@ const Fuzzer = struct {
214 });214 });
215 defer coverage_file.close();215 defer coverage_file.close();
216 const n_bitset_elems = (flagged_pcs.len + 7) / 8;216 const n_bitset_elems = (flagged_pcs.len + 7) / 8;
217 comptime assert(SeenPcsHeader.trailing[0] == .pc_addr);
218 comptime assert(SeenPcsHeader.trailing[1][0] == .pc_bits);
219 comptime assert(SeenPcsHeader.trailing[1][1] == u8);
217 const bytes_len = @sizeOf(SeenPcsHeader) + flagged_pcs.len * @sizeOf(usize) + n_bitset_elems;220 const bytes_len = @sizeOf(SeenPcsHeader) + flagged_pcs.len * @sizeOf(usize) + n_bitset_elems;
218 const existing_len = coverage_file.getEndPos() catch |err| {221 const existing_len = coverage_file.getEndPos() catch |err| {
219 fatal("unable to check len of coverage file: {s}", .{@errorName(err)});222 fatal("unable to check len of coverage file: {s}", .{@errorName(err)});
...@@ -301,6 +304,10 @@ const Fuzzer = struct {...@@ -301,6 +304,10 @@ const Fuzzer = struct {
301304
302 // Track code coverage from all runs.305 // Track code coverage from all runs.
303 {306 {
307 comptime assert(SeenPcsHeader.trailing[0] == .pc_addr);
308 comptime assert(SeenPcsHeader.trailing[1][0] == .pc_bits);
309 comptime assert(SeenPcsHeader.trailing[1][1] == u8);
310
304 const seen_pcs = f.seen_pcs.items[@sizeOf(SeenPcsHeader) + f.flagged_pcs.len * @sizeOf(usize) ..];311 const seen_pcs = f.seen_pcs.items[@sizeOf(SeenPcsHeader) + f.flagged_pcs.len * @sizeOf(usize) ..];
305 for (seen_pcs, 0..) |*elem, i| {312 for (seen_pcs, 0..) |*elem, i| {
306 const byte_i = i * 8;313 const byte_i = i * 8;
lib/std/Build/Fuzz/WebServer.zig+6
...@@ -7,6 +7,7 @@ const Step = std.Build.Step;...@@ -7,6 +7,7 @@ const Step = std.Build.Step;
7const Coverage = std.debug.Coverage;7const Coverage = std.debug.Coverage;
8const abi = std.Build.Fuzz.abi;8const abi = std.Build.Fuzz.abi;
9const log = std.log;9const log = std.log;
10const assert = std.debug.assert;
1011
11const WebServer = @This();12const WebServer = @This();
1213
...@@ -383,7 +384,10 @@ fn sendCoverageContext(...@@ -383,7 +384,10 @@ fn sendCoverageContext(
383 // TODO: make each events URL correspond to one coverage map384 // TODO: make each events URL correspond to one coverage map
384 const coverage_map = &coverage_maps[0];385 const coverage_map = &coverage_maps[0];
385 const cov_header: *const abi.SeenPcsHeader = @ptrCast(coverage_map.mapped_memory[0..@sizeOf(abi.SeenPcsHeader)]);386 const cov_header: *const abi.SeenPcsHeader = @ptrCast(coverage_map.mapped_memory[0..@sizeOf(abi.SeenPcsHeader)]);
387 comptime assert(abi.SeenPcsHeader.trailing[0] == .pc_addr);
386 const seen_pcs = coverage_map.mapped_memory[@sizeOf(abi.SeenPcsHeader) + coverage_map.source_locations.len * @sizeOf(usize) ..];388 const seen_pcs = coverage_map.mapped_memory[@sizeOf(abi.SeenPcsHeader) + coverage_map.source_locations.len * @sizeOf(usize) ..];
389 comptime assert(abi.SeenPcsHeader.trailing[1][0] == .pc_bits);
390 comptime assert(abi.SeenPcsHeader.trailing[1][1] == u8);
387 const n_runs = @atomicLoad(usize, &cov_header.n_runs, .monotonic);391 const n_runs = @atomicLoad(usize, &cov_header.n_runs, .monotonic);
388 const unique_runs = @atomicLoad(usize, &cov_header.unique_runs, .monotonic);392 const unique_runs = @atomicLoad(usize, &cov_header.unique_runs, .monotonic);
389 const lowest_stack = @atomicLoad(usize, &cov_header.lowest_stack, .monotonic);393 const lowest_stack = @atomicLoad(usize, &cov_header.lowest_stack, .monotonic);
...@@ -630,6 +634,7 @@ fn prepareTables(...@@ -630,6 +634,7 @@ fn prepareTables(
630 gop.value_ptr.mapped_memory = mapped_memory;634 gop.value_ptr.mapped_memory = mapped_memory;
631635
632 const header: *const abi.SeenPcsHeader = @ptrCast(mapped_memory[0..@sizeOf(abi.SeenPcsHeader)]);636 const header: *const abi.SeenPcsHeader = @ptrCast(mapped_memory[0..@sizeOf(abi.SeenPcsHeader)]);
637 comptime assert(abi.SeenPcsHeader.trailing[0] == .pc_addr);
633 const pcs_bytes = mapped_memory[@sizeOf(abi.SeenPcsHeader)..][0 .. header.pcs_len * @sizeOf(usize)];638 const pcs_bytes = mapped_memory[@sizeOf(abi.SeenPcsHeader)..][0 .. header.pcs_len * @sizeOf(usize)];
634 const pcs = std.mem.bytesAsSlice(usize, pcs_bytes);639 const pcs = std.mem.bytesAsSlice(usize, pcs_bytes);
635 const source_locations = try gpa.alloc(Coverage.SourceLocation, pcs.len);640 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...@@ -649,6 +654,7 @@ fn addEntryPoint(ws: *WebServer, coverage_id: u64, addr: u64) error{ AlreadyRepo
649654
650 const coverage_map = ws.coverage_files.getPtr(coverage_id).?;655 const coverage_map = ws.coverage_files.getPtr(coverage_id).?;
651 const ptr = coverage_map.mapped_memory;656 const ptr = coverage_map.mapped_memory;
657 comptime assert(abi.SeenPcsHeader.trailing[0] == .pc_addr);
652 const pcs_bytes = ptr[@sizeOf(abi.SeenPcsHeader)..][0 .. coverage_map.source_locations.len * @sizeOf(usize)];658 const pcs_bytes = ptr[@sizeOf(abi.SeenPcsHeader)..][0 .. coverage_map.source_locations.len * @sizeOf(usize)];
653 const pcs: []const usize = @alignCast(std.mem.bytesAsSlice(usize, pcs_bytes));659 const pcs: []const usize = @alignCast(std.mem.bytesAsSlice(usize, pcs_bytes));
654 const index = std.sort.upperBound(usize, pcs, addr, struct {660 const index = std.sort.upperBound(usize, pcs, addr, struct {
lib/std/Build/Fuzz/abi.zig+8-1
...@@ -8,12 +8,19 @@...@@ -8,12 +8,19 @@
8///8///
9/// Trailing:9/// Trailing:
10/// * pc_addr: usize for each pcs_len10/// * pc_addr: usize for each pcs_len
11/// * 1 bit per pc_addr, usize elements11/// * 1 bit per pc_addr, u8 elements
12pub const SeenPcsHeader = extern struct {12pub const SeenPcsHeader = extern struct {
13 n_runs: usize,13 n_runs: usize,
14 unique_runs: usize,14 unique_runs: usize,
15 pcs_len: usize,15 pcs_len: usize,
16 lowest_stack: usize,16 lowest_stack: usize,
17
18 /// Used for comptime assertions. Provides a mechanism for strategically
19 /// causing compile errors.
20 pub const trailing = .{
21 .pc_addr,
22 .{ .pc_bits, u8 },
23 };
17};24};
1825
19pub const ToClientTag = enum(u8) {26pub const ToClientTag = enum(u8) {