From e6fbad13c6caee9ef233ae16a6c95518195f8f70 Mon Sep 17 00:00:00 2001 From: Nia Waldvogel Date: Wed, 15 Dec 2021 17:17:18 -0500 Subject: [PATCH] runtime (gc): correct scan bounds This fixes 2 bugs in the GC scan bounds: 1. On AVR, the GC could sometimes read one byte past the end of a block due to the difference between pointer size and alignment. 2. On WASM, the linker does not properly align the marker for the end of the globals section. A manual alignment operation has been added to markGlobals to work around this. --- src/runtime/gc_conservative.go | 10 ++++++++++ src/runtime/gc_globals_conservative.go | 14 +++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/runtime/gc_conservative.go b/src/runtime/gc_conservative.go index 955b6d99..e0e13bc2 100644 --- a/src/runtime/gc_conservative.go +++ b/src/runtime/gc_conservative.go @@ -430,8 +430,18 @@ func markRoots(start, end uintptr) { if start >= end { runtimePanic("gc: unexpected range to mark") } + if start%unsafe.Alignof(start) != 0 { + runtimePanic("gc: unaligned start pointer") + } + if end%unsafe.Alignof(end) != 0 { + runtimePanic("gc: unaligned end pointer") + } } + // Reduce the end bound to avoid reading too far on platforms where pointer alignment is smaller than pointer size. + // If the size of the range is 0, then end will be slightly below start after this. + end -= unsafe.Sizeof(end) - unsafe.Alignof(end) + for addr := start; addr < end; addr += unsafe.Alignof(addr) { root := *(*uintptr)(unsafe.Pointer(addr)) markRoot(addr, root) diff --git a/src/runtime/gc_globals_conservative.go b/src/runtime/gc_globals_conservative.go index 56476551..b4d19470 100644 --- a/src/runtime/gc_globals_conservative.go +++ b/src/runtime/gc_globals_conservative.go @@ -1,12 +1,24 @@ +//go:build (gc.conservative || gc.extalloc) && (baremetal || tinygo.wasm) // +build gc.conservative gc.extalloc // +build baremetal tinygo.wasm package runtime +import "unsafe" + // markGlobals marks all globals, which are reachable by definition. // // This implementation marks all globals conservatively and assumes it can use // linker-defined symbols for the start and end of the .data section. func markGlobals() { - markRoots(globalsStart, globalsEnd) + end := globalsEnd + if GOARCH == "wasm" { + // This is a workaround for a bug in wasm-ld: wasm-ld doesn't always + // align __heap_base and when this memory is shared through an API, it + // might result in unaligned memory. For details, see: + // https://reviews.llvm.org/D106499 + // It should be removed once we switch to LLVM 13, where this is fixed. + end = end &^ (unsafe.Alignof(end) - 1) + } + markRoots(globalsStart, end) }