@zigc/lib 0.16.0-dev.3091 → 0.16.0-dev.3128

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/c/math.zig +121 -30
  2. package/compiler/build_runner.zig +1 -0
  3. package/compiler/test_runner.zig +191 -59
  4. package/compiler_rt/cos.zig +141 -52
  5. package/compiler_rt/long_double.zig +37 -0
  6. package/compiler_rt/rem_pio2l.zig +173 -0
  7. package/compiler_rt/sin.zig +140 -55
  8. package/compiler_rt/sincos.zig +279 -72
  9. package/compiler_rt/tan.zig +118 -47
  10. package/compiler_rt/trig.zig +256 -6
  11. package/fuzzer.zig +855 -307
  12. package/package.json +1 -1
  13. package/std/Build/Fuzz.zig +6 -19
  14. package/std/Build/Step/Run.zig +530 -68
  15. package/std/Build/abi.zig +39 -7
  16. package/std/Build.zig +3 -0
  17. package/std/compress/flate/Compress.zig +3 -3
  18. package/std/debug/Info.zig +4 -0
  19. package/std/heap/ArenaAllocator.zig +145 -154
  20. package/std/mem/Allocator.zig +4 -5
  21. package/std/mem.zig +48 -0
  22. package/std/priority_dequeue.zig +13 -12
  23. package/std/priority_queue.zig +5 -4
  24. package/std/zig/Client.zig +8 -3
  25. package/std/zig/Server.zig +26 -0
  26. package/libc/mingw/complex/cabs.c +0 -48
  27. package/libc/mingw/complex/cabsf.c +0 -48
  28. package/libc/mingw/complex/cacos.c +0 -50
  29. package/libc/mingw/complex/cacosf.c +0 -50
  30. package/libc/mingw/complex/carg.c +0 -48
  31. package/libc/mingw/complex/cargf.c +0 -48
  32. package/libc/mingw/complex/casin.c +0 -50
  33. package/libc/mingw/complex/casinf.c +0 -50
  34. package/libc/mingw/complex/catan.c +0 -50
  35. package/libc/mingw/complex/catanf.c +0 -50
  36. package/libc/mingw/complex/ccos.c +0 -50
  37. package/libc/mingw/complex/ccosf.c +0 -50
  38. package/libc/mingw/complex/cexp.c +0 -48
  39. package/libc/mingw/complex/cexpf.c +0 -48
  40. package/libc/mingw/complex/cimag.c +0 -48
  41. package/libc/mingw/complex/cimagf.c +0 -48
  42. package/libc/mingw/complex/clog.c +0 -48
  43. package/libc/mingw/complex/clog10.c +0 -49
  44. package/libc/mingw/complex/clog10f.c +0 -49
  45. package/libc/mingw/complex/clogf.c +0 -48
  46. package/libc/mingw/complex/conj.c +0 -48
  47. package/libc/mingw/complex/conjf.c +0 -48
  48. package/libc/mingw/complex/cpow.c +0 -48
  49. package/libc/mingw/complex/cpowf.c +0 -48
  50. package/libc/mingw/complex/cproj.c +0 -48
  51. package/libc/mingw/complex/cprojf.c +0 -48
  52. package/libc/mingw/complex/creal.c +0 -48
  53. package/libc/mingw/complex/crealf.c +0 -48
  54. package/libc/mingw/complex/csin.c +0 -50
  55. package/libc/mingw/complex/csinf.c +0 -50
  56. package/libc/mingw/complex/csqrt.c +0 -48
  57. package/libc/mingw/complex/csqrtf.c +0 -48
  58. package/libc/mingw/complex/ctan.c +0 -50
  59. package/libc/mingw/complex/ctanf.c +0 -50
  60. package/libc/mingw/math/arm/s_rint.c +0 -86
  61. package/libc/mingw/math/arm/s_rintf.c +0 -51
  62. package/libc/mingw/math/arm/sincos.S +0 -30
  63. package/libc/mingw/math/arm-common/sincosl.c +0 -13
  64. package/libc/mingw/math/arm64/rint.c +0 -12
  65. package/libc/mingw/math/arm64/rintf.c +0 -12
  66. package/libc/mingw/math/arm64/sincos.S +0 -32
  67. package/libc/mingw/math/bsd_private_base.h +0 -148
  68. package/libc/mingw/math/frexpf.c +0 -13
  69. package/libc/mingw/math/frexpl.c +0 -71
  70. package/libc/mingw/math/x86/acosf.c +0 -29
  71. package/libc/mingw/math/x86/atanf.c +0 -23
  72. package/libc/mingw/math/x86/atanl.c +0 -18
  73. package/libc/mingw/math/x86/cos.def.h +0 -65
  74. package/libc/mingw/math/x86/cosl.c +0 -46
  75. package/libc/mingw/math/x86/cosl_internal.S +0 -55
  76. package/libc/mingw/math/x86/ldexp.c +0 -23
  77. package/libc/mingw/math/x86/scalbn.S +0 -41
  78. package/libc/mingw/math/x86/scalbnf.S +0 -40
  79. package/libc/mingw/math/x86/sin.def.h +0 -65
  80. package/libc/mingw/math/x86/sinl.c +0 -46
  81. package/libc/mingw/math/x86/sinl_internal.S +0 -58
  82. package/libc/mingw/math/x86/tanl.S +0 -62
  83. package/libc/mingw/misc/btowc.c +0 -28
  84. package/libc/mingw/misc/wcstof.c +0 -66
  85. package/libc/mingw/misc/wcstoimax.c +0 -132
  86. package/libc/mingw/misc/wcstoumax.c +0 -126
  87. package/libc/mingw/misc/wctob.c +0 -29
  88. package/libc/mingw/misc/winbs_uint64.c +0 -6
  89. package/libc/mingw/misc/winbs_ulong.c +0 -6
  90. package/libc/mingw/misc/winbs_ushort.c +0 -6
  91. package/libc/mingw/stdio/_Exit.c +0 -10
  92. package/libc/mingw/stdio/_findfirst64i32.c +0 -21
  93. package/libc/mingw/stdio/_findnext64i32.c +0 -21
  94. package/libc/mingw/stdio/_fstat64i32.c +0 -37
  95. package/libc/mingw/stdio/_stat64i32.c +0 -37
  96. package/libc/mingw/stdio/_wfindfirst64i32.c +0 -21
  97. package/libc/mingw/stdio/_wfindnext64i32.c +0 -21
  98. package/libc/mingw/stdio/_wstat64i32.c +0 -37
  99. package/libc/musl/src/legacy/valloc.c +0 -8
  100. package/libc/musl/src/math/__cosl.c +0 -96
  101. package/libc/musl/src/math/__sinl.c +0 -78
  102. package/libc/musl/src/math/__tanl.c +0 -143
  103. package/libc/musl/src/math/aarch64/lrint.c +0 -10
  104. package/libc/musl/src/math/aarch64/lrintf.c +0 -10
  105. package/libc/musl/src/math/aarch64/rintf.c +0 -7
  106. package/libc/musl/src/math/cosl.c +0 -39
  107. package/libc/musl/src/math/exp_data.c +0 -182
  108. package/libc/musl/src/math/exp_data.h +0 -26
  109. package/libc/musl/src/math/finite.c +0 -7
  110. package/libc/musl/src/math/finitef.c +0 -7
  111. package/libc/musl/src/math/frexp.c +0 -23
  112. package/libc/musl/src/math/frexpf.c +0 -23
  113. package/libc/musl/src/math/frexpl.c +0 -29
  114. package/libc/musl/src/math/i386/lrint.c +0 -8
  115. package/libc/musl/src/math/i386/lrintf.c +0 -8
  116. package/libc/musl/src/math/i386/rintf.c +0 -7
  117. package/libc/musl/src/math/lrint.c +0 -72
  118. package/libc/musl/src/math/lrintf.c +0 -8
  119. package/libc/musl/src/math/pow_data.c +0 -180
  120. package/libc/musl/src/math/pow_data.h +0 -22
  121. package/libc/musl/src/math/powerpc64/lrint.c +0 -16
  122. package/libc/musl/src/math/powerpc64/lrintf.c +0 -16
  123. package/libc/musl/src/math/rintf.c +0 -30
  124. package/libc/musl/src/math/s390x/rintf.c +0 -15
  125. package/libc/musl/src/math/sincosl.c +0 -60
  126. package/libc/musl/src/math/sinl.c +0 -41
  127. package/libc/musl/src/math/tanl.c +0 -29
  128. package/libc/musl/src/math/x32/lrint.s +0 -5
  129. package/libc/musl/src/math/x32/lrintf.s +0 -5
  130. package/libc/musl/src/math/x86_64/lrint.c +0 -8
  131. package/libc/musl/src/math/x86_64/lrintf.c +0 -8
  132. package/libc/wasi/libc-bottom-half/sources/reallocarray.c +0 -14
