Given an object obj is there a guarantee that
uintptr(unsafe.Pointer(&obj))
will always evaluate to the same value regardless of w
There is no such guarantee, exactly so that it is possible to implement a moving collector.
In fact, although the garbage collector does not move heap objects today, in Go 1.3 stacks can move when needing to grow, so it is entirely possible that
var obj int
fmt.Println(uintptr(unsafe.Pointer(&obj)))
bigFunc()
fmt.Println(uintptr(unsafe.Pointer(&obj)))
will print two different pointers, because bigFunc grew the stack, causing obj and everything else on the stack to move.
No absolute guarantee. Especially if Go adds compaction to its mark and sweep garbage collector.
Addresses stored in pointer types and type unsafe.Pointer will be updated, if necessary, by any garbage collector. Addresses stored in type uintptr as unsigned integers will not be updated by a garbage collector. The uintptr
type is not a pointer type, it's an integer type.
Numeric types
uintptr
an unsigned integer large enough to store the uninterpreted bits of a pointer valueconverting unsafe.Pointers to uintptr
Pointers should have been kept in unsafe.Pointers - not uintptrs - always.
Russ
For your example,
uintptr(unsafe.Pointer(&obj))
you have an unsigned integer, not an address.
There isn't anything in the specification that guarantees this, probably to allow implementations of the language to use compacting garbage collectors in the future. In this golang-nuts thread one of the developers suggests that a compacting GC would be possible provided unsafe.Pointer
values were pinned in memory, but this couldn't extend to all unitptr
values.
For the current Go runtime I believe it is true, but relying on it would still be undefined behaviour. There are a few caveats though:
If obj
is a zero size type, the value of the expression may not be unique, as described in the spec.
Over the lifetime of a program, a particular uintptr
value might refer to different objects.