Skip to content

reflect: Memory unsafety due to interface shadowing in reflect #80332

Description

@pitust

Go version

go version go1.26.4-X:nodwarf5 linux/amd64; 1.25, 1.26 and dev branch on go.dev/play

Output of go env in your module/workspace:

AR='ar'
CC='gcc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='g++'
GCCGO='gccgo'
GO111MODULE=''
GOAMD64='v1'
GOARCH='amd64'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/home/pitust/.cache/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/home/pitust/.config/go/env'
GOEXE=''
GOEXPERIMENT='nodwarf5'
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build4045048003=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/home/pitust/bs/poc/go.mod'
GOMODCACHE='/home/pitust/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/pitust/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/lib/go'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/home/pitust/.config/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/lib/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.26.4-X:nodwarf5'
GOWORK=''
PKG_CONFIG='pkg-config'

What did you do?

Code: https://go.dev/play/p/8UUAdr7Vizz

The reflect package widely trusts that exported methods from the reflect.Type interface correspond to a real type, while at the same time relying on it being represented by an rtype. This assumption is unsound when combined with the ability to shadow interface methods (even those with other private methods) by embedding the original definition of the interface.

What did you see happen?

A crash:

unexpected fault address 0xdeadbeef
fatal error: fault
[signal SIGSEGV: segmentation violation code=0x1 addr=0xdeadbeef pc=0x48ba3f]

goroutine 1 gp=0x173d065161e0 m=0 mp=0x553480 [running]:
runtime.throw({0x48c254?, 0x173d06526070?})
	/usr/local/go-faketime/src/runtime/panic.go:1243 +0x48 fp=0x173d06586e30 sp=0x173d06586e00 pc=0x4776c8
runtime.sigpanic()
	/usr/local/go-faketime/src/runtime/signal_unix.go:945 +0x285 fp=0x173d06586e90 sp=0x173d06586e30 pc=0x478b25
main.main()
	/tmp/sandbox2303561854/prog.go:28 +0x1f fp=0x173d06586eb8 sp=0x173d06586e90 pc=0x48ba3f
runtime.main()
	/usr/local/go-faketime/src/runtime/proc.go:302 +0x407 fp=0x173d06586fe0 sp=0x173d06586eb8 pc=0x446247
runtime.goexit({})
	/usr/local/go-faketime/src/runtime/asm_amd64.s:1264 +0x1 fp=0x173d06586fe8 sp=0x173d06586fe0 pc=0x47cce1

What did you expect to see?

A panic due to the incorrect type cast

Metadata

Metadata

Assignees

Labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

Status
No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions