terminal: PageList.reset needs to reset page serial mins

pull/12794/head
Mitchell Hashimoto 2026-05-23 15:26:24 -07:00
parent ae839393d9
commit 7b49d1f129
No known key found for this signature in database
GPG Key ID: 523D5DC389D273BC
1 changed files with 29 additions and 0 deletions

View File

@ -658,6 +658,11 @@ pub fn deinit(self: *PageList) void {
pub fn reset(self: *PageList) void { pub fn reset(self: *PageList) void {
defer self.assertIntegrity(); defer self.assertIntegrity();
// Invalidate all external page refs to the previous list. The reset below
// rebuilds the page list from the pools, so old untracked refs must be
// rejected before any validation attempts to inspect their node pointers.
self.page_serial_min = self.page_serial;
// We need enough pages/nodes to keep our active area. This should // We need enough pages/nodes to keep our active area. This should
// never fail since we by definition have allocated a page already // never fail since we by definition have allocated a page already
// that fits our size but I'm not confident to make that assertion. // that fits our size but I'm not confident to make that assertion.
@ -13543,6 +13548,30 @@ test "PageList reset" {
}, s.getTopLeft(.active)); }, s.getTopLeft(.active));
} }
test "PageList reset invalidates stale untracked refs even if node memory is reused" {
const testing = std.testing;
const alloc = testing.allocator;
var s = try init(alloc, 80, 24, null);
defer s.deinit();
const old_serial = s.pages.first.?.serial;
try testing.expect(old_serial >= s.page_serial_min);
try testing.expect(old_serial < s.page_serial);
s.reset();
// The important safety property is that stale serials are rejected before
// the node pointer is inspected. Reset rebuilds the page list from the
// pools, so old untracked refs may contain node pointers that are no
// longer safe to dereference.
try testing.expect(old_serial < s.page_serial_min);
const new_serial = s.pages.first.?.serial;
try testing.expect(new_serial >= s.page_serial_min);
try testing.expect(new_serial < s.page_serial);
}
test "PageList reset across two pages" { test "PageList reset across two pages" {
const testing = std.testing; const testing = std.testing;
const alloc = testing.allocator; const alloc = testing.allocator;