| author | |
| committer | |
| log | d5bfa657c48e9d023bb789fbf8dacbcbd42f528d |
| tree | b5934c60fcecd60f3710594c94d0f26cbcf20ab4 |
| parent | eff332fd042a4ef556409c7650c6b74da0e30235 |
| parent | 9d1e47d220a50fc5db4b622bd86e2fe51673c163 |
Reviewed-on: https://codeberg.org/ziglang/zig/pulls/31470
Reviewed-by: Andrew Kelley <andrew@ziglang.org>8 files changed, 103 insertions(+), 50 deletions(-)
lib/build-web/fuzz.zig+1-1| ... | ... | @@ -255,7 +255,7 @@ fn unpackSourcesInner(tar_bytes: []u8) !void { |
| 255 | 255 | } |
| 256 | 256 | |
| 257 | 257 | fn updateStats() error{OutOfMemory}!void { |
| 258 | @setFloatMode(.optimized); | |
| 258 | // No @setFloatMode(.optimized) since some stats may be at zero and lead to divisions by zero | |
| 259 | 259 | |
| 260 | 260 | if (recent_coverage_update.items.len == 0) return; |
| 261 | 261 |
lib/compiler/test_runner.zig+20-3| ... | ... | @@ -180,7 +180,23 @@ fn mainServer(init: std.process.Init.Minimal) !void { |
| 180 | 180 | // since they are not present. |
| 181 | 181 | if (!builtin.fuzz) unreachable; |
| 182 | 182 | |
| 183 | const index = try server.receiveBody_u32(); | |
| 183 | const index: u32 = @intCast(index: { | |
| 184 | testing.allocator_instance = .{}; | |
| 185 | defer if (testing.allocator_instance.deinit() == .leak) { | |
| 186 | @panic("internal test runner memory leak"); | |
| 187 | }; | |
| 188 | ||
| 189 | const name_len = try server.receiveBody_u32(); | |
| 190 | const name = try server.in.readAlloc(testing.allocator, @intCast(name_len)); | |
| 191 | defer testing.allocator.free(name); | |
| 192 | for (0.., builtin.test_functions) |i, test_fn| { | |
| 193 | if (std.mem.eql(u8, name, test_fn.name)) { | |
| 194 | break :index i; | |
| 195 | } | |
| 196 | } else { | |
| 197 | std.debug.panic("fuzz test {s} no longer exists", .{name}); | |
| 198 | } | |
| 199 | }); | |
| 184 | 200 | const mode: fuzz_abi.LimitKind = @enumFromInt(try server.receiveBody_u8()); |
| 185 | 201 | const amount_or_instance = try server.receiveBody_u64(); |
| 186 | 202 | |
| ... | ... | @@ -406,13 +422,13 @@ pub fn fuzz( |
| 406 | 422 | const global = struct { |
| 407 | 423 | var ctx: @TypeOf(context) = undefined; |
| 408 | 424 | |
| 409 | fn test_one() callconv(.c) void { | |
| 425 | fn test_one() callconv(.c) bool { | |
| 410 | 426 | @disableInstrumentation(); |
| 411 | 427 | testing.allocator_instance = .{}; |
| 412 | 428 | defer if (testing.allocator_instance.deinit() == .leak) std.process.exit(1); |
| 413 | 429 | log_err_count = 0; |
| 414 | 430 | testOne(ctx, @constCast(&testing.Smith{ .in = null })) catch |err| switch (err) { |
| 415 | error.SkipZigTest => return, | |
| 431 | error.SkipZigTest => return true, | |
| 416 | 432 | else => { |
| 417 | 433 | const stderr = std.debug.lockStderr(&.{}).terminal(); |
| 418 | 434 | p: { |
| ... | ... | @@ -429,6 +445,7 @@ pub fn fuzz( |
| 429 | 445 | stderr.writer.print("error logs detected\n", .{}) catch {}; |
| 430 | 446 | std.process.exit(1); |
| 431 | 447 | } |
| 448 | return false; | |
| 432 | 449 | } |
| 433 | 450 | }; |
| 434 | 451 | if (builtin.fuzz) { |
lib/fuzzer.zig+44-18| ... | ... | @@ -686,7 +686,7 @@ const Fuzzer = struct { |
| 686 | 686 | const len = mem.readInt(u32, f.mmap_input.mmap.memory[0..4], .little); |
| 687 | 687 | if (len < f.mmap_input.mmap.memory[4..].len) { |
| 688 | 688 | f.mmap_input.len = len; |
| 689 | f.runBytes(f.mmap_input.inputSlice(), .bytes_dry); | |
| 689 | _ = f.runBytes(f.mmap_input.inputSlice(), .bytes_dry); | |
| 690 | 690 | f.mmap_input.clearRetainingCapacity(); |
| 691 | 691 | } |
| 692 | 692 | } |
| ... | ... | @@ -703,7 +703,7 @@ const Fuzzer = struct { |
| 703 | 703 | else => panic("failed to read corpus file '{s}': {t}", .{ name, e }), |
| 704 | 704 | }; |
| 705 | 705 | defer gpa.free(bytes); |
| 706 | f.newInput(bytes, false); | |
| 706 | f.newInputExternal(bytes); | |
| 707 | 707 | } |
| 708 | 708 | f.corpus_pos = @enumFromInt(0); |
| 709 | 709 | } |
| ... | ... | @@ -761,12 +761,13 @@ const Fuzzer = struct { |
| 761 | 761 | return fresh; |
| 762 | 762 | } |
| 763 | 763 | |
| 764 | fn runBytes(f: *Fuzzer, bytes: []const u8, mode: Input.Index) void { | |
| 764 | /// Returns if `error.SkipZigTest` was indicated | |
| 765 | fn runBytes(f: *Fuzzer, bytes: []const u8, mode: Input.Index) bool { | |
| 765 | 766 | assert(mode == .bytes_dry or mode == .bytes_fresh); |
| 766 | 767 | |
| 767 | 768 | f.bytes_input = .{ .in = bytes }; |
| 768 | 769 | f.corpus_pos = mode; |
| 769 | f.run(0); // 0 since `f.uid_data` is unused | |
| 770 | return f.run(0); // 0 since `f.uid_data` is unused | |
| 770 | 771 | } |
| 771 | 772 | |
| 772 | 773 | fn updateSeenPcs(f: *Fuzzer) void { |
| ... | ... | @@ -861,8 +862,21 @@ const Fuzzer = struct { |
| 861 | 862 | } |
| 862 | 863 | } |
| 863 | 864 | |
| 864 | pub fn newInput(f: *Fuzzer, bytes: []const u8, modify_fs_corpus: bool) void { | |
| 865 | f.runBytes(bytes, .bytes_fresh); | |
| 865 | pub fn newInputExternal(f: *Fuzzer, bytes: []const u8) void { | |
| 866 | // All inputs including the corpus are required to go through the memory | |
| 867 | // mapped input in case they cause a crash so they can be identified. | |
| 868 | f.mmap_input.appendSlice(bytes); | |
| 869 | f.newInput(false); | |
| 870 | f.mmap_input.clearRetainingCapacity(); | |
| 871 | } | |
| 872 | ||
| 873 | fn newInput(f: *Fuzzer, modify_fs_corpus: bool) void { | |
| 874 | const bytes = f.mmap_input.inputSlice(); | |
| 875 | // `error.SkipZigTest` here can be from one of these causes: | |
| 876 | // * The test has changed and a previous corpus input is being used | |
| 877 | // * An input provided by the test results in it | |
| 878 | // * The test is non-deterministic | |
| 879 | if (f.runBytes(bytes, .bytes_fresh)) return; | |
| 866 | 880 | f.req_values = f.input_builder.total_ints + f.input_builder.total_bytes; |
| 867 | 881 | f.req_bytes = @intCast(f.input_builder.bytes_table.items.len); |
| 868 | 882 | var input = f.input_builder.build(); |
| ... | ... | @@ -996,15 +1010,17 @@ const Fuzzer = struct { |
| 996 | 1010 | panic("failed to write corpus file '{s}': {t}", .{ name, e }); |
| 997 | 1011 | } |
| 998 | 1012 | |
| 999 | fn run(f: *Fuzzer, input_uids: usize) void { | |
| 1013 | /// Returns if `error.SkipZigTest` was indicated | |
| 1014 | fn run(f: *Fuzzer, input_uids: usize) bool { | |
| 1000 | 1015 | @memset(exec.pc_counters, 0); |
| 1001 | 1016 | f.uid_data_i.items.len = input_uids; |
| 1002 | 1017 | @memset(f.uid_data_i.items, 0); |
| 1003 | 1018 | f.req_values = 0; |
| 1004 | 1019 | f.req_bytes = 0; |
| 1005 | 1020 | |
| 1006 | f.test_one(); | |
| 1021 | const skip = f.test_one(); | |
| 1007 | 1022 | _ = @atomicRmw(usize, &exec.seenPcsHeader().n_runs, .Add, 1, .monotonic); |
| 1023 | return skip; | |
| 1008 | 1024 | } |
| 1009 | 1025 | |
| 1010 | 1026 | /// Returns a number of mutations to perform from 1-4 |
| ... | ... | @@ -1076,12 +1092,12 @@ const Fuzzer = struct { |
| 1076 | 1092 | i.* = data.order[order_i]; |
| 1077 | 1093 | }; |
| 1078 | 1094 | |
| 1079 | f.run(data.uid_slices.entries.len); | |
| 1080 | if (f.isFresh()) { | |
| 1095 | const skip = f.run(data.uid_slices.entries.len); | |
| 1096 | if (!skip and f.isFresh()) { | |
| 1081 | 1097 | @branchHint(.unlikely); |
| 1082 | 1098 | |
| 1083 | 1099 | _ = @atomicRmw(usize, &exec.seenPcsHeader().unique_runs, .Add, 1, .monotonic); |
| 1084 | f.newInput(f.mmap_input.inputSlice(), true); | |
| 1100 | f.newInput(true); | |
| 1085 | 1101 | } |
| 1086 | 1102 | f.mmap_input.clearRetainingCapacity(); |
| 1087 | 1103 | |
| ... | ... | @@ -1320,13 +1336,23 @@ const Fuzzer = struct { |
| 1320 | 1336 | |
| 1321 | 1337 | if (opts.copy != 0) { |
| 1322 | 1338 | if (opts.fresh == 0 or slice_i == data_slice.len) return .fresh; |
| 1323 | return .{ .mutate = switch (uid.kind) { | |
| 1324 | .int => .{ .int = data.ints[data_i] }, | |
| 1325 | .bytes => .{ .bytes = b: { | |
| 1339 | switch (uid.kind) { | |
| 1340 | .int => { | |
| 1341 | const int = data.ints[data_i]; | |
| 1342 | if (weightsContain(int, weights)) { | |
| 1343 | @branchHint(.likely); | |
| 1344 | return .{ .mutate = .{ .int = int } }; | |
| 1345 | } | |
| 1346 | }, | |
| 1347 | .bytes => { | |
| 1326 | 1348 | const entry = data.bytes.entries[data_i]; |
| 1327 | break :b data.bytes.table[entry.off..][0..entry.len]; | |
| 1328 | } }, | |
| 1329 | } }; | |
| 1349 | const bytes = data.bytes.table[entry.off..][0..entry.len]; | |
| 1350 | if (weightsContainBytes(bytes, weights)) { | |
| 1351 | @branchHint(.likely); | |
| 1352 | return .{ .mutate = .{ .bytes = bytes } }; | |
| 1353 | } | |
| 1354 | }, | |
| 1355 | } | |
| 1330 | 1356 | } |
| 1331 | 1357 | |
| 1332 | 1358 | if (!opts.splice) { |
| ... | ... | @@ -1665,7 +1691,7 @@ export fn fuzzer_set_test(test_one: abi.TestOne, unit_test_name: abi.Slice) void |
| 1665 | 1691 | |
| 1666 | 1692 | export fn fuzzer_new_input(bytes: abi.Slice) void { |
| 1667 | 1693 | if (bytes.len == 0) return; // An entry of length zero is always present |
| 1668 | fuzzer.newInput(bytes.toSlice(), false); | |
| 1694 | fuzzer.newInputExternal(bytes.toSlice()); | |
| 1669 | 1695 | } |
| 1670 | 1696 | |
| 1671 | 1697 | export fn fuzzer_main(limit_kind: abi.LimitKind, amount: u64) void { |
lib/std/Build/Fuzz.zig+7-8| ... | ... | @@ -145,9 +145,9 @@ pub fn start(fuzz: *Fuzz) void { |
| 145 | 145 | } |
| 146 | 146 | |
| 147 | 147 | for (fuzz.run_steps) |run| { |
| 148 | for (run.fuzz_tests.items) |unit_test_index| { | |
| 148 | for (run.fuzz_tests.items) |unit_test_name| { | |
| 149 | 149 | assert(run.rebuilt_executable != null); |
| 150 | fuzz.group.async(io, fuzzWorkerRun, .{ fuzz, run, unit_test_index }); | |
| 150 | fuzz.group.async(io, fuzzWorkerRun, .{ fuzz, run, unit_test_name }); | |
| 151 | 151 | } |
| 152 | 152 | } |
| 153 | 153 | } |
| ... | ... | @@ -193,17 +193,16 @@ fn rebuildTestsWorkerRunFallible(run: *Step.Run, gpa: Allocator, parent_prog_nod |
| 193 | 193 | run.rebuilt_executable = try rebuilt_bin_path.join(gpa, compile.out_filename); |
| 194 | 194 | } |
| 195 | 195 | |
| 196 | fn fuzzWorkerRun(fuzz: *Fuzz, run: *Step.Run, unit_test_index: u32) void { | |
| 196 | fn fuzzWorkerRun(fuzz: *Fuzz, run: *Step.Run, unit_test_name: []const u8) void { | |
| 197 | 197 | const owner = run.step.owner; |
| 198 | 198 | const gpa = owner.allocator; |
| 199 | 199 | const graph = owner.graph; |
| 200 | 200 | const io = graph.io; |
| 201 | const test_name = run.cached_test_metadata.?.testName(unit_test_index); | |
| 202 | 201 | |
| 203 | const prog_node = fuzz.prog_node.start(test_name, 0); | |
| 202 | const prog_node = fuzz.prog_node.start(unit_test_name, 0); | |
| 204 | 203 | defer prog_node.end(); |
| 205 | 204 | |
| 206 | run.rerunInFuzzMode(fuzz, unit_test_index, prog_node) catch |err| switch (err) { | |
| 205 | run.rerunInFuzzMode(fuzz, unit_test_name, prog_node) catch |err| switch (err) { | |
| 207 | 206 | error.MakeFailed => { |
| 208 | 207 | var buf: [256]u8 = undefined; |
| 209 | 208 | const stderr = io.lockStderr(&buf, graph.stderr_mode) catch |e| switch (e) { |
| ... | ... | @@ -214,7 +213,7 @@ fn fuzzWorkerRun(fuzz: *Fuzz, run: *Step.Run, unit_test_index: u32) void { |
| 214 | 213 | return; |
| 215 | 214 | }, |
| 216 | 215 | else => { |
| 217 | log.err("step '{s}': failed to rerun '{s}' in fuzz mode: {t}", .{ run.step.name, test_name, err }); | |
| 216 | log.err("step '{s}': failed to rerun '{s}' in fuzz mode: {t}", .{ run.step.name, unit_test_name, err }); | |
| 218 | 217 | return; |
| 219 | 218 | }, |
| 220 | 219 | }; |
| ... | ... | @@ -588,7 +587,7 @@ pub fn waitAndPrintReport(fuzz: *Fuzz) Io.Cancelable!void { |
| 588 | 587 | \\ |
| 589 | 588 | , .{ |
| 590 | 589 | cov.run.step.name, |
| 591 | cov.run.cached_test_metadata.?.testName(cov.run.fuzz_tests.items[0]), | |
| 590 | cov.run.fuzz_tests.items[0], | |
| 592 | 591 | cov.id, |
| 593 | 592 | cov.cumulative.runs, |
| 594 | 593 | header.n_runs, |
lib/std/Build/Step/Run.zig+18-14| ... | ... | @@ -88,9 +88,10 @@ dep_output_file: ?*Output, |
| 88 | 88 | |
| 89 | 89 | has_side_effects: bool, |
| 90 | 90 | |
| 91 | /// If this is a Zig unit test binary, this tracks the indexes of the unit | |
| 92 | /// tests that are also fuzz tests. | |
| 93 | fuzz_tests: std.ArrayList(u32), | |
| 91 | /// If this is a Zig unit test binary, this tracks the names of the unit | |
| 92 | /// tests that are also fuzz tests. Indexes cannot be used as they may | |
| 93 | /// change between reruns. | |
| 94 | fuzz_tests: std.ArrayList([]const u8), | |
| 94 | 95 | cached_test_metadata: ?CachedTestMetadata = null, |
| 95 | 96 | |
| 96 | 97 | /// Populated during the fuzz phase if this run step corresponds to a unit test |
| ... | ... | @@ -1067,7 +1068,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void { |
| 1067 | 1068 | pub fn rerunInFuzzMode( |
| 1068 | 1069 | run: *Run, |
| 1069 | 1070 | fuzz: *std.Build.Fuzz, |
| 1070 | unit_test_index: u32, | |
| 1071 | unit_test_name: []const u8, | |
| 1071 | 1072 | prog_node: std.Progress.Node, |
| 1072 | 1073 | ) !void { |
| 1073 | 1074 | const step = &run.step; |
| ... | ... | @@ -1138,7 +1139,7 @@ pub fn rerunInFuzzMode( |
| 1138 | 1139 | .unit_test_timeout_ns = null, // don't time out fuzz tests for now |
| 1139 | 1140 | .gpa = fuzz.gpa, |
| 1140 | 1141 | }, .{ |
| 1141 | .unit_test_index = unit_test_index, | |
| 1142 | .unit_test_name = unit_test_name, | |
| 1142 | 1143 | .fuzz = fuzz, |
| 1143 | 1144 | }); |
| 1144 | 1145 | } |
| ... | ... | @@ -1210,7 +1211,7 @@ fn termMatches(expected: ?process.Child.Term, actual: process.Child.Term) bool { |
| 1210 | 1211 | |
| 1211 | 1212 | const FuzzContext = struct { |
| 1212 | 1213 | fuzz: *std.Build.Fuzz, |
| 1213 | unit_test_index: u32, | |
| 1214 | unit_test_name: []const u8, | |
| 1214 | 1215 | }; |
| 1215 | 1216 | |
| 1216 | 1217 | fn runCommand( |
| ... | ... | @@ -1843,7 +1844,7 @@ fn waitZigTest( |
| 1843 | 1844 | sendRunFuzzTestMessage( |
| 1844 | 1845 | io, |
| 1845 | 1846 | child.stdin.?, |
| 1846 | ctx.unit_test_index, | |
| 1847 | ctx.unit_test_name, | |
| 1847 | 1848 | .forever, |
| 1848 | 1849 | 0, // instance ID; will be used by multiprocess forever fuzzing in the future |
| 1849 | 1850 | ) catch |err| return .{ .write_failed = err }; |
| ... | ... | @@ -1852,7 +1853,7 @@ fn waitZigTest( |
| 1852 | 1853 | sendRunFuzzTestMessage( |
| 1853 | 1854 | io, |
| 1854 | 1855 | child.stdin.?, |
| 1855 | ctx.unit_test_index, | |
| 1856 | ctx.unit_test_name, | |
| 1856 | 1857 | .iterations, |
| 1857 | 1858 | limit.amount, |
| 1858 | 1859 | ) catch |err| return .{ .write_failed = err }; |
| ... | ... | @@ -2001,10 +2002,10 @@ fn waitZigTest( |
| 2001 | 2002 | results.leak_count +|= leak_count; |
| 2002 | 2003 | results.log_err_count +|= log_err_count; |
| 2003 | 2004 | |
| 2004 | if (tr_hdr.flags.fuzz) try run.fuzz_tests.append(gpa, tr_hdr.index); | |
| 2005 | if (tr_hdr.flags.fuzz) try run.fuzz_tests.append(gpa, md.testName(tr_hdr.index)); | |
| 2005 | 2006 | |
| 2006 | 2007 | if (tr_hdr.flags.status == .fail) { |
| 2007 | const name = std.mem.sliceTo(md.testName(tr_hdr.index), 0); | |
| 2008 | const name = md.testName(tr_hdr.index); | |
| 2008 | 2009 | const stderr_bytes = std.mem.trim(u8, stderr.buffered(), "\n"); |
| 2009 | 2010 | stderr.tossBuffered(); |
| 2010 | 2011 | if (stderr_bytes.len == 0) { |
| ... | ... | @@ -2013,12 +2014,12 @@ fn waitZigTest( |
| 2013 | 2014 | try run.step.addError("'{s}' failed:\n{s}", .{ name, stderr_bytes }); |
| 2014 | 2015 | } |
| 2015 | 2016 | } else if (leak_count > 0) { |
| 2016 | const name = std.mem.sliceTo(md.testName(tr_hdr.index), 0); | |
| 2017 | const name = md.testName(tr_hdr.index); | |
| 2017 | 2018 | const stderr_bytes = std.mem.trim(u8, stderr.buffered(), "\n"); |
| 2018 | 2019 | stderr.tossBuffered(); |
| 2019 | 2020 | try run.step.addError("'{s}' leaked {d} allocations:\n{s}", .{ name, leak_count, stderr_bytes }); |
| 2020 | 2021 | } else if (log_err_count > 0) { |
| 2021 | const name = std.mem.sliceTo(md.testName(tr_hdr.index), 0); | |
| 2022 | const name = md.testName(tr_hdr.index); | |
| 2022 | 2023 | const stderr_bytes = std.mem.trim(u8, stderr.buffered(), "\n"); |
| 2023 | 2024 | stderr.tossBuffered(); |
| 2024 | 2025 | try run.step.addError("'{s}' logged {d} errors:\n{s}", .{ name, log_err_count, stderr_bytes }); |
| ... | ... | @@ -2148,7 +2149,7 @@ fn sendRunTestMessage(io: Io, file: Io.File, tag: std.zig.Client.Message.Tag, in |
| 2148 | 2149 | fn sendRunFuzzTestMessage( |
| 2149 | 2150 | io: Io, |
| 2150 | 2151 | file: Io.File, |
| 2151 | index: u32, | |
| 2152 | test_name: []const u8, | |
| 2152 | 2153 | kind: std.Build.abi.fuzz.LimitKind, |
| 2153 | 2154 | amount_or_instance: u64, |
| 2154 | 2155 | ) !void { |
| ... | ... | @@ -2160,7 +2161,10 @@ fn sendRunFuzzTestMessage( |
| 2160 | 2161 | w.interface.writeStruct(header, .little) catch |err| switch (err) { |
| 2161 | 2162 | error.WriteFailed => return w.err.?, |
| 2162 | 2163 | }; |
| 2163 | w.interface.writeInt(u32, index, .little) catch |err| switch (err) { | |
| 2164 | w.interface.writeInt(u32, @intCast(test_name.len), .little) catch |err| switch (err) { | |
| 2165 | error.WriteFailed => return w.err.?, | |
| 2166 | }; | |
| 2167 | w.interface.writeAll(test_name) catch |err| switch (err) { | |
| 2164 | 2168 | error.WriteFailed => return w.err.?, |
| 2165 | 2169 | }; |
| 2166 | 2170 | w.interface.writeByte(@intFromEnum(kind)) catch |err| switch (err) { |
lib/std/Build/abi.zig+8-4| ... | ... | @@ -139,7 +139,8 @@ pub const Rebuild = extern struct { |
| 139 | 139 | |
| 140 | 140 | /// ABI bits specifically relating to the fuzzer interface. |
| 141 | 141 | pub const fuzz = struct { |
| 142 | pub const TestOne = *const fn () callconv(.c) void; | |
| 142 | /// Returns if `error.SkipZigTest` was indicated | |
| 143 | pub const TestOne = *const fn () callconv(.c) bool; | |
| 143 | 144 | |
| 144 | 145 | /// A unique value to identify the related requests across runs |
| 145 | 146 | pub const Uid = packed struct(u32) { |
| ... | ... | @@ -249,9 +250,12 @@ pub const fuzz = struct { |
| 249 | 250 | } |
| 250 | 251 | // Reject types that don't have a fixed bitsize (esp. usize) |
| 251 | 252 | // since they are not gauraunteed to fit in a u64 across targets. |
| 252 | if (std.mem.indexOfScalar(type, &.{ | |
| 253 | usize, c_char, c_ushort, c_uint, c_ulong, c_ulonglong, | |
| 254 | }, T) != null) { | |
| 253 | // | |
| 254 | // std.mem.indexOfScalar is not used to avoid backward branches | |
| 255 | // and preserve the eval branch quota. | |
| 256 | if (T == usize or T == c_char or T == c_ushort or | |
| 257 | T == c_uint or T == c_ulong or T == c_ulonglong) | |
| 258 | { | |
| 255 | 259 | @compileError("type does not have a fixed bitsize: " ++ @typeName(T)); |
| 256 | 260 | } |
| 257 | 261 | } |
lib/std/zig/Client.zig+2-1| ... | ... | @@ -35,7 +35,8 @@ pub const Message = struct { |
| 35 | 35 | run_test, |
| 36 | 36 | /// Ask the test runner to start fuzzing a particular test forever or for a given amount of time/iterations. |
| 37 | 37 | /// The message body is: |
| 38 | /// - a u32 test index. | |
| 38 | /// - a u32 test name len. | |
| 39 | /// - a test name with the above length | |
| 39 | 40 | /// - a u8 test limit kind (std.Build.api.fuzz.LimitKind) |
| 40 | 41 | /// - a u64 value whose meaning depends on FuzzLimitKind (either a limit amount or an instance id) |
| 41 | 42 | start_fuzzing, |
test/standalone/libfuzzer/main.zig+3-1| ... | ... | @@ -2,7 +2,9 @@ const std = @import("std"); |
| 2 | 2 | const abi = std.Build.abi.fuzz; |
| 3 | 3 | const native_endian = @import("builtin").cpu.arch.endian(); |
| 4 | 4 | |
| 5 | fn testOne() callconv(.c) void {} | |
| 5 | fn testOne() callconv(.c) bool { | |
| 6 | return false; | |
| 7 | } | |
| 6 | 8 | |
| 7 | 9 | pub fn main(init: std.process.Init) !void { |
| 8 | 10 | const gpa = init.gpa; |