Over on r/golang, an interesting question was asked :
[Is it] possible to parse a struct or interface to get its pointer address as an integer? [...]
The practical answer today is yes, as noted in the answers to the question. You can convert any Go pointer to
uintptr
by going through
unsafe.Pointer()
, and then convert the
uintptr
into some more conventional integer type if you want. If you're going to convert to another integer type, you should probably use
uint64
for safety, since that should hold any
uintptr
value on any current Go platform.
However, the theoretical answer is no, in that this conversion doesn't quite get you what you might think it does. What this conversion really gives you is the address that the addressable value had at the moment the conversion to
uintptr
was done. Go very carefully does not guarantee that this past address is the same as the current address, although it always will be today.
(I'm assuming here that there are other references to the addressable value that keep it from being garbage collected.)
Go's current garbage collector is a non-compacting garbage collector, where once things are allocated somewhere in memory, they never move for as long as they're alive. Since a non-compacting garbage collector has stable memory addresses for things, converting an address to an integer gives you something that is always the integer value of the current address of that thing. However, there are also compacting garbage collectors , which move live things around during garbage collection for various reasons. In these garbage collectors, the memory address of things is not stable.
Go is deliberately specified so that you could implement it using a compacting GC, and at one point this was the long term plan . When it moved things as part of garbage collection, such a Go would update the address of actual pointers to them to the new value. However, it would not magically update integer values derived from those pointers, whether they're
uintptr
s or some other integer types. In a compacting GC world, getting the
uintptr
of the address of something twice at different times could give you two different values. Each value was accurate at the moment you got it, but it's not guaranteed to be accurate one instant past that; a GC pass could happen at any time and thus the thing could be moved at any time.
Leaving the door open for a compacting GC is one of the reasons that the rules surrounding the use of
unsafe.Pointer()
and
uintptr
are so carefully and narrowly specified, as we've seen before . In fact the documentation points this out explicitly:
A uintptr is an integer, not a reference. Converting a Pointer to a uintptr creates an integer value with no pointer semantics. Even if a uintptr holds the address of some object, the garbage collector will not update that uintptr's value if the object moves , nor will that uintptr keep the object from being reclaimed.
(The emphasis is mine.)
The Go garbage collector never moves things today, which leads to the practical answer for today of 'yes, you can do this'. But the theoretical answer is that the address of things could be constantly changing, and maybe someday in the future they sometimes will.
Update : As pointed out in the r/golang comments on my entry , I'm wrong here. In Go today, stacks are movable as stack usage grows and shrinks, and you can take the address of a value that is on the stack and that subsequently gets moved with the stack.