Issue 47197: ctypes mishandles void
return type (original) (raw)
On wasm targets, test_code
fails. It's because of a bad function pointer cast. The problematic code is as follows:
import ctypes
py = ctypes.pythonapi
freefunc = ctypes.CFUNCTYPE(None, ctypes.c_voidp)
RequestCodeExtraIndex = py._PyEval_RequestCodeExtraIndex
RequestCodeExtraIndex.argtypes = (freefunc,)
RequestCodeExtraIndex.restype = ctypes.c_ssize_t
SetExtra = py._PyCode_SetExtra
SetExtra.argtypes = (ctypes.py_object, ctypes.c_ssize_t, ctypes.c_voidp)
SetExtra.restype = ctypes.c_int
LAST_FREED = None
def myfree(ptr):
global LAST_FREED
LAST_FREED = ptr
FREE_FUNC = freefunc(myfree)
FREE_INDEX = RequestCodeExtraIndex(FREE_FUNC)
# Verify that the provided free function gets invoked
# when the code object is cleaned up.
f = eval('lambda:42')
SetExtra(f.__code__, FREE_INDEX, ctypes.c_voidp(100))
del f # crashes!!
The problem: freefunc = ctypes.CFUNCTYPE(None, ctypes.c_voidp)
declares a function with signature int f(void*)
. However, the definition of freefunc
is void f(void*)
. These function signatures do not agree, and trying to make the call crashes.
Due to a bug(?) ctypes can produce closures that have void
return type but it can't produce simple functions with void return type.
Closures code: checks if restype == Py_None
and if so gives the callback a void return type
https://github.com/python/cpython/blob/main/Modules/_ctypes/callbacks.c#L381
Direct call code: calls _ctypes_get_ffi_type
which never returns ffi_type_void
:
https://github.com/python/cpython/blob/b183f486493e7e4c332566392ef18c6b346a6561/Modules/_ctypes/callproc.c#L1212