Skip to content

Commit cf59bc3

Browse files
gh-127945: fix critical sections around ctypes array (#132646)
1 parent a23ed8b commit cf59bc3

File tree

3 files changed

+61
-18
lines changed

3 files changed

+61
-18
lines changed

Lib/test/test_ctypes/test_find.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import unittest.mock
66
from ctypes import CDLL, RTLD_GLOBAL
77
from ctypes.util import find_library
8-
from test.support import os_helper
8+
from test.support import os_helper, thread_unsafe
99

1010

1111
# On some systems, loading the OpenGL libraries needs the RTLD_GLOBAL mode.
@@ -78,6 +78,7 @@ def test_shell_injection(self):
7878
@unittest.skipUnless(sys.platform.startswith('linux'),
7979
'Test only valid for Linux')
8080
class FindLibraryLinux(unittest.TestCase):
81+
@thread_unsafe('uses setenv')
8182
def test_find_on_libpath(self):
8283
import subprocess
8384
import tempfile

Lib/test/test_ctypes/test_values.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from ctypes import (Structure, CDLL, POINTER, pythonapi,
1010
_pointer_type_cache,
1111
c_ubyte, c_char_p, c_int)
12-
from test.support import import_helper
12+
from test.support import import_helper, thread_unsafe
1313

1414

1515
class ValuesTestCase(unittest.TestCase):
@@ -18,6 +18,7 @@ def setUp(self):
1818
_ctypes_test = import_helper.import_module("_ctypes_test")
1919
self.ctdll = CDLL(_ctypes_test.__file__)
2020

21+
@thread_unsafe("static global variables aren't thread-safe")
2122
def test_an_integer(self):
2223
# This test checks and changes an integer stored inside the
2324
# _ctypes_test dll/shared lib.
@@ -46,6 +47,7 @@ def test_optimizeflag(self):
4647
opt = c_int.in_dll(pythonapi, "Py_OptimizeFlag").value
4748
self.assertEqual(opt, sys.flags.optimize)
4849

50+
@thread_unsafe('overrides frozen modules')
4951
def test_frozentable(self):
5052
# Python exports a PyImport_FrozenModules symbol. This is a
5153
# pointer to an array of struct _frozen entries. The end of the

Modules/_ctypes/_ctypes.c

+56-16
Original file line numberDiff line numberDiff line change
@@ -4892,8 +4892,10 @@ Array_init(PyObject *self, PyObject *args, PyObject *kw)
48924892
}
48934893

48944894
static PyObject *
4895-
Array_item(PyObject *myself, Py_ssize_t index)
4895+
Array_item_lock_held(PyObject *myself, Py_ssize_t index)
48964896
{
4897+
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(myself);
4898+
48974899
CDataObject *self = _CDataObject_CAST(myself);
48984900
Py_ssize_t offset, size;
48994901

@@ -4920,8 +4922,20 @@ Array_item(PyObject *myself, Py_ssize_t index)
49204922
}
49214923

49224924
static PyObject *
4923-
Array_subscript(PyObject *myself, PyObject *item)
4925+
Array_item(PyObject *myself, Py_ssize_t index)
49244926
{
4927+
PyObject *result;
4928+
Py_BEGIN_CRITICAL_SECTION(myself);
4929+
result = Array_item_lock_held(myself, index);
4930+
Py_END_CRITICAL_SECTION();
4931+
return result;
4932+
}
4933+
4934+
static PyObject *
4935+
Array_subscript_lock_held(PyObject *myself, PyObject *item)
4936+
{
4937+
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(myself);
4938+
49254939
CDataObject *self = _CDataObject_CAST(myself);
49264940

49274941
if (PyIndex_Check(item)) {
@@ -4931,7 +4945,7 @@ Array_subscript(PyObject *myself, PyObject *item)
49314945
return NULL;
49324946
if (i < 0)
49334947
i += self->b_length;
4934-
return Array_item(myself, i);
4948+
return Array_item_lock_held(myself, i);
49354949
}
49364950
else if (PySlice_Check(item)) {
49374951
PyObject *proto;
@@ -4966,23 +4980,19 @@ Array_subscript(PyObject *myself, PyObject *item)
49664980
return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES);
49674981
if (step == 1) {
49684982
PyObject *res;
4969-
Py_BEGIN_CRITICAL_SECTION(self);
49704983
res = PyBytes_FromStringAndSize(ptr + start,
49714984
slicelen);
4972-
Py_END_CRITICAL_SECTION();
49734985
return res;
49744986
}
49754987
dest = (char *)PyMem_Malloc(slicelen);
49764988

49774989
if (dest == NULL)
49784990
return PyErr_NoMemory();
49794991

4980-
Py_BEGIN_CRITICAL_SECTION(self);
49814992
for (cur = start, i = 0; i < slicelen;
49824993
cur += step, i++) {
49834994
dest[i] = ptr[cur];
49844995
}
4985-
Py_END_CRITICAL_SECTION();
49864996

49874997
np = PyBytes_FromStringAndSize(dest, slicelen);
49884998
PyMem_Free(dest);
@@ -4996,10 +5006,8 @@ Array_subscript(PyObject *myself, PyObject *item)
49965006
return Py_GetConstant(Py_CONSTANT_EMPTY_STR);
49975007
if (step == 1) {
49985008
PyObject *res;
4999-
Py_BEGIN_CRITICAL_SECTION(self);
50005009
res = PyUnicode_FromWideChar(ptr + start,
50015010
slicelen);
5002-
Py_END_CRITICAL_SECTION();
50035011
return res;
50045012
}
50055013

@@ -5009,12 +5017,10 @@ Array_subscript(PyObject *myself, PyObject *item)
50095017
return NULL;
50105018
}
50115019

