should this uintptr->unsafe.Pointer panic in go1.3?

187 views
Skip to first unread message

James Bardin

unread,
May 21, 2014, 4:48:53 PM5/21/14
to golan...@googlegroups.com

The current vet tool warns about this, but the release notes say that this is illegal, and should fail (runs fine with go1.3beta2). 

a := "ok"
var b *string

p := uintptr(unsafe.Pointer(&a))
b = (*string)(unsafe.Pointer(p))

fmt.Println(*b)




Rui Ueyama

unread,
May 21, 2014, 5:03:11 PM5/21/14
to James Bardin, golang-nuts
"Illegal" does not mean that such program is expected to always fail. Something bad may happen, but may not, depending on other conditions. In your case, the value at the address in a variable p is a constant string, so it's pretty likely that that's still there when fmt.Println is called, but it's not guaranteed, so you shouldn't rely on that.

James Bardin

unread,
May 21, 2014, 5:20:43 PM5/21/14
to golan...@googlegroups.com, James Bardin


On Wednesday, May 21, 2014 5:03:11 PM UTC-4, Rui Ueyama wrote:

"Illegal" does not mean that such program is expected to always fail. Something bad may happen, but may not, depending on other conditions. In your case, the value at the address in a variable p is a constant string, so it's pretty likely that that's still there when fmt.Println is called, but it's not guaranteed, so you shouldn't rely on that.


I'm aware of why, it's just that the release notes say: "Programs that use package unsafe to store uintptrs in pointer values are illegal and will crash if the runtime detects the behavior". 

This seems like a basic example of storing a uintptr into a pointer that should be detected; should it be filed as a bug?


Rui Ueyama

unread,
May 21, 2014, 5:27:49 PM5/21/14
to James Bardin, golang-nuts
I think it just says "if the runtime does not detect the behavior, it may or may not crash", no?


--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Ian Lance Taylor

unread,
May 21, 2014, 6:43:33 PM5/21/14
to James Bardin, golang-nuts
No, this is not a bug. The runtime does not promise to detect the
bug. It only promises that if it does detect it, it will crash.

The runtime is only likely to detect the bug if you store the bad
pointer in the heap, not the stack, and if the garbage collector runs.

Ian

Russ Cox

unread,
May 22, 2014, 11:13:59 AM5/22/14
to James Bardin, golang-nuts
On Wed, May 21, 2014 at 5:20 PM, James Bardin <j.ba...@gmail.com> wrote:
On Wednesday, May 21, 2014 5:03:11 PM UTC-4, Rui Ueyama wrote:
"Illegal" does not mean that such program is expected to always fail. Something bad may happen, but may not, depending on other conditions. In your case, the value at the address in a variable p is a constant string, so it's pretty likely that that's still there when fmt.Println is called, but it's not guaranteed, so you shouldn't rely on that.


I'm aware of why, it's just that the release notes say: "Programs that use package unsafe to store uintptrs in pointer values are illegal and will crash if the runtime detects the behavior". 

This wording is not quite right. I'll fix it. s/store uintptrs/store integers/. 

This is a program that stores an integer in a pointer value:

package main
import (
"runtime"
"unsafe"
)
func main() {
var x *int
x = (*int)(unsafe.Pointer(uintptr(5)))
runtime.GC()
println(x)
}

It crashes in Go 1.3, because runtime.GC knows that 5 is not a valid pointer.

Your program is doing the opposite: it is storing a pointer into an integer. That's not okay either, because it hides the value from the garbage collector, but it's not something the runtime can detect: there are invalid pointers like 5 but there are no invalid integers.

This program hides a pointer in an integer value during a garbage collection:

package main
import (
"runtime"
"unsafe"
)
var (
sp *string
x  uintptr
)
func main() {
sp = new(string)
*sp = "hello"
println("sp:", *sp) // sp: hello

x = uintptr(unsafe.Pointer(sp))
sp = nil
runtime.GC()
sp = (*string)(unsafe.Pointer(x))

println("sp:", *sp) // sp: <not hello!>
}

Because the garbage collector could not see the pointer in x, it recycled the memory for the new(string); the final print does not print "hello" for *sp.

Russ

James Bardin

unread,
May 22, 2014, 11:25:46 AM5/22/14
to golan...@googlegroups.com, James Bardin

Thanks Russ, that makes sense and is really the behavior I would expect.

I think the confusion is that the release notes make it sound as if the runtime will panic anytime it encounters this.

Would it also make sense to change the note to: "Programs that use package unsafe to store integers in pointer values are illegal and will crash if the runtime detects an invalid pointer"

The behavior is questionable, but it's the invalid pointer that causes a panic.
Reply all
Reply to author
Forward
0 new messages