Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
MKLepium opened this issue May 5, 2025 · 3 comments
Labels
BugReport Issues describing a possible bug in the Go implementation. compiler/runtime Issues related to the Go compiler and/or runtime.

Comments

@MKLepium
Copy link

MKLepium commented May 5, 2025

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.

@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label May 5, 2025
@mateusz834
Copy link
Member

mateusz834 commented May 5, 2025

First of all, code now should avoid using the reflect.StringHeader (it is depereated) and the unsafe.String should be used instead. If we look at the unsafe.Strings docs, you can see that:

if ptr is nil and len is not zero, a run-time panic occurs

go/src/unsafe/unsafe.go

Lines 253 to 264 in 8ec5559

// String returns a string value whose underlying bytes
// start at ptr and whose length is len.
//
// The len argument must be of integer type or an untyped constant.
// A constant len argument must be non-negative and representable by a value of type int;
// if it is an untyped constant it is given type int.
// At run time, if len is negative, or if ptr is nil and len is not zero,
// a run-time panic occurs.
//
// Since Go strings are immutable, the bytes passed to String
// must not be modified as long as the returned string value exists.
func String(ptr *byte, len IntegerType) string

So i would say that this is the expected behavior, and such strings where data == nil and Len > 0 are invalid.

@gabyhelp gabyhelp added the BugReport Issues describing a possible bug in the Go implementation. label May 5, 2025
@MKLepium
Copy link
Author

MKLepium commented May 5, 2025

I kind of figured that this would be the case.
Then I guess this ticket is obsolete, since this seems to be expected behaviour.

@MKLepium MKLepium closed this as completed May 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
BugReport Issues describing a possible bug in the Go implementation. compiler/runtime Issues related to the Go compiler and/or runtime.
Projects
None yet
Development

No branches or pull requests

4 participants