Assigning a value to a function pointer

113 views
Skip to first unread message

ju...@sqreen.io

unread,
Dec 23, 2019, 8:49:32 AM12/23/19
to golang-nuts
Hello,

The following Go program has a valid syntax:
https://play.golang.org/p/V7bIGnTu1fb

But I cannot find any way of assigning a value to the function pointer `f` even using the `unsafe` package.
My main reason for willing this is to be able to:
- atomically load a dynamic address.
- avoid using instead `*interface{}` (that I can atomically load + type-assert + call).

Thanks for your help,
Julio

Jan Mercl

unread,
Dec 23, 2019, 8:56:03 AM12/23/19
to ju...@sqreen.io, golang-nuts
On Mon, Dec 23, 2019 at 2:49 PM <ju...@sqreen.io> wrote:

> But I cannot find any way of assigning a value to the function pointer `f` even using the `unsafe` package.

https://play.golang.org/p/qP5kuSCW6dO

Note that while you can a pointer to a function, you rarely need that.
Function is just a value like int (in the very first approximation).

> My main reason for willing this is to be able to:
> - atomically load a dynamic address.

Depends very much on what a "dynamic address" is. Functions are
normally static. Functions literals a bit less, but actually the code
address is always fixed in both cases, only the closure parameter, if
any, differs.

ju...@sqreen.io

unread,
Dec 23, 2019, 12:41:41 PM12/23/19
to golang-nuts

> But I cannot find any way of assigning a value to the function pointer `f` even using the `unsafe` package.

https://play.golang.org/p/qP5kuSCW6dO

Thanks, unfortunately the asm shows that what gets into `f` is the stack address of `f0` and not the address of the function:

LEAQ    "".foo·f(SB), DX
MOVQ    DX
, "".f0(SP) // f0 = foo
MOVQ    
"".f0(SP), DX // f = &f0
MOVQ    
(DX), AX // *f

I'd love to find how to directly use the address without any local variable :-)

Jan Mercl

unread,
Dec 23, 2019, 1:00:08 PM12/23/19
to ju...@sqreen.io, golang-nuts
On Mon, Dec 23, 2019 at 6:41 PM <ju...@sqreen.io> wrote:

>> > But I cannot find any way of assigning a value to the function pointer `f` even using the `unsafe` package.
>>
>> https://play.golang.org/p/qP5kuSCW6dO
>
> Thanks, unfortunately the asm shows that what gets into `f` is the stack address of `f0` and not the address of the function:

Nothing unfortunate about it, that's a perfectly correct value. I
mentioned before that you don't want a pointer to a function but a
function value, that one is found in f0 in the example.

However, the value of f0 is _not_ the function's code address. Go
function values are a pointer to a variable length structure that
supports the closes over variables of the function.

Axel Wagner

unread,
Dec 23, 2019, 1:28:50 PM12/23/19
to Jan Mercl, ju...@sqreen.io, golang-nuts
If what you want is a) assume that a `func()` is pointer-shaped and b) treat it as an unsafe.Pointer for use with atomics, then that's a problem that - as all problems in computer science - can be solved with another layer of indirection: https://play.golang.org/p/o0DvCxPTG1O
As Jan mentioned, a `func()`-value (disclaimer: as implemented by gc currently) is not the actual code-address. But this still lets you move between `func()` and `unsafe.Pointer`.

However, I feel compelled to point out that assumption a) is not in general true. It *does* hold in the current implementation of gc on common architectures, but I don't know if it's true for gccgo, I wouldn't be surprised if it isn't true for GopherJS or on wasm and someone recently told me that it's not true for tinygo. It's also, as far as I can tell, not covered by the rules for unsafe.Pointer: https://golang.org/pkg/unsafe/#Pointer
So while I *think* it will work as expected, there is no guarantee that it will continue to do so.

So, in conclusion: If you do that, then when it will break, it will do so non-deterministically, with a confusing failure mode and only when you're not looking ;) I strongly advise you against it and treat the memory layout of func() as the opaque implementation detail that it is intended to be. And just use sync.Value if you need to operate on it with atomics.

--
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.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CAA40n-W3%3Dm-r%3DYQtnwbQOmyA31GegS4tu5Wqm4oi9s0Bh2QOgw%40mail.gmail.com.
Reply all
Reply to author
Forward
0 new messages