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

Reply via email to