Browse Source

mem: Fix `Buddy_Allocator` size calculation to truly include alignment

This didn't take into account the size of the header plus the size of
the allocation itself by virtue of `align_forward_uint`; this could
result in no change if `size` was equal to `b.alignment` because the
number is aligned, and if `actual_size` and `size` ended up being equal,
no additional space would be requested.

This meant that a block would end up being allocated on top of its
buddy's head.

Fixes #3435
Feoramund 2 months ago
parent
commit
57e2d8f1dd
1 changed files with 8 additions and 6 deletions
  1. 8 6
      core/mem/allocators.odin

+ 8 - 6
core/mem/allocators.odin

@@ -2247,12 +2247,14 @@ Get required block size to fit in the allocation as well as the alignment paddin
 */
 */
 @(require_results)
 @(require_results)
 buddy_block_size_required :: proc(b: ^Buddy_Allocator, size: uint) -> uint {
 buddy_block_size_required :: proc(b: ^Buddy_Allocator, size: uint) -> uint {
-	size := size
-	actual_size := b.alignment
-	size += size_of(Buddy_Block)
-	size = align_forward_uint(size, b.alignment)
-	for size > actual_size {
-		actual_size <<= 1
+	assert(size > 0)
+	// NOTE: `size_of(Buddy_Block)` will be accounted for in `b.alignment`.
+	// This calculation is also previously guarded against being given a `size`
+	// 0 by `buddy_allocator_alloc_bytes_non_zeroed` checking for that.
+	actual_size := b.alignment + size
+	if intrinsics.count_ones(actual_size) != 1 {
+		// We're not a power of two. Let's fix that.
+		actual_size = 1 << (size_of(uint) * 8 - intrinsics.count_leading_zeros(actual_size))
 	}
 	}
 	return actual_size
 	return actual_size
 }
 }