authorgravatar for 19855629+SuperAuguste@users.noreply.github.comAuguste Rame <19855629+SuperAuguste@users.noreply.github.com> 2025-04-02 08:15:04-04:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-04-02 14:22:15+02:00
log0b4176891c33c990e9d40523a8eaceea6d172c8e
treefea1e4583b67291379bd3fdd74244045d8bc502c
parentceb84c647b5cf6ad6a17b829a78e1c079a6ab5a5
signaturebadge-check Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM

DebugAllocator: Fix bucket removal logic causing segfault/leak (#23390)

Make buckets doubly linked

1 files changed, 16 insertions(+), 2 deletions(-)

lib/std/heap/debug_allocator.zig+16-2
...@@ -281,6 +281,7 @@ pub fn DebugAllocator(comptime config: Config) type {...@@ -281,6 +281,7 @@ pub fn DebugAllocator(comptime config: Config) type {
281 allocated_count: SlotIndex,281 allocated_count: SlotIndex,
282 freed_count: SlotIndex,282 freed_count: SlotIndex,
283 prev: ?*BucketHeader,283 prev: ?*BucketHeader,
284 next: ?*BucketHeader,
284 canary: usize = config.canary,285 canary: usize = config.canary,
285286
286 fn fromPage(page_addr: usize, slot_count: usize) *BucketHeader {287 fn fromPage(page_addr: usize, slot_count: usize) *BucketHeader {
...@@ -782,7 +783,11 @@ pub fn DebugAllocator(comptime config: Config) type {...@@ -782,7 +783,11 @@ pub fn DebugAllocator(comptime config: Config) type {
782 .allocated_count = 1,783 .allocated_count = 1,
783 .freed_count = 0,784 .freed_count = 0,
784 .prev = self.buckets[size_class_index],785 .prev = self.buckets[size_class_index],
786 .next = null,
785 };787 };
788 if (self.buckets[size_class_index]) |old_head| {
789 old_head.next = bucket;
790 }
786 self.buckets[size_class_index] = bucket;791 self.buckets[size_class_index] = bucket;
787792
788 if (!config.backing_allocator_zeroes) {793 if (!config.backing_allocator_zeroes) {
...@@ -935,9 +940,18 @@ pub fn DebugAllocator(comptime config: Config) type {...@@ -935,9 +940,18 @@ pub fn DebugAllocator(comptime config: Config) type {
935 }940 }
936 bucket.freed_count += 1;941 bucket.freed_count += 1;
937 if (bucket.freed_count == bucket.allocated_count) {942 if (bucket.freed_count == bucket.allocated_count) {
938 if (self.buckets[size_class_index] == bucket) {943 if (bucket.prev) |prev| {
939 self.buckets[size_class_index] = null;944 prev.next = bucket.next;
940 }945 }
946
947 if (bucket.next) |next| {
948 assert(self.buckets[size_class_index] != bucket);
949 next.prev = bucket.prev;
950 } else {
951 assert(self.buckets[size_class_index] == bucket);
952 self.buckets[size_class_index] = bucket.prev;
953 }
954
941 if (!config.never_unmap) {955 if (!config.never_unmap) {
942 const page: [*]align(page_size) u8 = @ptrFromInt(page_addr);956 const page: [*]align(page_size) u8 = @ptrFromInt(page_addr);
943 self.backing_allocator.rawFree(page[0..page_size], page_align, @returnAddress());957 self.backing_allocator.rawFree(page[0..page_size], page_align, @returnAddress());