1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
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 });
}
|