Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

fuzz

ABI bits specifically relating to the fuzzer interface.

abi.fuzz
pub const fuzz = struct

File

lib/std/Build/abi.zig:141

Code

pub const fuzz = struct {
    /// Returns if `error.SkipZigTest` was indicated
    pub const TestOne = *const fn () callconv(.c) bool;

    /// A unique value to identify the related requests across runs
    pub const Uid = packed struct(u32) {
        kind: enum(u1) { int, bytes },
        hash: u31,

        pub const hashmap_ctx = struct {
            pub fn hash(_: @This(), u: Uid) u32 {
                // We can ignore `kind` since `hash` should be unique regardless
                return u.hash;
            }

            pub fn eql(_: @This(), a: Uid, b: Uid, _: usize) bool {
                return a == b;
            }
        };
    };

    pub extern fn fuzzer_init(cache_dir_path: Slice) void;
    /// `fuzzer_init` must be called first.
    pub extern fn fuzzer_coverage() Coverage;
    pub extern fn fuzzer_unslide_address(addr: usize) usize;

    /// Performs all the fuzzing work and selects tests to run
    ///
    /// `fuzzer_init` must be called first.
    pub extern fn fuzzer_main(
        n_tests: u32,
        seed: u32,
        limit_kind: LimitKind,
        amount_or_instance: u64,
    ) void;
    pub extern fn runner_test_run(i: u32) void;
    pub extern fn runner_test_name(i: u32) Slice;
    // Since the runner owns the `std.zig.Server` instance, it also controls the
    // concurrent Io instance so reads can be canceled. As such, the fuzzer has
    // to call into the runner for any zig server / concurrent operation.
    pub extern fn runner_start_input_poller() void;
    pub extern fn runner_stop_input_poller() void;
    /// Returns if cancelation has been indicated.
    pub extern fn runner_futex_wait(*const u32, expected: u32) bool;
    pub extern fn runner_futex_wake(*const u32, waiters: u32) void;
    pub extern fn runner_broadcast_input(test_i: u32, bytes: Slice) void;
    /// `fuzzer_main` must be called first.
    ///
    /// Called concurrently with `fuzzer_main`. Returns if cancelation has been indicated.
    pub extern fn fuzzer_receive_input(test_i: u32, bytes: Slice) bool;

    /// Must be called from inside a test function
    pub extern fn fuzzer_set_test(test_one: TestOne) void;
    /// Must be called from inside a test function where `fuzzer_set_test` has been called first.
    pub extern fn fuzzer_new_input(bytes: Slice) void;
    /// Must be called from inside a test function where `fuzzer_set_test` has been called first.
    pub extern fn fuzzer_start_test() void;

    pub extern fn fuzzer_int(uid: Uid, weights: Weights) u64;
    pub extern fn fuzzer_eos(uid: Uid, weights: Weights) bool;
    pub extern fn fuzzer_bytes(uid: Uid, out: MutSlice, weights: Weights) void;
    pub extern fn fuzzer_slice(
        uid: Uid,
        buf: MutSlice,
        len_weights: Weights,
        byte_weights: Weights,
    ) u32;

    pub const Slice = extern struct {
        ptr: [*]const u8,
        len: usize,

        pub fn toSlice(s: Slice) []const u8 {
            return s.ptr[0..s.len];
        }

        pub fn fromSlice(s: []const u8) Slice {
            return .{ .ptr = s.ptr, .len = s.len };
        }
    };

    pub const MutSlice = extern struct {
        ptr: [*]u8,
        len: usize,

        pub fn toSlice(s: MutSlice) []u8 {
            return s.ptr[0..s.len];
        }

        pub fn fromSlice(s: []u8) MutSlice {
            return .{ .ptr = s.ptr, .len = s.len };
        }
    };

    pub const Weights = extern struct {
        ptr: [*]const Weight,
        len: usize,

        pub fn toSlice(s: Weights) []const Weight {
            return s.ptr[0..s.len];
        }

        pub fn fromSlice(s: []const Weight) Weights {
            return .{ .ptr = s.ptr, .len = s.len };
        }
    };

    /// Increases the probability of values being selected by the fuzzer.
    ///
    /// `weight` applies to each value in the range (i.e. not evenly across
    /// the range) and must be nonzero.
    ///
    /// In a set of weights, the total weight must not exceed 2^64 and be
    /// nonzero.
    pub const Weight = extern struct {
        /// Inclusive
        min: u64,
        /// Inclusive
        max: u64,
        weight: u64,

        /// `inline` to propogate comptimeness
        inline fn intFromValue(x: anytype) u64 {
            const T = @TypeOf(x);
            return switch (@typeInfo(T)) {
                .comptime_int => x,
                .bool => @intFromBool(x),
                .@"enum" => @backingInt(x),
                else => @as(@Int(.unsigned, @bitSizeOf(T)), @bitCast(x)),

                .int => |i| x: {
                    comptime {
                        if (i.signedness == .signed) {
                            @compileError("type does not have a continous range: " ++ @typeName(T));
                        }
                        // Reject types that don't have a fixed bitsize (esp. usize)
                        // since they are not gauraunteed to fit in a u64 across targets.
                        //
                        // std.mem.indexOfScalar is not used to avoid backward branches
                        // and preserve the eval branch quota.
                        if (T == usize or T == c_char or T == c_ushort or
                            T == c_uint or T == c_ulong or T == c_ulonglong)
                        {
                            @compileError("type does not have a fixed bitsize: " ++ @typeName(T));
                        }
                    }
                    break :x x;
                },

                .comptime_float,
                .float,
                => @compileError("type does not have a continous range: " ++ @typeName(T)),
                .pointer => @compileError("type does not have a fixed bitsize: " ++ @typeName(T)),
            };
        }

        /// `inline` to propogate comptimeness
        pub inline fn value(T: type, x: T, weight: u64) Weight {
            return .{ .min = intFromValue(x), .max = intFromValue(x), .weight = weight };
        }

        /// `inline` to propogate comptimeness
        pub inline fn rangeAtMost(T: type, at_least: T, at_most: T, weight: u64) Weight {
            std.debug.assert(intFromValue(at_least) <= intFromValue(at_most));
            return .{
                .min = intFromValue(at_least),
                .max = intFromValue(at_most),
                .weight = weight,
            };
        }

        /// `inline` to propogate comptimeness
        pub inline fn rangeLessThan(T: type, at_least: T, less_than: T, weight: u64) Weight {
            std.debug.assert(intFromValue(at_least) < intFromValue(less_than));
            return .{
                .min = intFromValue(at_least),
                .max = intFromValue(less_than) - 1,
                .weight = weight,
            };
        }
    };

    pub const LimitKind = enum(u8) { forever, iterations };

    /// libfuzzer uses this and its usize is the one that counts. To match the ABI,
    /// make the ints be the size of the target used with libfuzzer.
    ///
    /// Trailing:
    /// * 1 bit per pc_addr, usize elements
    /// * pc_addr: usize for each pcs_len
    pub const SeenPcsHeader = extern struct {
        n_runs: usize,
        unique_runs: usize,
        pcs_len: usize,

        /// Used for comptime assertions. Provides a mechanism for strategically
        /// causing compile errors.
        pub const trailing = .{
            .pc_bits_usize,
            .pc_addr,
        };

        pub fn headerEnd(header: *const SeenPcsHeader) []const usize {
            const ptr: [*]align(@alignOf(usize)) const u8 = @ptrCast(header);
            const header_end_ptr: [*]const usize = @ptrCast(ptr + @sizeOf(SeenPcsHeader));
            const pcs_len = header.pcs_len;
            return header_end_ptr[0 .. pcs_len + seenElemsLen(pcs_len)];
        }

        pub fn seenBits(header: *const SeenPcsHeader) []const usize {
            return header.headerEnd()[0..seenElemsLen(header.pcs_len)];
        }

        pub fn seenElemsLen(pcs_len: usize) usize {
            return (pcs_len + @bitSizeOf(usize) - 1) / @bitSizeOf(usize);
        }

        pub fn pcAddrs(header: *const SeenPcsHeader) []const usize {
            const pcs_len = header.pcs_len;
            return header.headerEnd()[seenElemsLen(pcs_len)..][0..pcs_len];
        }
    };

    /// Fields are little-endian
    pub const MmapInputHeader = extern struct {
        pc_digest: u64 align(4), // aligned so header does not have padding
        instance_id: u32,
        test_i: u32,
        len: u32,
    };

    /// WebSocket server->client.
    ///
    /// Sent once, when fuzzing starts, to indicate the available coverage data.
    ///
    /// Trailing:
    /// * std.debug.Coverage.String for each directories_len
    /// * std.debug.Coverage.File for each files_len
    /// * std.debug.Coverage.SourceLocation for each source_locations_len
    /// * u8 for each string_bytes_len
    pub const SourceIndexHeader = extern struct {
        tag: ToClientTag = .fuzz_source_index,
        _: [3]u8 = @splat(0),
        directories_len: u32,
        files_len: u32,
        source_locations_len: u32,
        string_bytes_len: u32,
        /// When, according to the server, fuzzing started.
        start_timestamp: i64 align(4),
        start_n_runs: u64 align(4),
    };

    /// WebSocket server->client.
    ///
    /// Sent whenever the set of covered source locations is updated.
    ///
    /// Trailing:
    /// * one bit per source_locations_len, contained in u64 elements
    pub const CoverageUpdateHeader = extern struct {
        tag: ToClientTag = .fuzz_coverage_update,
        _: [7]u8 = @splat(0),
        n_runs: u64,
        unique_runs: u64,

        pub const trailing = .{
            .pc_bits_usize,
        };
    };

    /// WebSocket server->client.
    ///
    /// Sent whenever the set of entry points is updated.
    ///
    /// Trailing:
    /// * one u32 index of source_locations per locsLen()
    pub const EntryPointHeader = extern struct {
        tag: ToClientTag = .fuzz_entry_points,
        locs_len_raw: [3]u8,

        pub fn locsLen(hdr: EntryPointHeader) u24 {
            return @bitCast(hdr.locs_len_raw);
        }
        pub fn init(locs_len: u24) EntryPointHeader {
            return .{ .locs_len_raw = @bitCast(locs_len) };
        }
    };

    /// Sent by lib/fuzzer to test_runner to obtain information about the
    /// active memory mapped input file and cumulative stats about previous
    /// fuzzing runs.
    pub const Coverage = extern struct {
        id: u64,
        runs: u64,
        unique: u64,
        seen: u64,
    };
}