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.

testFuzzedHuffmanInput

This function is derived from testFuzzedRawInput with a few changes for fuzzing Huffman.

Compress.testFuzzedHuffmanInput
fn testFuzzedHuffmanInput(fbufs: *const [2][65536]u8, smith: *std.testing.Smith) !void

File

lib/std/compress/flate/Compress.zig:2509

Code

fn testFuzzedHuffmanInput(fbufs: *const [2][65536]u8, smith: *std.testing.Smith) !void {
    @disableInstrumentation();
    const container = smith.value(flate.Container);
    var flate_buf: [2 * 65536]u8 = undefined;
    var flate_w: Writer = .fixed(&flate_buf);
    var expected_hash: flate.Container.Hasher = .init(container);
    var expected_size: u32 = 0;
    const max_size = 4 * @as(u32, Huffman.max_tokens);

    var h_buf: [2 * @as(usize, Huffman.max_tokens)]u8 = undefined;
    const h_buf_len = smith.valueWeighted(u32, &.{
        .value(u32, 0, @intCast(h_buf.len)), // unbuffered
        .rangeAtMost(u32, 0, @intCast(h_buf.len), 1),
    });
    var h: Huffman = try .init(&flate_w, h_buf[0..h_buf_len], container);

    var vecs: [32][]const u8 = undefined;
    var vecs_n: usize = 0;

    while (true) {
        const Op = packed struct {
            drain: bool = false,
            add_vec: bool = false,
            rebase: enum(u2) { none, rebase, flush } = .none,

            pub const drain_only: @This() = .{ .drain = true };
            pub const add_vec_only: @This() = .{ .add_vec = true };
            pub const add_vec_and_drain: @This() = .{ .add_vec = true, .drain = true };
            pub const drain_and_rebase: @This() = .{ .drain = true, .rebase = .rebase };
            pub const drain_and_flush: @This() = .{ .drain = true, .rebase = .flush };
        };

        const is_eos = expected_size == max_size or smith.eosWeightedSimple(7, 1);
        var op: Op = if (!is_eos) smith.valueWeighted(Op, &.{
            .value(Op, .add_vec_only, 5),
            .value(Op, .add_vec_and_drain, 1),
            .value(Op, .drain_and_rebase, 1),
            .value(Op, .drain_and_flush, 1),
        }) else .drain_only;

        if (op.add_vec) {
            const max_write = max_size - expected_size;
            const buffered: u32 = @intCast(h.writer.buffered().len + countVec(vecs[0..vecs_n]));
            const to_align = Huffman.max_tokens - buffered % Huffman.max_tokens;
            assert(to_align != 0); // otherwise, not helpful.

            const data_buf = &fbufs[
                smith.valueWeighted(u1, &.{
                    .value(FreqBufIndex, .gradient, 3),
                    .value(FreqBufIndex, .random, 1),
                })
            ];
            const data_buf_len: u32 = @intCast(data_buf.len);

            const max_data = @min(data_buf_len, max_write);
            const len = smith.valueWeighted(u32, &.{
                .rangeAtMost(u32, 0, max_data, 1),
                .rangeAtMost(u32, 0, @min(Huffman.max_tokens, max_data), 4),
                .value(u32, @min(to_align, max_data), max_data), // @min 2nd arg is an edge-case
            });
            const off = smith.valueRangeAtMost(u32, 0, data_buf_len - len);

            expected_size += len;
            vecs[vecs_n] = data_buf[off..][0..len];
            vecs_n += 1;
            op.drain |= vecs_n == vecs.len;
        }

        op.drain |= is_eos;
        op.drain &= vecs_n != 0;
        if (op.drain) {
            const pattern_len: u32 = @intCast(vecs[vecs_n - 1].len);
            const pattern_len_z = @max(pattern_len, 1);

            const max_write = max_size - (expected_size - pattern_len);
            const buffered: u32 = @intCast(h.writer.buffered().len + countVec(vecs[0 .. vecs_n - 1]));
            const to_align = Huffman.max_tokens - buffered % Huffman.max_tokens;
            assert(to_align != 0); // otherwise, not helpful.

            const max_splat = max_write / pattern_len_z;
            const weights: [3]std.testing.Smith.Weight = .{
                .rangeAtMost(u32, 0, max_splat, 1),
                .rangeAtMost(u32, 0, @min(
                    Huffman.max_tokens + pattern_len_z,
                    max_write,
                ) / pattern_len_z, 4),
                .value(u32, to_align / pattern_len_z, max_splat * 4),
            };
            const align_weight = to_align % pattern_len_z == 0 and to_align <= max_write;
            const n_weights = @as(u8, 2) + @intFromBool(align_weight);
            const splat = smith.valueWeighted(u32, weights[0..n_weights]);

            expected_size = expected_size - pattern_len + pattern_len * splat; // splat may be zero
            for (vecs[0 .. vecs_n - 1]) |v| expected_hash.update(v);
            for (0..splat) |_| expected_hash.update(vecs[vecs_n - 1]);

            const max_space = fuzzedHuffmanDrainSpaceLimit(
                buffered + pattern_len * splat,
                flate_w.buffered().len,
                false,
            );
            h.writer.writeSplatAll(vecs[0..vecs_n], splat) catch
                return if (max_space <= flate_w.buffer.len) error.OverheadTooLarge else {};
            if (flate_w.buffered().len > max_space) return error.OverheadTooLarge;

            vecs_n = 0;
        }

        if (op.rebase != .none) {
            const capacity = smith.valueRangeAtMost(u32, 0, h_buf_len);
            const preserve = smith.valueRangeAtMost(u32, 0, h_buf_len - capacity);

            const max_space = fuzzedHuffmanDrainSpaceLimit(
                h.writer.buffered().len,
                flate_w.buffered().len,
                false,
            ) + @as(usize, 8) * @intFromBool(op.rebase == .flush); // Overhead from byte alignment
            switch (op.rebase) {
                .none => unreachable,
                .rebase => h.writer.rebase(preserve, capacity) catch
                    return if (max_space <= flate_w.buffer.len) error.OverheadTooLarge else {},
                .flush => h.writer.flush() catch
                    return if (max_space <= flate_w.buffer.len) error.OverheadTooLarge else {},
            }
            if (flate_w.buffered().len > max_space) return error.OverheadTooLarge;
        }

        if (is_eos) break;
    }

    const max_space = fuzzedHuffmanDrainSpaceLimit(
        h.writer.buffered().len,
        flate_w.buffered().len,
        true,
    );
    h.finish() catch return if (max_space <= flate_w.buffer.len) error.OverheadTooLarge else {};
    if (flate_w.buffered().len > max_space) return error.OverheadTooLarge;

    try testingCheckDecompressedMatches(flate_w.buffered(), expected_size, expected_hash);
}