authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-09-25 19:56:44-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-09-26 19:08:50-04:00
loge0beb0222312a5c4737ccfe76e75e414f594bd9a
tree721d74b231e567ce866e3c1ddea45795dc6fbacf
parent2cdf284af96ea016a5553ae9f6516b9b2c8f3f8e

Runner: fix crashes caused by noop mutations of read-only data

`std.Io.Reader.ending` is pretty much unusable, so just make my own on the stack.

1 files changed, 29 insertions(+), 6 deletions(-)

test/src/Runner.zig+29-6
...@@ -598,10 +598,10 @@ fn testOne(runner: *Runner, test_index: u32) TestError!void {...@@ -598,10 +598,10 @@ fn testOne(runner: *Runner, test_index: u32) TestError!void {
598 defer if (contents_file) |file| file.close(runner.io);598 defer if (contents_file) |file| file.close(runner.io);
599 var contents_buffer: [512]u8 = undefined;599 var contents_buffer: [512]u8 = undefined;
600 var contents_impl: union(enum) {600 var contents_impl: union(enum) {
601 ending,601 ending: std.Io.Reader,
602 dr: DelimitedReader,602 dr: DelimitedReader,
603 fr: std.Io.File.Reader,603 fr: std.Io.File.Reader,
604 } = .ending;604 } = undefined;
605 const contents_r: *std.Io.Reader = contents_r: switch (cmd) {605 const contents_r: *std.Io.Reader = contents_r: switch (cmd) {
606 .skip, .delete => {606 .skip, .delete => {
607 const unexpected = line_it.rest();607 const unexpected = line_it.rest();
...@@ -610,11 +610,15 @@ fn testOne(runner: *Runner, test_index: u32) TestError!void {...@@ -610,11 +610,15 @@ fn testOne(runner: *Runner, test_index: u32) TestError!void {
610 "unexpected argument {q}",610 "unexpected argument {q}",
611 .{unexpected},611 .{unexpected},
612 );612 );
613 break :contents_r .ending;613 contents_impl = .{ .ending = .ending_instance };
614 break :contents_r &contents_impl.ending;
614 },615 },
615 else => {616 else => {
616 const contents_path = line_it.rest();617 const contents_path = line_it.rest();
617 if (contents_path.len == 0) break :contents_r .ending;618 if (contents_path.len == 0) {
619 contents_impl = .{ .ending = .ending_instance };
620 break :contents_r &contents_impl.ending;
621 }
618622
619 if (std.mem.eql(u8, contents_path, "{")) {623 if (std.mem.eql(u8, contents_path, "{")) {
620 contents_impl = .{624 contents_impl = .{
...@@ -743,8 +747,27 @@ fn handleCommand(...@@ -743,8 +747,27 @@ fn handleCommand(
743 else => |e| return update.manifest_sr.fail(arg.?, "unable to create file: {t}", .{e}),747 else => |e| return update.manifest_sr.fail(arg.?, "unable to create file: {t}", .{e}),
744 };748 };
745 defer file.close(runner.io);749 defer file.close(runner.io);
746 var fw = file.writer(runner.io, &.{});750 var fw_buffer: [512]u8 = undefined;
747 _ = try contents_r.streamRemaining(&fw.interface);751 var fw = file.writer(runner.io, &fw_buffer);
752 _ = contents_r.streamRemaining(&fw.interface) catch |err| switch (err) {
753 error.ReadFailed => |e| return e,
754 error.WriteFailed => switch (fw.err.?) {
755 error.Canceled => |e| return e,
756 else => |e| return update.manifest_sr.fail(
757 arg.?,
758 "unable to write file: {t}",
759 .{e},
760 ),
761 },
762 };
763 fw.flush() catch |err| switch (err) {
764 error.Canceled => |e| return e,
765 else => |e| return update.manifest_sr.fail(
766 arg.?,
767 "unable to write file: {t}",
768 .{e},
769 ),
770 };
748 file.setTimestamps(runner.io, .{ .modify_timestamp = .{771 file.setTimestamps(runner.io, .{ .modify_timestamp = .{
749 .new = update.mtime,772 .new = update.mtime,
750 } }) catch |err| switch (err) {773 } }) catch |err| switch (err) {