Problem
In libgodc, spawned goroutines get fixed 64KB stacks and the main goroutine gets 128KB. There is no stack growth and no overflow detection (see #4).
A fixed-size array local variable that doesn't escape will be placed entirely on the stack by the compiler:
func loadLevel() {
var buf [100000]byte // 100KB on stack - overflows 64KB goroutine stack
// ...
}
This silently overflows the stack and corrupts adjacent memory. The developer gets no warning at compile time or runtime.
Note that make([]byte, 100000) is safe - make always heap-allocates the backing array through gc_alloc, which routes large objects (>64KB) to malloc(). Only fixed-size arrays are at risk.
Possible solutions
1. Compile-time detection
Add a lint or build step that scans Go source for fixed-size array declarations and warns when the total size of local arrays in a function approaches the stack limit. Could use go vet-style analysis or gccgo's -fgo-dump-escape output to identify stack-allocated large arrays.
2. Compiler flag for max stack frame size
gccgo/GCC has -Wframe-larger-than=N which warns when a function's stack frame exceeds N bytes. Setting -Wframe-larger-than=32768 (half the goroutine stack, leaving room for call depth) would catch the obvious cases at compile time.
3. Runtime canary check
As proposed in #4, a stack canary at the bottom of each goroutine's stack would detect overflow after the fact (at yield/GC points).
4. Documentation
At minimum, document this pitfall clearly: use make for large buffers, keep fixed-size arrays well under the stack size.
Action items
Problem
In libgodc, spawned goroutines get fixed 64KB stacks and the main goroutine gets 128KB. There is no stack growth and no overflow detection (see #4).
A fixed-size array local variable that doesn't escape will be placed entirely on the stack by the compiler:
This silently overflows the stack and corrupts adjacent memory. The developer gets no warning at compile time or runtime.
Note that
make([]byte, 100000)is safe -makealways heap-allocates the backing array throughgc_alloc, which routes large objects (>64KB) tomalloc(). Only fixed-size arrays are at risk.Possible solutions
1. Compile-time detection
Add a lint or build step that scans Go source for fixed-size array declarations and warns when the total size of local arrays in a function approaches the stack limit. Could use
go vet-style analysis or gccgo's-fgo-dump-escapeoutput to identify stack-allocated large arrays.2. Compiler flag for max stack frame size
gccgo/GCC has
-Wframe-larger-than=Nwhich warns when a function's stack frame exceeds N bytes. Setting-Wframe-larger-than=32768(half the goroutine stack, leaving room for call depth) would catch the obvious cases at compile time.3. Runtime canary check
As proposed in #4, a stack canary at the bottom of each goroutine's stack would detect overflow after the fact (at yield/GC points).
4. Documentation
At minimum, document this pitfall clearly: use
makefor large buffers, keep fixed-size arrays well under the stack size.Action items
-Wframe-larger-than=Nworks with gccgo for Go source (it may only apply to C)