mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-04-06 07:38:21 +00:00
fuzz/stream: clean up
This commit is contained in:
@@ -3,32 +3,9 @@ const ghostty_vt = @import("ghostty-vt");
|
||||
const Terminal = ghostty_vt.Terminal;
|
||||
const ReadonlyStream = ghostty_vt.ReadonlyStream;
|
||||
|
||||
/// Fixed-capacity allocator that avoids heap allocation and gives the
|
||||
/// fuzzer deterministic, bounded memory behaviour. Backed by a single
|
||||
/// fixed buffer; every `reset()` returns the bump pointer to the start
|
||||
/// so the same memory is reused across iterations.
|
||||
const FuzzAllocator = struct {
|
||||
buf: [mem_size]u8 = undefined,
|
||||
state: std.heap.FixedBufferAllocator = undefined,
|
||||
|
||||
/// 4 MiB is plenty for a small terminal with a few pages of
|
||||
/// scrollback, while staying within the resident-set limits
|
||||
/// that AFL++ expects.
|
||||
const mem_size = 4 * 1024 * 1024;
|
||||
|
||||
fn init(self: *FuzzAllocator) void {
|
||||
self.state = std.heap.FixedBufferAllocator.init(&self.buf);
|
||||
}
|
||||
|
||||
fn allocator(self: *FuzzAllocator) std.mem.Allocator {
|
||||
return self.state.allocator();
|
||||
}
|
||||
|
||||
fn reset(self: *FuzzAllocator) void {
|
||||
self.state.reset();
|
||||
}
|
||||
};
|
||||
|
||||
/// Use a single global allocator for simplicity and to avoid heap
|
||||
/// allocation overhead in the fuzzer. The allocator is backed by a fixed
|
||||
/// buffer, and every fuzz input resets the bump pointer to the start.
|
||||
var fuzz_alloc: FuzzAllocator = .{};
|
||||
|
||||
pub export fn zig_fuzz_init() callconv(.c) void {
|
||||
@@ -39,33 +16,63 @@ pub export fn zig_fuzz_test(
|
||||
buf: [*]const u8,
|
||||
len: usize,
|
||||
) callconv(.c) void {
|
||||
// Do not test zero-length input paths.
|
||||
if (len == 0) return;
|
||||
|
||||
fuzz_alloc.reset();
|
||||
const alloc = fuzz_alloc.allocator();
|
||||
const input = buf[0..@intCast(len)];
|
||||
const input = buf[0..len];
|
||||
|
||||
// Allocate a terminal; if we run out of fixed-buffer space just
|
||||
// skip this input (not a bug, just a very large allocation).
|
||||
var term = Terminal.init(alloc, .{
|
||||
var t = Terminal.init(alloc, .{
|
||||
.cols = 80,
|
||||
.rows = 24,
|
||||
.max_scrollback = 100,
|
||||
}) catch return;
|
||||
defer term.deinit(alloc);
|
||||
defer t.deinit(alloc);
|
||||
|
||||
var stream: ReadonlyStream = term.vtStream();
|
||||
var stream: ReadonlyStream = t.vtStream();
|
||||
defer stream.deinit();
|
||||
|
||||
// Use the first byte to decide between the scalar and slice paths
|
||||
// so both code paths get exercised by the fuzzer.
|
||||
if (input.len == 0) return;
|
||||
const mode = input[0];
|
||||
const data = input[1..];
|
||||
|
||||
if (mode & 1 == 0) {
|
||||
// Slice path — exercises SIMD fast-path
|
||||
stream.nextSlice(data) catch {};
|
||||
// Slice path — exercises SIMD fast-path if enabled
|
||||
stream.nextSlice(data) catch |err|
|
||||
std.debug.panic("nextSlice: {}", .{err});
|
||||
} else {
|
||||
// Scalar path — exercises byte-at-a-time UTF-8 decoding
|
||||
for (data) |byte| _ = stream.next(byte) catch {};
|
||||
for (data) |byte| _ = stream.next(byte) catch |err|
|
||||
std.debug.panic("next: {}", .{err});
|
||||
}
|
||||
}
|
||||
|
||||
/// Fixed-capacity allocator that avoids heap allocation and gives the
|
||||
/// fuzzer deterministic, bounded memory behaviour. Backed by a single
|
||||
/// fixed buffer; every `reset()` returns the bump pointer to the start
|
||||
/// so the same memory is reused across iterations.
|
||||
const FuzzAllocator = struct {
|
||||
buf: [mem_size]u8 = undefined,
|
||||
state: std.heap.FixedBufferAllocator = undefined,
|
||||
|
||||
/// 64 MiB gives the fuzzer enough headroom to exercise terminal
|
||||
/// resizes, large scrollback, and other allocation-heavy paths
|
||||
/// without running into out-of-memory on every other input.
|
||||
const mem_size = 64 * 1024 * 1024;
|
||||
|
||||
fn init(self: *FuzzAllocator) void {
|
||||
self.state = .init(&self.buf);
|
||||
}
|
||||
|
||||
fn allocator(self: *FuzzAllocator) std.mem.Allocator {
|
||||
return self.state.allocator();
|
||||
}
|
||||
|
||||
fn reset(self: *FuzzAllocator) void {
|
||||
self.state.reset();
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user