From a14a619ceb5d5518155b1e1657f69a3928e9ea9b Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 9 Jul 2026 21:52:24 -0700 Subject: [PATCH] terminal: handle aliased pwd updates setPwd can receive the slice returned by getPwd. Clearing the list retained its allocation, so appending that same slice used memcpy with aliased source and destination ranges and panicked in runtime-safe builds. Resize the list within its reserved capacity and copy the value forward before writing the sentinel. This supports the complete current value and its subslices without weakening allocation-failure atomicity. --- src/terminal/Terminal.zig | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/terminal/Terminal.zig b/src/terminal/Terminal.zig index 0880ee975..64b8d9452 100644 --- a/src/terminal/Terminal.zig +++ b/src/terminal/Terminal.zig @@ -3583,9 +3583,9 @@ pub fn setPwd(self: *Terminal, pwd: []const u8) !void { return error.OutOfMemory; try self.pwd.ensureTotalCapacity(self.gpa(), capacity); - self.pwd.clearRetainingCapacity(); - self.pwd.appendSliceAssumeCapacity(pwd); - self.pwd.appendAssumeCapacity(0); + self.pwd.items.len = capacity; + std.mem.copyForwards(u8, self.pwd.items[0..pwd.len], pwd); + self.pwd.items[pwd.len] = 0; } /// Returns the pwd for the terminal, if any. The memory is owned by the @@ -3607,6 +3607,15 @@ test "Terminal: setPwd preserves a sentinel on allocation failure" { try testing.expect(t.getPwd() == null); } +test "Terminal: setPwd accepts its current value" { + var t = try init(testing.allocator, .{ .cols = 5, .rows = 1 }); + defer t.deinit(testing.allocator); + + try t.setPwd("file:///tmp"); + try t.setPwd(t.getPwd().?); + try testing.expectEqualStrings("file:///tmp", t.getPwd().?); +} + /// Set the title for the terminal, as set by escape sequences (e.g. OSC 0/2). pub fn setTitle(self: *Terminal, t: []const u8) !void { if (t.len == 0) {