diff --git a/Lib/test/test_ctypes/test_delattr.py b/Lib/test/test_ctypes/test_delattr.py index e80b5fa6efb5455..eb99c0dafc86563 100644 --- a/Lib/test/test_ctypes/test_delattr.py +++ b/Lib/test/test_ctypes/test_delattr.py @@ -1,5 +1,5 @@ import unittest -from ctypes import Structure, c_char, c_int +from ctypes import POINTER, Structure, c_char, c_int class X(Structure): @@ -16,6 +16,11 @@ def test_chararray(self): with self.assertRaises(TypeError): del chararray.value + def test_pointer_contents(self): + ptr = POINTER(c_int)(c_int(42)) + with self.assertRaises(TypeError): + del ptr.contents + def test_struct(self): struct = X() with self.assertRaises(TypeError): diff --git a/Misc/NEWS.d/next/Library/2026-08-20-16-30-00.gh-issue-156124.Kq3vXz.rst b/Misc/NEWS.d/next/Library/2026-08-20-16-30-00.gh-issue-156124.Kq3vXz.rst new file mode 100644 index 000000000000000..64882cbc40e2450 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-08-20-16-30-00.gh-issue-156124.Kq3vXz.rst @@ -0,0 +1,2 @@ +Fix a crash in the free-threaded build when deleting the :attr:`!contents` +attribute of a :mod:`ctypes` pointer. diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 034f26807f84aa8..3882b9a5ddff3c6 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -5713,11 +5713,6 @@ Pointer_set_contents_lock_held(PyObject *op, PyObject *value, void *closure) PyObject *keep; CDataObject *self = _CDataObject_CAST(op); - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, - "Pointer does not support item deletion"); - return -1; - } ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self))); StgInfo *stginfo; if (PyStgInfo_FromObject(st, op, &stginfo) < 0) { @@ -5761,6 +5756,11 @@ Pointer_set_contents_lock_held(PyObject *op, PyObject *value, void *closure) static int Pointer_set_contents(PyObject *op, PyObject *value, void *closure) { + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, + "Pointer does not support item deletion"); + return -1; + } int res; Py_BEGIN_CRITICAL_SECTION2(op, value); res = Pointer_set_contents_lock_held(op, value, closure);