Skip to content

Commit 0aabe44

Browse files
[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 2aab2db) Co-authored-by: Nicolas Trangez <[email protected]>
1 parent 089c43f commit 0aabe44

File tree

3 files changed

+22
-3
lines changed

3 files changed

+22
-3
lines changed

Lib/test/test_ctypes/test_refcounts.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,5 +124,20 @@ def test_finalize(self):
124124
script_helper.assert_python_ok("-c", script)
125125

126126

127+
class PyObjectRestypeTest(unittest.TestCase):
128+
def test_restype_py_object_with_null_return(self):
129+
# Test that a function which returns a NULL PyObject *
130+
# without setting an exception does not crash.
131+
PyErr_Occurred = ctypes.pythonapi.PyErr_Occurred
132+
PyErr_Occurred.argtypes = []
133+
PyErr_Occurred.restype = ctypes.py_object
134+
135+
# At this point, there's no exception set, so PyErr_Occurred
136+
# returns NULL. Given the restype is py_object, the
137+
# ctypes machinery will raise a custom error.
138+
with self.assertRaisesRegex(ValueError, "PyObject is NULL"):
139+
PyErr_Occurred()
140+
141+
127142
if __name__ == '__main__':
128143
unittest.main()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix a ``NULL`` pointer dereference when a C function called using
2+
:mod:`ctypes` with ``restype`` :class:`~ctypes.py_object` returns
3+
``NULL``.

Modules/_ctypes/callproc.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,11 +1016,12 @@ static PyObject *GetResult(ctypes_state *st,
10161016
if (info->getfunc && !_ctypes_simple_instance(st, restype)) {
10171017
retval = info->getfunc(result, info->size);
10181018
/* If restype is py_object (detected by comparing getfunc with
1019-
O_get), we have to call Py_DECREF because O_get has already
1020-
called Py_INCREF.
1019+
O_get), we have to call Py_XDECREF because O_get has already
1020+
called Py_INCREF, unless the result was NULL, in which case
1021+
an error is set (by the called function, or by O_get).
10211022
*/
10221023
if (info->getfunc == _ctypes_get_fielddesc("O")->getfunc) {
1023-
Py_DECREF(retval);
1024+
Py_XDECREF(retval);
10241025
}
10251026
}
10261027
else {

0 commit comments

Comments
 (0)