mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-04-30 14:52:41 +03:00
d8ba173e5e
- New Features -- Multiprocess Fuzzing The fuzzer now is able to utilize multiple cores. This is controllable with the `-j` build option. Limited fuzzing still uses one core. -- Fuzzing Infinite Mode When provided multiple tests, the fuzzer now switches between them and prioritizes the most effective and interesting ones. Over time already explored tests will become barely run compared to tests yielding new inputs. -- Crash Dumps Crashing inputs are now saved to a file indicated by the crash message. It is recommended to use these files to reproduce the crash using `std.testing.FuzzInputOptions.corpus` and @embedFile. - Design Each fuzzing process is assigned an instance id which has the following uses: * In conjunction with the pc hash and running test index, they uniquely identify input files in the case of a crash. * It is combined with the test seed for a unique rng seed. * Instance 0 is solely responsible for syncing the filesystem corpus. When new inputs are found, they are sent to the build server. It then distributes the new input to the other instances. Each instance has a concurrent poller managed by the test runner which sends received inputs to libfuzzer. (note that this is affected by #31718 and so can (rarely) deadlock) For fuzzing infinite mode, the test runner now receives a list of tests from the build server. The fuzzer runs tests in batches of one second, approximated in cycles by the previous batch's run speed. Tests finding new inputs or with few runs are given a higher run chance. The baseline run chance is based off the recency of the last find and the number of pcs the test has hit.
73 lines
2.2 KiB
Zig
73 lines
2.2 KiB
Zig
const std = @import("std");
|
|
const assert = std.debug.assert;
|
|
const abi = std.Build.abi.fuzz;
|
|
const native_endian = @import("builtin").cpu.arch.endian();
|
|
|
|
fn testOne() callconv(.c) bool {
|
|
return false;
|
|
}
|
|
|
|
export fn runner_test_run(i: u32) void {
|
|
assert(i == 0);
|
|
abi.fuzzer_set_test(testOne);
|
|
abi.fuzzer_new_input(.fromSlice(""));
|
|
abi.fuzzer_new_input(.fromSlice("hello"));
|
|
abi.fuzzer_start_test();
|
|
}
|
|
|
|
export fn runner_test_name(i: u32) abi.Slice {
|
|
assert(i == 0);
|
|
return .fromSlice("test");
|
|
}
|
|
|
|
export fn runner_start_input_poller() void {}
|
|
export fn runner_stop_input_poller() void {}
|
|
|
|
export fn runner_futex_wait(ptr: *const u32, expected: u32) bool {
|
|
assert(ptr.* == expected); // single-threaded
|
|
return false;
|
|
}
|
|
|
|
export fn runner_futex_wake(ptr: *const u32, waiters: u32) void {
|
|
_ = ptr;
|
|
_ = waiters;
|
|
}
|
|
|
|
export fn runner_broadcast_input(test_i: u32, bytes: abi.Slice) void {
|
|
_ = test_i;
|
|
_ = bytes;
|
|
}
|
|
|
|
pub fn main(init: std.process.Init) !void {
|
|
const gpa = init.gpa;
|
|
const io = init.io;
|
|
|
|
var args = try init.minimal.args.iterateAllocator(gpa);
|
|
defer args.deinit();
|
|
_ = args.skip(); // executable name
|
|
|
|
const cache_dir_path = args.next() orelse @panic("expected cache directory path argument");
|
|
var cache_dir = try std.Io.Dir.cwd().openDir(io, cache_dir_path, .{});
|
|
defer cache_dir.close(io);
|
|
|
|
abi.fuzzer_init(.fromSlice(cache_dir_path));
|
|
abi.fuzzer_main(1, 0, .iterations, 100);
|
|
|
|
const pc_digest = abi.fuzzer_coverage().id;
|
|
const coverage_file_path = "v/" ++ std.fmt.hex(pc_digest);
|
|
const coverage_file = try cache_dir.openFile(io, coverage_file_path, .{});
|
|
defer coverage_file.close(io);
|
|
|
|
var read_buf: [@sizeOf(abi.SeenPcsHeader)]u8 = undefined;
|
|
var r = coverage_file.reader(io, &read_buf);
|
|
const pcs_header = r.interface.takeStruct(abi.SeenPcsHeader, native_endian) catch return r.err.?;
|
|
|
|
if (pcs_header.pcs_len == 0)
|
|
return error.ZeroPcs;
|
|
const expected_len = @sizeOf(abi.SeenPcsHeader) +
|
|
try std.math.divCeil(usize, pcs_header.pcs_len, @bitSizeOf(usize)) * @sizeOf(usize) +
|
|
pcs_header.pcs_len * @sizeOf(usize);
|
|
if (try coverage_file.length(io) != expected_len)
|
|
return error.WrongEnd;
|
|
}
|