13

I tried to run a simple in a go script from python and I got a segmentation fault. Here is my code:

main.go

package main

import (
    /*
typedef struct foo{
int a;
int b;
int c;
int d;
int e;
int f;
} foo;
*/
    "C"
)

func main() {}

//export Foo
func Foo(t []int) C.foo {
    return C.foo{}
}

main.py

# loading shared object
lib = cdll.LoadLibrary("main.so")

# go type
class GoSlice(Structure):
    _fields_ = [("data", POINTER(c_void_p)), ("len", c_longlong), ("cap", c_longlong)]

lib.Foo.argtypes = [GoSlice]
lib.Foo.restype = c_void_p

t = GoSlice((c_void_p * 5)(1, 2, 3, 4, 5), 5, 5)
f = lib.Foo(t)
print(f)

With that code, I got

140362617287784
[1]    23067 segmentation fault  python3 main.py

Now If I remove e and f from the main.go I got

None

and no more segmentation fault.

Why the number of members in the struct does matter here?

[EDIT] Both are running at the same place, I run one command clear && go build -o main.so -buildmode=c-shared main.go && python3 main.py

2
  • Are you sure your Python installation and Go generated library are both 32 or 64 bits? Commented Jun 13, 2019 at 21:29
  • @georgeok Hello, both are running on my computer at the same place with only one command clear && go build -o main.so -buildmode=c-shared main.go && python3 main.py Commented Jun 14, 2019 at 2:12

1 Answer 1

14

Your GO/C code is correct. The problem is in the python script. The lib.Foo.restype = c_void_p call expects a void pointer but the library return a C struct. You need to define the return type a ctypes struct in python then it will work as you expect.

The main.go:

package main

import (
    /*
    typedef struct foo{
    int a;
    int b;
    int c;
    int d;
    int e;
    int f;
    } foo;
    */
    "C"
)

func main() {
}

//export Foo
func Foo(t []int) C.foo {
    foo := C.foo{}
    foo.a = 1 // setting some values to avoid seeing zeros
    foo.b = 2
    return foo
}

The main.py:

from ctypes import *

# loading shared object
lib = cdll.LoadLibrary("main.so")


# go type
class GoSlice(Structure):
    _fields_ = [("data", POINTER(c_void_p)), ("len", c_longlong), ("cap", c_longlong)]


class Foo(Structure):
    _fields_ = [('a', c_int),
                ('b', c_int),
                ('c', c_int),
                ('d', c_int),
                ('e', c_int),
                ('f', c_int)]


lib.Foo.argtypes = [GoSlice]
lib.Foo.restype = Foo

t = GoSlice((c_void_p * 5)(1, 2, 3, 4, 5), 5, 5)
f = lib.Foo(t)
print(f)
print(f.a)
print(f.b)

Then run go build -o main.so -buildmode=c-shared main.go && python main.py and it will print:

go build -o main.so -buildmode=c-shared main.go && python3 main.py 
<__main__.Foo object at 0x102608830>
1
2
Sign up to request clarification or add additional context in comments.

1 Comment

It works! Thank you a lot. Actually, I read another topic on stackoverflow (I do not find it anymore) that explained (if I well understood) that c_void_p is enough as return type to handle struct. And since it was working for another struct of my program, I thought it was the correct way. Thank you for clarifying that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.