Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fuzzer: don't remove or modify byte of empty input #23180

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

McSinyx
Copy link
Contributor

@McSinyx McSinyx commented Mar 10, 2025

The actual patch is rather trivial, but the debugging process reveals more hidden problems. In today's episode of Who Fuzzes the Fuzzer?, I got a segfault with the following:

const std = @import("std");

fn findSecret(context: []const u8, input: []const u8) !void {
    if (std.mem.eql(u8, context, input))
        return error.FoundSecretString;
}

test "fuzz example" {
    try std.testing.fuzz(@as([]const u8, "canyoufindme"), findSecret, .{
        .corpus = &.{ "c" }
    });
}

Relevant log:

Segmentation fault at address 0x0
.../lib/fuzzer.zig:589:35: 0x11a2880 in start (fuzzer)
        @memcpy(l.items[old_len..][0..items.len], items);
                                  ^
.../lib/fuzzer.zig:460:17: 0x11a4e9f in fuzzer_start (fuzzer)
    fuzzer.start() catch |err| oom(err);

Yes, part of the trace is missing, but I managed to pinpoint the bug to be from below when old_input.len == 0, leading to omitted_index == std.math.maxInt(usize):

zig/lib/fuzzer.zig

Lines 314 to 318 in 8e0a4ca

.remove_byte => {
const omitted_index = rng.uintLessThanBiased(usize, old_input.len);
f.input.appendSliceAssumeCapacity(old_input[0..omitted_index]);
f.input.appendSliceAssumeCapacity(old_input[omitted_index + 1 ..]);
},

Mysteriously, assertions are evaded, unreachables are reached, bound checks are ignored and panics don't pan above the segfaulting statement. I took a look at lib/fuzzer/web/main.zig's panic function does indeed call @trap:

pub fn panic(msg: []const u8, st: ?*std.builtin.StackTrace, addr: ?usize) noreturn {
_ = st;
_ = addr;
log.err("panic: {s}", .{msg});
@trap();
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant