Skip to content

runtime: range over string with ill-formated string leads to nil pointer dereferenced #73597

Closed
@MKLepium

Description

@MKLepium

Go version

1.24

Output of go env in your module/workspace:

It works even in the go playground, however here is my go env output:
AR='ar'
CC='clang'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='clang++'
GCCGO='gccgo'
GO111MODULE='on'
GOARCH='arm64'
GOARM64='v8.0'
GOAUTH='netrc'
GOBIN='/Users/mgk/go/bin'
GOCACHE='/Users/mgk/Library/Caches/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/Users/mgk/Library/Application Support/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOGCCFLAGS='-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/48/cr9dcv1d6tqghyswpt5d306m0000gn/T/go-build3280202846=/tmp/go-build -gno-record-gcc-switches -fno-common'
GOHOSTARCH='arm64'
GOHOSTOS='darwin'
GOINSECURE=''
GOMOD='/dev/null'
GOMODCACHE='/Users/mgk/go/pkg/mod'
GOOS='darwin'
GOPATH='/Users/mgk/go'
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/Users/mgk/sdk/go1.24.1'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/Users/mgk/Library/Application Support/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/Users/mgk/sdk/go1.24.1/pkg/tool/darwin_arm64'
GOVCS=''
GOVERSION='go1.24.1'
GOWORK=''
PKG_CONFIG='pkg-config'

What did you do?

I am working on a pretty big project where multiple libraries are working together. I have recently found out the weird following behaviour after one of the libraries in use produced a string with a nil-data pointer and a non-zero length.

https://go.dev/play/p/xGBLKtttmdC
I have put the example into this string, however here once again:

var s string

// Der Stacktrace zeigt uns nen String wie diesen hier
// Sowas kann im Normalfall gar nicht entstehen, aber zur Demo Hier mal ein Beispiel
hdr := reflect.StringHeader{
	Data: 0,  // nil pointer
	Len:  40, // non-zero length
}

// Convert to string using unsafe
s = *(*string)(unsafe.Pointer(&hdr))

// Extract StringHeader from the resulting string
hdr2 := (*reflect.StringHeader)(unsafe.Pointer(&s))

// Print pointer and length
fmt.Printf("Data pointer: %v\n", hdr2.Data)
fmt.Printf("Length: %d\n", hdr2.Len)

// This will panic:
for i, r := range s {
	fmt.Printf("Index: %d, Rune: %c\n", i, r)
}

What did you see happen?

The range will panic since (presumably) the range does only check if the len is greater than 0, not if the Data pointer is valid.

What did you expect to see?

I am not sure if this is expected behaviour in the go runtime. I can also not tell you which of the libraries I use in my project produced such a string, however I will continue to investigate and try to find the broken library.

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugReportIssues describing a possible bug in the Go implementation.compiler/runtimeIssues related to the Go compiler and/or runtime.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions