v1.77.0: nan() and parsing "nan" with strtod or scanf crash with a fatal stack overflow on linux
Summary
In v1.77.0, Xnanf calls itself on linux/386, amd64, arm, arm64, loong64, ppc64le, riscv64 and s390x. A program that does any of the following dies with fatal error: stack overflow, which recover() cannot catch:
- calls nan(), nanf() or nanl();
- parses "nan" with strtod(), strtof(), strtold() or atof();
- parses "nan" with a floating point conversion of the scanf family, e.g.
sscanf("nan", "%f", &f).
Parsing "inf" works. darwin, freebsd, netbsd, openbsd, illumos and windows are not affected. v1.76.0 is fine.
Reproducer
package main
import (
"fmt"
"modernc.org/libc"
)
func main() {
tls := libc.NewTLS()
defer tls.Close()
s, err := libc.CString("nan")
if err != nil {
panic(err)
}
fmt.Println(libc.Xstrtod(tls, s, 0))
}Expected
With v1.76.0:
NaNActual
With v1.77.0 on linux/amd64, Go 1.27.0:
runtime: goroutine stack exceeds 1000000000-byte limit
fatal error: stack overflow
...
modernc.org/libc.Xnanf(...)
modernc.org/libc@v1.77.0/ccgo_linux_amd64.go:109130
...
modernc.org/libc.X__floatscan(...)
modernc.org/libc@v1.77.0/ccgo_linux_amd64.go:25868Cause
v1.77.0 is the first libc generated by ccgo v4.36.0, and no C source changed. That ccgo links musl's __builtin_nanf("") to musl's own nanf, see ccgo#67. modernc.org/libexpat's tests crash this way since its go.mod moved to v1.77.0.
Workaround
Use v1.76.0. Its API is the same. v1.77.0 only adds e99ffe10 (abort() dies by SIGABRT again, #53) and dependency updates.
Fix
The next release, regenerated with the fixed ccgo, retracts v1.77.0. The new TestNaN calls nan, nanf and nanl, and parses "nan" and "inf" variants with strtod, strtof, strtold and sscanf.