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.
This commit is contained in:
Nicolas Trangez 2025-04-12 09:40:34 +02:00 committed by GitHub
parent e0dffc54b8
commit 2aab2db146
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 22 additions and 3 deletions

View file

@ -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()

View file

@ -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``.

View file

@ -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 {