go: cmd/compile: internal compiler error: Type.Elem UNSAFEPTR

What version of Go are you using (go version)?

$ go version
go version devel +4091cf972a Sun Mar 31 23:35:35 2019 +0000 linux/amd64

Does this issue reproduce with the latest release?

reproducible only on tip

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/travis/.cache/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/travis/gopath"
GOPROXY=""
GORACE=""
GOROOT="/home/travis/.gimme/versions/go"
GOTMPDIR=""
GOTOOLDIR="/home/travis/.gimme/versions/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build848806544=/tmp/go-build -gno-record-gcc-switches"

What did you do?

I have a pretty old package with some hacks for optimization. I use some of its features in my web framework. In travis, I check if the framework pass the tests on tip. One of the steps in travis script is the go get -v. When go get tries to precompile that old package, it crashes.

So, one of the files looks like this:

package runtimer

import (
	"unsafe" // #nosec
)

func PtrToString(ptr unsafe.Pointer) string {
	return *(*string)(ptr)
}

func PtrToStringPtr(ptr unsafe.Pointer) *string {
	return (*string)(ptr)
}

func PtrPtrToStringPtr(ptr *unsafe.Pointer) *string {
	return (*string)(*ptr) // <- compiler complains about this line
}

Then I’ve commented out the last func.

Then the file looks like this:

package runtimer

import (
	"unsafe" // #nosec
)

func PtrToString(ptr unsafe.Pointer) string {
	return *(*string)(ptr)
}

func PtrToStringPtr(ptr unsafe.Pointer) *string {
	return (*string)(ptr) // <- and then it complains about this line
}
/*
func PtrPtrToStringPtr(ptr *unsafe.Pointer) *string {
	return (*string)(*ptr)
}
*/

What did you expect to see?

unsafe.Pointer works as it work two years ago

What did you see instead?

# github.com/gramework/runtimer
../runtimer/utils.go:16:2: internal compiler error: Type.Elem UNSAFEPTR
goroutine 34 [running]:
runtime/debug.Stack(0x1039ae0, 0xc00000e018, 0x0)
	/home/travis/.gimme/versions/go/src/runtime/debug/stack.go:24 +0x9d
cmd/compile/internal/gc.Fatalf(0xe8ef7d, 0xc, 0xc0007c7550, 0x1, 0x1)
	/home/travis/.gimme/versions/go/src/cmd/compile/internal/gc/subr.go:190 +0x292
cmd/compile/internal/types.(*Type).Elem(0xc000061e60, 0xc000538460)
	/home/travis/.gimme/versions/go/src/cmd/compile/internal/types/type.go:801 +0xff
cmd/compile/internal/ssa.(*Func).computeZeroMap(0xc000804000, 0xe12f01)
	/home/travis/.gimme/versions/go/src/cmd/compile/internal/ssa/writebarrier.go:391 +0x101
cmd/compile/internal/ssa.writebarrier(0xc000804000)
	/home/travis/.gimme/versions/go/src/cmd/compile/internal/ssa/writebarrier.go:80 +0x6b
cmd/compile/internal/ssa.Compile(0xc000804000)
	/home/travis/.gimme/versions/go/src/cmd/compile/internal/ssa/compile.go:90 +0x476
cmd/compile/internal/gc.buildssa(0xc0003c9b80, 0x0, 0x0)
	/home/travis/.gimme/versions/go/src/cmd/compile/internal/gc/ssa.go:288 +0xbf3
cmd/compile/internal/gc.compileSSA(0xc0003c9b80, 0x0)
	/home/travis/.gimme/versions/go/src/cmd/compile/internal/gc/pgen.go:297 +0x4d
cmd/compile/internal/gc.compileFunctions.func2(0xc000404de0, 0xc000407200, 0x0)
	/home/travis/.gimme/versions/go/src/cmd/compile/internal/gc/pgen.go:362 +0x49
created by cmd/compile/internal/gc.compileFunctions
	/home/travis/.gimme/versions/go/src/cmd/compile/internal/gc/pgen.go:360 +0x128

About this issue

  • Original URL
  • State: open
  • Created 5 years ago
  • Comments: 22 (18 by maintainers)

Most upvoted comments

With more than 4 concurrent compilation, all of them will modify the global lineno variable concurrently, so we won’t have the right ineno where error occurs.

Right. We’d have to plumb the line number to the error reporter some other way, so that it uses the function-currently-being-compiled line number instead of the global one.

We’re on a slow burn to remove all the global variables in the compiler anyway. This would be one step in that direction as well.

Honestly, I don’t think that changing the compiler behavior in such a way that folks can’t use basically one of the unsafe features is a good idea for a release.

We do this all the time for unexported API. The fact that the function named runtime.newobject even exists from one release to the next is surprising. For example, all of these functions disappeared from package runtime from 1.11 to 1.12:

< acquirep1
< casp
< clearScheduledCallback
< convT2E16
< convT2E32
< convT2E64
< convT2Eslice
< convT2Estring
< convT2I16
< convT2I32
< convT2I64
< convT2Islice
< convT2Istring
< endcgo
< gchelper
< gchelperstart
< gcprocs
< genasm
< getfull
< gosweepdone
< gosweepone
< hasprefix
< helpgc
< internal_cpu_initialize
< maxSliceCap
< mhelpgc
< needaddgcproc
< pauseSchedulerUntilCallback
< pauseSchedulerUntilCallback
< pauseSchedulerUntilCallback
< poll_runtimeNano
< poll_runtime_pollServerDescriptor
< scavengelist
< scavengetreap
< scavengeTreapNode
< scheduleCallback
< sleepUntilCallback
< time_runtimeNano

linkname is not even an unsafe feature. It’s not documented in the unsafe package or the unsafe section of the spec. It’s doubly unsafe. We never intended it to be used outside the stdlib (which needs it to, e.g., allow reflect to access runtime services).

If you’re using linkname, the onus is on you to adapt to changes in the compiler and runtime.

#31121 is about exported API, and that’s a totally different ballgame. For that we have the Go 1 compatibility guarantee. I think the relevant clause is

Bugs. If a compiler or library has a bug that violates the specification, a program that depends on the buggy behavior may break if the bug is fixed. We reserve the right to fix such bugs.

But I agree that it’s a grey area, and whether #31121 fits in that category isn’t as clear cut as this issue is.

That’s because the compiler has control over all calls to runtime.newobject (except for linkname shenanigans, of course), and ensures that the type of the result of that call is always correct - a pointer to a base type.