https://github.com/python/cpython/commit/2aab2db1461ef49b42549255af16a74b1bf8a5ef
commit: 2aab2db1461ef49b42549255af16a74b1bf8a5ef
branch: main
author: Nicolas Trangez <[email protected]>
committer: picnixz <[email protected]>
date: 2025-04-12T07:40:34Z
summary:
GH-132417: ctypes: Fix potential `Py_DECREF(NULL)` when handling functions
returning `PyObject *` (#132418)
Some functions (such as `PyErr_Occurred`) with a `restype` set to
`ctypes.py_object` may return NULL without setting an exception.
files:
A Misc/NEWS.d/next/Library/2025-04-11-21-48-49.gh-issue-132417.uILGdS.rst
M Lib/test/test_ctypes/test_refcounts.py
M Modules/_ctypes/callproc.c
diff --git a/Lib/test/test_ctypes/test_refcounts.py
b/Lib/test/test_ctypes/test_refcounts.py
index 1fe4b3eca2c50e..5f2f5c4a84d52e 100644
--- a/Lib/test/test_ctypes/test_refcounts.py
+++ b/Lib/test/test_ctypes/test_refcounts.py
@@ -123,5 +123,20 @@ def test_finalize(self):
script_helper.assert_python_ok("-c", script)
+class PyObjectRestypeTest(unittest.TestCase):
+ def test_restype_py_object_with_null_return(self):
+ # Test that a function which returns a NULL PyObject *
+ # without setting an exception does not crash.
+ PyErr_Occurred = ctypes.pythonapi.PyErr_Occurred
+ PyErr_Occurred.argtypes = []
+ PyErr_Occurred.restype = ctypes.py_object
+
+ # At this point, there's no exception set, so PyErr_Occurred
+ # returns NULL. Given the restype is py_object, the
+ # ctypes machinery will raise a custom error.
+ with self.assertRaisesRegex(ValueError, "PyObject is NULL"):
+ PyErr_Occurred()
+
+
if __name__ == '__main__':
unittest.main()
diff --git
a/Misc/NEWS.d/next/Library/2025-04-11-21-48-49.gh-issue-132417.uILGdS.rst
b/Misc/NEWS.d/next/Library/2025-04-11-21-48-49.gh-issue-132417.uILGdS.rst
new file mode 100644
index 00000000000000..878651c8a0ad5c
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-04-11-21-48-49.gh-issue-132417.uILGdS.rst
@@ -0,0 +1,3 @@
+Fix a ``NULL`` pointer dereference when a C function called using
+:mod:`ctypes` with ``restype`` :class:`~ctypes.py_object` returns
+``NULL``.
diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c
index 352487ed964b54..4e69c4e0a99ca2 100644
--- a/Modules/_ctypes/callproc.c
+++ b/Modules/_ctypes/callproc.c
@@ -1022,11 +1022,12 @@ static PyObject *GetResult(ctypes_state *st,
if (info->getfunc && !_ctypes_simple_instance(st, restype)) {
retval = info->getfunc(result, info->size);
/* If restype is py_object (detected by comparing getfunc with
- O_get), we have to call Py_DECREF because O_get has already
- called Py_INCREF.
+ O_get), we have to call Py_XDECREF because O_get has already
+ called Py_INCREF, unless the result was NULL, in which case
+ an error is set (by the called function, or by O_get).
*/
if (info->getfunc == _ctypes_get_fielddesc("O")->getfunc) {
- Py_DECREF(retval);
+ Py_XDECREF(retval);
}
}
else {
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]