authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-02-03 21:38:08-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-02-06 14:23:23-08:00
log601f632c274cee4e8b9780c436be0771d856ade0
treec9027773ff90fc4f3e3cad8a15c0d50a19a2cd56
parentbecd16859dbc9d6357099f660408b54d00aa18ef

std.heap.GeneralPurposeAllocator: fix large alloc accounting

when mremap relocates an allocation

1 files changed, 29 insertions(+), 4 deletions(-)

lib/std/heap/general_purpose_allocator.zig+29-4
...@@ -608,7 +608,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -608,7 +608,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
608608
609 if (config.safety and old_mem.len != entry.value_ptr.bytes.len) {609 if (config.safety and old_mem.len != entry.value_ptr.bytes.len) {
610 var addresses: [stack_n]usize = [1]usize{0} ** stack_n;610 var addresses: [stack_n]usize = [1]usize{0} ** stack_n;
611 var free_stack_trace = StackTrace{611 var free_stack_trace: StackTrace = .{
612 .instruction_addresses = &addresses,612 .instruction_addresses = &addresses,
613 .index = 0,613 .index = 0,
614 };614 };
...@@ -635,9 +635,15 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -635,9 +635,15 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
635 self.total_requested_bytes = new_req_bytes;635 self.total_requested_bytes = new_req_bytes;
636 }636 }
637637
638 const opt_resized_ptr = if (may_move)638 const opt_resized_ptr = if (may_move) b: {
639 self.backing_allocator.rawRemap(old_mem, alignment, new_size, ret_addr)639 // So that if the allocation moves, we can memcpy the
640 else if (self.backing_allocator.rawResize(old_mem, alignment, new_size, ret_addr))640 // `LargeAlloc` value directly from old to new location.
641 // It's also not clear to me whether removing one item from std
642 // lib hash map guarantees that unused capacity increases by
643 // one.
644 self.large_allocations.ensureUnusedCapacity(self.backing_allocator, 1) catch return null;
645 break :b self.backing_allocator.rawRemap(old_mem, alignment, new_size, ret_addr);
646 } else if (self.backing_allocator.rawResize(old_mem, alignment, new_size, ret_addr))
641 old_mem.ptr647 old_mem.ptr
642 else648 else
643 null;649 null;
...@@ -660,6 +666,25 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -660,6 +666,25 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
660 }666 }
661 entry.value_ptr.bytes = resized_ptr[0..new_size];667 entry.value_ptr.bytes = resized_ptr[0..new_size];
662 entry.value_ptr.captureStackTrace(ret_addr, .alloc);668 entry.value_ptr.captureStackTrace(ret_addr, .alloc);
669
670 // Update the key of the hash map if the memory was relocated.
671 if (resized_ptr != old_mem.ptr) {
672 const gop = self.large_allocations.getOrPutAssumeCapacity(@intFromPtr(resized_ptr));
673 if (config.retain_metadata and !config.never_unmap) {
674 // Backing allocator may be reusing memory that we're retaining metadata for
675 assert(!gop.found_existing or gop.value_ptr.freed);
676 } else {
677 assert(!gop.found_existing); // This would mean the kernel double-mapped pages.
678 }
679 gop.value_ptr.* = entry.value_ptr.*;
680 if (!config.retain_metadata) {
681 self.large_allocations.removeByPtr(entry.key_ptr);
682 } else {
683 entry.value_ptr.freed = true;
684 entry.value_ptr.captureStackTrace(ret_addr, .free);
685 }
686 }
687
663 return resized_ptr;688 return resized_ptr;
664 }689 }
665690