pythonc++ctypeslanguage-binding

C/Python binding: pointer address modification


Source

C++

extern "C"
{
    Service* create_service( int port )
    {
        Settings settings;
        settings.set_port( port );

        auto service = new Service( settings );

        std::cout << "create_service returning pointer address: " << service << std::endl;

        return service;
    }

    void release_service( Service* service )
    {
        std::cout << "release_service consuming pointer address: " << service << std::endl;
        delete service;
    }
}

Python

from ctypes import *

library = cdll.LoadLibrary('distribution/library/libhelpers.dylib')

class Service(object):
    def __init__(self, port):
        self.obj = library.create_service(port)
        print "__init__ address: ", self.obj

    def __del__(self):
        print "__del__", self.obj
        library.release_service(self.obj);

Console

create_service returning pointer address: 0x7fc3a0e330e0

init address: -1595723552

del address: -1595723552

release_service consuming pointer address: 0xffffffffa0e330e0

Segmentation fault: 11

Error

Exception Type: EXC_BAD_ACCESS (SIGSEGV)

Exception Codes: KERN_INVALID_ADDRESS at 0xffffffff914d37a0

Build (cmake)

set( CMAKE_CXX_COMPILER clang++ )

set( CMAKE_CXX_FLAGS "-stdlib=libc++ -std=c++11 -Wall -Wextra -Weffc++ -pedantic" )

add_library( helpers SHARED ${MANIFEST} )

target_link_libraries( helpers restbed )

Description

When returning a C++ class instance as a pointer. Python receives the correct address. However when using this address at a later date, it appears to have been modified.


Solution

  • It appears I was giving insufficient context to ctypes.

    from ctypes import *
    
    library = cdll.LoadLibrary('distribution/library/libhelpers.dylib')
    
    class Service(object):
        def __init__(self, port):
            library.create_service.restype = c_void_p
            self.obj = library.create_service(port)
    
        def __del__(self):
            library.release_service.argtypes = [c_void_p]
            library.release_service(self.obj);