diff --git a/Lib/ctypes/test/test_refcounts.py b/Lib/ctypes/test/test_refcounts.py index f2edfa6400ef24..48958cd2a60196 100644 --- a/Lib/ctypes/test/test_refcounts.py +++ b/Lib/ctypes/test/test_refcounts.py @@ -97,5 +97,20 @@ def func(a, b): 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 00000000000000..f65323813d0543 --- /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 c28762d49ba497..b46067bf2fa655 100644 --- a/Modules/_ctypes/callbacks.c +++ b/Modules/_ctypes/callbacks.c @@ -276,15 +276,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);