2

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.

7
  • 1
    Why are you returning a local variable? Commented Dec 7, 2013 at 17:31
  • 1
    It has been allocated on the heap. The assumption is this would be acceptable? Commented Dec 7, 2013 at 17:33
  • 1
    "Python receives the correct address" - you haven't demonstrated that in what you show above. Commented Dec 7, 2013 at 17:34
  • Settings settings; is not on the heap. Commented Dec 7, 2013 at 17:42
  • @Mat I've updated with additional logging showing the address status when in the Python environment. Commented Dec 7, 2013 at 17:43

1 Answer 1

2

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);
Sign up to request clarification or add additional context in comments.

2 Comments

ctypes defaults to C int for integers, which, as you discovered, truncates a 64-bit pointer. You can use CDLL directly instead of cdll.LoadLibrary. cdll is meant for Windows, such as cdll.msvcrt. BTW, the typical tag for Python ctypes is just "ctypes", not "python-ctypes".
You should move setting restype and argtypes out of the method definitions. There's no point in redefining them for the single library instance each time you init/deallocate a Service object.

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.