authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-05-23 21:46:06-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-05-25 18:54:36-07:00
logc0504a8fa87f66c5ddb2c02c35c10c945f4bb8b9
tree8a2c0bddff77844f915369c81eb7faafca80b0cf
parent1c8d50e0624c7099e82a35c78b135c59e2dbeaa3

fuzzer: get it working again


5 files changed, 146 insertions(+), 75 deletions(-)

lib/compiler/Maker.zig+2
......@@ -317,6 +317,7 @@ pub fn main(init: process.Init.Minimal) !void {
317317 if (webui_listen == null) webui_listen = .{ .ip6 = .loopback(0) };
318318 } else if (mem.eql(u8, arg, "--fuzz")) {
319319 fuzz = .{ .forever = undefined };
320 graph.fuzzing = true;
320321 if (webui_listen == null) webui_listen = .{ .ip6 = .loopback(0) };
321322 } else if (mem.startsWith(u8, arg, "--fuzz=")) {
322323 const value = arg["--fuzz=".len..];
......@@ -352,6 +353,7 @@ pub fn main(init: process.Init.Minimal) !void {
352353 .amount = normalized_amount,
353354 },
354355 };
356 graph.fuzzing = true;
355357 } else if (mem.eql(u8, arg, "-fincremental")) {
356358 graph.incremental = true;
357359 } else if (mem.eql(u8, arg, "-fno-incremental")) {
lib/compiler/Maker/Fuzz.zig+123-64
......@@ -83,6 +83,7 @@ pub fn init(
8383 const graph = maker.graph;
8484 const gpa = graph.cache.gpa;
8585 const io = graph.io;
86 const conf = &maker.scanned_config.configuration;
8687
8788 const run_steps: []const Configuration.Step.Index = steps: {
8889 var steps: std.ArrayList(Configuration.Step.Index) = .empty;
......@@ -92,13 +93,13 @@ pub fn init(
9293 var rebuild_group: Io.Group = .init;
9394 defer rebuild_group.cancel(io);
9495
95 for (all_steps) |step| {
96 if (true) @panic("TODO update the fuzzer");
97 const run = step.cast(std.Build.Step.Run) orelse continue;
98 if (run.producer == null) continue;
96 for (all_steps) |step_index| {
97 const conf_run = step_index.ptr(conf).extended.cast(conf, Configuration.Step.Run) orelse continue;
98 if (conf_run.producer.value == null) continue;
99 const run = &maker.stepByIndex(step_index).extended.run;
99100 if (run.fuzz_tests.items.len == 0) continue;
100 try steps.append(gpa, run);
101 rebuild_group.async(io, rebuildTestsWorkerRun, .{ run, gpa, rebuild_node });
101 try steps.append(gpa, step_index);
102 rebuild_group.async(io, rebuildTestsWorkerRun, .{ maker, step_index, rebuild_node });
102103 }
103104
104105 if (steps.items.len == 0) fatal("no fuzz tests found", .{});
......@@ -109,10 +110,10 @@ pub fn init(
109110 };
110111 errdefer gpa.free(run_steps);
111112
112 for (run_steps) |run_step_index| {
113 if (true) @panic("TODO update the fuzzer");
114 assert(run_step_index.fuzz_tests.items.len > 0);
115 if (run_step_index.rebuilt_executable == null)
113 for (run_steps) |run_index| {
114 const run = &maker.stepByIndex(run_index).extended.run;
115 assert(run.fuzz_tests.items.len > 0);
116 if (run.rebuilt_executable == null)
116117 fatal("one or more unit tests failed to be rebuilt in fuzz mode", .{});
117118 }
118119
......@@ -144,11 +145,10 @@ pub fn start(fuzz: *Fuzz) void {
144145 fatal("unable to spawn coverage task: {t}", .{err});
145146 }
146147
147 if (true) @panic("TODO update the fuzzer");
148
149 for (fuzz.run_steps) |run| {
148 for (fuzz.run_steps) |run_index| {
149 const run = &maker.stepByIndex(run_index).extended.run;
150150 assert(run.rebuilt_executable != null);
151 fuzz.group.async(io, fuzzWorkerRun, .{ fuzz, run });
151 fuzz.group.async(io, fuzzWorkerRun, .{ fuzz, run_index });
152152 }
153153}
154154
......@@ -163,67 +163,111 @@ pub fn deinit(fuzz: *Fuzz) void {
163163 gpa.free(fuzz.run_steps);
164164}
165165
166fn rebuildTestsWorkerRun(run: Configuration.Step.Index, gpa: Allocator, parent_prog_node: std.Progress.Node) void {
167 rebuildTestsWorkerRunFallible(run, gpa, parent_prog_node) catch |err| {
168 const compile = run.producer.?;
169 log.err("step '{s}': failed to rebuild in fuzz mode: {t}", .{ compile.step.name, err });
166fn rebuildTestsWorkerRun(
167 maker: *Maker,
168 run_index: Configuration.Step.Index,
169 parent_prog_node: std.Progress.Node,
170) void {
171 rebuildTestsWorkerRunFallible(maker, run_index, parent_prog_node) catch |err| {
172 const conf = &maker.scanned_config.configuration;
173 const conf_run = run_index.ptr(conf).extended.cast(conf, Configuration.Step.Run).?;
174 const comp_index = conf_run.producer.value.?;
175 const step_name = comp_index.ptr(conf).name.slice(conf);
176 log.err("step {s}: failed to rebuild in fuzz mode: {t}", .{ step_name, err });
170177 };
171178}
172179
173fn rebuildTestsWorkerRunFallible(run: Configuration.Step.Index, gpa: Allocator, parent_prog_node: std.Progress.Node) !void {
174 const graph = run.step.owner.graph;
180fn rebuildTestsWorkerRunFallible(
181 maker: *Maker,
182 run_index: Configuration.Step.Index,
183 parent_prog_node: std.Progress.Node,
184) !void {
185 const graph = maker.graph;
175186 const io = graph.io;
176 const compile = run.producer.?;
177 const prog_node = parent_prog_node.start(compile.step.name, 0);
187 const gpa = maker.gpa;
188 const conf = &maker.scanned_config.configuration;
189 const run = &maker.stepByIndex(run_index).extended.run;
190 const conf_run = run_index.ptr(conf).extended.cast(conf, Configuration.Step.Run).?;
191 const comp_index = conf_run.producer.value.?;
192 const comp_step = maker.stepByIndex(comp_index);
193 const comp = &comp_step.extended.compile;
194 const conf_comp_step = comp_index.ptr(conf);
195 const conf_comp = conf_comp_step.extended.cast(conf, Configuration.Step.Compile).?;
196 const root_module = conf_comp.root_module.get(conf);
197 const target = root_module.resolved_target.get(conf).?.result.get(conf);
198
199 const prog_node = parent_prog_node.start(conf_comp_step.name.slice(conf), 0);
178200 defer prog_node.end();
179201
180 const result = compile.rebuildInFuzzMode(gpa, prog_node);
202 const result = comp.rebuildInFuzzMode(maker, comp_index, prog_node);
181203
182 const show_compile_errors = compile.step.result_error_bundle.errorMessageCount() > 0;
183 const show_error_msgs = compile.step.result_error_msgs.items.len > 0;
184 const show_stderr = compile.step.result_stderr.len > 0;
204 const show_compile_errors = comp_step.result_error_bundle.errorMessageCount() > 0;
205 const show_error_msgs = comp_step.result_error_msgs.items.len > 0;
206 const show_stderr = comp_step.result_stderr.len > 0;
185207
186208 if (show_error_msgs or show_compile_errors or show_stderr) {
187209 var buf: [256]u8 = undefined;
188210 const stderr = try io.lockStderr(&buf, graph.stderr_mode);
189211 defer io.unlockStderr();
190 Maker.printErrorMessages(gpa, &compile.step, .{}, stderr.terminal(), .verbose, .indent) catch {};
212 maker.printErrorMessages(comp_index, .{}, stderr.terminal(), .verbose, .indent) catch {};
191213 }
192214
193215 const rebuilt_bin_path = result catch |err| switch (err) {
194216 error.MakeFailed => return,
195217 else => |other| return other,
196218 };
197 run.rebuilt_executable = try rebuilt_bin_path.join(gpa, compile.out_filename);
219 const compile_filename = try std.zig.binNameAlloc(gpa, .{
220 .root_name = conf_comp.root_name.slice(conf),
221 .cpu_arch = target.flags.cpu_arch.unwrap().?,
222 .os_tag = target.flags.os_tag.unwrap().?,
223 .ofmt = target.flags.object_format.unwrap().?,
224 .abi = target.flags.abi.unwrap().?,
225 .output_mode = switch (conf_comp.flags3.kind) {
226 .lib => .Lib,
227 .obj, .test_obj => .Obj,
228 .exe, .@"test" => .Exe,
229 },
230 .link_mode = conf_comp.flags2.linkage.unwrap(),
231 .version = if (conf_comp.version.value) |v|
232 std.SemanticVersion.parse(v.slice(conf)) catch unreachable
233 else
234 null,
235 });
236 defer gpa.free(compile_filename);
237
238 run.rebuilt_executable = try rebuilt_bin_path.join(gpa, compile_filename);
198239}
199240
200fn fuzzWorkerRun(fuzz: *Fuzz, run: Configuration.Step.Index) void {
201 const owner = run.step.owner;
202 const gpa = owner.allocator;
203 const graph = owner.graph;
241fn fuzzWorkerRun(fuzz: *Fuzz, run_index: Configuration.Step.Index) void {
242 const maker = fuzz.maker;
243 const graph = maker.graph;
204244 const io = graph.io;
245 const conf = &maker.scanned_config.configuration;
246 const run = &maker.stepByIndex(run_index).extended.run;
205247
206 run.rerunInFuzzMode(run, fuzz, fuzz.prog_node) catch |err| switch (err) {
248 run.rerunInFuzzMode(run_index, fuzz, fuzz.prog_node) catch |err| switch (err) {
207249 error.MakeFailed => {
208250 var buf: [256]u8 = undefined;
209251 const stderr = io.lockStderr(&buf, graph.stderr_mode) catch |e| switch (e) {
210252 error.Canceled => return,
211253 };
212254 defer io.unlockStderr();
213 Maker.printErrorMessages(gpa, &run.step, .{}, stderr.terminal(), .verbose, .indent) catch {};
255 maker.printErrorMessages(run_index, .{}, stderr.terminal(), .verbose, .indent) catch {};
214256 return;
215257 },
216258 else => {
217 log.err("step '{s}': failed to rerun in fuzz mode: {t}", .{ run.step.name, err });
259 const step_name = run_index.ptr(conf).name.slice(conf);
260 log.err("step {s}: failed to rerun in fuzz mode: {t}", .{ step_name, err });
218261 return;
219262 },
220263 };
221264}
222265
223266pub fn serveSourcesTar(fuzz: *Fuzz, req: *std.http.Server.Request) !void {
224 if (true) @panic("TODO update the fuzzer");
225267 assert(fuzz.mode == .forever);
226 const gpa = fuzz.maker.gpa;
268 const maker = fuzz.maker;
269 const gpa = maker.gpa;
270 const conf = &maker.scanned_config.configuration;
227271
228272 var arena_state: std.heap.ArenaAllocator = .init(gpa);
229273 defer arena_state.deinit();
......@@ -233,8 +277,11 @@ pub fn serveSourcesTar(fuzz: *Fuzz, req: *std.http.Server.Request) !void {
233277 var dedup_table: DedupTable = .empty;
234278 defer dedup_table.deinit(gpa);
235279
236 for (fuzz.run_steps) |run_step| {
237 const compile_inputs = run_step.producer.?.step.inputs.table;
280 for (fuzz.run_steps) |run_index| {
281 const conf_run = run_index.ptr(conf).extended.cast(conf, Configuration.Step.Run) orelse continue;
282 const comp_index = conf_run.producer.value.?;
283 const comp_step = maker.stepByIndex(comp_index);
284 const compile_inputs = comp_step.inputs.table;
238285 for (compile_inputs.keys(), compile_inputs.values()) |dir_path, *file_list| {
239286 try dedup_table.ensureUnusedCapacity(gpa, file_list.items.len);
240287 for (file_list.items) |sub_path| {
......@@ -372,14 +419,15 @@ fn coverageRunCancelable(fuzz: *Fuzz) Io.Cancelable!void {
372419 fuzz.msg_queue.clearRetainingCapacity();
373420 }
374421}
375fn prepareTables(fuzz: *Fuzz, run_step_index: Configuration.Step.Index, coverage_id: u64) error{ OutOfMemory, AlreadyReported, Canceled }!void {
376 if (true) @panic("TODO update the fuzzer");
422fn prepareTables(fuzz: *Fuzz, run_index: Configuration.Step.Index, coverage_id: u64) error{ OutOfMemory, AlreadyReported, Canceled }!void {
377423 assert(fuzz.mode == .forever);
378424 const ws = fuzz.mode.forever.ws;
379425 const maker = fuzz.maker;
380426 const graph = maker.graph;
381427 const io = graph.io;
382428 const gpa = maker.gpa;
429 const conf = &maker.scanned_config.configuration;
430 const cache_root = graph.local_cache_root;
383431
384432 try fuzz.coverage_mutex.lock(io);
385433 defer fuzz.coverage_mutex.unlock(io);
......@@ -405,37 +453,45 @@ fn prepareTables(fuzz: *Fuzz, run_step_index: Configuration.Step.Index, coverage
405453 };
406454 errdefer gop.value_ptr.coverage.deinit(gpa);
407455
408 const rebuilt_exe_path = run_step_index.rebuilt_executable.?;
409 const target = run_step_index.producer.?.rootModuleTarget();
456 const run_step = maker.stepByIndex(run_index);
457 const conf_run_step = run_index.ptr(conf);
458 const conf_run = conf_run_step.extended.cast(conf, Configuration.Step.Run).?;
459 const comp_index = conf_run.producer.value.?;
460 const conf_comp_step = comp_index.ptr(conf);
461 const conf_comp = conf_comp_step.extended.cast(conf, Configuration.Step.Compile).?;
462 const rebuilt_exe_path = run_step.extended.run.rebuilt_executable.?;
463 const root_module = conf_comp.root_module.get(conf);
464 const target = root_module.resolved_target.get(conf).?.result.get(conf);
465
410466 var debug_info = std.debug.Info.load(
411467 gpa,
412468 io,
413469 rebuilt_exe_path,
414470 &gop.value_ptr.coverage,
415 target.ofmt,
416 target.cpu.arch,
471 target.flags.object_format.unwrap().?,
472 target.flags.cpu_arch.unwrap().?,
417473 ) catch |err| {
418 log.err("step '{s}': failed to load debug information for '{f}': {t}", .{
419 run_step_index.step.name, rebuilt_exe_path, err,
474 log.err("step {s}: failed to load debug information for {f}: {t}", .{
475 conf_run_step.name.slice(conf), rebuilt_exe_path, err,
420476 });
421477 return error.AlreadyReported;
422478 };
423479 defer debug_info.deinit(gpa);
424480
425481 const coverage_file_path: Build.Cache.Path = .{
426 .root_dir = run_step_index.step.owner.cache_root,
482 .root_dir = cache_root,
427483 .sub_path = "v/" ++ std.fmt.hex(coverage_id),
428484 };
429485 var coverage_file = coverage_file_path.root_dir.handle.openFile(io, coverage_file_path.sub_path, .{}) catch |err| {
430 log.err("step '{s}': failed to load coverage file '{f}': {t}", .{
431 run_step_index.step.name, coverage_file_path, err,
486 log.err("step {s}: failed to load coverage file {f}: {t}", .{
487 conf_run_step.name.slice(conf), coverage_file_path, err,
432488 });
433489 return error.AlreadyReported;
434490 };
435491 defer coverage_file.close(io);
436492
437493 const file_size = coverage_file.length(io) catch |err| {
438 log.err("unable to check len of coverage file '{f}': {t}", .{ coverage_file_path, err });
494 log.err("unable to check len of coverage file {f}: {t}", .{ coverage_file_path, err });
439495 return error.AlreadyReported;
440496 };
441497
......@@ -447,7 +503,7 @@ fn prepareTables(fuzz: *Fuzz, run_step_index: Configuration.Step.Index, coverage
447503 coverage_file.handle,
448504 0,
449505 ) catch |err| {
450 log.err("failed to map coverage file '{f}': {t}", .{ coverage_file_path, err });
506 log.err("failed to map coverage file {f}: {t}", .{ coverage_file_path, err });
451507 return error.AlreadyReported;
452508 };
453509 gop.value_ptr.mapped_memory = mapped_memory;
......@@ -538,11 +594,12 @@ fn addEntryPoint(fuzz: *Fuzz, coverage_id: u64, addr: u64) error{ AlreadyReporte
538594}
539595
540596pub fn waitAndPrintReport(fuzz: *Fuzz) Io.Cancelable!void {
541 if (true) @panic("TODO update the fuzzer");
542597 assert(fuzz.mode == .limit);
543598 const maker = fuzz.maker;
544599 const graph = maker.graph;
545600 const io = graph.io;
601 const cache_root = graph.local_cache_root;
602 const conf = &maker.scanned_config.configuration;
546603
547604 try fuzz.group.await(io);
548605 fuzz.group = .init;
......@@ -552,13 +609,15 @@ pub fn waitAndPrintReport(fuzz: *Fuzz) Io.Cancelable!void {
552609 if (msg != .coverage) continue;
553610
554611 const cov = msg.coverage;
612 const run_step_name = cov.run.ptr(conf).name.slice(conf);
613 const run = &maker.stepByIndex(cov.run).extended.run;
555614 const coverage_file_path: std.Build.Cache.Path = .{
556 .root_dir = cov.run.step.owner.cache_root,
615 .root_dir = cache_root,
557616 .sub_path = "v/" ++ std.fmt.hex(cov.id),
558617 };
559618 var coverage_file = coverage_file_path.root_dir.handle.openFile(io, coverage_file_path.sub_path, .{}) catch |err| {
560 fatal("step '{s}': failed to load coverage file '{f}': {t}", .{
561 cov.run.step.name, coverage_file_path, err,
619 fatal("step {s}: failed to load coverage file {f}: {t}", .{
620 run_step_name, coverage_file_path, err,
562621 });
563622 };
564623 defer coverage_file.close(io);
......@@ -569,14 +628,14 @@ pub fn waitAndPrintReport(fuzz: *Fuzz) Io.Cancelable!void {
569628
570629 var header: fuzz_abi.SeenPcsHeader = undefined;
571630 r.interface.readSliceAll(std.mem.asBytes(&header)) catch |err| {
572 fatal("step '{s}': failed to read from coverage file '{f}': {t}", .{
573 cov.run.step.name, coverage_file_path, err,
631 fatal("step {s}: failed to read from coverage file {f}: {t}", .{
632 run_step_name, coverage_file_path, err,
574633 });
575634 };
576635
577636 if (header.pcs_len == 0) {
578 fatal("step '{s}': corrupted coverage file '{f}': pcs_len was zero", .{
579 cov.run.step.name, coverage_file_path,
637 fatal("step {s}: corrupted coverage file {f}: pcs_len was zero", .{
638 run_step_name, coverage_file_path,
580639 });
581640 }
582641
......@@ -584,8 +643,8 @@ pub fn waitAndPrintReport(fuzz: *Fuzz) Io.Cancelable!void {
584643 const chunk_count = fuzz_abi.SeenPcsHeader.seenElemsLen(header.pcs_len);
585644 for (0..chunk_count) |_| {
586645 const seen = r.interface.takeInt(usize, .little) catch |err| {
587 fatal("step '{s}': failed to read from coverage file '{f}': {t}", .{
588 cov.run.step.name, coverage_file_path, err,
646 fatal("step {s}: failed to read from coverage file {f}: {t}", .{
647 run_step_name, coverage_file_path, err,
589648 });
590649 };
591650 seen_count += @popCount(seen);
......@@ -602,8 +661,8 @@ pub fn waitAndPrintReport(fuzz: *Fuzz) Io.Cancelable!void {
602661 \\Coverage: {}/{} -> {}/{} ({:.02}%)
603662 \\
604663 , .{
605 cov.run.step.name,
606 cov.run.fuzz_tests.items[0],
664 run_step_name,
665 run.fuzz_tests.items[0],
607666 cov.id,
608667 cov.cumulative.runs,
609668 header.n_runs,
lib/compiler/Maker/Graph.zig+1
......@@ -31,6 +31,7 @@ reference_trace: ?u32 = null,
3131debug_log_scopes: std.ArrayList([]const u8) = .empty,
3232debug_compile_errors: bool = false,
3333debug_incremental: bool = false,
34fuzzing: bool = false,
3435verbose: bool = false,
3536verbose_air: bool = false,
3637verbose_cc: bool = false,
lib/compiler/Maker/Step/Compile.zig+6-9
......@@ -947,11 +947,11 @@ fn lowerZigArgs(
947947pub fn rebuildInFuzzMode(
948948 compile: *Compile,
949949 maker: *Maker,
950 step_index: Configuration.Step.Index,
950 compile_index: Configuration.Step.Index,
951951 progress_node: std.Progress.Node,
952952) !Path {
953 const gpa = maker.graph.gpa;
954 const step = maker.stepByIndex(step_index);
953 const gpa = maker.gpa;
954 const step = maker.stepByIndex(compile_index);
955955
956956 step.result_error_msgs.clearRetainingCapacity();
957957 step.result_stderr = "";
......@@ -966,8 +966,8 @@ pub fn rebuildInFuzzMode(
966966
967967 const zig_args = &compile.zig_args;
968968 zig_args.clearRetainingCapacity();
969 try lowerZigArgs(compile, maker, progress_node, zig_args, true);
970 const maybe_output_bin_path = try step.evalZigProcess(zig_args.items, progress_node, false, maker);
969 try lowerZigArgs(compile, compile_index, maker, progress_node, zig_args, true);
970 const maybe_output_bin_path = try Step.evalZigProcess(compile_index, maker, zig_args.items, progress_node, false);
971971 return maybe_output_bin_path.?;
972972}
973973
......@@ -980,10 +980,7 @@ fn addFlag(gpa: Allocator, args: *std.ArrayList([]const u8), comptime name: []co
980980 try args.append(gpa, if (cond) "-f" ++ name else "-fno-" ++ name);
981981}
982982
983fn checkCompileErrors(
984 maker: *Maker,
985 step_index: Configuration.Step.Index,
986) Step.ExtendedMakeError!void {
983fn checkCompileErrors(maker: *Maker, step_index: Configuration.Step.Index) Step.ExtendedMakeError!void {
987984 const step = maker.stepByIndex(step_index);
988985 const graph = maker.graph;
989986 const arena = graph.arena; // TODO don't leak into the process arena
lib/compiler/Maker/Step/Run.zig+14-2
......@@ -67,6 +67,7 @@ pub fn make(
6767 }
6868 }
6969
70 man.hash.add(graph.fuzzing);
7071 man.hash.add(conf_run.flags.color);
7172 man.hash.add(conf_run.flags.disable_zig_progress);
7273
......@@ -234,7 +235,8 @@ pub fn make(
234235 }
235236
236237 // Whether the Run step has side effects *other than* updating the output arguments.
237 const has_side_effects = conf_run.flags.has_side_effects or any_cli_positionals or
238 // When fuzzing we need to always run the test runner to populate fuzz_tests.
239 const has_side_effects = graph.fuzzing or conf_run.flags.has_side_effects or any_cli_positionals or
238240 switch (conf_run.flags.stdio) {
239241 .infer_from_args => !any_output_args and
240242 conf_run.captured_stdout.value == null and
......@@ -1511,7 +1513,7 @@ const IndexedOutput = struct {
15111513pub fn rerunInFuzzMode(
15121514 run: *Run,
15131515 run_index: Configuration.Step.Index,
1514 fuzz: *std.Build.Fuzz,
1516 fuzz: *Fuzz,
15151517 prog_node: std.Progress.Node,
15161518) !void {
15171519 const maker = fuzz.maker;
......@@ -1524,6 +1526,7 @@ pub fn rerunInFuzzMode(
15241526 const conf_step = run_index.ptr(conf);
15251527 const conf_run = conf_step.extended.get(conf.extra).run;
15261528 const argv_list = &run.argv;
1529 const cache_root = graph.local_cache_root;
15271530
15281531 argv_list.clearRetainingCapacity();
15291532
......@@ -1599,6 +1602,15 @@ pub fn rerunInFuzzMode(
15991602 }
16001603 }
16011604
1605 if (conf_run.flags.test_runner_mode) {
1606 const cache_dir_string = try convertPathArg(run_index, maker, .{ .root_dir = cache_root });
1607
1608 try argv_list.ensureUnusedCapacity(gpa, 3);
1609 argv_list.appendAssumeCapacity(try allocPrint(arena, "--cache-dir={s}", .{cache_dir_string}));
1610 argv_list.appendAssumeCapacity(try allocPrint(arena, "--seed=0x{x}", .{graph.random_seed}));
1611 argv_list.appendAssumeCapacity("--listen=-");
1612 }
1613
16021614 if (step.result_failed_command) |cmd| {
16031615 gpa.free(cmd);
16041616 step.result_failed_command = null;