What happened ?
var n interface{} = 2
var pn = &n
var pf = (*int64)(unsafe.Pointer(pn))
fmt.Println(pf)
fmt.Println(pn)
fmt.Println(*pn) // 2
fmt.Println(*pf) // not 2
*pf = 9
fmt.Println(*pn) //error invalid memory address or nil pointer dereference
fmt.Println(*pf) // 9
My question is Why is *pf not equal to *pn and error ?
Thanks for your reply.
n
is of an interface{}
type, so in memory it is represented by a struct of 2 values: a type and data. The type comes first. So you dereference it and interpret as a number.
*pf = 9
breaks that structure, so next time you try to dereference it - the runtime fails.
An interface value contains information about the type of the data it contains and then the actual value (or a pointer to the value). When you cast a pointer to the interface to *int64
, the *int64
will point into some random data in the interface value (which today happens to be a pointer to the information about the type, but this is allowed to change, this part of the language is not covered by the compatibility guarantee). When you then overwrite that data, things break, unsafe is called unsafe for a reason.
*pf
is not equal to *pn
because they have different types even though they might contain the same bit pattern.
For simplicity let’s think we have 64-bit machine. n
is pair of 2 words of 64-bit: first is a pointer to a variable, second is a pointer to information about type - so called itab
.
When you get a value pointed by pn
compiler knows you want value of an interface, so it goes by the first pointer and returns int value. Compiler thinks pf
is a pointer to float64
. So it lets. You to overwrite first word in the interface n
with some likely incorrect address (equal to binary value of 9.0
). Next time you see the value in the interface compiler uses incorrect address. And return some garbage or even SegFault.
That’s why it’s called unsafe.Pointer
and is not recommended to use. Until you have very serious concerns.