authorgravatar for erik.arvstedt@gmail.comErik Arvstedt <erik.arvstedt@gmail.com> 2023-06-12 22:21:30+02:00
committergravatar for erik.arvstedt@gmail.comErik Arvstedt <erik.arvstedt@gmail.com> 2023-06-13 09:48:51+02:00
log5d3c8f4913884a4503e9f183e471b6090bb5bc92
tree5234a6c84904d8cc70e26e5690c6448f4c3665b1
parent41430a366f75eb7301deaca91d4aea3bbf61c8ec

arena_allocator/reset: fix use after free

Previously, when the last buffer in `buffer_list` was retained after deleting all other buffers, `buffer_list` wasn't updated and pointed to a deleted buffer.

1 files changed, 17 insertions(+), 0 deletions(-)

lib/std/heap/arena_allocator.zig+17
...@@ -139,6 +139,7 @@ pub const ArenaAllocator = struct {...@@ -139,6 +139,7 @@ pub const ArenaAllocator = struct {
139 // reset the state before we try resizing the buffers, so we definitely have reset the arena to 0.139 // reset the state before we try resizing the buffers, so we definitely have reset the arena to 0.
140 self.state.end_index = 0;140 self.state.end_index = 0;
141 if (maybe_first_node) |first_node| {141 if (maybe_first_node) |first_node| {
142 self.state.buffer_list.first = first_node;
142 // perfect, no need to invoke the child_allocator143 // perfect, no need to invoke the child_allocator
143 if (first_node.data == total_size)144 if (first_node.data == total_size)
144 return true;145 return true;
...@@ -270,3 +271,19 @@ test "ArenaAllocator (reset with preheating)" {...@@ -270,3 +271,19 @@ test "ArenaAllocator (reset with preheating)" {
270 }271 }
271 }272 }
272}273}
274
275test "ArenaAllocator (reset while retaining a buffer)" {
276 var arena_allocator = ArenaAllocator.init(std.testing.allocator);
277 defer arena_allocator.deinit();
278 const a = arena_allocator.allocator();
279
280 // Create two internal buffers
281 _ = try a.alloc(u8, 1);
282 _ = try a.alloc(u8, 1000);
283
284 // Check that we have at least two buffers
285 try std.testing.expect(arena_allocator.state.buffer_list.first.?.next != null);
286
287 // This retains the first allocated buffer
288 try std.testing.expect(arena_allocator.reset(.{ .retain_with_limit = 1 }));
289}