From ae27ef79db0f5958e7207934f702c692078cd5c5 Mon Sep 17 00:00:00 2001 From: Jerry Deng Date: Sat, 18 Apr 2026 21:42:10 +0800 Subject: [PATCH 1/2] gh-148596: Fix callback return handling for subclassed ctypes types --- Lib/test/test_ctypes/test_callbacks.py | 11 +++++++++++ Modules/_ctypes/callbacks.c | 14 +++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_ctypes/test_callbacks.py b/Lib/test/test_ctypes/test_callbacks.py index 6c7c2e5270736e..b07638c34b61b4 100644 --- a/Lib/test/test_ctypes/test_callbacks.py +++ b/Lib/test/test_ctypes/test_callbacks.py @@ -328,6 +328,17 @@ def func(): f"of ctypes callback function {func!r}") self.assertIsNone(cm.unraisable.object) + def test_callback_return_subclass(self): + class MyInt(ctypes.c_int): + pass + + @ctypes.CFUNCTYPE(MyInt, MyInt) + def identity(x): + return x + + result = identity(MyInt(42)) + assert isinstance(result, MyInt) + assert result.value == 42 if __name__ == '__main__': unittest.main() diff --git a/Modules/_ctypes/callbacks.c b/Modules/_ctypes/callbacks.c index fd508ae61f2e04..965b1168a61f99 100644 --- a/Modules/_ctypes/callbacks.c +++ b/Modules/_ctypes/callbacks.c @@ -239,7 +239,19 @@ static void _CallPythonObject(ctypes_state *st, be the result. EXCEPT when restype is py_object - Python itself knows how to manage the refcount of these objects. */ - PyObject *keep = setfunc(mem, result, restype->size); + PyObject *value = result; /* borrowed */ + PyObject *unwrapped = NULL; /* new ref if created */ + if (value != NULL && PyObject_TypeCheck(value, st->PyCData_Type)) { + unwrapped = PyObject_GetAttrString(value, "value"); + if (unwrapped != NULL) { + value = unwrapped; + } else { + /* fallback: clear error and keep original */ + PyErr_Clear(); + } + } + + PyObject *keep = setfunc(mem, value, restype->size); if (keep == NULL) { /* Could not convert callback result. */ From ed5ee0a7ff2d57b178e755008e9bcf54dc9bdbfc Mon Sep 17 00:00:00 2001 From: Jerry Deng Date: Sun, 19 Apr 2026 07:57:22 +0800 Subject: [PATCH 2/2] Add NEWS entry for gh-148596 --- .../Library/2026-04-19-07-56-51.gh-issue-148596.SKckm9.rst | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-04-19-07-56-51.gh-issue-148596.SKckm9.rst diff --git a/Misc/NEWS.d/next/Library/2026-04-19-07-56-51.gh-issue-148596.SKckm9.rst b/Misc/NEWS.d/next/Library/2026-04-19-07-56-51.gh-issue-148596.SKckm9.rst new file mode 100644 index 00000000000000..bd9a25b4736f34 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-04-19-07-56-51.gh-issue-148596.SKckm9.rst @@ -0,0 +1,5 @@ +Fix ctypes callback return handling for subclassed simple types. + +Returning a ctypes instance (e.g. a subclass of c_int) from a CFUNCTYPE +callback no longer raises an unraisable TypeError or leaves the result +buffer uninitialized.