terminal: preserve tabstops on resize failure

Terminal.resize deinitialized the current tab stops before allocating their replacement. If a resize beyond the inline tab-stop capacity ran out of memory, the terminal retained an undefined tab-stop value and normal deinitialization dereferenced a poisoned pointer.

Allocate and initialize the replacement first, then release the old tab stops only after allocation succeeds. A failed resize now retains the original tab stops and remains safe to destroy.
This commit is contained in:
Mitchell Hashimoto
2026-07-09 21:45:15 -07:00
parent fdd255c782
commit 91f0cf67d5

View File

@@ -3518,8 +3518,13 @@ pub fn resize(
// Resize our tabstops
if (self.cols != cols) {
const tabstops: Tabstops = try .init(
alloc,
cols,
TABSTOP_INTERVAL,
);
self.tabstops.deinit(alloc);
self.tabstops = try .init(alloc, cols, 8);
self.tabstops = tabstops;
}
// Resize primary screen, which supports reflow
@@ -3554,6 +3559,19 @@ pub fn resize(
};
}
test "Terminal: resize preserves tabstops on allocation failure" {
var failing = testing.FailingAllocator.init(testing.allocator, .{});
const alloc = failing.allocator();
var t = try init(alloc, .{ .cols = 10, .rows = 1 });
defer t.deinit(alloc);
failing.fail_index = failing.alloc_index;
try testing.expectError(error.OutOfMemory, t.resize(alloc, 513, 1));
try testing.expectEqual(@as(size.CellCountInt, 10), t.cols);
try testing.expect(t.tabstops.get(8));
}
/// Set the pwd for the terminal.
pub fn setPwd(self: *Terminal, pwd: []const u8) !void {
if (pwd.len == 0) {