https://github.com/python/cpython/commit/cf59bc3ae7d34060e55542b6df6786aa2d9a457c
commit: cf59bc3ae7d34060e55542b6df6786aa2d9a457c
branch: main
author: Kumar Aditya <[email protected]>
committer: kumaraditya303 <[email protected]>
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 -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]