4

I'm interested in using a c++ class in python. Looking at Calling C/C++ from python?, I decided to try ctypes. However, I get segfault when I try to change the value of a class member.

Here is a simple example that reproduce my problem:

The C/C++ side:

#include <iostream>

class Foo{
    private:
        int mValue;
    public:
        void bar(){
            std::cout << "Hello" << std::endl;
        }
        void setValue(int inValue) {
            mValue = inValue;
            std::cout << "Value is now: " << mValue << std::endl;
        }
        void setValue2() {
            mValue = 2;
            std::cout << "Value is now: " << mValue << std::endl;
        }
};

extern "C" {
    Foo* Foo_new(){ return new Foo(); }
    void Foo_bar(Foo* foo){ foo->bar(); }
    void Foo_setValue(Foo* foo, int v) { foo->setValue(v); }
    void Foo_setValue2(Foo* foo) { foo->setValue2(); }
}

The code is compile on OSX with:

g++ -c -fPIC foo.cpp -o foo.o && g++ -shared -Wl -o libfoo.dylib  foo.o

The python side:

from ctypes import *
lib = cdll.LoadLibrary('./libfoo.dylib')

class Foo(object):
    def __init__(self):
        self.obj = lib.Foo_new()
    def bar(self):
        lib.Foo_bar(self.obj)
    def set(self, v):
        lib.Foo_setValue(self.obj, v);
    def set2(self):
        lib.Foo_setValue2(self.obj);

I can call bar without problem, but I get segfault if I call set or set2.

f = Foo()
f.bar()  # Ok
f.set(3) # Segfault

Obviously, I'm missing something.

Community
  • 1
  • 1
jfdupuis
  • 51
  • 5
  • specifically, I used the exact compile parameters from the linked post: `g++ -c -fPIC foo.cpp -o foo.o` and `g++ -shared -Wl,-soname,libfoo.so -o libfoo.so foo.o`, and loading `./libfoo.so` – Nisan.H Sep 18 '12 at 18:08
  • Just tried on a Linux box and as you said it works. However, on OSX 10.7.4 and 10.6.8, I get segfault. Seems to be a platform specific problem. – jfdupuis Sep 18 '12 at 18:44
  • Seems that way. Also, I noticed you're not disposing the memory you allocate to `mValue` in the c++ part. I know it's just a sample code to illustrate the segfault, but still. – Nisan.H Sep 18 '12 at 18:44

1 Answers1

1

Using the following solved the problem:

def __init__(self):
    lib.Foo_new.restype = c_void_p # Needed
    self.obj = lib.Foo_new()

def set(self, v):
    lib.Foo_setValue(c_void_p(self.obj), v) # c_void_p needed

Reading around, it seems to be a 64 bit pointer issue.

jfdupuis
  • 51
  • 5
  • You can also use `lib.Foo_setValue.argtypes=[c_void_p,c_int]` to declare the argument types. Then you don't have to wrap arguments each time they are used. – Mark Tolonen Sep 20 '12 at 14:17