https://github.com/python/cpython/commit/0aabe44fa8a8159561c04a9b6e7450bfaa319e94
commit: 0aabe44fa8a8159561c04a9b6e7450bfaa319e94
branch: 3.13
author: Miss Islington (bot) <31488909+miss-isling...@users.noreply.github.com>
committer: picnixz <10796600+picn...@users.noreply.github.com>
date: 2025-04-12T09:14:07Z
summary:

[3.13] GH-132417: ctypes: Fix potential `Py_DECREF(NULL)` when handling 
functions returning `PyObject *` (GH-132418) (#132425)

GH-132417: ctypes: Fix potential `Py_DECREF(NULL)` when handling functions 
returning `PyObject *` (GH-132418)

Some functions (such as `PyErr_Occurred`) with a `restype` set to 
`ctypes.py_object` may return NULL without setting an exception.
(cherry picked from commit 2aab2db1461ef49b42549255af16a74b1bf8a5ef)

Co-authored-by: Nicolas Trangez <i...@nicolast.be>

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 012722d8486218..9e87cfc661edf1 100644
--- a/Lib/test/test_ctypes/test_refcounts.py
+++ b/Lib/test/test_ctypes/test_refcounts.py
@@ -124,5 +124,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 f9864ebb735ddf..8f94d19024e62c 100644
--- a/Modules/_ctypes/callproc.c
+++ b/Modules/_ctypes/callproc.c
@@ -1016,11 +1016,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 -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to