https://github.com/python/cpython/commit/cf59bc3ae7d34060e55542b6df6786aa2d9a457c commit: cf59bc3ae7d34060e55542b6df6786aa2d9a457c branch: main author: Kumar Aditya <kumaradi...@python.org> committer: kumaraditya303 <kumaradi...@python.org> date: 2025-04-17T18:44:14Z summary:
gh-127945: fix critical sections around ctypes array (#132646) files: M Lib/test/test_ctypes/test_find.py M Lib/test/test_ctypes/test_values.py M Modules/_ctypes/_ctypes.c diff --git a/Lib/test/test_ctypes/test_find.py b/Lib/test/test_ctypes/test_find.py index 85b28617d2d754..3bd41a0e435d91 100644 --- a/Lib/test/test_ctypes/test_find.py +++ b/Lib/test/test_ctypes/test_find.py @@ -5,7 +5,7 @@ import unittest.mock from ctypes import CDLL, RTLD_GLOBAL from ctypes.util import find_library -from test.support import os_helper +from test.support import os_helper, thread_unsafe # On some systems, loading the OpenGL libraries needs the RTLD_GLOBAL mode. @@ -78,6 +78,7 @@ def test_shell_injection(self): @unittest.skipUnless(sys.platform.startswith('linux'), 'Test only valid for Linux') class FindLibraryLinux(unittest.TestCase): + @thread_unsafe('uses setenv') def test_find_on_libpath(self): import subprocess import tempfile diff --git a/Lib/test/test_ctypes/test_values.py b/Lib/test/test_ctypes/test_values.py index 1b757e020d5ce2..1e209797606275 100644 --- a/Lib/test/test_ctypes/test_values.py +++ b/Lib/test/test_ctypes/test_values.py @@ -9,7 +9,7 @@ from ctypes import (Structure, CDLL, POINTER, pythonapi, _pointer_type_cache, c_ubyte, c_char_p, c_int) -from test.support import import_helper +from test.support import import_helper, thread_unsafe class ValuesTestCase(unittest.TestCase): @@ -18,6 +18,7 @@ def setUp(self): _ctypes_test = import_helper.import_module("_ctypes_test") self.ctdll = CDLL(_ctypes_test.__file__) + @thread_unsafe("static global variables aren't thread-safe") def test_an_integer(self): # This test checks and changes an integer stored inside the # _ctypes_test dll/shared lib. @@ -46,6 +47,7 @@ def test_optimizeflag(self): opt = c_int.in_dll(pythonapi, "Py_OptimizeFlag").value self.assertEqual(opt, sys.flags.optimize) + @thread_unsafe('overrides frozen modules') def test_frozentable(self): # Python exports a PyImport_FrozenModules symbol. This is a # pointer to an array of struct _frozen entries. The end of the diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 9858ec8e714dbb..5c25bff960e45f 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -4892,8 +4892,10 @@ Array_init(PyObject *self, PyObject *args, PyObject *kw) } static PyObject * -Array_item(PyObject *myself, Py_ssize_t index) +Array_item_lock_held(PyObject *myself, Py_ssize_t index) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(myself); + CDataObject *self = _CDataObject_CAST(myself); Py_ssize_t offset, size; @@ -4920,8 +4922,20 @@ Array_item(PyObject *myself, Py_ssize_t index) } static PyObject * -Array_subscript(PyObject *myself, PyObject *item) +Array_item(PyObject *myself, Py_ssize_t index) { + PyObject *result; + Py_BEGIN_CRITICAL_SECTION(myself); + result = Array_item_lock_held(myself, index); + Py_END_CRITICAL_SECTION(); + return result; +} + +static PyObject * +Array_subscript_lock_held(PyObject *myself, PyObject *item) +{ + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(myself); + CDataObject *self = _CDataObject_CAST(myself); if (PyIndex_Check(item)) { @@ -4931,7 +4945,7 @@ Array_subscript(PyObject *myself, PyObject *item) return NULL; if (i < 0) i += self->b_length; - return Array_item(myself, i); + return Array_item_lock_held(myself, i); } else if (PySlice_Check(item)) { PyObject *proto; @@ -4966,10 +4980,8 @@ Array_subscript(PyObject *myself, PyObject *item) return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); if (step == 1) { PyObject *res; - Py_BEGIN_CRITICAL_SECTION(self); res = PyBytes_FromStringAndSize(ptr + start, slicelen); - Py_END_CRITICAL_SECTION(); return res; } dest = (char *)PyMem_Malloc(slicelen); @@ -4977,12 +4989,10 @@ Array_subscript(PyObject *myself, PyObject *item) if (dest == NULL) return PyErr_NoMemory(); - Py_BEGIN_CRITICAL_SECTION(self); for (cur = start, i = 0; i < slicelen; cur += step, i++) { dest[i] = ptr[cur]; } - Py_END_CRITICAL_SECTION(); np = PyBytes_FromStringAndSize(dest, slicelen); PyMem_Free(dest); @@ -4996,10 +5006,8 @@ Array_subscript(PyObject *myself, PyObject *item) return Py_GetConstant(Py_CONSTANT_EMPTY_STR); if (step == 1) { PyObject *res; - Py_BEGIN_CRITICAL_SECTION(self); res = PyUnicode_FromWideChar(ptr + start, slicelen); - Py_END_CRITICAL_SECTION(); return res; } @@ -5009,12 +5017,10 @@ Array_subscript(PyObject *myself, PyObject *item) return NULL; } - Py_BEGIN_CRITICAL_SECTION(self); for (cur = start, i = 0; i < slicelen; cur += step, i++) { dest[i] = ptr[cur]; } - Py_END_CRITICAL_SECTION(); np = PyUnicode_FromWideChar(dest, slicelen); PyMem_Free(dest); @@ -5027,7 +5033,7 @@ Array_subscript(PyObject *myself, PyObject *item) for (cur = start, i = 0; i < slicelen; cur += step, i++) { - PyObject *v = Array_item(myself, cur); + PyObject *v = Array_item_lock_held(myself, cur); if (v == NULL) { Py_DECREF(np); return NULL; @@ -5041,12 +5047,24 @@ Array_subscript(PyObject *myself, PyObject *item) "indices must be integers"); return NULL; } +} + +static PyObject * +Array_subscript(PyObject *myself, PyObject *item) +{ + PyObject *result; + Py_BEGIN_CRITICAL_SECTION(myself); + result = Array_subscript_lock_held(myself, item); + Py_END_CRITICAL_SECTION(); + return result; } static int -Array_ass_item(PyObject *myself, Py_ssize_t index, PyObject *value) +Array_ass_item_lock_held(PyObject *myself, Py_ssize_t index, PyObject *value) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(myself); + CDataObject *self = _CDataObject_CAST(myself); Py_ssize_t size, offset; char *ptr; @@ -5078,7 +5096,18 @@ Array_ass_item(PyObject *myself, Py_ssize_t index, PyObject *value) } static int -Array_ass_subscript(PyObject *myself, PyObject *item, PyObject *value) +Array_ass_item(PyObject *myself, Py_ssize_t index, PyObject *value) +{ + int result; + Py_BEGIN_CRITICAL_SECTION(myself); + result = Array_ass_item_lock_held(myself, index, value); + Py_END_CRITICAL_SECTION(); + return result; +} + + +static int +Array_ass_subscript_lock_held(PyObject *myself, PyObject *item, PyObject *value) { CDataObject *self = _CDataObject_CAST(myself); @@ -5095,7 +5124,7 @@ Array_ass_subscript(PyObject *myself, PyObject *item, PyObject *value) return -1; if (i < 0) i += self->b_length; - return Array_ass_item(myself, i, value); + return Array_ass_item_lock_held(myself, i, value); } else if (PySlice_Check(item)) { Py_ssize_t start, stop, step, slicelen, otherlen, i; @@ -5120,7 +5149,7 @@ Array_ass_subscript(PyObject *myself, PyObject *item, PyObject *value) int result; if (item == NULL) return -1; - result = Array_ass_item(myself, cur, item); + result = Array_ass_item_lock_held(myself, cur, item); Py_DECREF(item); if (result == -1) return -1; @@ -5134,6 +5163,17 @@ Array_ass_subscript(PyObject *myself, PyObject *item, PyObject *value) } } +static int +Array_ass_subscript(PyObject *myself, PyObject *item, PyObject *value) +{ + int result; + Py_BEGIN_CRITICAL_SECTION(myself); + result = Array_ass_subscript_lock_held(myself, item, value); + Py_END_CRITICAL_SECTION(); + return result; +} + + static Py_ssize_t Array_length(PyObject *myself) { _______________________________________________ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com