mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-02-04 14:33:47 +00:00
Add double-free detection to ArenaPool (in Debug Mode)
Double-freeing should eventually cause a segfault (on ArenaPool.deinit, if not sooner), but having an explicit check allows us to log the responsible owner.
This commit is contained in:
@@ -174,7 +174,10 @@ call_arena: Allocator,
|
|||||||
arena_pool: *ArenaPool,
|
arena_pool: *ArenaPool,
|
||||||
// In Debug, we use this to see if anything fails to release an arena back to
|
// In Debug, we use this to see if anything fails to release an arena back to
|
||||||
// the pool.
|
// the pool.
|
||||||
_arena_pool_leak_track: (if (IS_DEBUG) std.AutoHashMapUnmanaged(usize, []const u8) else void),
|
_arena_pool_leak_track: (if (IS_DEBUG) std.AutoHashMapUnmanaged(usize, struct {
|
||||||
|
owner: []const u8,
|
||||||
|
count: usize,
|
||||||
|
}) else void),
|
||||||
|
|
||||||
window: *Window,
|
window: *Window,
|
||||||
document: *Document,
|
document: *Document,
|
||||||
@@ -236,7 +239,9 @@ pub fn deinit(self: *Page) void {
|
|||||||
if (comptime IS_DEBUG) {
|
if (comptime IS_DEBUG) {
|
||||||
var it = self._arena_pool_leak_track.valueIterator();
|
var it = self._arena_pool_leak_track.valueIterator();
|
||||||
while (it.next()) |value_ptr| {
|
while (it.next()) |value_ptr| {
|
||||||
log.err(.bug, "ArenaPool Leak", .{ .owner = value_ptr.* });
|
if (value_ptr.count > 0) {
|
||||||
|
log.err(.bug, "ArenaPool Leak", .{ .owner = value_ptr.owner });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,7 +252,9 @@ fn reset(self: *Page, comptime initializing: bool) !void {
|
|||||||
if (comptime IS_DEBUG) {
|
if (comptime IS_DEBUG) {
|
||||||
var it = self._arena_pool_leak_track.valueIterator();
|
var it = self._arena_pool_leak_track.valueIterator();
|
||||||
while (it.next()) |value_ptr| {
|
while (it.next()) |value_ptr| {
|
||||||
log.err(.bug, "ArenaPool Leak", .{ .owner = value_ptr.* });
|
if (value_ptr.count > 0) {
|
||||||
|
log.err(.bug, "ArenaPool Leak", .{ .owner = value_ptr.owner });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self._arena_pool_leak_track.clearRetainingCapacity();
|
self._arena_pool_leak_track.clearRetainingCapacity();
|
||||||
}
|
}
|
||||||
@@ -370,14 +377,23 @@ const GetArenaOpts = struct {
|
|||||||
pub fn getArena(self: *Page, comptime opts: GetArenaOpts) !Allocator {
|
pub fn getArena(self: *Page, comptime opts: GetArenaOpts) !Allocator {
|
||||||
const allocator = try self.arena_pool.acquire();
|
const allocator = try self.arena_pool.acquire();
|
||||||
if (comptime IS_DEBUG) {
|
if (comptime IS_DEBUG) {
|
||||||
try self._arena_pool_leak_track.put(self.arena, @intFromPtr(allocator.ptr), opts.debug);
|
const gop = try self._arena_pool_leak_track.getOrPut(self.arena, @intFromPtr(allocator.ptr));
|
||||||
|
if (gop.found_existing) {
|
||||||
|
std.debug.assert(gop.value_ptr.count == 0);
|
||||||
|
}
|
||||||
|
gop.value_ptr.* = .{ .owner = opts.debug, .count = 1 };
|
||||||
}
|
}
|
||||||
return allocator;
|
return allocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn releaseArena(self: *Page, allocator: Allocator) void {
|
pub fn releaseArena(self: *Page, allocator: Allocator) void {
|
||||||
if (comptime IS_DEBUG) {
|
if (comptime IS_DEBUG) {
|
||||||
_ = self._arena_pool_leak_track.remove(@intFromPtr(allocator.ptr));
|
const found = self._arena_pool_leak_track.getPtr(@intFromPtr(allocator.ptr)).?;
|
||||||
|
if (found.count != 1) {
|
||||||
|
log.err(.bug, "ArenaPool Double Free", .{ .owner = found.owner, .count = found.count });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
found.count = 0;
|
||||||
}
|
}
|
||||||
return self.arena_pool.release(allocator);
|
return self.arena_pool.release(allocator);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user