Merge pull request #6476 from MortimerSnerd/scratch_allocator_fix

Fix for corner case in the scratch allocator.
This commit is contained in:
gingerBill
2026-03-26 11:16:27 +00:00
committed by GitHub
4 changed files with 40 additions and 9 deletions

View File

@@ -536,15 +536,8 @@ scratch_alloc_bytes_non_zeroed :: proc(
// we don't need to be so strict about every byte.
aligned_size += alignment - 1
}
if aligned_size <= len(s.data) {
offset := uintptr(0)
if s.curr_offset+aligned_size <= len(s.data) {
offset = uintptr(s.curr_offset)
} else {
// The allocation will cause an overflow past the boundary of the
// space available, so reset to the starting offset.
offset = 0
}
if s.curr_offset+aligned_size <= len(s.data) {
offset := uintptr(s.curr_offset)
start := uintptr(raw_data(s.data))
ptr := rawptr(offset+start)
// We keep track of the original base pointer without extra alignment

View File

@@ -34,6 +34,7 @@ set COMMON=-define:ODIN_TEST_FANCY=false -file -vet -strict-style -ignore-unused
..\..\..\odin build ..\test_issue_6401.odin %COMMON% 2>&1 | find /c "Error:" | findstr /x "3" || exit /b
..\..\..\odin test ..\test_pr_6470.odin %COMMON% || exit /b
..\..\..\odin test ..\test_pr_6470.odin -define:TEST_EXPECT_FAILURE=true %COMMON% 2>&1 | find /c "Error:" | findstr /x "1" || exit /b
..\..\..\odin test ..\test_pr_6476.odin %COMMON% || exit /b
@echo off

View File

@@ -37,6 +37,8 @@ $ODIN test ../test_issue_6068.odin $COMMON
$ODIN test ../test_issue_6101.odin $COMMON
$ODIN test ../test_issue_6165.odin $COMMON
$ODIN test ../test_issue_6396.odin $COMMON
$ODIN test ../test_pr_6476.odin $COMMON
if [[ $($ODIN build ../test_issue_6240.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 3 ]] ; then
echo "SUCCESSFUL 1/1"
else

View File

@@ -0,0 +1,35 @@
package test_issues
import "core:testing"
import "core:mem"
// Test for a problem encountered with the scratch allocator.
// Say you have a scratch allocator with an arena size of N.
// If you make an allocation whose size is <= N but greater than
// the amount of free space left in the arena, the allocator
// will return a slice of memory from the start of the arena,
// overlapping previous allocations. (the expected
// behavior is it satisfies the request with the backup allocator)
@test
test_scratch_smash :: proc(t: ^testing.T) {
// setup
frAlloc: mem.Scratch
err := mem.scratch_init(&frAlloc, 1 * mem.Kilobyte)
testing.expect(t, err == nil)
talloc := mem.scratch_allocator(&frAlloc)
defer mem.scratch_destroy(&frAlloc)
// First allocation fits in arena.
a1 := make([]byte, 512, talloc)
// Second allocation does not fit in the free space, but is
// <= the arena size.
a2 := make([]byte, 1024, talloc)
// Should be true, but bug in scratch allocator returns space
// overlapping a1 when allocating a2.
testing.expect(t, &a1[0] != &a2[0])
}