8000 Merge pull request #517 from beeware/none-setfunc-restype · beeware/rubicon-objc@a128b1e · GitHub
[go: up one dir, main page]

8000
Skip to content

Commit a128b1e

Browse files
authored
Merge pull request #517 from beeware/none-setfunc-restype
Remove workaround for python/cpython#81061.
2 parents 92dcc5b + 2ff2dbd commit a128b1e

File tree

2 files changed

+28
-20
lines changed

2 files changed

+28
-20
lines changed

changes/517.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
A workaround for `python/cpython#81061 <https://github.com/python/cpython/issues/81061>`__ is now conditionally applied only for the Python versions that require it (Python 3.9 and earlier).

src/rubicon/objc/ctypes_patch.py

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,17 @@ class ffi_type(ctypes.Structure):
8181

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

9196

9297
if sys.version_info < (3, 13):
@@ -287,20 +292,22 @@ def setfunc(ptr, value, size):
287292
)
288293

289294
ctypes.memmove(ptr, ctypes.addressof(value), actual_size)
290-
# Because of a ctypes bug (https://github.com/python/cpython/issues/81061),
291-
# returning None from a callback with restype py_object causes a reference
292-
# counting error that can crash Python. To work around this bug, the restype of
293-
# SETFUNC is declared as c_void_p instead. This way ctypes performs no automatic
294-
# reference counting for the returned object, which avoids the bug. However,
295-
# this way we have to manually convert the Python object to a pointer and adjust
296-
# its reference count.
297-
none_ptr = ctypes.cast(id(None), ctypes.POINTER(PyObject))
298-
# The return value of a SETFUNC is expected to have an extra reference
299-
# (which will be owned by the caller of the SETFUNC).
300-
ctypes.pythonapi.Py_IncRef(none_ptr)
301-
# The returned pointer must be returned as a plain int, not as a c_void_p,
302-
# otherwise ctypes won't recognize it and will raise a TypeError.
303-
return ctypes.cast(none_ptr, ctypes.c_void_p).value
295+
296+
if sys.version_info < (3, 10):
297+
# Because of a ctypes bug (https://github.com/python/cpython/issues/81061),
298+
# returning None from a callback with restype py_object causes a reference
299+
# counting error that can crash Python. To work around this bug, the restype of
300+
# SETFUNC is declared as c_void_p instead. This way ctypes performs no automatic
301+
# reference counting for the returned object, which avoids the bug. However,
302+
# this way we have to manually convert the Python object to a pointer and adjust
303+
# its reference count. This bug was fixed in 3.10.
304+
none_ptr = ctypes.cast(id(None), ctypes.POINTER(PyObject))
305+
# The return value of a SETFUNC is expected to have an extra reference
306+
# (which will be owned by the caller of the SETFUNC).
307+
ctypes.pythonapi.Py_IncRef(none_ptr)
308+
# The returned pointer must be returned as a plain int, not as a c_void_p,
309+
# otherwise ctypes won't recognize it and will raise a TypeError.
310+
return ctypes.cast(none_ptr, ctypes.c_void_p).value
304311

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

0 commit comments

Comments
 (0)
0