Go version

go version go1.22.4 linux/amd64

Output of go env in your module/workspace:

GO111MODULE=''
GOARCH='amd64'
GOBIN=''
GOCACHE='/home/ronanj/.cache/go-build'
GOENV='/home/ronanj/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/home/ronanj/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/ronanj/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/local/go'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/local/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.22.4'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='/dev/null'
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-build4169732472=/tmp/go-build -gno-record-gcc-switches'

What did you do?

The following program will generate a fatal error: concurrent map writes

package main

import (
    "runtime/debug"
    "time"
)

var l = map[nt]int{}

func worker() {
    for {
        l[1] = 0
    }
}

func main() {
    debug.SetTraceback("all")
    go worker()
    go worker()
    for {
        time.Sleep(time.Second)
    }
}

Run it with go run

$go build -o test test.go
$./test
fatal error: concurrent map writes

goroutine 6 gp=0xc000007500 m=2 mp=0xc000048808 [running]:
runtime.fatal({0x47c06b?, 0x0?})
    /usr/local/go/src/runtime/panic.go:1042 +0x5c fp=0xc000044f78 sp=0xc000044f48 pc=0x430fdc
runtime.mapassign_fast64(0x46e140, 0xc000072090, 0x1)
    /usr/local/go/src/runtime/map_fast64.go:102 +0x4d fp=0xc000044fb8 sp=0xc000044f78 pc=0x40ed2d
main.worker()
    /tmp/test.go:12 +0x26 fp=0xc000044fe0 sp=0xc000044fb8 pc=0x4654e6
runtime.goexit({})
    /usr/local/go/src/runtime/asm_amd64.s:1695 +0x1 fp=0xc000044fe8 sp=0xc000044fe0 pc=0x45f101
created by main.main in goroutine 1
    /tmp/test.go:18 +0x2b

goroutine 1 gp=0xc0000061c0 m=nil [sleep]:
runtime.gopark(0x1bdc37393cd958?, 0xc000042700?, 0x40?, 0xd4?, 0x480f28?)
    /usr/local/go/src/runtime/proc.go:402 +0xce fp=0xc0000426f0 sp=0xc0000426d0 pc=0x433dee
time.Sleep(0x3b9aca00)
    /usr/local/go/src/runtime/time.go:195 +0x115 fp=0xc000042730 sp=0xc0000426f0 pc=0x45c395
main.main()
    /tmp/test.go:21 +0x45 fp=0xc000042750 sp=0xc000042730 pc=0x465545
runtime.main()
    /usr/local/go/src/runtime/proc.go:271 +0x29d fp=0xc0000427e0 sp=0xc000042750 pc=0x4339bd
runtime.goexit({})
    /usr/local/go/src/runtime/asm_amd64.s:1695 +0x1 fp=0xc0000427e8 sp=0xc0000427e0 pc=0x45f101```

...

Now run it with elevated privileges

$ go build -o test test.go
$ sudo setcap CAP_NET_BIND_SERVICE+eip ./test
$ ./test
fatal error: concurrent map writes

Stack traces are gone.

What did you see happen?

A stack trace

What did you expect to see?

Referring to https://github.com/golang/go/issues/60272, I expected the traces to be shown when using debug.SetTraceback("all"). But this solution only works for panic errors, and does not for fatal errors thrown internally from the go runtime (especially the map implementation).

Referring to the internal go runtime panic.go, it is mentioned that fatal does not include runtime frames, system goroutines, or frame metadata (fp, sp, pc) in the stack trace unless GOTRACEBACK=system or higher. Setting SetTraceback to system does not work either, as traces are also swallowed.

This issue, related to the change https://github.com/golang/go/issues/60272 , is because the fatal function only checks for isSecureMode, while the panic function checks the gotraceback value before dumping the stack trace.

Comment From: gabyhelp

Similar Issues

(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)

Comment From: dr2chase

@golang/runtime

Comment From: shuxiao9058

The same issue.