Corruption issue when passing GoString from C to Go via cgo

Issue #6 resolved
Keith Lea created an issue

I'm having an issue calling Go functions from C. Arguments passed to my Go function are being corrupted, but only when a GoString is the first argument to the function. This appears to be ios-specific, as I can't reproduce on OS X with stock Go 1.4.

See attached Xcode project (for iOS) and simple Go program (for OS X).

When running GoBugReportIOS on my iPhone 6 and iPhone 6 Plus, it crashes because it gets the wrong value for the function pointer:

Hello from Go! I'm in func main()!
Hello from Objective C! I'm in int iosmain()!
Go: (no path) Calling 91d9 ( b16e4 ) - 37337 ( 726756 ) 
C: Calling 91d9 / b16e4 - as pointer: 0x91d9
Go: (path=ok) Calling 91d900000000 ( b16e400000000 ) - 160361193930752 ( 3121393252171776 ) 
C: Calling 91d900000000 / b16e400000000 - as pointer: 0x0

The same problem does not exist on OS X:

$ ./GoBugReportOSX 
Hello from Go! I'm in func main()!
Go: (no path) Calling 4000a40 ( 40955d0 ) - 67111488 ( 67720656 ) 
C: Calling 4000a40 / 40955d0 - as pointer: 0x4000a40
C: Successfully called callMeFromGo with arg 0x40955d0 - useMeForData
Go: (path=ok) Calling 4000a40 ( 40955d0 ) - 67111488 ( 67720656 ) 
C: Calling 4000a40 / 40955d0 - as pointer: 0x4000a40
C: Successfully called callMeFromGo with arg 0x40955d0 - useMeForData

Comments (8)

  1. minux repo owner

    It has something to do with function argument alignments.

    I'm wondering if Obj-C has different function argument alignment rules (for 64-bit integer) than C.

  2. Keith Lea reporter

    I can test tomorrow. Should be pretty easy to confirm, just rename main.c to main.m in the OS X folder and rebuild.

  3. minux repo owner

    I think I found the problem.

    You've used _cgo_export.h generated for host, and the type of GoInt is different on ARM and x86_64.

    Essentially Go thinks GoString is two words (one pointer and one 32-bit length), but the Obj-C code thinks the GoString structure is made of one pointer and one 64-bit integer, this mismatches causes the function argument to be incompatible.

    Please use _cgo_export.h generated with GOARCH=arm cgo (the usual way is to use GOARCH=arm CGO_ENABLED=1 go build -work main.go, and then copy the correct _cgo_export.h from the displayed $WORK)

  4. Keith Lea reporter

    Wow! Yes you're right! I wonder if _cgo_export.h should include a header explaining what arch it was generated for. Or even an #ifdef!

  5. Log in to comment