Skip to content

Commit 2aab2db

Browse files
authored
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.
1 parent e0dffc5 commit 2aab2db

File tree

3 files changed

+22
-3
lines changed

3 files changed

+22
-3
lines changed

Lib/test/test_ctypes/test_refcounts.py

+15
Original file line numberDiff line numberDiff line change
@@ -123,5 +123,20 @@ def test_finalize(self):
123123
script_helper.assert_python_ok("-c", script)
124124

125125

126+
class PyObjectRestypeTest(unittest.TestCase):
127+
def test_restype_py_object_with_null_return(self):
128+
# Test that a function which returns a NULL PyObject *
129+
# without setting an exception does not crash.
130+
PyErr_Occurred = ctypes.pythonapi.PyErr_Occurred
131+
PyErr_Occurred.argtypes = []
132+
PyErr_Occurred.restype = ctypes.py_object
133+
134+
# At this point, there's no exception set, so PyErr_Occurred
135+
# returns NULL. Given the restype is py_object, the
136+
# ctypes machinery will raise a custom error.
137+
with self.assertRaisesRegex(ValueError, "PyObject is NULL"):
138+
PyErr_Occurred()
139+
140+
126141
if __name__ == '__main__':
127142
unittest.main()
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

+4-3
Original file line numberDiff line numberDiff line change
@@ -1022,11 +1022,12 @@ static PyObject *GetResult(ctypes_state *st,
10221022
if (info->getfunc && !_ctypes_simple_instance(st, restype)) {
10231023
retval = info->getfunc(result, info->size);
10241024
/* If restype is py_object (detected by comparing getfunc with
1025-
O_get), we have to call Py_DECREF because O_get has already
1026-
called Py_INCREF.
1025+
O_get), we have to call Py_XDECREF because O_get has already
1026+
called Py_INCREF, unless the result was NULL, in which case
1027+
an error is set (by the called function, or by O_get).
10271028
*/
10281029
if (info->getfunc == _ctypes_get_fielddesc("O")->getfunc) {
1029-
Py_DECREF(retval);
1030+
Py_XDECREF(retval);
10301031
}
10311032
}
10321033
else {

0 commit comments

Comments
 (0)