From e62ed261c55a3acaaa9cce73257181eb22cb4601 Mon Sep 17 00:00:00 2001 From: KBS Date: Sun, 16 Aug 2026 19:54:16 +0900 Subject: [PATCH] base/runtime: do not free the original block on a failed heap resize `base/runtime`: do not free the original block on a failed heap resize The default heap allocator freed old_ptr when the underlying allocation failed (allocated_mem == nil). On the realloc path (heap_resize) the original block is left intact on failure, and on the copy/fresh path old_ptr has not been copied or freed yet, so freeing it left the caller holding a dangling pointer. A [dynamic] array whose resize failed therefore double-freed its data on the next delete (reported as free(): invalid pointer / use-after-free). Return .Out_Of_Memory without freeing anything; the caller retains ownership of the original block. Fixes #7262 --- base/runtime/heap_allocator.odin | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/base/runtime/heap_allocator.odin b/base/runtime/heap_allocator.odin index e2667a78c..4dfe95393 100644 --- a/base/runtime/heap_allocator.odin +++ b/base/runtime/heap_allocator.odin @@ -42,8 +42,10 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, ptr := uintptr(aligned_mem) aligned_ptr := (ptr + uintptr(a)-1) & ~(uintptr(a)-1) if allocated_mem == nil { - aligned_free(old_ptr) - aligned_free(allocated_mem) + // On failure nothing must be freed: heap_resize (realloc) leaves the + // original block intact, and on the copy/fresh path old_ptr has not + // been copied or freed yet. Freeing old_ptr here left the caller's + // pointer dangling, causing a later double free. (#7262) return nil, .Out_Of_Memory }