package/c/math.zig CHANGED
@@ -35,33 +35,47 @@ comptime {
35
35
  }
36
36
 
37
37
  if (builtin.target.isMinGW() or builtin.target.isMuslLibC() or builtin.target.isWasiLibC()) {
38
- symbol(&coshf, "coshf");
38
+ symbol(&frexpf, "frexpf");
39
+ symbol(&frexpl, "frexpl");
39
40
  symbol(&hypotf, "hypotf");
40
41
  symbol(&hypotl, "hypotl");
41
- symbol(&modff, "modff");
42
42
  symbol(&modfl, "modfl");
43
- symbol(&nan, "nan");
44
- symbol(&nanf, "nanf");
43
+ }
44
+
45
+ if ((builtin.target.isMinGW() and @sizeOf(f64) != @sizeOf(c_longdouble)) or builtin.target.isMuslLibC() or builtin.target.isWasiLibC()) {
46
+ symbol(&atanl, "atanl");
47
+ symbol(&copysignl, "copysignl");
45
48
  symbol(&nanl, "nanl");
49
+ }
50
+
51
+ if ((builtin.target.isMinGW() and builtin.cpu.arch == .x86) or builtin.target.isMuslLibC() or builtin.target.isWasiLibC()) {
52
+ symbol(&acosf, "acosf");
53
+ symbol(&atanf, "atanf");
54
+ symbol(&coshf, "coshf");
55
+ symbol(&modff, "modff");
46
56
  symbol(&tanhf, "tanhf");
47
57
  }
