Skip to content

Commit

Permalink
Remove workaround for python/cpython#81061.
Browse files Browse the repository at this point in the history
  • Loading branch information
freakboy3742 committed Sep 25, 2024
1 parent 92dcc5b commit 4c23fd7
Showing 1 changed file with 27 additions and 20 deletions.
47 changes: 27 additions & 20 deletions src/rubicon/objc/ctypes_patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,17 @@ class ffi_type(ctypes.Structure):

# The GETFUNC and SETFUNC typedefs from "Modules/_ctypes/ctypes.h".
GETFUNC = ctypes.PYFUNCTYPE(ctypes.py_object, ctypes.c_void_p, ctypes.c_ssize_t)
# The return type of SETFUNC is declared here as a c_void_p instead of py_object to work
# around a ctypes bug (https://github.com/python/cpython/issues/81061). See the comment
# in make_callback_returnable's setfunc for details.
SETFUNC = ctypes.PYFUNCTYPE(
ctypes.c_void_p, ctypes.c_void_p, ctypes.py_object, ctypes.c_ssize_t
)
if sys.version_info < (3, 10):
# The return type of SETFUNC is declared here as a c_void_p instead of py_object to work
# around a ctypes bug (https://github.com/python/cpython/issues/81061). See the comment
# in make_callback_returnable's setfunc for details. This bug was fixed in 3.10.
SETFUNC = ctypes.PYFUNCTYPE(
ctypes.c_void_p, ctypes.c_void_p, ctypes.py_object, ctypes.c_ssize_t
)
else:
SETFUNC = ctypes.PYFUNCTYPE(
ctypes.py_object, ctypes.c_void_p, ctypes.py_object, ctypes.c_ssize_t
)


if sys.version_info < (3, 13):
Expand Down Expand Up @@ -287,20 +292,22 @@ def setfunc(ptr, value, size):
)

ctypes.memmove(ptr, ctypes.addressof(value), actual_size)
# Because of a ctypes bug (https://github.com/python/cpython/issues/81061),
# returning None from a callback with restype py_object causes a reference
# counting error that can crash Python. To work around this bug, the restype of
# SETFUNC is declared as c_void_p instead. This way ctypes performs no automatic
# reference counting for the returned object, which avoids the bug. However,
# this way we have to manually convert the Python object to a pointer and adjust
# its reference count.
none_ptr = ctypes.cast(id(None), ctypes.POINTER(PyObject))
# The return value of a SETFUNC is expected to have an extra reference
# (which will be owned by the caller of the SETFUNC).
ctypes.pythonapi.Py_IncRef(none_ptr)
# The returned pointer must be returned as a plain int, not as a c_void_p,
# otherwise ctypes won't recognize it and will raise a TypeError.
return ctypes.cast(none_ptr, ctypes.c_void_p).value

if sys.version_info < (3, 10):
# Because of a ctypes bug (https://github.com/python/cpython/issues/81061),
# returning None from a callback with restype py_object causes a reference
# counting error that can crash Python. To work around this bug, the restype of
# SETFUNC is declared as c_void_p instead. This way ctypes performs no automatic
# reference counting for the returned object, which avoids the bug. However,
# this way we have to manually convert the Python object to a pointer and adjust
# its reference count. This bug was fixed in 3.10.
none_ptr = ctypes.cast(id(None), ctypes.POINTER(PyObject))
# The return value of a SETFUNC is expected to have an extra reference
# (which will be owned by the caller of the SETFUNC).
ctypes.pythonapi.Py_IncRef(none_ptr)
# The returned pointer must be returned as a plain int, not as a c_void_p,
# otherwise ctypes won't recognize it and will raise a TypeError.
return ctypes.cast(none_ptr, ctypes.c_void_p).value

# Store the getfunc and setfunc as attributes on the ctype, so they don't
# get garbage-collected.
Expand Down

0 comments on commit 4c23fd7

Please sign in to comment.