Description
What version of Go are you using (go version
)?
tip (d49b11b)
Does this issue reproduce with the latest release?
No
What operating system and processor architecture are you using (go env
)?
linux/amd64
What did you do?
Build a Go c-archive, call the Go function from C.
x.go
package main
import "C"
func main() {}
//export GoF
func GoF() {}
c.c
#include "x.h"
void callGoFWithDeepStack(int n) {
if (n > 0)
callGoFWithDeepStack(n - 1);
GoF();
}
int main() {
GoF(); // call GoF without using much stack
callGoFWithDeepStack(100000); // call GoF with a deep stack
}
$ go build -buildmode=c-archive x.go
$ cc -O0 c.c x.a # don't optimize out my recursion
$ ./a.out
What did you expect to see?
Run without error.
What did you see instead?
fatal: morestack on g0
This is a regression from CL https://golang.org/cl/392854 . The first time when C calls into Go, we create an M and a g0. We compute a stack bound using the current SP. We don't know how big the C stack is, so we simply assume 32K https://cs.opensource.google/go/go/+/master:src/runtime/proc.go;l=1937-1946
Previously, when the Go function returns to C, we drop the M. And the next time C calls into Go, we put a new stack bound on the g0 based on the current SP.
After the CL, we don't drop the M, so the next time C calls into Go, we reuse the same g0, without recomputing the stack bounds. If the C code uses quite a bit of stack before calling into Go, the SP may be well below the 32K stack bound we assumed, so the runtime thinks the g0 stack overflows.
We probably need to either try to get a more accurate stack bounds the first time C calling into Go, like we do in x_cgo_init https://cs.opensource.google/go/go/+/master:src/runtime/cgo/gcc_linux_amd64.c;l=46 , or recompute the g0 stack bounds based on the current SP each time when C calls into Go.