5012-
Py_BEGIN_CRITICAL_SECTION(self);
50135020
for (cur = start, i = 0; i < slicelen;
50145021
cur += step, i++) {
50155022
dest[i] = ptr[cur];
50165023
}
5017-
Py_END_CRITICAL_SECTION();
50185024

50195025
np = PyUnicode_FromWideChar(dest, slicelen);
50205026
PyMem_Free(dest);
@@ -5027,7 +5033,7 @@ Array_subscript(PyObject *myself, PyObject *item)
50275033

50285034
for (cur = start, i = 0; i < slicelen;
50295035
cur += step, i++) {
5030-
PyObject *v = Array_item(myself, cur);
5036+
PyObject *v = Array_item_lock_held(myself, cur);
50315037
if (v == NULL) {
50325038
Py_DECREF(np);
50335039
return NULL;
@@ -5041,12 +5047,24 @@ Array_subscript(PyObject *myself, PyObject *item)
50415047
"indices must be integers");
50425048
return NULL;
50435049
}
5050+
}
50445051

5052+
5053+
static PyObject *
5054+
Array_subscript(PyObject *myself, PyObject *item)
5055+
{
5056+
PyObject *result;
5057+
Py_BEGIN_CRITICAL_SECTION(myself);
5058+
result = Array_subscript_lock_held(myself, item);
5059+
Py_END_CRITICAL_SECTION();
5060+
return result;
50455061
}
50465062

50475063
static int
5048-
Array_ass_item(PyObject *myself, Py_ssize_t index, PyObject *value)
5064+
Array_ass_item_lock_held(PyObject *myself, Py_ssize_t index, PyObject *value)
50495065
{
5066+
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(myself);
5067+
50505068
CDataObject *self = _CDataObject_CAST(myself);
50515069
Py_ssize_t size, offset;
50525070
char *ptr;
@@ -5078,7 +5096,18 @@ Array_ass_item(PyObject *myself, Py_ssize_t index, PyObject *value)
50785096
}
50795097

50805098
static int
5081-
Array_ass_subscript(PyObject *myself, PyObject *item, PyObject *value)
5099+
Array_ass_item(PyObject *myself, Py_ssize_t index, PyObject *value)
5100+
{
5101+
int result;
5102+
Py_BEGIN_CRITICAL_SECTION(myself);
5103+
result = Array_ass_item_lock_held(myself, index, value);
5104+
Py_END_CRITICAL_SECTION();
5105+
return result;
5106+
}
5107+
5108+
5109+
static int
5110+
Array_ass_subscript_lock_held(PyObject *myself, PyObject *item, PyObject *value)
50825111
{
50835112
CDataObject *self = _CDataObject_CAST(myself);
50845113

@@ -5095,7 +5124,7 @@ Array_ass_subscript(PyObject *myself, PyObject *item, PyObject *value)
50955124
return -1;
50965125
if (i < 0)
50975126
i += self->b_length;
5098-
return Array_ass_item(myself, i, value);
5127+
return Array_ass_item_lock_held(myself, i, value);
50995128
}
51005129
else if (PySlice_Check(item)) {
51015130
Py_ssize_t start, stop, step, slicelen, otherlen, i;
@@ -5120,7 +5149,7 @@ Array_ass_subscript(PyObject *myself, PyObject *item, PyObject *value)
51205149
int result;
51215150
if (item == NULL)
51225151
return -1;
5123-
result = Array_ass_item(myself, cur, item);
5152+
result = Array_ass_item_lock_held(myself, cur, item);
51245153
Py_DECREF(item);
51255154
if (result == -1)
51265155
return -1;
@@ -5134,6 +5163,17 @@ Array_ass_subscript(PyObject *myself, PyObject *item, PyObject *value)
51345163
}
51355164
}
51365165

5166+
static int
5167+
Array_ass_subscript(PyObject *myself, PyObject *item, PyObject *value)
5168+
{
5169+
int result;
5170+
Py_BEGIN_CRITICAL_SECTION(myself);
5171+
result = Array_ass_subscript_lock_held(myself, item, value);
5172+
Py_END_CRITICAL_SECTION();
5173+
return result;
5174+
}
5175+
5176+
51375177
static Py_ssize_t
51385178
Array_length(PyObject *myself)
51395179
{

0 commit comments

Comments
 (0)