Skip to content

cmd/compile: -d=checkptr should not reject unaligned pointers to non-pointer data #37298

@cespare

Description

@cespare

I'm testing some code with Go 1.14 and found that some tests are failing which passed in Go 1.13 while running under -race.

This is due to the new checkptr checks that are enabled by -race. Here's a minimized repro:

// +build ignore

package main

import (
	"fmt"
	"reflect"
	"unsafe"
)

func main() {
	b := make([]byte, 20)
	s := unsafeInts(b, 1) // with 0 or 8, no failure
	fmt.Println(s)
}

func unsafeInts(b []byte, offs int) []int64 {
	var s []int64
	sh := (*reflect.SliceHeader)(unsafe.Pointer(&s))
	sh.Data = uintptr(unsafe.Pointer(&b[offs]))
	sh.Cap = (len(b) - offs) / 8
	sh.Len = sh.Cap
	return s
}
$ go1.13.4 run -race checkptr.go
[0 0]
$ go1.14beta1 run -race checkptr.go
panic: runtime error: unsafe pointer conversion

goroutine 1 [running]:
reflect.Value.Int(...)
        /home/caleb/sdk/go1.14beta1/src/reflect/value.go:974
fmt.(*pp).printValue(0xc0000a08f0, 0x5150a0, 0xc0000bc001, 0x186, 0x76, 0x1)
        /home/caleb/sdk/go1.14beta1/src/fmt/print.go:749 +0x3694
fmt.(*pp).printValue(0xc0000a08f0, 0x5136e0, 0xc0000aa020, 0x97, 0x76, 0x0)
        /home/caleb/sdk/go1.14beta1/src/fmt/print.go:869 +0xfd3
fmt.(*pp).printArg(0xc0000a08f0, 0x5136e0, 0xc0000aa020, 0x76)
        /home/caleb/sdk/go1.14beta1/src/fmt/print.go:716 +0x25b
fmt.(*pp).doPrintln(0xc0000a08f0, 0xc00005af50, 0x1, 0x1)
        /home/caleb/sdk/go1.14beta1/src/fmt/print.go:1173 +0xae
fmt.Fprintln(0x55d520, 0xc0000b8008, 0xc00005af50, 0x1, 0x1, 0x432142, 0xc000092058, 0x0)
        /home/caleb/sdk/go1.14beta1/src/fmt/print.go:264 +0x66
fmt.Println(...)
        /home/caleb/sdk/go1.14beta1/src/fmt/print.go:274
main.main()
        /home/caleb/p/misc/checkptr/checkptr.go:14 +0x18f
exit status 2
$

This error isn't particularly helpful (why is it unsafe?) and when I looked at the source, it still wasn't clear to me what the problem is.

	// Check that (*[n]elem)(p) is appropriately aligned.
	// TODO(mdempsky): What about fieldAlign?
	if uintptr(p)&(uintptr(elem.align)-1) != 0 {
		throw("checkptr: unsafe pointer conversion")
	}

Even if there's some problem with unaligned pointers into the Go heap, in my application the backing data doesn't come from make([]byte) but rather from unix.Mmap. And my CPU (amd64) should have no problem with reading unaligned data, right?

It's also strange that the crash didn't happen in my code, but inside the reflect-y fmt code that looked at my data. (Not that it matters, but in my real code the crash isn't triggered by fmt but rather by go-cmp, also via use of reflect.Value.Int.)

/cc @mdempsky

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions