Go version
go version go1.24.4 darwin/arm64
Output of go env
in your module/workspace:
AR='ar'
CC='cc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='c++'
GCCGO='gccgo'
GO111MODULE=''
GOARCH='arm64'
GOARM64='v8.0'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/Users/fxrlv/Library/Caches/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/Users/fxrlv/Library/Application Support/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/mg/1l0261p97kzflrmx68mm4z7c0000gn/T/go-build2006285917=/tmp/go-build -gno-record-gcc-switches -fno-common'
GOHOSTARCH='arm64'
GOHOSTOS='darwin'
GOINSECURE=''
GOMOD='/tmp/checkptr/go.mod'
GOMODCACHE='/Users/fxrlv/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='darwin'
GOPATH='/Users/fxrlv/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/opt/homebrew/Cellar/go/1.24.4/libexec'
GOSUMDB='sum.golang.org'
GOTELEMETRY='on'
GOTELEMETRYDIR='/Users/fxrlv/Library/Application Support/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/opt/homebrew/Cellar/go/1.24.4/libexec/pkg/tool/darwin_arm64'
GOVCS=''
GOVERSION='go1.24.4'
GOWORK=''
PKG_CONFIG='pkg-config'
What did you do?
There is an inconsistency in how the checkptr
runtime check validates pointer arithmetic.
The issue is that checkptr
validates manual pointer arithmetic using uintptr
conversions but does not validate the unsafe.Add
function, which can perform equivalent potentially unsafe operations.
package main
import (
"fmt"
"unsafe"
)
func main() {
data := make([]byte, 10)
// This triggers checkptr validation and can panic with:
// "fatal error: checkptr: pointer arithmetic result points to invalid allocation"
manualArithmetic := func(offset int) *byte {
return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(unsafe.SliceData(data))) + uintptr(offset)))
}
// This does NOT trigger checkptr validation, even with equivalent dangerous operations
unsafeAdd := func(offset int) *byte {
return (*byte)(unsafe.Add(unsafe.Pointer(unsafe.SliceData(data)), offset))
}
// Both can be equally dangerous when offset >= len(data) or offset < 0
a := unsafeAdd(10) // No checkptr validation
b := manualArithmetic(10) // May trigger checkptr panic
fmt.Println(a)
fmt.Println(b)
}
$ go run -race main.go
fatal error: checkptr: pointer arithmetic result points to invalid allocation
goroutine 1 gp=0xc0000021c0 m=0 mp=0x100c056e0 [running]:
runtime.throw({0x100b0ac29?, 0x100b3e520?})
/opt/homebrew/Cellar/go/1.24.4/libexec/src/runtime/panic.go:1101 +0x38 fp=0xc000187ea0 sp=0xc000187e70 pc=0x100ab5b68
runtime.checkptrArithmetic(0x100a56ec0?, {0xc000187f30, 0x1, 0x0?})
/opt/homebrew/Cellar/go/1.24.4/libexec/src/runtime/checkptr.go:69 +0xa8 fp=0xc000187ed0 sp=0xc000187ea0 pc=0x100a58238
main.main.func1(...)
/tmp/checkptr/main.go:14
main.main()
/tmp/checkptr/main.go:24 +0x70 fp=0xc000187f40 sp=0xc000187ed0 pc=0x100b01550
runtime.main()
/opt/homebrew/Cellar/go/1.24.4/libexec/src/runtime/proc.go:283 +0x284 fp=0xc000187fd0 sp=0xc000187f40 pc=0x100a84ef4
runtime.goexit({})
/opt/homebrew/Cellar/go/1.24.4/libexec/src/runtime/asm_arm64.s:1223 +0x4 fp=0xc000187fd0 sp=0xc000187fd0 pc=0x100abc744
What did you see happen?
unsafe.Add
calls: No validation, no panics- Manual pointer arithmetic:
checkptr
validates and panics with "pointer arithmetic result points to invalid allocation"
What did you expect to see?
Both manual pointer arithmetic and unsafe.Add
should receive the same level of validation from checkptr
. If manual uintptr arithmetic is checked for validity, then unsafe.Add
calls should also be validated.
Comment From: gabyhelp
Related Issues
- runtime: checkptr incorrectly -race flagging when using \&^ arithmetic #40917 (closed)
- x/sys/unix: MmapPtr upsets checkptr #70721 (closed)
- runtime/checkptr: fatal error: checkptr: pointer arithmetic result points to invalid allocation #68415 (closed)
- runtime/checkptr: erroneous "pointer arithmetic result points to invalid allocation" #48501 (closed)
- proposal: cmd/go: consider adding unsafeptr to go vet during test list #57794 (closed)
- cmd/compile: -d=checkptr should not reject unaligned pointers to non-pointer data #37298 (closed)
- cmd/compile: fatal error: checkptr: pointer arithmetic computed bad pointer value #64467
- go build use -asan it panic. #69225 (closed)
- cmd/compile,runtime: checkptr false negatives for tiny-alloced objects #38872 (closed)
- cmd/compile: -d=checkptr should disable inlining reflect.Value.{Pointer,UnsafeAddr} even when package reflect is compiled without it #35073 (closed)
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
Comment From: zigo101
Isn't it just the purpose of unsafe.Add
? (to avoid checkptr)
Comment From: zigo101
Aha, it looks the effect of -race
is different from -gcflags=all=-d=checkptr
. The latter option doesn't report errors for both ways.
Sorry, my last comment is irrelevant.