From ed1d77d518f58ca97895ff789c69b54d3a3bf1b4 Mon Sep 17 00:00:00 2001 From: Leah Amelia Chen Date: Sun, 7 Dec 2025 13:35:52 +0800 Subject: [PATCH 1/2] os: fix off-by-one error in ShellEscapeWriter I am truly not sure why the tests never caught this, but I just fell for the oldest trick in the book --- src/os/shell.zig | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/os/shell.zig b/src/os/shell.zig index a6f23e843..7f3254d87 100644 --- a/src/os/shell.zig +++ b/src/os/shell.zig @@ -5,8 +5,6 @@ const Writer = std.Io.Writer; /// Writer that escapes characters that shells treat specially to reduce the /// risk of injection attacks or other such weirdness. Specifically excludes /// linefeeds so that they can be used to delineate lists of file paths. -/// -/// T should be a Zig type that follows the `std.Io.Writer` interface. pub const ShellEscapeWriter = struct { writer: Writer, child: *Writer, @@ -33,7 +31,7 @@ pub const ShellEscapeWriter = struct { var count: usize = 0; for (data[0 .. data.len - 1]) |chunk| try self.writeEscaped(chunk, &count); - for (0..splat) |_| try self.writeEscaped(data[data.len], &count); + for (0..splat) |_| try self.writeEscaped(data[data.len - 1], &count); return count; } From 6da2f0e3e76336ab0c761fccae267efc20301ac7 Mon Sep 17 00:00:00 2001 From: Leah Amelia Chen Date: Mon, 8 Dec 2025 12:50:04 +0800 Subject: [PATCH 2/2] os/shell: actually run tests --- src/os/main.zig | 1 + src/os/shell.zig | 14 +++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/os/main.zig b/src/os/main.zig index 2d269e412..c105f6143 100644 --- a/src/os/main.zig +++ b/src/os/main.zig @@ -69,6 +69,7 @@ test { _ = i18n; _ = path; _ = uri; + _ = shell; if (comptime builtin.os.tag == .linux) { _ = kernel_info; diff --git a/src/os/shell.zig b/src/os/shell.zig index 7f3254d87..9fce3e385 100644 --- a/src/os/shell.zig +++ b/src/os/shell.zig @@ -65,7 +65,7 @@ pub const ShellEscapeWriter = struct { test "shell escape 1" { var buf: [128]u8 = undefined; var writer: std.Io.Writer = .fixed(&buf); - var shell: ShellEscapeWriter = .{ .child_writer = &writer }; + var shell: ShellEscapeWriter = .init(&writer); try shell.writer.writeAll("abc"); try testing.expectEqualStrings("abc", writer.buffered()); } @@ -73,7 +73,7 @@ test "shell escape 1" { test "shell escape 2" { var buf: [128]u8 = undefined; var writer: std.Io.Writer = .fixed(&buf); - var shell: ShellEscapeWriter = .{ .child_writer = &writer }; + var shell: ShellEscapeWriter = .init(&writer); try shell.writer.writeAll("a c"); try testing.expectEqualStrings("a\\ c", writer.buffered()); } @@ -81,7 +81,7 @@ test "shell escape 2" { test "shell escape 3" { var buf: [128]u8 = undefined; var writer: std.Io.Writer = .fixed(&buf); - var shell: ShellEscapeWriter = .{ .child_writer = &writer }; + var shell: ShellEscapeWriter = .init(&writer); try shell.writer.writeAll("a?c"); try testing.expectEqualStrings("a\\?c", writer.buffered()); } @@ -89,7 +89,7 @@ test "shell escape 3" { test "shell escape 4" { var buf: [128]u8 = undefined; var writer: std.Io.Writer = .fixed(&buf); - var shell: ShellEscapeWriter = .{ .child_writer = &writer }; + var shell: ShellEscapeWriter = .init(&writer); try shell.writer.writeAll("a\\c"); try testing.expectEqualStrings("a\\\\c", writer.buffered()); } @@ -97,7 +97,7 @@ test "shell escape 4" { test "shell escape 5" { var buf: [128]u8 = undefined; var writer: std.Io.Writer = .fixed(&buf); - var shell: ShellEscapeWriter = .{ .child_writer = &writer }; + var shell: ShellEscapeWriter = .init(&writer); try shell.writer.writeAll("a|c"); try testing.expectEqualStrings("a\\|c", writer.buffered()); } @@ -105,7 +105,7 @@ test "shell escape 5" { test "shell escape 6" { var buf: [128]u8 = undefined; var writer: std.Io.Writer = .fixed(&buf); - var shell: ShellEscapeWriter = .{ .child_writer = &writer }; + var shell: ShellEscapeWriter = .init(&writer); try shell.writer.writeAll("a\"c"); try testing.expectEqualStrings("a\\\"c", writer.buffered()); } @@ -113,7 +113,7 @@ test "shell escape 6" { test "shell escape 7" { var buf: [128]u8 = undefined; var writer: std.Io.Writer = .fixed(&buf); - var shell: ShellEscapeWriter = .{ .child_writer = &writer }; + var shell: ShellEscapeWriter = .init(&writer); try shell.writer.writeAll("a(1)"); try testing.expectEqualStrings("a\\(1\\)", writer.buffered()); }