terminal: saturate origin cursor offsets

setCursorPos added origin-mode margins to requested row and column
values before clamping them to the scrolling region. A request near
maxInt(usize) overflowed during that addition and crashed instead of
landing on the region boundary.

Use saturating addition for the origin offsets. The existing clamp then
places oversized requests on the bottom-right margin without changing
normal cursor positioning.
This commit is contained in:
Mitchell Hashimoto
2026-07-09 19:55:13 -07:00
parent 0ff4e41b22
commit 0aaedf4360

View File

@@ -2120,8 +2120,8 @@ pub fn setCursorPos(self: *Terminal, row_req: usize, col_req: usize) void {
// Calculate our new x/y
const row = if (row_req == 0) 1 else row_req;
const col = if (col_req == 0) 1 else col_req;
const x = @min(params.x_max, col + params.x_offset) -| 1;
const y = @min(params.y_max, row + params.y_offset) -| 1;
const x = @min(params.x_max, col +| params.x_offset) -| 1;
const y = @min(params.y_max, row +| params.y_offset) -| 1;
// If the y is unchanged then this is fast pointer math
if (y == self.screens.active.cursor.y) {
@@ -3816,6 +3816,24 @@ fn clearDirty(t: *Terminal) void {
t.screens.active.pages.clearDirty();
}
test "Terminal: setCursorPos saturates overflowing origin offsets" {
const alloc = testing.allocator;
var t = try init(alloc, .{ .cols = 10, .rows = 10 });
defer t.deinit(alloc);
t.scrolling_region = .{
.top = 2,
.bottom = 7,
.left = 3,
.right = 8,
};
t.modes.set(.origin, true);
t.setCursorPos(std.math.maxInt(usize), std.math.maxInt(usize));
try testing.expectEqual(@as(size.CellCountInt, 8), t.screens.active.cursor.x);
try testing.expectEqual(@as(size.CellCountInt, 7), t.screens.active.cursor.y);
}
test "Terminal: input with no control characters" {
const alloc = testing.allocator;
var t = try init(alloc, .{ .cols = 40, .rows = 40 });