summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordgelessus <dgelessus@users.noreply.github.com>2023-01-09 10:13:04 (GMT)
committerGitHub <noreply@github.com>2023-01-09 10:13:04 (GMT)
commit837ba052672d1a5f85a46c1b6d4b6e7d192af6f3 (patch)
treecd0869c5b13a7fc35add579ac8b11f48554c23ae
parent4e544eafcb603babe0db01270bd1c6d5d0f5d6ea (diff)
downloadcpython-837ba052672d1a5f85a46c1b6d4b6e7d192af6f3.zip
cpython-837ba052672d1a5f85a46c1b6d4b6e7d192af6f3.tar.gz
cpython-837ba052672d1a5f85a46c1b6d4b6e7d192af6f3.tar.bz2
GH-81061: Fix refcount issue when returning `None` from a `ctypes.py_object` callback (#13364)
-rw-r--r--Lib/test/test_ctypes/test_refcounts.py15
-rw-r--r--Misc/NEWS.d/next/Library/2019-05-13-11-37-30.bpo-36880.ZgBgH0.rst2
-rw-r--r--Modules/_ctypes/callbacks.c15
3 files changed, 24 insertions, 8 deletions
diff --git a/Lib/test/test_ctypes/test_refcounts.py b/Lib/test/test_ctypes/test_refcounts.py
index f2edfa6..48958cd 100644
--- a/Lib/test/test_ctypes/test_refcounts.py
+++ b/Lib/test/test_ctypes/test_refcounts.py
@@ -97,5 +97,20 @@ class AnotherLeak(unittest.TestCase):
f(1, 2)
self.assertEqual(sys.getrefcount(ctypes.c_int), a)
+ @support.refcount_test
+ def test_callback_py_object_none_return(self):
+ # bpo-36880: test that returning None from a py_object callback
+ # does not decrement the refcount of None.
+
+ for FUNCTYPE in (ctypes.CFUNCTYPE, ctypes.PYFUNCTYPE):
+ with self.subTest(FUNCTYPE=FUNCTYPE):
+ @FUNCTYPE(ctypes.py_object)
+ def func():
+ return None
+
+ # Check that calling func does not affect None's refcount.
+ for _ in range(10000):
+ func()
+
if __name__ == '__main__':
unittest.main()
diff --git a/Misc/NEWS.d/next/Library/2019-05-13-11-37-30.bpo-36880.ZgBgH0.rst b/Misc/NEWS.d/next/Library/2019-05-13-11-37-30.bpo-36880.ZgBgH0.rst
new file mode 100644
index 0000000..f653238
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-05-13-11-37-30.bpo-36880.ZgBgH0.rst
@@ -0,0 +1,2 @@
+Fix a reference counting issue when a :mod:`ctypes` callback with return
+type :class:`~ctypes.py_object` returns ``None``, which could cause crashes.
diff --git a/Modules/_ctypes/callbacks.c b/Modules/_ctypes/callbacks.c
index f688088..bc87500 100644
--- a/Modules/_ctypes/callbacks.c
+++ b/Modules/_ctypes/callbacks.c
@@ -275,15 +275,14 @@ static void _CallPythonObject(void *mem,
"of ctypes callback function",
callable);
}
- else if (keep == Py_None) {
- /* Nothing to keep */
- Py_DECREF(keep);
- }
else if (setfunc != _ctypes_get_fielddesc("O")->setfunc) {
- if (-1 == PyErr_WarnEx(PyExc_RuntimeWarning,
- "memory leak in callback function.",
- 1))
- {
+ if (keep == Py_None) {
+ /* Nothing to keep */
+ Py_DECREF(keep);
+ }
+ else if (PyErr_WarnEx(PyExc_RuntimeWarning,
+ "memory leak in callback function.",
+ 1) == -1) {
_PyErr_WriteUnraisableMsg("on converting result "
"of ctypes callback function",
callable);