Reputation: 30142
I'm using ctypes to work with libgphoto2 in Python. The following code succeeds on a 32-bit machine, but fails with a Segmentation Fault on a 64-bit machine (Linux, Ubuntu):
import ctypes
gp = ctypes.CDLL('libgphoto2.so')
a = gp.gp_library_version(0)
x = ctypes.c_char_p.from_address(a)
x.value
libphoto2, ctypes and python are all from repositories, so I assume that the problem is in my code; I need to consider pointers in a more general way or something like that. gp_library_version()
returns const char **
, an array of string constants. Other gp_*
functions work fine.
Upvotes: 1
Views: 2065
Reputation: 110440
If you don't annotate anything about functions in ctypes, it is assumed that they return 32bit integers. In 32 bit processes, these integers and pointers are mostly interchangeable - not so for 64 bit builds.
Just doing
gp.gp_library_version.restype = ctypes.c_void_p
before your call should suffice in this case (You will still need the
x = ctypes.c_char_p.from_address(a)
line).
Check the API docs on wether you should free this pointer yourself after yu use it (probably yes in this case).
Upvotes: 1
Reputation: 400414
The problem is that, by default, ctypes assumes that all functions return int
, which is 32 bits. But, on a 64-bit system, a pointer is 64 bits, so you're dropping the upper 32 bits from the pointer return value, so you then get a segfault when you try to dereference that invalid pointer.
You can change the expected return type of a function by assigning a type to its restype
attribute like so:
gp = ctypes.CDLL('libgphoto2.so')
gp.gp_library_version.restype = ctypes.POINTER(ctypes.c_char_p)
a = gp.gp_library_version(0)
print a[0].value
Upvotes: 3