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
This commit is contained in:
KBS
2026-08-16 19:54:16 +09:00
committed by GitHub
parent 889ad95c7e
commit e62ed261c5

View File

@@ -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
}