48
58
 
49
59
  if (builtin.target.isMuslLibC() or builtin.target.isWasiLibC()) {
50
60
  symbol(&acos, "acos");
51
- symbol(&acosf, "acosf");
52
61
  symbol(&acoshf, "acoshf");
53
62
  symbol(&asin, "asin");
54
63
  symbol(&atan, "atan");
55
- symbol(&atanf, "atanf");
56
- symbol(&atanl, "atanl");
57
64
  symbol(&cbrt, "cbrt");
58
65
  symbol(&cbrtf, "cbrtf");
59
66
  symbol(&cosh, "cosh");
60
67
  symbol(&exp10, "exp10");
61
68
  symbol(&exp10f, "exp10f");
62
69
  symbol(&fdim, "fdim");
70
+ symbol(&finite, "finite");
71
+ symbol(&finitef, "finitef");
72
+ symbol(&frexp, "frexp");
63
73
  symbol(&hypot, "hypot");
74
+ symbol(&lrint, "lrint");
75
+ symbol(&lrintf, "lrintf");
64
76
  symbol(&modf, "modf");
77
+ symbol(&nan, "nan");
78
+ symbol(&nanf, "nanf");
65
79
  symbol(&pow, "pow");
66
80
  symbol(&pow10, "pow10");
67
81
  symbol(&pow10f, "pow10f");
@@ -72,9 +86,8 @@ comptime {
72
86
  symbol(&copysign, "copysign");
73
87
  symbol(&copysignf, "copysignf");
74
88
  symbol(&rint, "rint");
89
+ symbol(&rintf, "rintf");
75
90
  }
76
-
77
- symbol(&copysignl, "copysignl");
78
91
  }
79
92
 
