1
1
//! Default test runner for unit tests.
2
2
const builtin = @import ("builtin" );
3
+
3
4
const std = @import ("std" );
4
5
const io = std .io ;
5
6
const testing = std .testing ;
7
+ const assert = std .debug .assert ;
6
8
7
9
pub const std_options = .{
8
10
.logFn = log ,
@@ -28,19 +30,26 @@ pub fn main() void {
28
30
@panic ("unable to parse command line args" );
29
31
30
32
var listen = false ;
33
+ var opt_cache_dir : ? []const u8 = null ;
31
34
32
35
for (args [1.. ]) | arg | {
33
36
if (std .mem .eql (u8 , arg , "--listen=-" )) {
34
37
listen = true ;
35
38
} else if (std .mem .startsWith (u8 , arg , "--seed=" )) {
36
39
testing .random_seed = std .fmt .parseUnsigned (u32 , arg ["--seed=" .len .. ], 0 ) catch
37
40
@panic ("unable to parse --seed command line argument" );
41
+ } else if (std .mem .startsWith (u8 , arg , "--cache-dir" )) {
42
+ opt_cache_dir = arg ["--cache-dir=" .len .. ];
38
43
} else {
39
44
@panic ("unrecognized command line argument" );
40
45
}
41
46
}
42
47
43
48
fba .reset ();
49
+ if (builtin .fuzz ) {
50
+ const cache_dir = opt_cache_dir orelse @panic ("missing --cache-dir=[path] argument" );
51
+ fuzzer_init (FuzzerSlice .fromSlice (cache_dir ));
52
+ }
44
53
45
54
if (listen ) {
46
55
return mainServer () catch @panic ("internal test runner failure" );
@@ -59,6 +68,11 @@ fn mainServer() !void {
59
68
});
60
69
defer server .deinit ();
61
70
71
+ if (builtin .fuzz ) {
72
+ const coverage_id = fuzzer_coverage_id ();
73
+ try server .serveU64Message (.coverage_id , coverage_id );
74
+ }
75
+
62
76
while (true ) {
63
77
const hdr = try server .receiveMessage ();
64
78
switch (hdr .tag ) {
@@ -129,7 +143,9 @@ fn mainServer() !void {
129
143
});
130
144
},
131
145
.start_fuzzing = > {
146
+ if (! builtin .fuzz ) unreachable ;
132
147
const index = try server .receiveBody_u32 ();
148
+ var first = true ;
133
149
const test_fn = builtin .test_functions [index ];
134
150
while (true ) {
135
151
testing .allocator_instance = .{};
@@ -148,6 +164,10 @@ fn mainServer() !void {
148
164
};
149
165
if (! is_fuzz_test ) @panic ("missed call to std.testing.fuzzInput" );
150
166
if (log_err_count != 0 ) @panic ("error logs detected" );
167
+ if (first ) {
168
+ first = false ;
169
+ try server .serveU64Message (.fuzz_start_addr , entry_addr );
170
+ }
151
171
}
152
172
},
153
173
@@ -315,20 +335,32 @@ const FuzzerSlice = extern struct {
315
335
ptr : [* ]const u8 ,
316
336
len : usize ,
317
337
338
+ /// Inline to avoid fuzzer instrumentation.
318
339
inline fn toSlice (s : FuzzerSlice ) []const u8 {
319
340
return s .ptr [0.. s .len ];
320
341
}
342
+
343
+ /// Inline to avoid fuzzer instrumentation.
344
+ inline fn fromSlice (s : []const u8 ) FuzzerSlice {
345
+ return .{ .ptr = s .ptr , .len = s .len };
346
+ }
321
347
};
322
348
323
349
var is_fuzz_test : bool = undefined ;
350
+ var entry_addr : usize = 0 ;
324
351
325
352
extern fn fuzzer_next () FuzzerSlice ;
353
+ extern fn fuzzer_init (cache_dir : FuzzerSlice ) void ;
354
+ extern fn fuzzer_coverage_id () u64 ;
326
355
327
356
pub fn fuzzInput (options : testing.FuzzInputOptions ) []const u8 {
328
357
@disableInstrumentation ();
329
358
if (crippled ) return "" ;
330
359
is_fuzz_test = true ;
331
- if (builtin .fuzz ) return fuzzer_next ().toSlice ();
360
+ if (builtin .fuzz ) {
361
+ if (entry_addr == 0 ) entry_addr = @returnAddress ();
362
+ return fuzzer_next ().toSlice ();
363
+ }
332
364
if (options .corpus .len == 0 ) return "" ;
333
365
var prng = std .Random .DefaultPrng .init (testing .random_seed );
334
366
const random = prng .random ();
0 commit comments