From 5f24c4a2284a0af84fb9d116f7a39f6a58e42ae9 Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Mon, 14 Sep 2026 14:10:28 -0300 Subject: Implement base 9P2000 sessions, shared transports, and conformance probes --- test/fuzz.zig | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 test/fuzz.zig (limited to 'test/fuzz.zig') diff --git a/test/fuzz.zig b/test/fuzz.zig new file mode 100644 index 0000000..b7d9f21 --- /dev/null +++ b/test/fuzz.zig @@ -0,0 +1,70 @@ +//! Deterministic local robustness probes; reference implementations see valid traffic only. +const std = @import("std"); +const c9 = @import("cloud9"); +pub fn main(init: std.process.Init) !void { + const args = try init.minimal.args.toSlice(init.arena.allocator()); + const seed = if (args.len > 1) try std.fmt.parseInt(u64, args[1], 10) else 4200; + const iterations = if (args.len > 2) try std.fmt.parseInt(u32, args[2], 10) else 100000; + if (args.len > 3 or iterations > 10000000) return error.Arguments; + var prng: std.Random.DefaultPrng = .init(seed); + const random = prng.random(); + var accepted: usize = 0; + var rejected: usize = 0; + var buffer: [8192]u8 = undefined; + var encoded: [8192]u8 = undefined; + var payload: [4096]u8 = undefined; + var server_in: [8192]u8 = undefined; + var server_out: [8192]u8 = undefined; + for (0..iterations) |_| { + random.bytes(&payload); + const data = payload[0..random.uintLessThan(usize, payload.len)]; + const qid: c9.Qid = .{ .type = random.int(u8), .version = random.int(u32), .path = random.int(u64) }; + const stat: c9.Stat = .{ + .type = 0, + .dev = 0, + .qid = qid, + .mode = random.int(u32), + .atime = 0, + .mtime = 0, + .length = random.int(u64), + .name = "file", + .uid = "user", + .gid = "group", + .muid = "", + }; + const messages = [_]c9.Msg{ + .{ .tversion = .{ .msize = 8192, .version = "9P2000" } }, + .{ .twalk = .{ .fid = 0, .newfid = 1, .nwname = 16, .wname = @splat("dir") } }, + .{ .rwalk = .{ .nwqid = 16, .wqid = @splat(qid) } }, + .{ .twrite = .{ .fid = random.int(u32), .offset = random.int(u64), .data = data } }, + .{ .rread = .{ .data = data } }, + .{ .rstat = .{ .stat = stat } }, + .{ .twstat = .{ .fid = 1, .stat = stat } }, + .{ .tflush = .{ .oldtag = random.int(u16) } }, + .{ .tread = .{ .fid = 1, .offset = random.int(u64), .count = random.int(u32) } }, + }; + const msg = messages[random.uintLessThan(usize, messages.len)]; + var frame: []u8 = try c9.encode(msg, random.int(u16), &buffer); + // Leave some valid seeds unchanged; probe truncation and altered fields locally. + switch (random.uintLessThan(u8, 4)) { + 0 => {}, + 1 => frame = frame[0..random.uintLessThan(usize, frame.len)], + 2 => frame[random.uintLessThan(usize, frame.len)] ^= random.int(u8), + 3 => std.mem.writeInt(u32, frame[0..4], random.int(u32), .little), + else => unreachable, + } + if (c9.decode(frame)) |decoded| { + const output = try c9.encode(decoded.msg, decoded.tag, &encoded); + if (!std.mem.eql(u8, frame, output)) return error.RoundTrip; + accepted += 1; + } else |_| rejected += 1; + var server: c9.Server = .init(.{ .in = &server_in, .out = &server_out }); + _ = server.push(frame); + if (server.receive() catch null) |request| { + if (request.msg != .tversion) return error.BeforeVersion; + server.negotiate(request.msg.tversion.msize, request.msg.tversion.version) catch {}; + server.release(); + } + } + std.debug.print("seed={d} iterations={d} accepted={d} rejected={d}\n", .{ seed, iterations, accepted, rejected }); +} -- cgit v1.3