80
93
  fn acos(x: f64) callconv(.c) f64 {
@@ -161,6 +174,45 @@ fn fdim(x: f64, y: f64) callconv(.c) f64 {
161
174
  return 0;
162
175
  }
163
176
 
177
+ fn finite(x: f64) callconv(.c) c_int {
178
+ return if (math.isFinite(x)) 1 else 0;
179
+ }
180
+
181
+ fn finitef(x: f32) callconv(.c) c_int {
182
+ return if (math.isFinite(x)) 1 else 0;
183
+ }
184
+
185
+ fn frexpGeneric(comptime T: type, x: T, e: *c_int) T {
186
+ // libc expects `*e` to be unspecified in this case; an unspecified C value
187
+ // should be a valid value of the relevant type, yet Zig's std
188
+ // implementation sets it to `undefined` -- which can even be nonsense
189
+ // according to the type (int). Therefore, we're setting it to a valid
190
+ // int value in Zig -- a zero.
191
+ //
192
+ // This mirrors the handling of infinities, where libc also expects
193
+ // unspecified for the value of `*e` and Zig std sets it to a zero.
194
+ if (math.isNan(x)) {
195
+ e.* = 0;
196
+ return x;
197
+ }
198
+
199
+ const r = math.frexp(x);
200
+ e.* = r.exponent;
201
+ return r.significand;
202
+ }
203
+
204
+ fn frexp(x: f64, e: *c_int) callconv(.c) f64 {
205
+ return frexpGeneric(f64, x, e);
206
+ }
207
+
208
+ fn frexpf(x: f32, e: *c_int) callconv(.c) f32 {
209
+ return frexpGeneric(f32, x, e);
210
+ }
211
+
212
+ fn frexpl(x: c_longdouble, e: *c_int) callconv(.c) c_longdouble {
213
+ return frexpGeneric(c_longdouble, x, e);
214
+ }
215
+
164
216
  fn hypot(x: f64, y: f64) callconv(.c) f64 {
165
217
  return math.hypot(x, y);
166
218
  }
@@ -185,6 +237,14 @@ fn isnanl(x: c_longdouble) callconv(.c) c_int {
185
237
  return if (math.isNan(x)) 1 else 0;
186
238
  }
187
239
 
240
+ fn lrint(x: f64) callconv(.c) c_long {
241
+ return @intFromFloat(rint(x));
242
+ }
243
+
244
+ fn lrintf(x: f32) callconv(.c) c_long {
245
+ return @intFromFloat(rintf(x));
246
+ }
247
+
188
248
  fn modfGeneric(comptime T: type, x: T, iptr: *T) T {
189
249
  if (math.isNegativeInf(x)) {
190
250
  iptr.* = -math.inf(T);
@@ -299,7 +359,7 @@ fn pow10f(x: f32) callconv(.c) f32 {
299
359
  }
300
360
 
301
361
  fn rint(x: f64) callconv(.c) f64 {
302
- const toint: f64 = 1.0 / @as(f64, math.floatEps(f64));
362
+ const toint: f64 = 1.0 / math.floatEps(f64);
303
363
  const a: u64 = @bitCast(x);
304
364
  const e = a >> 52 & 0x7ff;
305
365
  const s = a >> 63;
@@ -319,39 +379,70 @@ fn rint(x: f64) callconv(.c) f64 {
319
379
  return y;
320
380
  }
321
381
 
322
- test "rint" {
382
+ fn rintf(x: f32) callconv(.c) f32 {
383
+ const toint: f32 = 1.0 / math.floatEps(f32);
384
+ const a: u32 = @bitCast(x);
385
+ const e = a >> 23 & 0xff;
386
+ const s = a >> 31;
387
+ var y: f32 = undefined;
388
+
389
+ if (e >= 0x7f + 23) {
390
+ return x;
391
+ }
392
+
393
+ if (s == 1) {
394
+ y = x - toint + toint;
395
+ } else {
396
+ y = x + toint - toint;
397
+ }
398
+
399
+ if (y == 0) {
400
+ return if (s == 1) -0.0 else 0;
401
+ }
402
+ return y;
403
+ }
404
+
405
+ fn testRint(comptime T: type) !void {
406
+ const f = switch (T) {
407
+ f32 => rintf,
408
+ f64 => rint,
409
+ else => @compileError("rint not implemented for" ++ @typeName(T)),
410
+ };
411
+
323
412
  // Positive numbers round correctly
324
- try expectEqual(@as(f64, 42.0), rint(42.2));
325
- try expectEqual(@as(f64, 42.0), rint(41.8));
413
+ try expectEqual(@as(T, 42.0), f(42.2));
414
+ try expectEqual(@as(T, 42.0), f(41.8));
326
415
 
327
416
  // Negative numbers round correctly
328
- try expectEqual(@as(f64, -6.0), rint(-5.9));
329
- try expectEqual(@as(f64, -6.0), rint(-6.1));
417
+ try expectEqual(@as(T, -6.0), f(-5.9));
418
+ try expectEqual(@as(T, -6.0), f(-6.1));
330
419
 
331
420
  // No rounding needed test
332
- try expectEqual(@as(f64, 5.0), rint(5.0));
333
- try expectEqual(@as(f64, -10.0), rint(-10.0));
334
- try expectEqual(@as(f64, 0.0), rint(0.0));
421
+ try expectEqual(@as(T, 5.0), f(5.0));
422
+ try expectEqual(@as(T, -10.0), f(-10.0));
423
+ try expectEqual(@as(T, 0.0), f(0.0));
335
424
 
336
425
  // Very large numbers return unchanged
337
- const large: f64 = 9007199254740992.0; // 2^53
338
- try expectEqual(large, rint(large));
339
- try expectEqual(-large, rint(-large));
426
+ const large: T = 9007199254740992.0; // 2^53
427
+ try expectEqual(large, f(large));
428
+ try expectEqual(-large, f(-large));
340
429
 
341
430
  // Small positive numbers round to zero
342
- const pos_result = rint(0.3);
343
- try expectEqual(@as(f64, 0.0), pos_result);
344
- try expect(@as(u64, @bitCast(pos_result)) == 0);
431
+ const pos_result = f(0.3);
432
+ try expect(math.isPositiveZero(pos_result));
345
433
 
346
434
  // Small negative numbers round to negative zero
347
- const neg_result = rint(-0.3);
348
- try expectEqual(@as(f64, 0.0), neg_result);
349
- const bits: u64 = @bitCast(neg_result);
350
- try expect((bits >> 63) == 1);
435
+ const neg_result = f(-0.3);
436
+ try expect(math.isNegativeZero(neg_result));
351
437
 
352
438
  // Exact half rounds to nearest even (banker's rounding)
353
- try expectEqual(@as(f64, 2.0), rint(2.5));
354
- try expectEqual(@as(f64, 4.0), rint(3.5));
439
+ try expectEqual(@as(T, 2.0), f(2.5));
440
+ try expectEqual(@as(T, 4.0), f(3.5));
441
+ }
442
+
443
+ test "rint" {
444
+ try testRint(f32);
445
+ try testRint(f64);
355
446
  }
356
447
 
357
448
  fn tanh(x: f64) callconv(.c) f64 {
@@ -424,6 +424,7 @@ pub fn main(init: process.Init.Minimal) !void {
424
424
  fatal("unable to parse jobs count '{s}': {t}", .{ text, err });
425
425
  if (n < 1) fatal("number of jobs must be at least 1", .{});
426
426
  threaded.setAsyncLimit(.limited(n));
427
+ graph.max_jobs = n;
427
428
  } else if (mem.eql(u8, arg, "--")) {
428
429
  builder.args = argsRest(args, arg_idx);
429
430
  break;
@@ -6,6 +6,7 @@ const Io = std.Io;
6
6
  const fatal = std.process.fatal;
7
7
  const testing = std.testing;
8
8
  const assert = std.debug.assert;
9
+ const panic = std.debug.panic;
9
10
  const fuzz_abi = std.Build.abi.fuzz;
10
11
 
11
12
  pub const std_options: std.Options = .{
@@ -17,6 +18,8 @@ var fba: std.heap.FixedBufferAllocator = .init(&fba_buffer);
17
18
  var fba_buffer: [8192]u8 = undefined;
18
19
  var stdin_buffer: [4096]u8 = undefined;
19
20
  var stdout_buffer: [4096]u8 = undefined;
21
+ var stdin_reader: Io.File.Reader = undefined;
22
+ var stdout_writer: Io.File.Writer = undefined;
20
23
  const runner_threaded_io: Io = Io.Threaded.global_single_threaded.io();
21
24
 
22
25
  /// Keep in sync with logic in `std.Build.addRunArtifact` which decides whether
@@ -38,10 +41,10 @@ pub fn main(init: std.process.Init.Minimal) void {
38
41
  }
39
42
 
40
43
  if (need_simple) {
41
- return mainSimple() catch |err| std.debug.panic("test failure: {t}", .{err});
44
+ return mainSimple() catch |err| panic("test failure: {t}", .{err});
42
45
  }
43
46
 
44
- const args = init.args.toSlice(fba.allocator()) catch |err| std.debug.panic("unable to parse command line args: {t}", .{err});
47
+ const args = init.args.toSlice(fba.allocator()) catch |err| panic("unable to parse command line args: {t}", .{err});
45
48
 
46
49
  var listen = false;
47
50
  var opt_cache_dir: ?[]const u8 = null;
@@ -55,7 +58,7 @@ pub fn main(init: std.process.Init.Minimal) void {
55
58
  } else if (std.mem.startsWith(u8, arg, "--cache-dir")) {
56
59
  opt_cache_dir = arg["--cache-dir=".len..];
57
60
  } else {
58
- std.debug.panic("unrecognized command line argument: {s}", .{arg});
61
+ panic("unrecognized command line argument: {s}", .{arg});
59
62
  }
60
63
  }
61
64
 
@@ -65,7 +68,7 @@ pub fn main(init: std.process.Init.Minimal) void {
65
68
  }
66
69
 
67
70
  if (listen) {
68
- return mainServer(init) catch |err| std.debug.panic("internal test runner failure: {t}", .{err});
71
+ return mainServer(init) catch |err| panic("internal test runner failure: {t}", .{err});
69
72
  } else {
70
73
  return mainTerminal(init);
71
74
  }
@@ -73,24 +76,14 @@ pub fn main(init: std.process.Init.Minimal) void {
73
76
 
74
77
  fn mainServer(init: std.process.Init.Minimal) !void {
75
78
  @disableInstrumentation();
76
- var stdin_reader = Io.File.stdin().readerStreaming(runner_threaded_io, &stdin_buffer);
77
- var stdout_writer = Io.File.stdout().writerStreaming(runner_threaded_io, &stdout_buffer);
79
+ stdin_reader = .initStreaming(.stdin(), runner_threaded_io, &stdin_buffer);
80
+ stdout_writer = .initStreaming(.stdout(), runner_threaded_io, &stdout_buffer);
78
81
  var server = try std.zig.Server.init(.{
79
82
  .in = &stdin_reader.interface,
80
83
  .out = &stdout_writer.interface,
81
84
  .zig_version = builtin.zig_version_string,
82
85
  });
83
86
 
84
- if (builtin.fuzz) {
85
- const coverage = fuzz_abi.fuzzer_coverage();
86
- try server.serveCoverageIdMessage(
87
- coverage.id,
88
- coverage.runs,
89
- coverage.unique,
90
- coverage.seen,
91
- );
92
- }
93
-
94
87
  while (true) {
95
88
  const hdr = try server.receiveMessage();
96
89
  switch (hdr.tag) {
@@ -180,48 +173,75 @@ fn mainServer(init: std.process.Init.Minimal) !void {
180
173
  // since they are not present.
181
174
  if (!builtin.fuzz) unreachable;
182
175
 
183
- const index: u32 = @intCast(index: {
184
- testing.allocator_instance = .{};
185
- defer if (testing.allocator_instance.deinit() == .leak) {
186
- @panic("internal test runner memory leak");
187
- };
188
-
189
- const name_len = try server.receiveBody_u32();
190
- const name = try server.in.readAlloc(testing.allocator, @intCast(name_len));
191
- defer testing.allocator.free(name);
192
- for (0.., builtin.test_functions) |i, test_fn| {
193
- if (std.mem.eql(u8, name, test_fn.name)) {
194
- break :index i;
195
- }
196
- } else {
197
- std.debug.panic("fuzz test {s} no longer exists", .{name});
198
- }
176
+ var gpa_instance: std.heap.DebugAllocator(.{}) = .init;
177
+ defer if (gpa_instance.deinit() == .leak) {
178
+ @panic("internal test runner memory leak");
179
+ };
180
+ const gpa = gpa_instance.allocator();
181
+ var io_instance: Io.Threaded = .init(gpa, .{
182
+ .argv0 = .init(init.args),
183
+ .environ = init.environ,
199
184
  });
185
+ defer io_instance.deinit();
186
+ const io = io_instance.io();
187
+
200
188
  const mode: fuzz_abi.LimitKind = @enumFromInt(try server.receiveBody_u8());
201
189
  const amount_or_instance = try server.receiveBody_u64();
190
+ const main_instance = mode == .iterations or amount_or_instance == 0;
191
+
192
+ if (main_instance) {
193
+ const coverage = fuzz_abi.fuzzer_coverage();
194
+ try server.serveCoverageIdMessage(
195
+ coverage.id,
196
+ coverage.runs,
197
+ coverage.unique,
198
+ coverage.seen,
199
+ );
200
+ }
202
201
 
203
- const test_fn = builtin.test_functions[index];
204
- const entry_addr = @intFromPtr(test_fn.func);
202
+ const n_tests: u32 = try server.receiveBody_u32();
203
+ const test_indexes = try gpa.alloc(u32, n_tests);
204
+ defer gpa.free(test_indexes);
205
+ fuzz_runner = .{
206
+ .indexes = test_indexes,
207
+ .server = &server,
208
+ .gpa = gpa,
209
+ .io = io,
210
+ .input_poller = undefined,
211
+ };
205
212
 
206
- try server.serveU64Message(.fuzz_start_addr, fuzz_abi.fuzzer_unslide_address(entry_addr));
207
- defer if (testing.allocator_instance.deinit() == .leak) std.process.exit(1);
208
- is_fuzz_test = false;
209
- fuzz_test_index = index;
210
- fuzz_mode = mode;
211
- fuzz_amount_or_instance = amount_or_instance;
213
+ {
214
+ var large_name_buf: std.ArrayList(u8) = .empty;
215
+ defer large_name_buf.deinit(gpa);
216
+ for (test_indexes) |*i| {
217
+ const name_len = try server.receiveBody_u32();
218
+ const name = if (name_len <= server.in.buffer.len)
219
+ try server.in.take(name_len)
220
+ else large_name: {
221
+ try large_name_buf.resize(gpa, name_len);
222
+ try server.in.readSliceAll(large_name_buf.items);
223
+ break :large_name large_name_buf.items;
224
+ };
225
+
226
+ for (0.., builtin.test_functions) |test_i, test_fn| {
227
+ if (std.mem.eql(u8, name, test_fn.name)) {
228
+ i.* = @intCast(test_i);
229
+ break;
230
+ }
231
+ } else {
232
+ panic("fuzz test {s} no longer exists", .{name});
233
+ }
212
234
 
213
- test_fn.func() catch |err| switch (err) {
214
- error.SkipZigTest => return,
215
- else => {
216
- if (@errorReturnTrace()) |trace| {
217
- std.debug.dumpStackTrace(trace);
235
+ if (main_instance) {
236
+ const relocated_entry_addr = @intFromPtr(builtin.test_functions[i.*].func);
237
+ const entry_addr = fuzz_abi.fuzzer_unslide_address(relocated_entry_addr);
238
+ try server.serveU64Message(.fuzz_start_addr, entry_addr);
218
239
  }
219
- std.debug.print("failed with error.{t}\n", .{err});
220
- std.process.exit(1);
221
- },
222
- };
223
- if (!is_fuzz_test) @panic("missed call to std.testing.fuzz");
224
- if (log_err_count != 0) @panic("error logs detected");
240
+ }
241
+ }
242
+
243
+ fuzz_abi.fuzzer_main(n_tests, testing.random_seed, mode, amount_or_instance);
244
+
225
245
  assert(mode != .forever);
226
246
  std.process.exit(0);
227
247
  },
@@ -382,16 +402,126 @@ pub fn mainSimple() anyerror!void {
382
402
  passed += 1;
383
403
  }
384
404
  if (enable_print) {
385
- var stdout_writer = stdout.writer(runner_threaded_io, &.{});
386
- stdout_writer.interface.print("{} passed, {} skipped, {} failed\n", .{ passed, skipped, failed }) catch {};
405
+ var unbuffered_stdout_writer = stdout.writer(runner_threaded_io, &.{});
406
+ unbuffered_stdout_writer.interface.print(
407
+ "{} passed, {} skipped, {} failed\n",
408
+ .{ passed, skipped, failed },
409
+ ) catch {};
387
410
  }
388
411
  if (failed != 0) std.process.exit(1);
389
412
  }
390
413
 
391
414
  var is_fuzz_test: bool = undefined;
392
- var fuzz_test_index: u32 = undefined;
393
- var fuzz_mode: fuzz_abi.LimitKind = undefined;
394
- var fuzz_amount_or_instance: u64 = undefined;
415
+ var fuzz_runner: if (builtin.fuzz) struct {
416
+ indexes: []u32,
417
+ server: *std.zig.Server,
418
+ gpa: std.mem.Allocator,
419
+ io: Io,
420
+ input_poller: Io.Future(Io.Cancelable!void),
421
+
422
+ comptime {
423
+ assert(builtin.fuzz); // `fuzz_runner` was analyzed in non-fuzzing compilation
424
+ }
425
+
426
+ export fn runner_test_run(i: u32) void {
427
+ @disableInstrumentation();
428
+
429
+ fuzz_runner.server.serveU32Message(.fuzz_test_change, i) catch |e| switch (e) {
430
+ error.WriteFailed => panic("failed to write to stdout: {t}", .{stdout_writer.err.?}),
431
+ };
432
+
433
+ testing.allocator_instance = .{};
434
+ defer if (testing.allocator_instance.deinit() == .leak) std.process.exit(1);
435
+ is_fuzz_test = false;
436
+
437
+ builtin.test_functions[fuzz_runner.indexes[i]].func() catch |err| switch (err) {
438
+ error.SkipZigTest => return,
439
+ else => {
440
+ if (@errorReturnTrace()) |trace| {
441
+ std.debug.dumpStackTrace(trace);
442
+ }
443
+ std.debug.print("failed with error.{t}\n", .{err});
444
+ std.process.exit(1);
445
+ },
446
+ };
447
+
448
+ if (!is_fuzz_test) @panic("missed call to std.testing.fuzz");
449
+ if (log_err_count != 0) @panic("error logs detected");
450
+ }
451
+
452
+ export fn runner_test_name(i: u32) fuzz_abi.Slice {
453
+ @disableInstrumentation();
454
+ return .fromSlice(builtin.test_functions[fuzz_runner.indexes[i]].name);
455
+ }
456
+
457
+ export fn runner_broadcast_input(test_i: u32, bytes_slice: fuzz_abi.Slice) void {
458
+ @disableInstrumentation();
459
+ const bytes = bytes_slice.toSlice();
460
+ fuzz_runner.server.serveBroadcastFuzzInputMessage(test_i, bytes) catch |e| switch (e) {
461
+ error.WriteFailed => panic("failed to write to stdout: {t}", .{stdout_writer.err.?}),
462
+ };
463
+ }
464
+
465
+ export fn runner_start_input_poller() void {
466
+ @disableInstrumentation();
467
+ const future = fuzz_runner.io.concurrent(inputPoller, .{}) catch |e| switch (e) {
468
+ error.ConcurrencyUnavailable => @panic("failed to spawn concurrent fuzz input poller"),
469
+ };
470
+ fuzz_runner.input_poller = future;
471
+ }
472
+
473
+ export fn runner_stop_input_poller() void {
474
+ @disableInstrumentation();
475
+ assert(fuzz_runner.input_poller.cancel(fuzz_runner.io) == error.Canceled);
476
+ }
477
+
478
+ export fn runner_futex_wait(ptr: *const u32, expected: u32) bool {
479
+ @disableInstrumentation();
480
+ return fuzz_runner.io.futexWait(u32, ptr, expected) == error.Canceled;
481
+ }
482
+
483
+ export fn runner_futex_wake(ptr: *const u32, waiters: u32) void {
484
+ @disableInstrumentation();
485
+ fuzz_runner.io.futexWake(u32, ptr, waiters);
486
+ }
487
+
488
+ fn inputPoller() Io.Cancelable!void {
489
+ @disableInstrumentation();
490
+ switch (inputPollerInner()) {
491
+ error.Canceled => return error.Canceled,
492
+ error.ReadFailed => {
493
+ if (stdin_reader.err.? == error.Canceled) return error.Canceled;
494
+ panic("failed to read from stdin: {t}", .{stdin_reader.err.?});
495
+ },
496
+ error.EndOfStream => @panic("unexpected end of stdin"),
497
+ }
498
+ }
499
+
500
+ fn inputPollerInner() (Io.Cancelable || Io.Reader.Error) {
501
+ @disableInstrumentation();
502
+ const server = fuzz_runner.server;
503
+ var large_bytes_list: std.ArrayList(u8) = .empty;
504
+ defer large_bytes_list.deinit(fuzz_runner.gpa);
505
+ while (true) {
506
+ const hdr = try server.receiveMessage();
507
+ if (hdr.tag != .new_fuzz_input) {
508
+ panic("unexpected message: {x}\n", .{@intFromEnum(hdr.tag)});
509
+ }
510
+ const test_i = try server.receiveBody_u32();
511
+ const input_len = hdr.bytes_len - 4;
512
+ const bytes = if (input_len <= server.in.buffer.len)
513
+ try server.in.take(input_len)
514
+ else bytes: {
515
+ large_bytes_list.resize(fuzz_runner.gpa, @intCast(input_len)) catch @panic("OOM");
516
+ try server.in.readSliceAll(large_bytes_list.items);
517
+ break :bytes large_bytes_list.items;
518
+ };
519
+ if (fuzz_abi.fuzzer_receive_input(test_i, .fromSlice(bytes))) {
520
+ return error.Canceled;
521
+ }
522
+ }
523
+ }
524
+ } else void = undefined;
395
525
 
396
526
  pub fn fuzz(
397
527
  context: anytype,
@@ -448,16 +578,18 @@ pub fn fuzz(
448
578
  return false;
449
579
  }
450
580
  };
581
+
451
582
  if (builtin.fuzz) {
583
+ // Preserve the calling test's allocator state
452
584
  const prev_allocator_state = testing.allocator_instance;
453
585
  testing.allocator_instance = .{};
454
586
  defer testing.allocator_instance = prev_allocator_state;
455
- global.ctx = context;
456
587
 
457
- fuzz_abi.fuzzer_set_test(&global.test_one, .fromSlice(builtin.test_functions[fuzz_test_index].name));
588
+ global.ctx = context;
589
+ fuzz_abi.fuzzer_set_test(&global.test_one);
458
590
  for (options.corpus) |elem|
459
591
  fuzz_abi.fuzzer_new_input(.fromSlice(elem));
460
- fuzz_abi.fuzzer_main(fuzz_mode, fuzz_amount_or_instance);
592
+ fuzz_abi.fuzzer_start_test();
461
593
  return;
462
594
  }
463
595