go: runtime: writebarrierptr panic in isolated code snippet on Go 1.8.3

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

1.8.3.

Does this issue reproduce with the latest release?

The issue does not repro with 1.9

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

Repro’ed on macOS and linux.

What did you do?

package main

import (
	"fmt"
	"unsafe"
	"time"
)

func main() {
	for i := 0; i < 1000000; i++ {
		x := unsafe.Pointer(uintptr(0x27))
		fmt.Printf("%p\n", x)
		time.Sleep(1)
	}
}

What did you expect to see?

No crash

What did you see instead?

....
0x27
0x27
0x27
0x27
0x27
0x27
runtime: writebarrierptr *0xc4200e80e0 = 0x27
fatal error: bad pointer in write barrier

runtime stack:
runtime.throw(0x10b6a19, 0x1c)
	/usr/local/Cellar/go/1.8.3/libexec/src/runtime/panic.go:596 +0x95
runtime.writebarrierptr.func1()
	/usr/local/Cellar/go/1.8.3/libexec/src/runtime/mbarrier.go:208 +0xbd
runtime.systemstack(0xc42001e600)
	/usr/local/Cellar/go/1.8.3/libexec/src/runtime/asm_amd64.s:327 +0x79
runtime.mstart()
	/usr/local/Cellar/go/1.8.3/libexec/src/runtime/proc.go:1132

goroutine 1 [running]:
runtime.systemstack_switch()
	/usr/local/Cellar/go/1.8.3/libexec/src/runtime/asm_amd64.s:281 fp=0xc420042cb8 sp=0xc420042cb0
runtime.writebarrierptr(0xc4200e80e0, 0x27)
	/usr/local/Cellar/go/1.8.3/libexec/src/runtime/mbarrier.go:209 +0x96 fp=0xc420042cf0 sp=0xc420042cb8
fmt.(*pp).printArg(0xc4200e80c0, 0x1097480, 0x27, 0x70)
	/usr/local/Cellar/go/1.8.3/libexec/src/fmt/print.go:605 +0xa10 fp=0xc420042d78 sp=0xc420042cf0
fmt.(*pp).doPrintf(0xc4200e80c0, 0x10b37d3, 0x3, 0xc420042f68, 0x1, 0x1)
	/usr/local/Cellar/go/1.8.3/libexec/src/fmt/print.go:998 +0x11e7 fp=0xc420042e58 sp=0xc420042d78
fmt.Fprintf(0x110a140, 0xc42000c018, 0x10b37d3, 0x3, 0xc420042f68, 0x1, 0x1, 0x13, 0x2, 0xc420446000)
	/usr/local/Cellar/go/1.8.3/libexec/src/fmt/print.go:181 +0x76 fp=0xc420042ec0 sp=0xc420042e58
fmt.Printf(0x10b37d3, 0x3, 0xc420042f68, 0x1, 0x1, 0x5, 0x0, 0x0)
	/usr/local/Cellar/go/1.8.3/libexec/src/fmt/print.go:190 +0x72 fp=0xc420042f20 sp=0xc420042ec0
main.main()
	/Users/max/src/go/src/play/play.go:12 +0x8c fp=0xc420042f88 sp=0xc420042f20
runtime.main()
	/usr/local/Cellar/go/1.8.3/libexec/src/runtime/proc.go:185 +0x20a fp=0xc420042fe0 sp=0xc420042f88
runtime.goexit()
	/usr/local/Cellar/go/1.8.3/libexec/src/runtime/asm_amd64.s:2197 +0x1 fp=0xc420042fe8 sp=0xc420042fe0

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 21 (9 by maintainers)

Commits related to this issue

Most upvoted comments

@akalin-keybase Go is not C, and Go has a simple rule: a variable of pointer type must hold a pointer value. Tricks like converting an integer to a pointer type, while valid in C, are not valid in Go.

@akalin-keybase That is unsafe at the moment. There are two reasons:

  1. Garbage collection can happen at the start of the cgo wrapper for the C function.
  2. The go<->c pointer checker runs in this wrapper and would also see (and barf on? I’m not sure) this bad pointer.

The first we might be able to fix with the right sprinkling of nosplit directives in cgo generated code. The second seems harder, as the test should fail on some pointers, and from C we can manufacture almost any pointer. Unless we turn this check off altogether.

Neither can happen on returns, so there immediately casting to uintptr is ok.

The only workaround I can see at the moment is to do the cast on the C side and pass uintptr across the c/go boundary.