Skip to content

Commit 24cc57e

Browse files
aarcampsimonklee
andauthored
fix: address link tracker clear decref imbalance (#803)
LinkTracker tracked one pool ref per link ID, but clear() decremented once per cell reference count. For links repeated across many cells this could cause one valid decref followed by many failing decref calls during buffer clear. --------- Co-authored-by: Simon Klee <hello@simonklee.dk>
1 parent 956f15c commit 24cc57e

File tree

2 files changed

+28
-5
lines changed

2 files changed

+28
-5
lines changed

packages/core/src/zig/link.zig

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -264,11 +264,7 @@ pub const LinkTracker = struct {
264264
var it = self.used_ids.iterator();
265265
while (it.next()) |entry| {
266266
const id = entry.key_ptr.*;
267-
const count = entry.value_ptr.*;
268-
var i: u32 = 0;
269-
while (i < count) : (i += 1) {
270-
self.pool.decref(id) catch {};
271-
}
267+
self.pool.decref(id) catch {};
272268
}
273269
}
274270

packages/core/src/zig/tests/link_test.zig

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,33 @@ test "LinkTracker - clear releases tracked IDs" {
121121
try std.testing.expectEqual(@as(u32, 0), try pool.getRefcount(id2));
122122
}
123123

124+
test "LinkTracker - clear only decrefs once per ID with multiple cell refs" {
125+
var pool = LinkPool.init(std.testing.allocator);
126+
defer pool.deinit();
127+
128+
const id = try pool.alloc("https://example.com/shared");
129+
130+
var tracker_a = LinkTracker.init(std.testing.allocator, &pool);
131+
defer tracker_a.deinit();
132+
133+
var tracker_b = LinkTracker.init(std.testing.allocator, &pool);
134+
defer tracker_b.deinit();
135+
136+
tracker_a.addCellRef(id);
137+
tracker_a.addCellRef(id);
138+
tracker_a.addCellRef(id);
139+
140+
tracker_b.addCellRef(id);
141+
142+
try std.testing.expectEqual(@as(u32, 2), try pool.getRefcount(id));
143+
144+
// Clear tracker A should decref once (2 -> 1).
145+
tracker_a.clear();
146+
147+
try std.testing.expectEqual(@as(u32, 1), try pool.getRefcount(id));
148+
try std.testing.expectEqualSlices(u8, "https://example.com/shared", try pool.get(id));
149+
}
150+
124151
test "LinkPool - leak repro: alloc-only IDs accumulate live slots" {
125152
var pool = LinkPool.init(std.testing.allocator);
126153
defer pool.deinit();

0 commit comments

Comments
 (0)