runtime (gc_blocks.go): clear full size of allocation

This fixes a bug where runtime.alloc would not clear the padding from rounding the allocation up to a multiple of the block size.
The GC still has to scan this, and this could result in permanent false positives (and therefore memory leaks).

It also handles overflow in the size calculation.
This commit is contained in:
Nia Waldvogel
2025-11-29 17:28:53 -05:00
committed by Ron Evans
parent 9118e91b72
commit 20e22d4507
2 changed files with 19 additions and 10 deletions
+3 -3
View File
@@ -42,9 +42,9 @@ func TestBinarySize(t *testing.T) {
// This is a small number of very diverse targets that we want to test.
tests := []sizeTest{
// microcontrollers
{"hifive1b", "examples/echo", 3884, 280, 0, 2268},
{"microbit", "examples/serial", 2844, 360, 8, 2272},
{"wioterminal", "examples/pininterrupt", 7349, 1491, 116, 6912},
{"hifive1b", "examples/echo", 3896, 280, 0, 2268},
{"microbit", "examples/serial", 2860, 360, 8, 2272},
{"wioterminal", "examples/pininterrupt", 7361, 1491, 116, 6912},
// TODO: also check wasm. Right now this is difficult, because
// wasm binaries are run through wasm-opt and therefore the
+16 -7
View File
@@ -311,22 +311,31 @@ func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer {
return unsafe.Pointer(&zeroSizedAlloc)
}
if preciseHeap {
size += align(unsafe.Sizeof(layout))
}
if interrupt.In() {
runtimePanicAt(returnAddress(0), "heap alloc in interrupt")
}
// Round the size up to a multiple of blocks.
rawSize := size
size += bytesPerBlock - 1
if preciseHeap {
// Add space for the layout.
size += align(unsafe.Sizeof(layout))
}
if size < rawSize {
// The size overflowed.
runtimePanicAt(returnAddress(0), "out of memory")
}
neededBlocks := size / bytesPerBlock
size = neededBlocks * bytesPerBlock
// Make sure there are no concurrent allocations. The heap is not currently
// designed for concurrent alloc/GC.
gcLock.Lock()
gcTotalAlloc += uint64(size)
// Update the total allocation counters.
gcTotalAlloc += uint64(rawSize)
gcMallocs++
neededBlocks := (size + (bytesPerBlock - 1)) / bytesPerBlock
gcTotalBlocks += uint64(neededBlocks)
// Continue looping until a run of free blocks has been found that fits the