Issue 28631: [2.7/3.5/3.6 Regression] crash using ctypes (original) (raw)
the following example started to segfault with the 2.7 branch 20161103, last working one 20160901, on 3.5 branch 20161103, last working one 20160922.
from future import print_function import ctypes import ctypes.util
lib_location = ctypes.util.find_library('gettextpo') gpo = ctypes.cdll.LoadLibrary(lib_location)
gpo_message = gpo.po_message_create() source = "foo"
print("calling po_message_set_msgid") gpo.po_message_set_msgid(gpo_message, source.encode('utf-8'))
print("success")
#0 0x00007ffff5e74906 in po_message_set_msgid () from /usr/lib/x86_64-linux-gnu/libgettextpo.so.0 #1 0x00007ffff6a4b038 in ffi_call_unix64 () from /usr/lib/x86_64-linux-gnu/libffi.so.6 #2 0x00007ffff6a4aa9a in ffi_call () from /usr/lib/x86_64-linux-gnu/libffi.so.6 #3 0x00007ffff6c662ec in _call_function_pointer (flags=4353, pProc=0x7ffff5e74900 , avalues=0x7fffffffd9c0, atypes=0x7fffffffd9a0, restype=0x7ffff6e9c530, resmem=0x7fffffffd9e0, argcount=2) at ./Modules/_ctypes/callproc.c:841 #4 0x00007ffff6c66f61 in _ctypes_callproc ( pProc=0x7ffff5e74900 , argtuple=(1439158016, 'foo'), flags=4353, argtypes=0x0, restype=<_ctypes.PyCSimpleType at remote 0x555555c43d70>, checker=0x0) at ./Modules/_ctypes/callproc.c:1184 #5 0x00007ffff6c5f7e2 in PyCFuncPtr_call (self=0x7ffff6ea6a60, inargs=(1439158016, 'foo'), kwds=0x0) at ./Modules/_ctypes/_ctypes.c:3973 #6 0x00005555555b3151 in PyObject_Call ( func=<_FuncPtr(__name__='po_message_set_msgid') at remote 0x7ffff6ea6a60>, arg=(1439158016, 'foo'), kw=0x0) at ../Objects/abstract.c:2547 #7 0x00005555556c5cef in do_call ( func=<_FuncPtr(__name__='po_message_set_msgid') at remote 0x7ffff6ea6a60>, pp_stack=0x7fffffffde70, na=2, nk=0) at ../Python/ceval.c:4569 #8 0x00005555556c5082 in call_function (pp_stack=0x7fffffffde70, oparg=2) at ../Python/ceval.c:4374 #9 0x00005555556bf492 in PyEval_EvalFrameEx ( f=Frame 0x7ffff7e3bc00, for file foo.py, line 12, in (), throwflag=0) at ../Python/ceval.c:2989
po_message_create() returns a po_message_t pointer:
/* A po_message_t represents a message in a PO file. */
typedef struct po_message *po_message_t;
/* Return a freshly constructed message.
To finish initializing the message, you must set the msgid
and msgstr. */
extern po_message_t po_message_create (void);
You're casting a pointer as a 32-bit C int, which isn't reliable in 64-bit Python. The value 0x55c7cf00 (1439158016) may be truncated. Try it using a po_message_t pointer type. For example:
gpo = ctypes.CDLL(lib_location)
class po_message_t(ctypes._Pointer):
"""A po_message_t represents a message in a PO file."""
class po_message(ctypes.Structure):
pass
_type_ = po_message
gpo.po_message_create.restype = po_message_t
Having added the suggested restype (plus a lot of others and also quite a few extra argtypes), we now have code that works across a few different versions of Python once again.
Thanks for the hint, eryksun and also thanks to doko for proxying the report and narrowing down the version range in the first place.