Repository: go
Issue: cmd/cgo: "fatal: morestack on g0" when interacting with PHP Fibers
Labels: NeedsDecision,compiler/runtime

### What version of Go are you using (`go version`)?

<pre>
$ go version
go version go1.20.5 linux/amd64
</pre>

### Does this issue reproduce with the latest release?

Yes.

### What operating system and processor architecture are you using (`go env`)?

<details><summary><code>go env</code> Output</summary><br><pre>
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/slim/.cache/go-build"
GOENV="/home/slim/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/slim/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/slim/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org/,direct"
GOROOT="/usr/local/go"
GOSUMDB="[sum.golang.org](http://sum.golang.org/)"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.20.5"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/home/slim/pub/src/frankenphp/go.mod"
GOWORK=""
CGO_CFLAGS="-O2 -g"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-O2 -g"
CGO_FFLAGS="-O2 -g"
CGO_LDFLAGS="-O2 -g"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build3097512463=/tmp/go-build -gno-record-gcc-switches"
</pre></details>

### What did you do?

[FrankenPHP](https://frankenphp.dev) is a Go module that embeds the PHP executor in Go programs such as the Caddy web server, and handles HTTP requests received by "net/http" with PHP scripts executed directly in the Go process, similarly to Apache mod_php.

To do so PHP is compiled as a C library and executed using cgo.

Under certain conditions, if the script uses [PHP fibers](https://www.php.net/manual/en/language.fibers.php), the program crashes with the message "fatal: morestack on g0" (see backtraces and reproducer below).

PHP Fibers do low-level stack manipulation and are likely badly interacting Go and cgo own stack management.
Under the hood, PHP Fibers can use the [boost.context library](https://github.com/boostorg/context) (by default) or `ucontext.h` (if PHP is compiled with `--disable-fiber-asm`). The problem occurs with both implementations.
Fibers code is in https://github.com/php/php-src/blob/master/Zend/zend_fibers.c.

The problem seems to only randomly occur and only on Linux with x86 processors (we're not able to reproduce this on Mac or on ARM).

The problem seems to occur when the C code executed in a PHP Fiber (with its own stack) calls a Go function using cgo.

We currently have no idea if it's a problem in Go, in PHP, or "just" a bad interaction of their respective stack management systems.

### What did you expect to see?

No error.

### What did you see instead?

`fatal: morestack on g0`

Here are some stack traces collected by @slim with GDB:

```
(gdb) backtrace
#0  0x0000000000470106 in ?? ()
#1  0x000000000046e165 in runtime.morestack () at /usr/local/go/src/runtime/asm_amd64.s:542
#2  0x000000000042b8dc in runtime.(*mheap).alloc.func1 () at /usr/local/go/src/runtime/mheap.go:955
#3  0x000000000046e0e9 in runtime.systemstack () at /usr/local/go/src/runtime/asm_amd64.s:496
#4  0x00007fffa7ffec38 in ?? ()
#5  0x00007fffa4bff770 in ?? ()
#6  0x000000c000480000 in ?? ()
#7  0x00007fffa4bff770 in ?? ()
#8  0x00000000005c6bbd in crosscall2 () at /usr/local/go/src/runtime/cgo/asm_amd64.s:30
#9  0x0000000000758a0e in go_add_header (rh=23, cString=0x0, length=12175376) at _cgo_export.c:135
#10 0x00000000007596ff in frankenphp_send_headers (sapi_headers=0x7fff3801d800) at frankenphp.c:461
#11 frankenphp_send_headers (sapi_headers=0x7fff3801d800) at frankenphp.c:446
#12 0x00007ffff73fc665 in sapi_send_headers () at /home/slim/pub/src/php-franken/main/SAPI.c:883
#13 0x00007ffff734367b in php_header () at /home/slim/pub/src/php-franken/ext/standard/head.c:72
#14 0x00007ffff74086b2 in php_output_header () at /home/slim/pub/src/php-franken/main/output.c:122
#15 0x00007ffff740b208 in php_output_op (op=0, str=0x7fffc6202068 "Fiber 54", len=8) at /home/slim/pub/src/php-franken/main/output.c:1077
#16 0x00007ffff7408ee2 in php_output_write (str=0x7fffc6202068 "Fiber 54", len=8) at /home/slim/pub/src/php-franken/main/output.c:261
#17 0x00007ffff750a407 in ZEND_ECHO_SPEC_TMPVAR_HANDLER () at /home/slim/pub/src/php-franken/Zend/zend_vm_execute.h:14221
#18 0x00007ffff7566b69 in execute_ex (ex=0x7fffc6269070) at /home/slim/pub/src/php-franken/Zend/zend_vm_execute.h:57509
#19 0x00007ffff748c221 in zend_call_function (fci=0x7fffc625bcb8, fci_cache=0x7fffc625bcf8) at /home/slim/pub/src/php-franken/Zend/zend_execute_API.c:949
#20 0x00007ffff75b4fc3 in zend_fiber_execute (transfer=0x7fffa4bfffc0) at /home/slim/pub/src/php-franken/Zend/zend_fibers.c:504
#21 0x00007ffff75b46b2 in zend_fiber_trampoline (data=...) at /home/slim/pub/src/php-franken/Zend/zend_fibers.c:299
#22 0x00007ffff73e772f in make_fcontext () at /home/slim/pub/src/php-franken/Zend/asm/make_x86_64_sysv_elf_gas.S:135
#23 0x00007fffa4c00040 in ?? ()
#24 0x00007fffa4c00000 in ?? ()
#25 0x00007fffa4c00000 in ?? ()
#26 0x0000009200000172 in ?? ()
#27 0x0000000000000000 in ?? ()
```

```
[New Thread 0x7fffa07f8700 (LWP 28725)]
fatal: morestack on g0

Thread 11 "thpool-0" received signal SIGTRAP, Trace/breakpoint trap.
[Switching to Thread 0x7fffa3fff700 (LWP 28718)]
0x0000000000471366 in ?? ()
(gdb) backtrace
#0  0x0000000000471366 in ?? ()
#1  0x000000000046f3c5 in runtime.morestack.abi0 ()
#2  0x000000000042c9fc in runtime.(*mheap).alloc.func1 ()
#3  0x000000000046f349 in runtime.systemstack.abi0 ()
#4  0x00007fffa3ffec38 in ?? ()
#5  0x00007fff9f9ff770 in ?? ()
#6  0x000000c000400400 in ?? ()
#7  0x00007fff9f9ff770 in ?? ()
#8  0x00000000005c7e1d in crosscall2 ()
#9  0x000000000070b780 in ?? ()
#10 0x00007fff9f9ff780 in ?? ()
#11 0x0000000000000000 in ?? ()

fatal: morestack on g0

Thread 10 "thpool-0" received signal SIGTRAP, Trace/breakpoint trap.
[Switching to Thread 0x7fffc4918700 (LWP 28744)]
0x0000000000471366 in ?? ()
(gdb) backtrace
#0  0x0000000000471366 in ?? ()
#1  0x000000000046f3c5 in runtime.morestack.abi0 ()
#2  0x000000000042c9fc in runtime.(*mheap).alloc.func1 ()
#3  0x000000000046f349 in runtime.systemstack.abi0 ()
#4  0x00007fffc4917c38 in ?? ()
#5  0x00007fff83fff770 in ?? ()
#6  0x000000c000380400 in ?? ()
#7  0x00007fff83fff770 in ?? ()
#8  0x00000000005c7e1d in crosscall2 ()
#9  0x000000000070b780 in ?? ()
#10 0x00007fff83fff780 in ?? ()
#11 0x0000000000000000 in ?? ()

fatal: morestack on g0

Thread 11 "thpool-1" received signal SIGTRAP, Trace/breakpoint trap.
[Switching to Thread 0x7fffabfff700 (LWP 28775)]
0x0000000000471366 in ?? ()
(gdb) backtrace
#0  0x0000000000471366 in ?? ()
#1  0x000000000046f3c5 in runtime.morestack.abi0 ()
#2  0x000000000042c9fc in runtime.(*mheap).alloc.func1 ()
#3  0x000000000046f349 in runtime.systemstack.abi0 ()
#4  0x00007fffabffec38 in ?? ()
#5  0x00007fff93fff770 in ?? ()
#6  0x000000c000300400 in ?? ()
#7  0x00007fff93fff770 in ?? ()
#8  0x00000000005c7e1d in crosscall2 ()
#9  0x000000000070b780 in ?? ()
#10 0x00007fff93fff780 in ?? ()
#11 0x0000000000000000 in ?? ()
```

The issue also always occurs when executing a Fiber in a Docker container running on GitHub Actions, (but oddly, not when running directly in a GHA runner).

A reproducer as well as some extra investigation are available in this PR: https://github.com/dunglas/frankenphp/pull/171

The problem can be reproduced locally [by compiling PHP with the appropriate flags needed by FrankenPHP](https://github.com/dunglas/frankenphp/blob/main/docs/compile.md), checking out the `fibers` branch of FrankenPHP and running `go test -run Fiber`.