Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/cgo: pointer to exported function in package scope only works if cast to another type #7665

Closed
andlabs opened this issue Mar 30, 2014 · 9 comments

Comments

@andlabs
Copy link
Contributor

commented Mar 30, 2014

What does 'go version' print?
go version devel +a70a32dc121a Thu Mar 27 20:23:16 2014 +0000 linux/amd64
go version devel +1afdecdd77c1 Sat Mar 29 17:10:25 2014 -0400 darwin/amd64 (testing both
darwin/amd64 and darwin/386)

What steps reproduce the problem?
If possible, include a link to a program on play.golang.org.

package main

import "fmt"
import "unsafe"

// extern void f(void);
import "C"

//export f
func f() {}

var bad unsafe.Pointer = C.f
var good uintptr = uintptr(C.f)

func main() {
    fmt.Printf("0x%X | 0x%X 0x%X | 0x%X\n", bad, good, unsafe.Pointer(good), C.f)
}


What happened?
(this output from the linux/amd64 build running with go run)
0x0 | 0x400F00 0x400F00 | 0x400F00

What should have happened instead?
0x400F00 | 0x400F00 0x400F00 | 0x400F00

Please provide any additional information below.
It does not matter how C.f is stored in bad (if it is stored directly as above, if it is
a member of a structure, a member of a slice of structures (my use case, for
initialization), etc.): if it's not cast to uintptr() or something else, I get nil. This
only affects package scope (as the last print shows).
@minux

This comment has been minimized.

Copy link
Member

commented Mar 31, 2014

Comment 1:

interesting.

Labels changed: added release-go1.3, repo-main.

Status changed to Accepted.

@minux

This comment has been minimized.

Copy link
Member

commented Mar 31, 2014

Comment 2:

A simpler repro without cgo, two files: z0.c and z1.go
$ cat z0.c
void *·aaaa = (void *)42;
$ cat z1.go
package main
import "unsafe"
var aaaa unsafe.Pointer
var bbbb unsafe.Pointer = aaaa
func main() {
    println(bbbb)
}
$ go tool 6c z0.c
$ go tool 6g z1.go
$ go tool pack grc z.a z0.6 z1.6
$ go tool 6l z.a
$ ./6.out
0x0
Somehow the gc compile thinks that aaaa is zero, so no need to assign to bbbb.
(This bug seems to have always been there, as even Go 1.0 has it)
@rsc

This comment has been minimized.

Copy link
Contributor

commented Apr 3, 2014

Comment 3:

The static init code in cmd/gc assumes that if you have
var x = 1
var y = x
then it is okay to infer that var y = 1.
Similarly it assumes that if you have
var x int
var y = x
then it is okay to infer that y = 0. It can't see that you intend to set x behind the
compiler's back.
The workaround is to initialize the variable in a func init block:
var x int
var y int
func init() {
    // x set elsewhere
    y = x
}
I think that's fine for now, honestly. This does not come up very often, as evidenced by
the fact that the behavior produced no complaints for years.
Logically you can think about it as C.f being initialized during an init block itself,
so you have to wait until init blocks to use it.

Status changed to WorkingAsIntended.

@minux

This comment has been minimized.

Copy link
Member

commented Apr 6, 2014

Comment 4:

my contrived repro could be regarded as WAI, but the reason for the original issue is
much more difficult to see. We should do something there (for example, we can rewrite
every variable initialized with cgo into a function call (or any other form that force
the
gc to re-evaluate it at runtime):
e.g.
var f = C.f
is translated to:
var f = func() unsafe.Pointer { return __cgo_fp_f }()
What do you think?

Status changed to Thinking.

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

commented Apr 7, 2014

Comment 5:

Or perhaps we could have cgo simply reject attempts to initialize a Go global variable
with a C variable.
@andlabs

This comment has been minimized.

Copy link
Contributor Author

commented May 9, 2014

Comment 6:

I'm sorry; I should have posted my original use case; perhaps minux realized this but
I'm not sure:
https://github.com/andlabs/ui/blob/22315bca596b4607b6f63e2746dda9f942008dad/area_darwin.go#L32
In this scenario, I'm building an Objective-C class to talk to Cocoa at runtime. Each of
these function pointers are actually //export-ed Go functions defined later in the same
file. If I remove the uintptr conversions, the function pointers become NULL and either
class creation fails or the program crashes when one of these selectors gets called (I
forget which now).
@gopherbot

This comment has been minimized.

Copy link

commented May 9, 2014

Comment 7:

CL https://golang.org/cl/93200044 mentions this issue.
@rsc

This comment has been minimized.

Copy link
Contributor

commented May 9, 2014

Comment 8:

This issue was closed by revision e5c1050.

Status changed to Fixed.

@gopherbot

This comment has been minimized.

Copy link

commented Nov 3, 2014

Comment 9:

CL https://golang.org/cl/165400043 mentions this issue.

@andlabs andlabs added fixed labels Nov 3, 2014

@rsc rsc added this to the Go1.3 milestone Apr 14, 2015

@rsc rsc removed the release-go1.3 label Apr 14, 2015

@golang golang locked and limited conversation to collaborators Jun 25, 2016

This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
5 participants
You can’t perform that action at this time.