From 7420697ca8007b26bed5163d8913b6740fe53794 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Fri, 2 May 2025 14:47:07 +0200 Subject: [PATCH] gh-133290: Use PyObject_SetAttr to set _type_ (GH-133292) (cherry picked from commit 2590774c9bb96ec75ca8a13b0c061fcc9db3eb65) Co-authored-by: Petr Viktorin --- Lib/test/test_ctypes/test_pointers.py | 11 +++++++++++ .../2025-05-02-13-16-44.gh-issue-133290.R5WrLM.rst | 3 +++ Modules/_ctypes/_ctypes.c | 12 +----------- 3 files changed, 15 insertions(+), 11 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-05-02-13-16-44.gh-issue-133290.R5WrLM.rst diff --git a/Lib/test/test_ctypes/test_pointers.py b/Lib/test/test_ctypes/test_pointers.py index fc558e10ba40c5..ed4541335dfca4 100644 --- a/Lib/test/test_ctypes/test_pointers.py +++ b/Lib/test/test_ctypes/test_pointers.py @@ -224,6 +224,17 @@ def test_pointer_type_str_name(self): def test_abstract(self): self.assertRaises(TypeError, _Pointer.set_type, 42) + def test_repeated_set_type(self): + # Regression test for gh-133290 + class C(Structure): + _fields_ = [('a', c_int)] + ptr = POINTER(C) + # Read _type_ several times to warm up cache + for i in range(5): + self.assertIs(ptr._type_, C) + ptr.set_type(c_int) + self.assertIs(ptr._type_, c_int) + if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS.d/next/Library/2025-05-02-13-16-44.gh-issue-133290.R5WrLM.rst b/Misc/NEWS.d/next/Library/2025-05-02-13-16-44.gh-issue-133290.R5WrLM.rst new file mode 100644 index 00000000000000..538cce9357dfec --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-05-02-13-16-44.gh-issue-133290.R5WrLM.rst @@ -0,0 +1,3 @@ +Fix attribute caching issue when setting :attr:`ctypes._Pointer._type_` in +the undocumented and deprecated :func:`!ctypes.SetPointerType` function and the +undocumented :meth:`!set_type` method. diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 3d7cb1b1164843..7f843a201cdb1f 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -1280,34 +1280,24 @@ PyCPointerType_set_type_impl(PyTypeObject *self, PyTypeObject *cls, PyObject *type) /*[clinic end generated code: output=51459d8f429a70ac input=67e1e8df921f123e]*/ { - PyObject *attrdict = PyType_GetDict(self); - if (!attrdict) { - return NULL; - } ctypes_state *st = get_module_state_by_class(cls); StgInfo *info; if (PyStgInfo_FromType(st, (PyObject *)self, &info) < 0) { - Py_DECREF(attrdict); return NULL; } if (!info) { PyErr_SetString(PyExc_TypeError, "abstract class"); - Py_DECREF(attrdict); return NULL; } if (PyCPointerType_SetProto(st, info, type) < 0) { - Py_DECREF(attrdict); return NULL; } - if (-1 == PyDict_SetItem(attrdict, &_Py_ID(_type_), type)) { - Py_DECREF(attrdict); + if (PyObject_SetAttr((PyObject *)self, &_Py_ID(_type_), type) < 0) { return NULL; } - - Py_DECREF(attrdict); Py_RETURN_NONE; }