mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-08-29 02:21:43 +00:00
terminal: document the pool reuse zeroing invariant
PageList skips zeroing pooled page buffers in release builds, relying on the OS page allocator handing out zeroed pages and destroyNodeExt zeroing buffers before returning them to the pool. There is a hidden exception: std.heap.MemoryPool writes its free list node into the first pointer-size bytes of a free-listed buffer, so a reused buffer is not fully zero. This is only safe because the page rows array is laid out at offset 0, a page always has at least one row, and initBuf fully rewrites every row, overwriting the stale free list pointer. None of that was written down or checked anywhere, so a future layout reorder (or a zero-row page) would corrupt pages in release builds only, in a way that depends on pool reuse patterns. This adds a comptime assert that a Row covers at least a pointer, a runtime assert that pages always have at least one row, and comments tying the invariant together at the layout, initBuf, and pool reuse sites. Also fixes stale doc comments: deinit referenced a clonePool function that no longer exists, and Screen tests referenced increaseCapacity by its old adjustCapacity name.
This commit is contained in:
@@ -10181,9 +10181,9 @@ test "Screen: cursorDown to page with insufficient capacity" {
|
||||
// cursor movement functions). The bug pattern:
|
||||
//
|
||||
// 1. cursorDown creates a by-value copy of the pin via page_pin.down(n)
|
||||
// 2. cursorChangePin is called, which may trigger adjustCapacity
|
||||
// 2. cursorChangePin is called, which may trigger increaseCapacity
|
||||
// if the target page's style map is full
|
||||
// 3. adjustCapacity frees the old page and creates a new one
|
||||
// 3. increaseCapacity frees the old page and creates a new one
|
||||
// 4. The local pin copy still points to the freed page
|
||||
// 5. rowAndCell() on the stale pin accesses freed memory
|
||||
|
||||
@@ -10206,7 +10206,7 @@ test "Screen: cursorDown to page with insufficient capacity" {
|
||||
try testing.expect(start_page != new_page);
|
||||
|
||||
// Fill new_page's style map to capacity. When we move INTO this page
|
||||
// with a style set, adjustCapacity will be triggered.
|
||||
// with a style set, increaseCapacity will be triggered.
|
||||
{
|
||||
new_page.pauseIntegrityChecks(true);
|
||||
defer new_page.pauseIntegrityChecks(false);
|
||||
@@ -10235,7 +10235,7 @@ test "Screen: cursorDown to page with insufficient capacity" {
|
||||
try testing.expect(&next_pin.node.data == new_page);
|
||||
|
||||
// This cursorDown triggers the bug: the local page_pin copy
|
||||
// becomes stale after adjustCapacity, causing rowAndCell()
|
||||
// becomes stale after increaseCapacity, causing rowAndCell()
|
||||
// to access freed memory.
|
||||
s.cursorDown(1);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user