Closed
Description
Go version
go version go1.22.0 darwin/arm64
Output of go env
in your module/workspace:
GO111MODULE=''
GOARCH='arm64'
GOBIN=''
GOCACHE='/Users/user/Library/Caches/go-build'
GOENV='/Users/user/Library/Application Support/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='arm64'
GOHOSTOS='darwin'
GOINSECURE=''
GOMODCACHE='/Users/user/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='darwin'
GOPATH='/Users/user/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/opt/homebrew/Cellar/go/1.22.0/libexec'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/opt/homebrew/Cellar/go/1.22.0/libexec/pkg/tool/darwin_arm64'
GOVCS=''
GOVERSION='go1.22.0'
GCCGO='gccgo'
AR='ar'
CC='cc'
CXX='c++'
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 -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/0_/clg6377n50x2gd3388rp147w0000gn/T/go-build4212135828=/tmp/go-build -gno-record-gcc-switches -fno-common'
What did you do?
Issue occurs intermittently in a highly concurrent program making HTTP requests using Go's http.Client. The issue manifests as a deadlock in the program.
What did you see happen?
goroutine 2270 gp=0xc0003e01c0 m=nil [sync.Mutex.Lock, 180 minutes]:
runtime.gopark(0x2?, 0x0?, 0xb0?, 0x89?, 0x4500c6?)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/runtime/proc.go:402 +0xce fp=0xc000048880 sp=0xc000048860 pc=0x43e76e
runtime.goparkunlock(...)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/runtime/proc.go:408
runtime.semacquire1(0xc000002354, 0x0, 0x3, 0x1, 0x15)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/runtime/sema.go:160 +0x225 fp=0xc0000488e8 sp=0xc000048880 pc=0x450c05
sync.runtime_SemacquireMutex(0x4?, 0x0?, 0xd5d8c0?)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/runtime/sema.go:77 +0x25 fp=0xc000048920 sp=0xc0000488e8 pc=0x46d6e5
sync.(*Mutex).lockSlow(0xc000002350)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/sync/mutex.go:171 +0x15d fp=0xc000048970 sp=0xc000048920 pc=0x47a6dd
sync.(*Mutex).Lock(...)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/sync/mutex.go:90
net/http.(*http2clientStream).abortStream(0xc000048a68?, {0xf98f60, 0x1578700})
/opt/homebrew/Cellar/go/1.22.0/libexec/src/net/http/h2_bundle.go:7438 +0x5d fp=0xc0000489c0 sp=0xc000048970 pc=0x65851d
net/http.(*http2ClientConn).RoundTrip(0xc000002300, 0xc000db4c60)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/net/http/h2_bundle.go:8340 +0x4f9 fp=0xc000048b00 sp=0xc0000489c0 pc=0x65c9b9
net/http.(*http2Transport).RoundTripOpt(0xc0004c2750, 0xc000db4c60, {0xf0?})
/opt/homebrew/Cellar/go/1.22.0/libexec/src/net/http/h2_bundle.go:7591 +0x1b1 fp=0xc000048c30 sp=0xc000048b00 pc=0x659131
net/http.(*http2Transport).RoundTrip(...)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/net/http/h2_bundle.go:7540
net/http.http2noDialH2RoundTripper.RoundTrip({0xc00025f040?}, 0xc000db4c60?)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/net/http/h2_bundle.go:10167 +0x1a fp=0xc000048c70 sp=0xc000048c30 pc=0x666f1a
net/http.(*Transport).roundTrip(0xc00025f040, 0xc000db4c60)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/net/http/transport.go:553 +0x39c fp=0xc000048e98 sp=0xc000048c70 pc=0x68dedc
net/http.(*Transport).RoundTrip(0xc000db4c60?, 0xf98de0?)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/net/http/roundtrip.go:17 +0x13 fp=0xc000048eb8 sp=0xc000048e98 pc=0x673813
net/http.send(0xc000db4b40, {0xf98de0, 0xc00025f040}, {0x1?, 0x496233?, 0x1510f40?})
/opt/homebrew/Cellar/go/1.22.0/libexec/src/net/http/client.go:259 +0x5e4 fp=0xc000049098 sp=0xc000048eb8 pc=0x6381a4
net/http.(*Client).send(0xc0009e88d0, 0xc000db4b40, {0x8?, 0xc000049180?, 0x1510f40?})
/opt/homebrew/Cellar/go/1.22.0/libexec/src/net/http/client.go:180 +0x98 fp=0xc000049110 sp=0xc000049098 pc=0x637a58
net/http.(*Client).do(0xc0009e88d0, 0xc000db4b40)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/net/http/client.go:724 +0x8dc fp=0xc000049300 sp=0xc000049110 pc=0x639d3c
net/http.(*Client).Do(...)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/net/http/client.go:590
<PRIVATE CODE>
goroutine 2377 gp=0xc000318700 m=nil [sync.Mutex.Lock, 180 minutes]:
runtime.gopark(0xd94b80?, 0xc000b87b60?, 0x60?, 0x92?, 0x23?)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/runtime/proc.go:402 +0xce fp=0xc00001c968 sp=0xc00001c948 pc=0x43e76e
runtime.goparkunlock(...)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/runtime/proc.go:408
runtime.semacquire1(0xc000002354, 0x0, 0x3, 0x1, 0x15)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/runtime/sema.go:160 +0x225 fp=0xc00001c9d0 sp=0xc00001c968 pc=0x450c05
sync.runtime_SemacquireMutex(0xc000618a90?, 0xa0?, 0xc0009e8c98?)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/runtime/sema.go:77 +0x25 fp=0xc00001ca08 sp=0xc00001c9d0 pc=0x46d6e5
sync.(*Mutex).lockSlow(0xc000002350)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/sync/mutex.go:171 +0x15d fp=0xc00001ca58 sp=0xc00001ca08 pc=0x47a6dd
sync.(*Mutex).Lock(...)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/sync/mutex.go:90
net/http.(*http2clientConnReadLoop).cleanup(0xc000318700?)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/net/http/h2_bundle.go:9241 +0x145 fp=0xc00001cb70 sp=0xc00001ca58 pc=0x6618e5
net/http.(*http2ClientConn).readLoop.deferwrap1()
/opt/homebrew/Cellar/go/1.22.0/libexec/src/net/http/h2_bundle.go:9197 +0x25 fp=0xc00001cb88 sp=0xc00001cb70 pc=0x661685
panic({0xd9e2a0?, 0x14ac430?})
/opt/homebrew/Cellar/go/1.22.0/libexec/src/runtime/panic.go:770 +0x132 fp=0xc00001cc38 sp=0xc00001cb88 pc=0x43acf2
runtime.panicmem(...)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/runtime/panic.go:261
runtime.sigpanic()
/opt/homebrew/Cellar/go/1.22.0/libexec/src/runtime/signal_unix.go:881 +0x378 fp=0xc00001cc98 sp=0xc00001cc38 pc=0x4537f8
net/http.(*http2pipe).Write(0xb100000000000009?, {0xc0001a0340?, 0xc0000de6e0?, 0xc00001cde0?})
/opt/homebrew/Cellar/go/1.22.0/libexec/src/net/http/h2_bundle.go:3751 +0x176 fp=0xc00001cd20 sp=0xc00001cc98 pc=0x648e56
net/http.(*http2clientConnReadLoop).processData(0xc00001cfa8, 0xc000dbff20)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/net/http/h2_bundle.go:9748 +0x21e fp=0xc00001cdf0 sp=0xc00001cd20 pc=0x66485e
net/http.(*http2clientConnReadLoop).run(0xc00001cfa8)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/net/http/h2_bundle.go:9337 +0x446 fp=0xc00001cf60 sp=0xc00001cdf0 pc=0x662306
net/http.(*http2ClientConn).readLoop(0xc000002300)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/net/http/h2_bundle.go:9198 +0x65 fp=0xc00001cfc8 sp=0xc00001cf60 pc=0x661565
net/http.(*http2Transport).newClientConn.gowrap1()
/opt/homebrew/Cellar/go/1.22.0/libexec/src/net/http/h2_bundle.go:7848 +0x25 fp=0xc00001cfe0 sp=0xc00001cfc8 pc=0x65adc5
runtime.goexit({})
/opt/homebrew/Cellar/go/1.22.0/libexec/src/runtime/asm_amd64.s:1695 +0x1 fp=0xc00001cfe8 sp=0xc00001cfe0 pc=0x4712e1
created by net/http.(*http2Transport).newClientConn in goroutine 2376
/opt/homebrew/Cellar/go/1.22.0/libexec/src/net/http/h2_bundle.go:7848 +0xca6
goroutine 2672 gp=0xc00081b500 m=nil [sync.Mutex.Lock, 180 minutes]:
runtime.gopark(0xf98f60?, 0x1578700?, 0x40?, 0xe5?, 0xc000002300?)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/runtime/proc.go:402 +0xce fp=0xc001070e30 sp=0xc001070e10 pc=0x43e76e
runtime.goparkunlock(...)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/runtime/proc.go:408
runtime.semacquire1(0xc000002354, 0x0, 0x3, 0x1, 0x15)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/runtime/sema.go:160 +0x225 fp=0xc001070e98 sp=0xc001070e30 pc=0x450c05
sync.runtime_SemacquireMutex(0xc0008f36e0?, 0x80?, 0x0?)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/runtime/sema.go:77 +0x25 fp=0xc001070ed0 sp=0xc001070e98 pc=0x46d6e5
sync.(*Mutex).lockSlow(0xc000002350)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/sync/mutex.go:171 +0x15d fp=0xc001070f20 sp=0xc001070ed0 pc=0x47a6dd
sync.(*Mutex).Lock(...)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/sync/mutex.go:90
net/http.(*http2clientStream).cleanupWriteRequest(0xc0008ee600, {0xf98f60, 0x1578700})
/opt/homebrew/Cellar/go/1.22.0/libexec/src/net/http/h2_bundle.go:8568 +0x85 fp=0xc001070f98 sp=0xc001070f20 pc=0x65e0a5
net/http.(*http2clientStream).doRequest(0xc0008ee600, 0xc0008a87e0?)
/opt/homebrew/Cellar/go/1.22.0/libexec/src/net/http/h2_bundle.go:8354 +0x28 fp=0xc001070fc0 sp=0xc001070f98 pc=0x65cd88
net/http.(*http2ClientConn).RoundTrip.gowrap1()
/opt/homebrew/Cellar/go/1.22.0/libexec/src/net/http/h2_bundle.go:8259 +0x25 fp=0xc001070fe0 sp=0xc001070fc0 pc=0x65cd25
runtime.goexit({})
/opt/homebrew/Cellar/go/1.22.0/libexec/src/runtime/asm_amd64.s:1695 +0x1 fp=0xc001070fe8 sp=0xc001070fe0 pc=0x4712e1
created by net/http.(*http2ClientConn).RoundTrip in goroutine 2270
/opt/homebrew/Cellar/go/1.22.0/libexec/src/net/http/h2_bundle.go:8259 +0x2ed
Looking specifically at the stack for goroutine 2377
it appears that there is a panic here:
Line 3751 in 6cbe522
which occurs as a result of p.b being nil. It looks like the deadlock occurs because as the stack unwinds and the deferred functions are called, cleanup() attempts to acquire a mutex which is already held further up the stack here:
Line 9733 in 6cbe522
What did you expect to see?
The HTTP2 round tripper should not panic and cause a deadlock.