diff --git a/Include/pymacro.h b/Include/pymacro.h index 218987a80b0d91..f0ca334e87545c 100644 --- a/Include/pymacro.h +++ b/Include/pymacro.h @@ -25,8 +25,8 @@ // _Py_ALIGN_AS: this compiler's spelling of `alignas` keyword, -// We currently use alignas for free-threaded builds only; additional compat -// checking would be great before we add it to the default build. +// additional compat checking would be great since we added it to the default +// build. // Standards/compiler support: // - `alignas` is a keyword in C23 and C++11. // - `_Alignas` is a keyword in C11 @@ -38,30 +38,28 @@ // unsupported platforms, we don't redefine _Py_ALIGN_AS if it's already // defined. Note that defining it wrong (including defining it to nothing) will // cause ABI incompatibilities. -#ifdef Py_GIL_DISABLED -# ifndef _Py_ALIGN_AS -# ifdef __cplusplus -# if __cplusplus >= 201103L -# define _Py_ALIGN_AS(V) alignas(V) -# elif defined(__GNUC__) || defined(__clang__) -# define _Py_ALIGN_AS(V) __attribute__((aligned(V))) -# elif defined(_MSC_VER) -# define _Py_ALIGN_AS(V) __declspec(align(V)) -# else -# define _Py_ALIGN_AS(V) alignas(V) -# endif -# elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L -# define _Py_ALIGN_AS(V) alignas(V) -# elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L -# define _Py_ALIGN_AS(V) _Alignas(V) -# elif (defined(__GNUC__) || defined(__clang__)) -# define _Py_ALIGN_AS(V) __attribute__((aligned(V))) -# elif defined(_MSC_VER) -# define _Py_ALIGN_AS(V) __declspec(align(V)) -# else -# define _Py_ALIGN_AS(V) _Alignas(V) -# endif -# endif +#ifndef _Py_ALIGN_AS +# ifdef __cplusplus +# if __cplusplus >= 201103L +# define _Py_ALIGN_AS(V) alignas(V) +# elif defined(__GNUC__) || defined(__clang__) +# define _Py_ALIGN_AS(V) __attribute__((aligned(V))) +# elif defined(_MSC_VER) +# define _Py_ALIGN_AS(V) __declspec(align(V)) +# else +# define _Py_ALIGN_AS(V) alignas(V) +# endif +# elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L +# define _Py_ALIGN_AS(V) alignas(V) +# elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +# define _Py_ALIGN_AS(V) _Alignas(V) +# elif (defined(__GNUC__) || defined(__clang__)) +# define _Py_ALIGN_AS(V) __attribute__((aligned(V))) +# elif defined(_MSC_VER) +# define _Py_ALIGN_AS(V) __declspec(align(V)) +# else +# define _Py_ALIGN_AS(V) _Alignas(V) +# endif #endif /* Minimum value between x and y */ diff --git a/Lib/test/libregrtest/tsan.py b/Lib/test/libregrtest/tsan.py index d984a735bdf92f..b914c6648fea25 100644 --- a/Lib/test/libregrtest/tsan.py +++ b/Lib/test/libregrtest/tsan.py @@ -2,6 +2,7 @@ # chosen because they use threads and run in a reasonable amount of time. TSAN_TESTS = [ + 'test_array', 'test_asyncio', # TODO: enable more of test_capi once bugs are fixed (GH-116908, GH-116909). 'test_capi.test_mem', diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py index 58ea89c4fac833..75c4b10adbbe02 100755 --- a/Lib/test/test_array.py +++ b/Lib/test/test_array.py @@ -3,16 +3,21 @@ """ import collections.abc +import io +import os import unittest from test import support from test.support import import_helper from test.support import os_helper +from test.support import threading_helper from test.support import _2G import weakref import pickle import operator +import random import struct import sys +import threading import warnings import array @@ -468,54 +473,59 @@ def test_insert(self): def test_tofromfile(self): a = array.array(self.typecode, 2*self.example) self.assertRaises(TypeError, a.tofile) - os_helper.unlink(os_helper.TESTFN) - f = open(os_helper.TESTFN, 'wb') - try: - a.tofile(f) - f.close() - b = array.array(self.typecode) - f = open(os_helper.TESTFN, 'rb') - self.assertRaises(TypeError, b.fromfile) - b.fromfile(f, len(self.example)) - self.assertEqual(b, array.array(self.typecode, self.example)) - self.assertNotEqual(a, b) - self.assertRaises(EOFError, b.fromfile, f, len(self.example)+1) - self.assertEqual(a, b) - f.close() - finally: - if not f.closed: + with os_helper.temp_dir() as temp_dir: + temp_path = os.path.join(temp_dir, os_helper.TESTFN) + f = open(temp_path, 'wb') + try: + a.tofile(f) + f.close() + b = array.array(self.typecode) + f = open(temp_path, 'rb') + self.assertRaises(TypeError, b.fromfile) + b.fromfile(f, len(self.example)) + self.assertEqual(b, array.array(self.typecode, self.example)) + self.assertNotEqual(a, b) + self.assertRaises(EOFError, b.fromfile, f, len(self.example)+1) + self.assertEqual(a, b) f.close() - os_helper.unlink(os_helper.TESTFN) + finally: + if not f.closed: + f.close() + os_helper.unlink(temp_path) def test_fromfile_ioerror(self): # Issue #5395: Check if fromfile raises a proper OSError # instead of EOFError. a = array.array(self.typecode) - f = open(os_helper.TESTFN, 'wb') - try: - self.assertRaises(OSError, a.fromfile, f, len(self.example)) - finally: - f.close() - os_helper.unlink(os_helper.TESTFN) + with os_helper.temp_dir() as temp_dir: + temp_path = os.path.join(temp_dir, os_helper.TESTFN) + f = open(temp_path, 'wb') + try: + self.assertRaises(OSError, a.fromfile, f, len(self.example)) + finally: + f.close() + os_helper.unlink(temp_path) def test_filewrite(self): a = array.array(self.typecode, 2*self.example) - f = open(os_helper.TESTFN, 'wb') - try: - f.write(a) - f.close() - b = array.array(self.typecode) - f = open(os_helper.TESTFN, 'rb') - b.fromfile(f, len(self.example)) - self.assertEqual(b, array.array(self.typecode, self.example)) - self.assertNotEqual(a, b) - b.fromfile(f, len(self.example)) - self.assertEqual(a, b) - f.close() - finally: - if not f.closed: + with os_helper.temp_dir() as temp_dir: + temp_path = os.path.join(temp_dir, os_helper.TESTFN) + f = open(temp_path, 'wb') + try: + f.write(a) + f.close() + b = array.array(self.typecode) + f = open(temp_path, 'rb') + b.fromfile(f, len(self.example)) + self.assertEqual(b, array.array(self.typecode, self.example)) + self.assertNotEqual(a, b) + b.fromfile(f, len(self.example)) + self.assertEqual(a, b) f.close() - os_helper.unlink(os_helper.TESTFN) + finally: + if not f.closed: + f.close() + os_helper.unlink(temp_path) def test_tofromlist(self): a = array.array(self.typecode, 2*self.example) @@ -1168,14 +1178,14 @@ def test_create_from_bytes(self): @support.cpython_only def test_sizeof_with_buffer(self): a = array.array(self.typecode, self.example) - basesize = support.calcvobjsize('Pn2Pi') + basesize = support.calcvobjsize('PnPi') buffer_size = a.buffer_info()[1] * a.itemsize support.check_sizeof(self, a, basesize + buffer_size) @support.cpython_only def test_sizeof_without_buffer(self): a = array.array(self.typecode) - basesize = support.calcvobjsize('Pn2Pi') + basesize = support.calcvobjsize('PnPi') support.check_sizeof(self, a, basesize) def test_initialize_with_unicode(self): @@ -1197,6 +1207,7 @@ def test_obsolete_write_lock(self): a = array.array('B', b"") self.assertRaises(BufferError, _testcapi.getbuffer_with_null_view, a) + @unittest.skipIf(support.Py_GIL_DISABLED, 'not freed if GIL disabled') def test_free_after_iterating(self): support.check_free_after_iterating(self, iter, array.array, (self.typecode,)) @@ -1251,6 +1262,7 @@ def test_issue17223(self): self.assertRaises(ValueError, a.tounicode) self.assertRaises(ValueError, str, a) + @unittest.skipIf(support.Py_GIL_DISABLED, 'warning stuff is not free-thread safe yet') def test_typecode_u_deprecation(self): with self.assertWarns(DeprecationWarning): array.array("u") @@ -1673,5 +1685,274 @@ def test_gh_128961(self): self.assertRaises(StopIteration, next, it) +class FreeThreadingTest(unittest.TestCase): + # Test pretty much everything that can break under free-threading. + # Non-deterministic, but at least one of these things will fail if + # array module is not free-thread safe. + + def setUp(self): + self.enterContext(warnings.catch_warnings()) + warnings.filterwarnings( + "ignore", + message="The 'u' type code is deprecated and " + "will be removed in Python 3.16", + category=DeprecationWarning) + + def check(self, funcs, a=None, *args): + if a is None: + a = array.array('i', [1]) + + barrier = threading.Barrier(len(funcs)) + threads = [] + + for func in funcs: + thread = threading.Thread(target=func, args=(barrier, a, *args)) + + threads.append(thread) + + with threading_helper.start_threads(threads): + pass + + @unittest.skipUnless(support.Py_GIL_DISABLED, 'this test can only possibly fail with GIL disabled') + @threading_helper.reap_threads + @threading_helper.requires_working_threading() + def test_free_threading(self): + def pop1(b, a): # MODIFIES! + b.wait() + try: a.pop() + except IndexError: pass + + def append1(b, a): # MODIFIES! + b.wait() + a.append(2) + + def insert1(b, a): # MODIFIES! + b.wait() + a.insert(0, 2) + + def extend(b, a): # MODIFIES! + c = array.array('i', [2]) + b.wait() + a.extend(c) + + def extend2(b, a, c): # MODIFIES! + b.wait() + a.extend(c) + + def inplace_concat(b, a): # MODIFIES! + c = array.array('i', [2]) + b.wait() + a += c + + def inplace_concat2(b, a, c): # MODIFIES! + b.wait() + a += c + + def inplace_repeat2(b, a): # MODIFIES! + b.wait() + a *= 2 + + def clear(b, a, *args): # MODIFIES! + b.wait() + a.clear() + + def clear2(b, a, c): # MODIFIES c! + b.wait() + try: c.clear() + except BufferError: pass + + def remove1(b, a): # MODIFIES! + b.wait() + try: a.remove(1) + except ValueError: pass + + def fromunicode(b, a): # MODIFIES! + b.wait() + a.fromunicode('test') + + def frombytes(b, a): # MODIFIES! + b.wait() + a.frombytes(b'0000') + + def frombytes2(b, a, c): # MODIFIES! + b.wait() + a.frombytes(c) + + def fromlist(b, a): # MODIFIES! + n = random.randint(0, 100) + b.wait() + a.fromlist([2] * n) + + def ass_subscr2(b, a, c): # MODIFIES! + b.wait() + a[:] = c + + def ass0(b, a): # modifies inplace + b.wait() + try: a[0] = 0 + except IndexError: pass + + def byteswap(b, a): # modifies inplace + b.wait() + a.byteswap() + + def tounicode(b, a): + b.wait() + a.tounicode() + + def tobytes(b, a): + b.wait() + a.tobytes() + + def tolist(b, a): + b.wait() + a.tolist() + + def tofile(b, a): + f = io.BytesIO() + b.wait() + a.tofile(f) + + def reduce_ex2(b, a): + b.wait() + a.__reduce_ex__(2) + + def reduce_ex3(b, a): + b.wait() + c = a.__reduce_ex__(3) + assert not c[1] or 0xdd not in c[1][3] + + def copy(b, a): + b.wait() + c = a.__copy__() + assert not c or 0xdd not in c + + def repr1(b, a): + b.wait() + repr(a) + + def repeat2(b, a): + b.wait() + a * 2 + + def count1(b, a): + b.wait() + a.count(1) + + def index1(b, a): + b.wait() + try: a.index(1) + except ValueError: pass + + def contains1(b, a): + b.wait() + try: 1 in a + except ValueError: pass + + def subscr0(b, a): + b.wait() + try: a[0] + except IndexError: pass + + def concat(b, a): + b.wait() + a + a + + def concat2(b, a, c): + b.wait() + a + c + + def richcmplhs(b, a): + c = a[:] + b.wait() + a == c + + def richcmprhs(b, a): + c = a[:] + b.wait() + c == a + + def new(b, a): + tc = a.typecode + b.wait() + array.array(tc, a) + + def repr_(b, a): + b.wait() + repr(a) + + def irepeat(b, a): # MODIFIES! + b.wait() + a *= 2 + + def newi(b, l): + b.wait() + array.array('i', l) + + def fromlistl(b, a, l): # MODIFIES! + b.wait() + a.fromlist(l) + + def fromlistlclear(b, a, l): # MODIFIES LIST! + b.wait() + l.clear() + + def iter_next(b, a, it): # MODIFIES ITERATOR! + b.wait() + list(it) + + def iter_reduce(b, a, it): + b.wait() + c = it.__reduce__() + assert not c[1] or 0xdd not in c[1][0] + + self.check([pop1] * 10) + self.check([pop1] + [subscr0] * 10) + self.check([append1] * 10) + self.check([insert1] * 10) + self.check([pop1] + [index1] * 10) + self.check([pop1] + [contains1] * 10) + self.check([insert1] + [repeat2] * 10) + self.check([pop1] + [repr1] * 10) + self.check([inplace_repeat2] * 10) + self.check([byteswap] * 10) + self.check([insert1] + [clear] * 10) + self.check([pop1] + [count1] * 10) + self.check([remove1] * 10) + self.check([clear] + [copy] * 10, array.array('B', b'0' * 0x400000)) + self.check([pop1] + [reduce_ex2] * 10) + self.check([clear] + [reduce_ex3] * 10, array.array('B', b'0' * 0x400000)) + self.check([pop1] + [tobytes] * 10) + self.check([pop1] + [tolist] * 10) + self.check([clear, tounicode] * 10, array.array('w', 'a'*10000)) + self.check([clear, tofile] * 10, array.array('w', 'a'*10000)) + self.check([clear] + [extend] * 10) + self.check([clear] + [inplace_concat] * 10) + self.check([clear] + [concat] * 10, array.array('w', 'a'*10000)) + self.check([fromunicode] * 10, array.array('w', 'a')) + self.check([frombytes] * 10) + self.check([fromlist] * 10) + self.check([clear] + [richcmplhs] * 10, array.array('i', [1]*10000)) + self.check([clear] + [richcmprhs] * 10, array.array('i', [1]*10000)) + self.check([clear, ass0] * 10, array.array('i', [1]*10000)) # to test array_ass_item must disable Py_mp_ass_subscript + self.check([clear] + [new] * 10, array.array('w', 'a'*10000)) + self.check([clear] + [repr_] * 10, array.array('B', b'0' * 0x40000)) + self.check([clear] + [repr_] * 10, array.array('B', b'0' * 0x40000)) + self.check([clear] + [irepeat] * 10, array.array('B', b'0' * 0x40000)) + self.check([clear] + [iter_reduce] * 10, a := array.array('B', b'0' * 0x400), iter(a)) + + # make sure we handle non-self objects correctly + self.check([clear] + [newi] * 10, [2] * random.randint(0, 100)) + self.check([fromlistlclear] + [fromlistl] * 10, array.array('i', [1]), [2] * random.randint(0, 100)) + self.check([clear2] + [concat2] * 10, array.array('w', 'a'*10000), array.array('w', 'a'*10000)) + self.check([clear2] + [inplace_concat2] * 10, array.array('w', 'a'*10000), array.array('w', 'a'*10000)) + self.check([clear2] + [extend2] * 10, array.array('w', 'a'*10000), array.array('w', 'a'*10000)) + self.check([clear2] + [ass_subscr2] * 10, array.array('w', 'a'*10000), array.array('w', 'a'*10000)) + self.check([clear2] + [frombytes2] * 10, array.array('w', 'a'*10000), array.array('B', b'a'*10000)) + + # iterator stuff + self.check([clear] + [iter_next] * 10, a := array.array('i', [1] * 10), iter(a)) + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2025-03-02-21-08-05.gh-issue-128942.4MTI6s.rst b/Misc/NEWS.d/next/Library/2025-03-02-21-08-05.gh-issue-128942.4MTI6s.rst new file mode 100644 index 00000000000000..0f2eb614e42374 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-03-02-21-08-05.gh-issue-128942.4MTI6s.rst @@ -0,0 +1 @@ +Make :mod:`array` module safe under :term:`free threading`. diff --git a/Modules/Setup.bootstrap.in b/Modules/Setup.bootstrap.in index 2b2e8cb3e3cacd..e02c2361a26bc2 100644 --- a/Modules/Setup.bootstrap.in +++ b/Modules/Setup.bootstrap.in @@ -38,3 +38,6 @@ _symtable symtablemodule.c # for systems without $HOME env, used by site._getuserbase() @MODULE_PWD_TRUE@pwd pwdmodule.c + +# for optimization purposes +@MODULE_ARRAY_TRUE@array arraymodule.c diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in index 3a38a60a152e8c..8e763ed2590f6b 100644 --- a/Modules/Setup.stdlib.in +++ b/Modules/Setup.stdlib.in @@ -31,7 +31,6 @@ ############################################################################ # Modules that should always be present (POSIX and Windows): -@MODULE_ARRAY_TRUE@array arraymodule.c @MODULE__ASYNCIO_TRUE@_asyncio _asynciomodule.c @MODULE__BISECT_TRUE@_bisect _bisectmodule.c @MODULE__CSV_TRUE@_csv _csv.c diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index 401a3a7072b846..4d1c9ab28a5fe7 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -11,8 +11,11 @@ #include "pycore_bytesobject.h" // _PyBytes_Repeat #include "pycore_call.h" // _PyObject_CallMethod() #include "pycore_ceval.h" // _PyEval_GetBuiltin() +#include "pycore_gc.h" // _PyObject_GC_IS_SHARED() #include "pycore_modsupport.h" // _PyArg_NoKeywords() #include "pycore_moduleobject.h" // _PyModule_GetState() +#include "pycore_pyatomic_ft_wrappers.h" +#include "pycore_pymem.h" // _PyMem_FreeDelayed #include // offsetof() #include @@ -32,18 +35,23 @@ static struct PyModuleDef arraymodule; struct arraydescr { char typecode; int itemsize; - PyObject * (*getitem)(struct arrayobject *, Py_ssize_t); - int (*setitem)(struct arrayobject *, Py_ssize_t, PyObject *); + PyObject * (*getitem)(char *, Py_ssize_t); + int (*setitem)(char *, Py_ssize_t, PyObject *); int (*compareitems)(const void *, const void *, Py_ssize_t); const char *formats; int is_integer_type; int is_signed; }; +typedef struct { + Py_ssize_t allocated; + _Py_ALIGN_AS(8) + char items[]; +} arraydata; + typedef struct arrayobject { PyObject_VAR_HEAD - char *ob_item; - Py_ssize_t allocated; + arraydata *data; const struct arraydescr *ob_descr; PyObject *weakreflist; /* List of weak references */ Py_ssize_t ob_exports; /* Number of exported buffers */ @@ -53,7 +61,6 @@ typedef struct { PyObject_HEAD Py_ssize_t index; arrayobject *ao; - PyObject* (*getitem)(struct arrayobject *, Py_ssize_t); } arrayiterobject; typedef struct { @@ -68,6 +75,20 @@ typedef struct { PyObject *str_iter; } array_state; +static Py_ssize_t +PyArray_GET_SIZE(PyObject *op) { + arrayobject *ao = (arrayobject *)op; +#ifdef Py_GIL_DISABLED + return _Py_atomic_load_ssize_relaxed(&(_PyVarObject_CAST(ao)->ob_size)); +#else + return Py_SIZE(ao); +#endif +} +#define PyArray_GET_SIZE(op) PyArray_GET_SIZE(_PyObject_CAST(op)) + +/* Forward declaration. */ +static PyObject *array_array_frombytes(PyObject *self, PyObject *bytes); + static array_state * get_array_state(PyObject *module) { @@ -130,11 +151,57 @@ enum machine_format_code { #define array_Check(op, state) PyObject_TypeCheck(op, state->ArrayType) +static arraydata * +arraydata_alloc(Py_ssize_t size, int itemsize) +{ + arraydata *data = (arraydata *)PyMem_Malloc(sizeof(arraydata) + size * itemsize); + if (data == NULL) { + return NULL; + } + data->allocated = size; + return data; +} + +static void +arraydata_free(arraydata *data, bool use_qsbr) +{ +#ifdef Py_GIL_DISABLED + if (use_qsbr) { + _PyMem_FreeDelayed(data); + } + else { + PyMem_Free(data); + } +#else + PyMem_Free(data); +#endif +} + +#ifndef Py_GIL_DISABLED + +static arraydata * +arraydata_realloc(arraydata *data, Py_ssize_t size, int itemsize) +{ + data = (arraydata *)PyMem_Realloc(data, sizeof(arraydata) + size * itemsize); + if (data == NULL) { + return NULL; + } + data->allocated = size; + return data; +} + +#endif + +static char * +array_items_ptr(arrayobject *self) +{ + return self->data == NULL ? NULL : self->data->items; +} + static int array_resize(arrayobject *self, Py_ssize_t newsize) { - char *items; - size_t _new_size; + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self); if (self->ob_exports > 0 && newsize != Py_SIZE(self)) { PyErr_SetString(PyExc_BufferError, @@ -147,18 +214,33 @@ array_resize(arrayobject *self, Py_ssize_t newsize) current size, then proceed with the realloc() to shrink the array. */ - if (self->allocated >= newsize && - Py_SIZE(self) < newsize + 16 && - self->ob_item != NULL) { + arraydata *data = self->data; + + if (data != NULL && + data->allocated >= newsize && + Py_SIZE(self) < newsize + 16) { Py_SET_SIZE(self, newsize); return 0; } +#ifdef Py_GIL_DISABLED + // Ensure that the array is freed using QSBR if we are not the + // owning thread. + if (!_Py_IsOwnedByCurrentThread((PyObject *)self) && + !_PyObject_GC_IS_SHARED(self)) + { + _PyObject_GC_SET_SHARED(self); + } +#endif + if (newsize == 0) { - PyMem_Free(self->ob_item); - self->ob_item = NULL; +#ifdef Py_GIL_DISABLED + arraydata_free(self->data, _PyObject_GC_IS_SHARED(self)); +#else + arraydata_free(self->data, false); +#endif Py_SET_SIZE(self, 0); - self->allocated = 0; + FT_ATOMIC_STORE_PTR_RELAXED(self->data, NULL); return 0; } @@ -174,21 +256,38 @@ array_resize(arrayobject *self, Py_ssize_t newsize) * memory critical. */ - _new_size = (newsize >> 4) + (Py_SIZE(self) < 8 ? 3 : 7) + newsize; - items = self->ob_item; + size_t _new_size = (newsize >> 4) + (Py_SIZE(self) < 8 ? 3 : 7) + newsize; + int itemsize = self->ob_descr->itemsize; + /* XXX The following multiplication and division does not optimize away like it does for lists since the size is not known at compile time */ - if (_new_size <= ((~(size_t)0) / self->ob_descr->itemsize)) - PyMem_RESIZE(items, char, (_new_size * self->ob_descr->itemsize)); - else - items = NULL; - if (items == NULL) { + if (_new_size > ((~(size_t)0) / itemsize)) { + PyErr_NoMemory(); + return -1; + } + +#ifdef Py_GIL_DISABLED + arraydata *newdata = arraydata_alloc(_new_size, itemsize); + if (newdata == NULL) { + PyErr_NoMemory(); + return -1; + } + if (data != NULL) { + Py_ssize_t size = Py_SIZE(self); + memcpy(newdata->items, data->items, Py_MIN(size, newsize) * itemsize); + arraydata_free(data, _PyObject_GC_IS_SHARED(self)); + } + _Py_atomic_store_ptr_release(&self->data, newdata); +#else + data = arraydata_realloc(data, _new_size, itemsize); + if (data == NULL) { PyErr_NoMemory(); return -1; } - self->ob_item = items; + self->data = data; +#endif + Py_SET_SIZE(self, newsize); - self->allocated = _new_size; return 0; } @@ -205,21 +304,22 @@ in bounds; that's the responsibility of the caller. ****************************************************************************/ static PyObject * -b_getitem(arrayobject *ap, Py_ssize_t i) +b_getitem(char *items, Py_ssize_t i) { - long x = ((signed char *)ap->ob_item)[i]; + long x = ((signed char *)items)[i]; return PyLong_FromLong(x); } static int -b_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) +b_setitem(char *items, Py_ssize_t i, PyObject *v) { short x; /* PyArg_Parse's 'b' formatter is for an unsigned char, therefore must use the next size up that is signed ('h') and manually do the overflow checking */ - if (!PyArg_Parse(v, "h;array item must be integer", &x)) + if (!PyArg_Parse(v, "h;array item must be integer", &x)) { return -1; + } else if (x < -128) { PyErr_SetString(PyExc_OverflowError, "signed char is less than minimum"); @@ -230,38 +330,41 @@ b_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) "signed char is greater than maximum"); return -1; } - if (i >= 0) - ((char *)ap->ob_item)[i] = (char)x; + if (i >= 0) { + ((char *)items)[i] = (char)x; + } return 0; } static PyObject * -BB_getitem(arrayobject *ap, Py_ssize_t i) +BB_getitem(char *items, Py_ssize_t i) { - long x = ((unsigned char *)ap->ob_item)[i]; + long x = ((unsigned char *)items)[i]; return PyLong_FromLong(x); } static int -BB_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) +BB_setitem(char *items, Py_ssize_t i, PyObject *v) { unsigned char x; /* 'B' == unsigned char, maps to PyArg_Parse's 'b' formatter */ - if (!PyArg_Parse(v, "b;array item must be integer", &x)) + if (!PyArg_Parse(v, "b;array item must be integer", &x)) { return -1; - if (i >= 0) - ((unsigned char *)ap->ob_item)[i] = x; + } + if (i >= 0) { + ((unsigned char *)items)[i] = x; + } return 0; } static PyObject * -u_getitem(arrayobject *ap, Py_ssize_t i) +u_getitem(char *items, Py_ssize_t i) { - return PyUnicode_FromOrdinal(((wchar_t *) ap->ob_item)[i]); + return PyUnicode_FromOrdinal(((wchar_t *) items)[i]); } static int -u_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) +u_setitem(char *items, Py_ssize_t i, PyObject *v) { if (!PyUnicode_Check(v)) { PyErr_Format(PyExc_TypeError, @@ -292,19 +395,19 @@ u_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) assert(len == 1); if (i >= 0) { - ((wchar_t *)ap->ob_item)[i] = w; + ((wchar_t *)items)[i] = w; } return 0; } static PyObject * -w_getitem(arrayobject *ap, Py_ssize_t i) +w_getitem(char *items, Py_ssize_t i) { - return PyUnicode_FromOrdinal(((Py_UCS4 *) ap->ob_item)[i]); + return PyUnicode_FromOrdinal(((Py_UCS4 *) items)[i]); } static int -w_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) +w_setitem(char *items, Py_ssize_t i, PyObject *v) { if (!PyUnicode_Check(v)) { PyErr_Format(PyExc_TypeError, @@ -322,44 +425,47 @@ w_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) } if (i >= 0) { - ((Py_UCS4 *)ap->ob_item)[i] = PyUnicode_READ_CHAR(v, 0); + ((Py_UCS4 *)items)[i] = PyUnicode_READ_CHAR(v, 0); } return 0; } static PyObject * -h_getitem(arrayobject *ap, Py_ssize_t i) +h_getitem(char *items, Py_ssize_t i) { - return PyLong_FromLong((long) ((short *)ap->ob_item)[i]); + return PyLong_FromLong((long) ((short *)items)[i]); } static int -h_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) +h_setitem(char *items, Py_ssize_t i, PyObject *v) { short x; /* 'h' == signed short, maps to PyArg_Parse's 'h' formatter */ - if (!PyArg_Parse(v, "h;array item must be integer", &x)) + if (!PyArg_Parse(v, "h;array item must be integer", &x)) { return -1; - if (i >= 0) - ((short *)ap->ob_item)[i] = x; + } + if (i >= 0) { + ((short *)items)[i] = x; + } return 0; } static PyObject * -HH_getitem(arrayobject *ap, Py_ssize_t i) +HH_getitem(char *items, Py_ssize_t i) { - return PyLong_FromLong((long) ((unsigned short *)ap->ob_item)[i]); + return PyLong_FromLong((long) ((unsigned short *)items)[i]); } static int -HH_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) +HH_setitem(char *items, Py_ssize_t i, PyObject *v) { int x; /* PyArg_Parse's 'h' formatter is for a signed short, therefore must use the next size up and manually do the overflow checking */ - if (!PyArg_Parse(v, "i;array item must be integer", &x)) + if (!PyArg_Parse(v, "i;array item must be integer", &x)) { return -1; + } else if (x < 0) { PyErr_SetString(PyExc_OverflowError, "unsigned short is less than minimum"); @@ -370,38 +476,41 @@ HH_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) "unsigned short is greater than maximum"); return -1; } - if (i >= 0) - ((short *)ap->ob_item)[i] = (short)x; + if (i >= 0) { + ((short *)items)[i] = (short)x; + } return 0; } static PyObject * -i_getitem(arrayobject *ap, Py_ssize_t i) +i_getitem(char *items, Py_ssize_t i) { - return PyLong_FromLong((long) ((int *)ap->ob_item)[i]); + return PyLong_FromLong((long) ((int *)items)[i]); } static int -i_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) +i_setitem(char *items, Py_ssize_t i, PyObject *v) { int x; /* 'i' == signed int, maps to PyArg_Parse's 'i' formatter */ - if (!PyArg_Parse(v, "i;array item must be integer", &x)) + if (!PyArg_Parse(v, "i;array item must be integer", &x)) { return -1; - if (i >= 0) - ((int *)ap->ob_item)[i] = x; + } + if (i >= 0) { + ((int *)items)[i] = x; + } return 0; } static PyObject * -II_getitem(arrayobject *ap, Py_ssize_t i) +II_getitem(char *items, Py_ssize_t i) { return PyLong_FromUnsignedLong( - (unsigned long) ((unsigned int *)ap->ob_item)[i]); + (unsigned long) ((unsigned int *)items)[i]); } static int -II_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) +II_setitem(char *items, Py_ssize_t i, PyObject *v) { unsigned long x; int do_decref = 0; /* if nb_int was called */ @@ -428,8 +537,9 @@ II_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) } return -1; } - if (i >= 0) - ((unsigned int *)ap->ob_item)[i] = (unsigned int)x; + if (i >= 0) { + ((unsigned int *)items)[i] = (unsigned int)x; + } if (do_decref) { Py_DECREF(v); @@ -438,30 +548,32 @@ II_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) } static PyObject * -l_getitem(arrayobject *ap, Py_ssize_t i) +l_getitem(char *items, Py_ssize_t i) { - return PyLong_FromLong(((long *)ap->ob_item)[i]); + return PyLong_FromLong(((long *)items)[i]); } static int -l_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) +l_setitem(char *items, Py_ssize_t i, PyObject *v) { long x; - if (!PyArg_Parse(v, "l;array item must be integer", &x)) + if (!PyArg_Parse(v, "l;array item must be integer", &x)) { return -1; - if (i >= 0) - ((long *)ap->ob_item)[i] = x; + } + if (i >= 0) { + ((long *)items)[i] = x; + } return 0; } static PyObject * -LL_getitem(arrayobject *ap, Py_ssize_t i) +LL_getitem(char *items, Py_ssize_t i) { - return PyLong_FromUnsignedLong(((unsigned long *)ap->ob_item)[i]); + return PyLong_FromUnsignedLong(((unsigned long *)items)[i]); } static int -LL_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) +LL_setitem(char *items, Py_ssize_t i, PyObject *v) { unsigned long x; int do_decref = 0; /* if nb_int was called */ @@ -480,8 +592,9 @@ LL_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) } return -1; } - if (i >= 0) - ((unsigned long *)ap->ob_item)[i] = x; + if (i >= 0) { + ((unsigned long *)items)[i] = x; + } if (do_decref) { Py_DECREF(v); @@ -490,31 +603,33 @@ LL_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) } static PyObject * -q_getitem(arrayobject *ap, Py_ssize_t i) +q_getitem(char *items, Py_ssize_t i) { - return PyLong_FromLongLong(((long long *)ap->ob_item)[i]); + return PyLong_FromLongLong(((long long *)items)[i]); } static int -q_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) +q_setitem(char *items, Py_ssize_t i, PyObject *v) { long long x; - if (!PyArg_Parse(v, "L;array item must be integer", &x)) + if (!PyArg_Parse(v, "L;array item must be integer", &x)) { return -1; - if (i >= 0) - ((long long *)ap->ob_item)[i] = x; + } + if (i >= 0) { + ((long long *)items)[i] = x; + } return 0; } static PyObject * -QQ_getitem(arrayobject *ap, Py_ssize_t i) +QQ_getitem(char *items, Py_ssize_t i) { return PyLong_FromUnsignedLongLong( - ((unsigned long long *)ap->ob_item)[i]); + ((unsigned long long *)items)[i]); } static int -QQ_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) +QQ_setitem(char *items, Py_ssize_t i, PyObject *v) { unsigned long long x; int do_decref = 0; /* if nb_int was called */ @@ -533,8 +648,9 @@ QQ_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) } return -1; } - if (i >= 0) - ((unsigned long long *)ap->ob_item)[i] = x; + if (i >= 0) { + ((unsigned long long *)items)[i] = x; + } if (do_decref) { Py_DECREF(v); @@ -543,36 +659,40 @@ QQ_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) } static PyObject * -f_getitem(arrayobject *ap, Py_ssize_t i) +f_getitem(char *items, Py_ssize_t i) { - return PyFloat_FromDouble((double) ((float *)ap->ob_item)[i]); + return PyFloat_FromDouble((double) ((float *)items)[i]); } static int -f_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) +f_setitem(char *items, Py_ssize_t i, PyObject *v) { float x; - if (!PyArg_Parse(v, "f;array item must be float", &x)) + if (!PyArg_Parse(v, "f;array item must be float", &x)) { return -1; - if (i >= 0) - ((float *)ap->ob_item)[i] = x; + } + if (i >= 0) { + ((float *)items)[i] = x; + } return 0; } static PyObject * -d_getitem(arrayobject *ap, Py_ssize_t i) +d_getitem(char *items, Py_ssize_t i) { - return PyFloat_FromDouble(((double *)ap->ob_item)[i]); + return PyFloat_FromDouble(((double *)items)[i]); } static int -d_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) +d_setitem(char *items, Py_ssize_t i, PyObject *v) { double x; - if (!PyArg_Parse(v, "d;array item must be float", &x)) + if (!PyArg_Parse(v, "d;array item must be float", &x)) { return -1; - if (i >= 0) - ((double *)ap->ob_item)[i] = x; + } + if (i >= 0) { + ((double *)items)[i] = x; + } return 0; } @@ -581,9 +701,11 @@ d_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) code##_compareitems(const void *lhs, const void *rhs, Py_ssize_t length) \ { \ const type *a = lhs, *b = rhs; \ - for (Py_ssize_t i = 0; i < length; ++i) \ - if (a[i] != b[i]) \ + for (Py_ssize_t i = 0; i < length; ++i) { \ + if (a[i] != b[i]) { \ return a[i] < b[i] ? -1 : 1; \ + } \ + } \ return 0; \ } @@ -635,7 +757,6 @@ static PyObject * newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *descr) { arrayobject *op; - size_t nbytes; if (size < 0) { PyErr_BadInternalCall(); @@ -646,21 +767,19 @@ newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *des if (size > PY_SSIZE_T_MAX / descr->itemsize) { return PyErr_NoMemory(); } - nbytes = size * descr->itemsize; op = (arrayobject *) type->tp_alloc(type, 0); if (op == NULL) { return NULL; } op->ob_descr = descr; - op->allocated = size; op->weakreflist = NULL; Py_SET_SIZE(op, size); if (size <= 0) { - op->ob_item = NULL; + op->data = NULL; } else { - op->ob_item = PyMem_NEW(char, nbytes); - if (op->ob_item == NULL) { + op->data = arraydata_alloc(size, descr->itemsize); + if (op->data == NULL) { Py_DECREF(op); return PyErr_NoMemory(); } @@ -669,34 +788,171 @@ newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *des return (PyObject *) op; } +static int +valid_index(Py_ssize_t i, Py_ssize_t limit) +{ + return (size_t) i < (size_t) limit; +} + static PyObject * -getarrayitem(PyObject *op, Py_ssize_t i) +getarrayitem(arrayobject *ap, Py_ssize_t i, arraydata *data) { #ifndef NDEBUG - array_state *state = find_array_state_by_type(Py_TYPE(op)); - assert(array_Check(op, state)); + array_state *state = find_array_state_by_type(Py_TYPE(ap)); + assert(array_Check(ap, state)); +#ifdef Py_GIL_DISABLED + assert(valid_index(i, data->allocated)); +#else + assert(valid_index(i, Py_SIZE(ap))); #endif - arrayobject *ap; - ap = (arrayobject *)op; - assert(i>=0 && iob_descr->getitem)(ap, i); +#endif + return (*ap->ob_descr->getitem)(data->items, i); +} + +static PyObject * +getarrayitem_locked(PyObject *op, Py_ssize_t i) +{ + PyObject *ret; + Py_BEGIN_CRITICAL_SECTION(op); +#ifdef Py_GIL_DISABLED + if (!_PyObject_GC_IS_SHARED(op)) { + _PyObject_GC_SET_SHARED(op); + } +#endif + if (!valid_index(i, Py_SIZE(op))) { + ret = NULL; + } + else { + arrayobject *ap = (arrayobject *)op; + ret = getarrayitem(ap, i, ap->data); + } + Py_END_CRITICAL_SECTION(); + return ret; } +#ifdef Py_GIL_DISABLED + +static PyObject * +getarrayitem_threadsafe(PyObject *op, Py_ssize_t i) +{ + if (!_Py_IsOwnedByCurrentThread((PyObject *)op) && !_PyObject_GC_IS_SHARED(op)) { + return getarrayitem_locked(op, i); + } + Py_ssize_t size = PyArray_GET_SIZE(op); + if (!valid_index(i, size)) { + return NULL; + } + arrayobject *ap = (arrayobject *)op; + arraydata *data = _Py_atomic_load_ptr_acquire(&ap->data); + if (data == NULL) { + return NULL; + } + if (!valid_index(i, data->allocated)) { + return NULL; + } + return getarrayitem(ap, i, data); +} + +#else // Py_GIL_DISABLED + +static PyObject * +getarrayitem_threadsafe(PyObject *op, Py_ssize_t i) +{ + return getarrayitem_locked(op, i); +} + +#endif // Py_GIL_DISABLED + +static int +setarrayitem(arrayobject *ap, Py_ssize_t i, PyObject *v, arraydata *data) +{ +#ifndef NDEBUG + array_state *state = find_array_state_by_type(Py_TYPE(ap)); + assert(array_Check(ap, state)); + if (data != NULL) { +#ifdef Py_GIL_DISABLED + assert(valid_index(i, data->allocated)); +#else + assert(valid_index(i, Py_SIZE(ap))); +#endif + } +#endif + return (*ap->ob_descr->setitem)(data->items, i, v); +} + +static int +setarrayitem_locked(PyObject *op, Py_ssize_t i, PyObject *v) +{ + int ret; + Py_BEGIN_CRITICAL_SECTION(op); +#ifdef Py_GIL_DISABLED + if (!_PyObject_GC_IS_SHARED(op)) { + _PyObject_GC_SET_SHARED(op); + } +#endif + if (!valid_index(i, Py_SIZE(op))) { + PyErr_SetString(PyExc_IndexError, "array index out of range"); + ret = -1; + } + else { + arrayobject *ap = arrayobject_CAST(op); + ret = setarrayitem(ap, i, v, ap->data); + } + Py_END_CRITICAL_SECTION(); + return ret; +} + +#ifdef Py_GIL_DISABLED + +static int +setarrayitem_threadsafe(PyObject *op, Py_ssize_t i, PyObject *v) +{ + if (!_Py_IsOwnedByCurrentThread((PyObject *)op) && !_PyObject_GC_IS_SHARED(op)) { + return setarrayitem_locked(op, i, v); + } + Py_ssize_t size = PyArray_GET_SIZE(op); + if (!valid_index(i, size)) { + goto error; + } + arrayobject *ap = (arrayobject *)op; + arraydata *data = _Py_atomic_load_ptr_acquire(&ap->data); + if (data == NULL) { + goto error; + } + if (!valid_index(i, data->allocated)) { + goto error; + } + return setarrayitem(ap, i, v, data); + +error: + PyErr_SetString(PyExc_IndexError, "array index out of range"); + return -1; +} + +#else // Py_GIL_DISABLED + +static int +setarrayitem_threadsafe(PyObject *op, Py_ssize_t i, PyObject *v) +{ + return setarrayitem_locked(op, i, v); +} + +#endif // Py_GIL_DISABLED + static int ins1(arrayobject *self, Py_ssize_t where, PyObject *v) { - char *items; + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self); Py_ssize_t n = Py_SIZE(self); if (v == NULL) { PyErr_BadInternalCall(); return -1; } - if ((*self->ob_descr->setitem)(self, -1, v) < 0) + if (setarrayitem(self, -1, v, NULL) < 0) return -1; if (array_resize(self, n+1) == -1) return -1; - items = self->ob_item; if (where < 0) { where += n; if (where < 0) @@ -706,10 +962,10 @@ ins1(arrayobject *self, Py_ssize_t where, PyObject *v) where = n; /* appends don't need to call memmove() */ if (where != n) - memmove(items + (where+1)*self->ob_descr->itemsize, - items + where*self->ob_descr->itemsize, + memmove(array_items_ptr(self) + (where+1)*self->ob_descr->itemsize, + array_items_ptr(self) + where*self->ob_descr->itemsize, (n-where)*self->ob_descr->itemsize); - return (*self->ob_descr->setitem)(self, where, v); + return setarrayitem(self, where, v, self->data); } /* Methods */ @@ -728,19 +984,26 @@ array_dealloc(PyObject *op) PyObject_GC_UnTrack(op); arrayobject *self = arrayobject_CAST(op); + if (self->ob_exports > 0) { + PyErr_SetString(PyExc_SystemError, + "deallocated array object has exported buffers"); + PyErr_WriteUnraisable(NULL); + } if (self->weakreflist != NULL) { PyObject_ClearWeakRefs(op); } - if (self->ob_item != NULL) { - PyMem_Free(self->ob_item); + if (self->data != NULL) { + arraydata_free(self->data, false); } tp->tp_free(op); Py_DECREF(tp); } static PyObject * -array_richcompare(PyObject *v, PyObject *w, int op) +array_richcompare_lock_held(PyObject *v, PyObject *w, int op) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(v); + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(w); array_state *state = find_array_state_by_type(Py_TYPE(v)); arrayobject *va, *wa; PyObject *vi = NULL; @@ -767,7 +1030,7 @@ array_richcompare(PyObject *v, PyObject *w, int op) /* Fast path: arrays with same types can have their buffers compared directly */ Py_ssize_t common_length = Py_MIN(Py_SIZE(va), Py_SIZE(wa)); - int result = va->ob_descr->compareitems(va->ob_item, wa->ob_item, + int result = va->ob_descr->compareitems(array_items_ptr(va), array_items_ptr(wa), common_length); if (result == 0) goto compare_sizes; @@ -790,11 +1053,11 @@ array_richcompare(PyObject *v, PyObject *w, int op) /* Search for the first index where items are different */ k = 1; for (i = 0; i < Py_SIZE(va) && i < Py_SIZE(wa); i++) { - vi = getarrayitem(v, i); + vi = getarrayitem(va, i, va->data); if (vi == NULL) { return NULL; } - wi = getarrayitem(w, i); + wi = getarrayitem(wa, i, wa->data); if (wi == NULL) { Py_DECREF(vi); return NULL; @@ -848,25 +1111,39 @@ array_richcompare(PyObject *v, PyObject *w, int op) return res; } +static PyObject * +array_richcompare(PyObject *v, PyObject *w, int op) +{ + PyObject *ret; + Py_BEGIN_CRITICAL_SECTION2(v, w); + ret = array_richcompare_lock_held(v, w, op); + Py_END_CRITICAL_SECTION2(); + return ret; +} + static Py_ssize_t array_length(PyObject *op) { - return Py_SIZE(op); + arrayobject *self = arrayobject_CAST(op); + return PyArray_GET_SIZE(self); } + static PyObject * array_item(PyObject *op, Py_ssize_t i) { - if (i < 0 || i >= Py_SIZE(op)) { + PyObject *item = getarrayitem_threadsafe(op, i); + if (item == NULL) { PyErr_SetString(PyExc_IndexError, "array index out of range"); - return NULL; } - return getarrayitem(op, i); + return item; } + static PyObject * array_slice(arrayobject *a, Py_ssize_t ilow, Py_ssize_t ihigh) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(a); array_state *state = find_array_state_by_type(Py_TYPE(a)); arrayobject *np; @@ -884,13 +1161,14 @@ array_slice(arrayobject *a, Py_ssize_t ilow, Py_ssize_t ihigh) if (np == NULL) return NULL; if (ihigh > ilow) { - memcpy(np->ob_item, a->ob_item + ilow * a->ob_descr->itemsize, - (ihigh-ilow) * a->ob_descr->itemsize); + memcpy(array_items_ptr(np), array_items_ptr(a) + ilow * a->ob_descr->itemsize, + (ihigh-ilow) * a->ob_descr->itemsize); } return (PyObject *)np; } /*[clinic input] +@critical_section array.array.clear Remove all items from the array. @@ -898,7 +1176,7 @@ Remove all items from the array. static PyObject * array_array_clear_impl(arrayobject *self) -/*[clinic end generated code: output=5efe0417062210a9 input=5dffa30e94e717a4]*/ +/*[clinic end generated code: output=5efe0417062210a9 input=1c9dfcc80f5b6731]*/ { if (array_resize(self, 0) == -1) { return NULL; @@ -907,6 +1185,7 @@ array_array_clear_impl(arrayobject *self) } /*[clinic input] +@critical_section array.array.__copy__ Return a copy of the array. @@ -914,12 +1193,13 @@ Return a copy of the array. static PyObject * array_array___copy___impl(arrayobject *self) -/*[clinic end generated code: output=dec7c3f925d9619e input=ad1ee5b086965f09]*/ +/*[clinic end generated code: output=dec7c3f925d9619e input=7622f8f9489472d5]*/ { return array_slice(self, 0, Py_SIZE(self)); } /*[clinic input] +@critical_section array.array.__deepcopy__ unused: object @@ -930,14 +1210,16 @@ Return a copy of the array. static PyObject * array_array___deepcopy___impl(arrayobject *self, PyObject *unused) -/*[clinic end generated code: output=703b4c412feaaf31 input=2405ecb4933748c4]*/ +/*[clinic end generated code: output=703b4c412feaaf31 input=1a29f718f5b8a1dc]*/ { return array_array___copy___impl(self); } static PyObject * -array_concat(PyObject *op, PyObject *bb) +array_concat_lock_held(PyObject *op, PyObject *bb) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op); + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(bb); arrayobject *a = arrayobject_CAST(op); array_state *state = find_array_state_by_type(Py_TYPE(a)); Py_ssize_t size; @@ -962,19 +1244,30 @@ array_concat(PyObject *op, PyObject *bb) return NULL; } if (Py_SIZE(a) > 0) { - memcpy(np->ob_item, a->ob_item, Py_SIZE(a)*a->ob_descr->itemsize); + memcpy(array_items_ptr(np), array_items_ptr(a), Py_SIZE(a)*a->ob_descr->itemsize); } if (Py_SIZE(b) > 0) { - memcpy(np->ob_item + Py_SIZE(a)*a->ob_descr->itemsize, - b->ob_item, Py_SIZE(b)*b->ob_descr->itemsize); + memcpy(array_items_ptr(np) + Py_SIZE(a)*a->ob_descr->itemsize, + array_items_ptr(b), Py_SIZE(b)*b->ob_descr->itemsize); } return (PyObject *)np; #undef b } static PyObject * -array_repeat(PyObject *op, Py_ssize_t n) +array_concat(PyObject *op, PyObject *bb) +{ + PyObject *ret; + Py_BEGIN_CRITICAL_SECTION2(op, bb); + ret = array_concat_lock_held(op, bb); + Py_END_CRITICAL_SECTION2(); + return ret; +} + +static PyObject * +array_repeat_lock_held(PyObject *op, Py_ssize_t n) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op); arrayobject *a = arrayobject_CAST(op); array_state *state = find_array_state_by_type(Py_TYPE(a)); @@ -993,14 +1286,25 @@ array_repeat(PyObject *op, Py_ssize_t n) const Py_ssize_t oldbytes = array_length * a->ob_descr->itemsize; const Py_ssize_t newbytes = oldbytes * n; - _PyBytes_Repeat(np->ob_item, newbytes, a->ob_item, oldbytes); + _PyBytes_Repeat(array_items_ptr(np), newbytes, array_items_ptr(a), oldbytes); return (PyObject *)np; } +static PyObject * +array_repeat(PyObject *op, Py_ssize_t n) +{ + PyObject *ret; + Py_BEGIN_CRITICAL_SECTION(op); + ret = array_repeat_lock_held(op, n); + Py_END_CRITICAL_SECTION(); + return ret; +} + static int array_del_slice(arrayobject *a, Py_ssize_t ilow, Py_ssize_t ihigh) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(a); char *item; Py_ssize_t d; /* Change in size */ if (ilow < 0) @@ -1013,7 +1317,7 @@ array_del_slice(arrayobject *a, Py_ssize_t ilow, Py_ssize_t ihigh) ihigh = ilow; else if (ihigh > Py_SIZE(a)) ihigh = Py_SIZE(a); - item = a->ob_item; + item = array_items_ptr(a); d = ihigh-ilow; /* Issue #4509: If the array has exported buffers and the slice assignment would change the size of the array, fail early to make @@ -1036,30 +1340,21 @@ array_del_slice(arrayobject *a, Py_ssize_t ilow, Py_ssize_t ihigh) static int array_ass_item(PyObject *op, Py_ssize_t i, PyObject *v) { - arrayobject *a = arrayobject_CAST(op); - if (i < 0 || i >= Py_SIZE(a)) { - PyErr_SetString(PyExc_IndexError, - "array assignment index out of range"); - return -1; + if (v != NULL) { + return setarrayitem_threadsafe(op, i, v); } - if (v == NULL) - return array_del_slice(a, i, i+1); - return (*a->ob_descr->setitem)(a, i, v); -} - -static int -setarrayitem(PyObject *a, Py_ssize_t i, PyObject *v) -{ -#ifndef NDEBUG - array_state *state = find_array_state_by_type(Py_TYPE(a)); - assert(array_Check(a, state)); -#endif - return array_ass_item(a, i, v); + int ret; + Py_BEGIN_CRITICAL_SECTION(op); + ret = array_del_slice(arrayobject_CAST(op), i, i+1); + Py_END_CRITICAL_SECTION(); + return ret; } static int array_iter_extend(arrayobject *self, PyObject *bb) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self); + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(bb); PyObject *it, *v; it = PyObject_GetIter(bb); @@ -1081,8 +1376,10 @@ array_iter_extend(arrayobject *self, PyObject *bb) } static int -array_do_extend(array_state *state, arrayobject *self, PyObject *bb) +array_do_extend_lock_held(array_state *state, arrayobject *self, PyObject *bb) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self); + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(bb); Py_ssize_t size, oldsize, bbsize; if (!array_Check(bb, state)) @@ -1105,14 +1402,24 @@ array_do_extend(array_state *state, arrayobject *self, PyObject *bb) if (array_resize(self, size) == -1) return -1; if (bbsize > 0) { - memcpy(self->ob_item + oldsize * self->ob_descr->itemsize, - b->ob_item, bbsize * b->ob_descr->itemsize); + memcpy(array_items_ptr(self) + oldsize * self->ob_descr->itemsize, + array_items_ptr(b), bbsize * b->ob_descr->itemsize); } return 0; #undef b } +static int +array_do_extend(array_state *state, arrayobject *self, PyObject *bb) +{ + int ret; + Py_BEGIN_CRITICAL_SECTION2(self, bb); + ret = array_do_extend_lock_held(state, self, bb); + Py_END_CRITICAL_SECTION2(); + return ret; +} + static PyObject * array_inplace_concat(PyObject *op, PyObject *bb) { @@ -1131,8 +1438,9 @@ array_inplace_concat(PyObject *op, PyObject *bb) } static PyObject * -array_inplace_repeat(PyObject *op, Py_ssize_t n) +array_inplace_repeat_lock_held(PyObject *op, Py_ssize_t n) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op); arrayobject *self = arrayobject_CAST(op); const Py_ssize_t array_size = Py_SIZE(self); @@ -1150,21 +1458,24 @@ array_inplace_repeat(PyObject *op, Py_ssize_t n) if (array_resize(self, n * array_size) == -1) return NULL; - _PyBytes_Repeat(self->ob_item, n*size, self->ob_item, size); + _PyBytes_Repeat(array_items_ptr(self), n*size, array_items_ptr(self), size); } return Py_NewRef(self); } - static PyObject * -ins(arrayobject *self, Py_ssize_t where, PyObject *v) +array_inplace_repeat(PyObject *op, Py_ssize_t n) { - if (ins1(self, where, v) != 0) - return NULL; - Py_RETURN_NONE; + PyObject *ret; + Py_BEGIN_CRITICAL_SECTION(op); + ret = array_inplace_repeat_lock_held(op, n); + Py_END_CRITICAL_SECTION(); + return ret; } + /*[clinic input] +@critical_section array.array.count v: object @@ -1175,7 +1486,7 @@ Return number of occurrences of v in the array. static PyObject * array_array_count_impl(arrayobject *self, PyObject *v) -/*[clinic end generated code: output=93ead26a2affb739 input=d9bce9d65e39d1f5]*/ +/*[clinic end generated code: output=93ead26a2affb739 input=c12c0042c1d0e27e]*/ { Py_ssize_t count = 0; Py_ssize_t i; @@ -1184,7 +1495,7 @@ array_array_count_impl(arrayobject *self, PyObject *v) PyObject *selfi; int cmp; - selfi = getarrayitem((PyObject *)self, i); + selfi = getarrayitem(self, i, self->data); if (selfi == NULL) return NULL; cmp = PyObject_RichCompareBool(selfi, v, Py_EQ); @@ -1199,6 +1510,7 @@ array_array_count_impl(arrayobject *self, PyObject *v) /*[clinic input] +@critical_section array.array.index v: object @@ -1214,7 +1526,7 @@ Raise ValueError if the value is not present. static PyObject * array_array_index_impl(arrayobject *self, PyObject *v, Py_ssize_t start, Py_ssize_t stop) -/*[clinic end generated code: output=c45e777880c99f52 input=089dff7baa7e5a7e]*/ +/*[clinic end generated code: output=c45e777880c99f52 input=fa32ac8ec22175d6]*/ { if (start < 0) { start += Py_SIZE(self); @@ -1231,7 +1543,7 @@ array_array_index_impl(arrayobject *self, PyObject *v, Py_ssize_t start, PyObject *selfi; int cmp; - selfi = getarrayitem((PyObject *)self, i); + selfi = getarrayitem(self, i, self->data); if (selfi == NULL) return NULL; cmp = PyObject_RichCompareBool(selfi, v, Py_EQ); @@ -1247,22 +1559,35 @@ array_array_index_impl(arrayobject *self, PyObject *v, Py_ssize_t start, } static int -array_contains(PyObject *self, PyObject *v) +array_contains_lock_held(PyObject *op, PyObject *v) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op); Py_ssize_t i; int cmp; - for (i = 0, cmp = 0 ; cmp == 0 && i < Py_SIZE(self); i++) { - PyObject *selfi = getarrayitem(self, i); - if (selfi == NULL) + for (i = 0, cmp = 0 ; cmp == 0 && i < Py_SIZE(op); i++) { + arrayobject *ap = (arrayobject *)op; + PyObject *opi = getarrayitem(ap, i, ap->data); + if (opi == NULL) return -1; - cmp = PyObject_RichCompareBool(selfi, v, Py_EQ); - Py_DECREF(selfi); + cmp = PyObject_RichCompareBool(opi, v, Py_EQ); + Py_DECREF(opi); } return cmp; } +static int +array_contains(PyObject *op, PyObject *v) +{ + int ret; + Py_BEGIN_CRITICAL_SECTION(op); + ret = array_contains_lock_held(op, v); + Py_END_CRITICAL_SECTION(); + return ret; +} + /*[clinic input] +@critical_section array.array.remove v: object @@ -1273,7 +1598,7 @@ Remove the first occurrence of v in the array. static PyObject * array_array_remove_impl(arrayobject *self, PyObject *v) -/*[clinic end generated code: output=f2a24e288ecb2a35 input=0b1e5aed25590027]*/ +/*[clinic end generated code: output=f2a24e288ecb2a35 input=78bef3fd40e62f7a]*/ { Py_ssize_t i; @@ -1281,7 +1606,7 @@ array_array_remove_impl(arrayobject *self, PyObject *v) PyObject *selfi; int cmp; - selfi = getarrayitem((PyObject *)self,i); + selfi = getarrayitem(self, i, self->data); if (selfi == NULL) return NULL; cmp = PyObject_RichCompareBool(selfi, v, Py_EQ); @@ -1299,6 +1624,7 @@ array_array_remove_impl(arrayobject *self, PyObject *v) } /*[clinic input] +@critical_section array.array.pop i: Py_ssize_t = -1 @@ -1311,7 +1637,7 @@ i defaults to -1. static PyObject * array_array_pop_impl(arrayobject *self, Py_ssize_t i) -/*[clinic end generated code: output=bc1f0c54fe5308e4 input=8e5feb4c1a11cd44]*/ +/*[clinic end generated code: output=bc1f0c54fe5308e4 input=c69a7f1f8c570e2f]*/ { PyObject *v; @@ -1326,7 +1652,7 @@ array_array_pop_impl(arrayobject *self, Py_ssize_t i) PyErr_SetString(PyExc_IndexError, "pop index out of range"); return NULL; } - v = getarrayitem((PyObject *)self, i); + v = getarrayitem(self, i, self->data); if (v == NULL) return NULL; if (array_del_slice(self, i, i+1) != 0) { @@ -1358,6 +1684,7 @@ array_array_extend_impl(arrayobject *self, PyTypeObject *cls, PyObject *bb) } /*[clinic input] +@critical_section array.array.insert i: Py_ssize_t @@ -1369,12 +1696,15 @@ Insert a new item v into the array before position i. static PyObject * array_array_insert_impl(arrayobject *self, Py_ssize_t i, PyObject *v) -/*[clinic end generated code: output=5a3648e278348564 input=5577d1b4383e9313]*/ +/*[clinic end generated code: output=5a3648e278348564 input=3c922bbd81462978]*/ { - return ins(self, i, v); + if (ins1(self, i, v) != 0) + return NULL; + Py_RETURN_NONE; } /*[clinic input] +@critical_section array.array.buffer_info Return a tuple (address, length) giving the current memory address and the length in items of the buffer used to hold array's contents. @@ -1385,7 +1715,7 @@ the buffer length in bytes. static PyObject * array_array_buffer_info_impl(arrayobject *self) -/*[clinic end generated code: output=9b2a4ec3ae7e98e7 input=a58bae5c6e1ac6a6]*/ +/*[clinic end generated code: output=9b2a4ec3ae7e98e7 input=9d0dc1ff0e6542e8]*/ { PyObject *retval = NULL, *v; @@ -1393,7 +1723,7 @@ array_array_buffer_info_impl(arrayobject *self) if (!retval) return NULL; - v = PyLong_FromVoidPtr(self->ob_item); + v = PyLong_FromVoidPtr(array_items_ptr(self)); if (v == NULL) { Py_DECREF(retval); return NULL; @@ -1411,6 +1741,7 @@ array_array_buffer_info_impl(arrayobject *self) } /*[clinic input] +@critical_section array.array.append v: object @@ -1421,12 +1752,15 @@ Append new value v to the end of the array. static PyObject * array_array_append_impl(arrayobject *self, PyObject *v) -/*[clinic end generated code: output=2f1e8cbad70c2a8b input=0b98d9d78e78f0fa]*/ +/*[clinic end generated code: output=2f1e8cbad70c2a8b input=9cdd897c66a40c3f]*/ { - return ins(self, Py_SIZE(self), v); + if (ins1(self, Py_SIZE(self), v) != 0) + return NULL; + Py_RETURN_NONE; } /*[clinic input] +@critical_section array.array.byteswap Byteswap all items of the array. @@ -1437,7 +1771,7 @@ raised. static PyObject * array_array_byteswap_impl(arrayobject *self) -/*[clinic end generated code: output=5f8236cbdf0d90b5 input=6a85591b950a0186]*/ +/*[clinic end generated code: output=5f8236cbdf0d90b5 input=e691b6eff94d8b2e]*/ { char *p; Py_ssize_t i; @@ -1446,14 +1780,14 @@ array_array_byteswap_impl(arrayobject *self) case 1: break; case 2: - for (p = self->ob_item, i = Py_SIZE(self); --i >= 0; p += 2) { + for (p = array_items_ptr(self), i = Py_SIZE(self); --i >= 0; p += 2) { char p0 = p[0]; p[0] = p[1]; p[1] = p0; } break; case 4: - for (p = self->ob_item, i = Py_SIZE(self); --i >= 0; p += 4) { + for (p = array_items_ptr(self), i = Py_SIZE(self); --i >= 0; p += 4) { char p0 = p[0]; char p1 = p[1]; p[0] = p[3]; @@ -1463,7 +1797,7 @@ array_array_byteswap_impl(arrayobject *self) } break; case 8: - for (p = self->ob_item, i = Py_SIZE(self); --i >= 0; p += 8) { + for (p = array_items_ptr(self), i = Py_SIZE(self); --i >= 0; p += 8) { char p0 = p[0]; char p1 = p[1]; char p2 = p[2]; @@ -1487,6 +1821,7 @@ array_array_byteswap_impl(arrayobject *self) } /*[clinic input] +@critical_section array.array.reverse Reverse the order of the items in the array. @@ -1494,7 +1829,7 @@ Reverse the order of the items in the array. static PyObject * array_array_reverse_impl(arrayobject *self) -/*[clinic end generated code: output=c04868b36f6f4089 input=cd904f01b27d966a]*/ +/*[clinic end generated code: output=c04868b36f6f4089 input=e3947e98aed068ed]*/ { Py_ssize_t itemsize = self->ob_descr->itemsize; char *p, *q; @@ -1503,8 +1838,8 @@ array_array_reverse_impl(arrayobject *self) assert((size_t)itemsize <= sizeof(tmp)); if (Py_SIZE(self) > 1) { - for (p = self->ob_item, - q = self->ob_item + (Py_SIZE(self) - 1)*itemsize; + for (p = array_items_ptr(self), + q = array_items_ptr(self) + (Py_SIZE(self) - 1)*itemsize; p < q; p += itemsize, q -= itemsize) { /* memory areas guaranteed disjoint, so memcpy @@ -1584,6 +1919,7 @@ array_array_fromfile_impl(arrayobject *self, PyTypeObject *cls, PyObject *f, } /*[clinic input] +@critical_section array.array.tofile cls: defining_class @@ -1595,7 +1931,7 @@ Write all items (as machine values) to the file object f. static PyObject * array_array_tofile_impl(arrayobject *self, PyTypeObject *cls, PyObject *f) -/*[clinic end generated code: output=4560c628d9c18bc2 input=5a24da7a7b407b52]*/ +/*[clinic end generated code: output=4560c628d9c18bc2 input=a26bc66df57864dd]*/ { Py_ssize_t nbytes = Py_SIZE(self) * self->ob_descr->itemsize; /* Write 64K blocks at a time */ @@ -1612,7 +1948,7 @@ array_array_tofile_impl(arrayobject *self, PyTypeObject *cls, PyObject *f) assert(state != NULL); for (i = 0; i < nblocks; i++) { - char* ptr = self->ob_item + i*BLOCKSIZE; + char *ptr = array_items_ptr(self) + i*BLOCKSIZE; Py_ssize_t size = BLOCKSIZE; PyObject *bytes, *res; @@ -1628,11 +1964,12 @@ array_array_tofile_impl(arrayobject *self, PyTypeObject *cls, PyObject *f) Py_DECREF(res); /* drop write result */ } - done: +done: Py_RETURN_NONE; } /*[clinic input] +@critical_section self list array.array.fromlist list: object @@ -1643,7 +1980,7 @@ Append items to array from list. static PyObject * array_array_fromlist_impl(arrayobject *self, PyObject *list) -/*[clinic end generated code: output=6c23733a68dd68df input=be2605a96c49680f]*/ +/*[clinic end generated code: output=6c23733a68dd68df input=c7c056aaf85d997a]*/ { Py_ssize_t n; @@ -1659,8 +1996,7 @@ array_array_fromlist_impl(arrayobject *self, PyObject *list) return NULL; for (i = 0; i < n; i++) { PyObject *v = PyList_GET_ITEM(list, i); - if ((*self->ob_descr->setitem)(self, - Py_SIZE(self) - n + i, v) != 0) { + if (setarrayitem(self, Py_SIZE(self) - n + i, v, self->data) != 0) { array_resize(self, old_size); return NULL; } @@ -1676,6 +2012,7 @@ array_array_fromlist_impl(arrayobject *self, PyObject *list) } /*[clinic input] +@critical_section array.array.tolist Convert array to an ordinary list with the same items. @@ -1683,7 +2020,7 @@ Convert array to an ordinary list with the same items. static PyObject * array_array_tolist_impl(arrayobject *self) -/*[clinic end generated code: output=00b60cc9eab8ef89 input=a8d7784a94f86b53]*/ +/*[clinic end generated code: output=00b60cc9eab8ef89 input=4543fdbac475c52c]*/ { PyObject *list = PyList_New(Py_SIZE(self)); Py_ssize_t i; @@ -1691,7 +2028,7 @@ array_array_tolist_impl(arrayobject *self) if (list == NULL) return NULL; for (i = 0; i < Py_SIZE(self); i++) { - PyObject *v = getarrayitem((PyObject *)self, i); + PyObject *v = getarrayitem(self, i, self->data); if (v == NULL) goto error; PyList_SET_ITEM(list, i, v); @@ -1703,19 +2040,29 @@ array_array_tolist_impl(arrayobject *self) return NULL; } + +/*[clinic input] +@critical_section +array.array.frombytes + + buffer: Py_buffer + / + +Appends items from the string, interpreting it as an array of machine values, as if it had been read from a file using the fromfile() method. +[clinic start generated code]*/ + static PyObject * -frombytes(arrayobject *self, Py_buffer *buffer) +array_array_frombytes_impl(arrayobject *self, Py_buffer *buffer) +/*[clinic end generated code: output=d9842c8f7510a516 input=2245f9ea58579960]*/ { int itemsize = self->ob_descr->itemsize; Py_ssize_t n; if (buffer->itemsize != 1) { - PyBuffer_Release(buffer); PyErr_SetString(PyExc_TypeError, "a bytes-like object is required"); return NULL; } n = buffer->len; if (n % itemsize != 0) { - PyBuffer_Release(buffer); PyErr_SetString(PyExc_ValueError, "bytes length not a multiple of item size"); return NULL; @@ -1725,37 +2072,19 @@ frombytes(arrayobject *self, Py_buffer *buffer) Py_ssize_t old_size = Py_SIZE(self); if ((n > PY_SSIZE_T_MAX - old_size) || ((old_size + n) > PY_SSIZE_T_MAX / itemsize)) { - PyBuffer_Release(buffer); return PyErr_NoMemory(); } if (array_resize(self, old_size + n) == -1) { - PyBuffer_Release(buffer); return NULL; } - memcpy(self->ob_item + old_size * itemsize, + memcpy(array_items_ptr(self) + old_size * itemsize, buffer->buf, n * itemsize); } - PyBuffer_Release(buffer); Py_RETURN_NONE; } /*[clinic input] -array.array.frombytes - - buffer: Py_buffer - / - -Appends items from the string, interpreting it as an array of machine values, as if it had been read from a file using the fromfile() method. -[clinic start generated code]*/ - -static PyObject * -array_array_frombytes_impl(arrayobject *self, Py_buffer *buffer) -/*[clinic end generated code: output=d9842c8f7510a516 input=378db226dfac949e]*/ -{ - return frombytes(self, buffer); -} - -/*[clinic input] +@critical_section array.array.tobytes Convert the array to an array of machine values and return the bytes representation. @@ -1763,10 +2092,10 @@ Convert the array to an array of machine values and return the bytes representat static PyObject * array_array_tobytes_impl(arrayobject *self) -/*[clinic end generated code: output=87318e4edcdc2bb6 input=90ee495f96de34f5]*/ +/*[clinic end generated code: output=87318e4edcdc2bb6 input=c4d44d5499d2320f]*/ { if (Py_SIZE(self) <= PY_SSIZE_T_MAX / self->ob_descr->itemsize) { - return PyBytes_FromStringAndSize(self->ob_item, + return PyBytes_FromStringAndSize(array_items_ptr(self), Py_SIZE(self) * self->ob_descr->itemsize); } else { return PyErr_NoMemory(); @@ -1774,6 +2103,7 @@ array_array_tobytes_impl(arrayobject *self) } /*[clinic input] +@critical_section array.array.fromunicode ustr: unicode @@ -1788,7 +2118,7 @@ some other type. static PyObject * array_array_fromunicode_impl(arrayobject *self, PyObject *ustr) -/*[clinic end generated code: output=24359f5e001a7f2b input=025db1fdade7a4ce]*/ +/*[clinic end generated code: output=24359f5e001a7f2b input=01e2a776cee82011]*/ { int typecode = self->ob_descr->typecode; if (typecode != 'u' && typecode != 'w') { @@ -1810,7 +2140,7 @@ array_array_fromunicode_impl(arrayobject *self, PyObject *ustr) // must not fail PyUnicode_AsWideChar( - ustr, ((wchar_t *)self->ob_item) + old_size, ustr_length); + ustr, ((wchar_t *)array_items_ptr(self)) + old_size, ustr_length); } } else { // typecode == 'w' @@ -1826,7 +2156,7 @@ array_array_fromunicode_impl(arrayobject *self, PyObject *ustr) } // must not fail - Py_UCS4 *u = PyUnicode_AsUCS4(ustr, ((Py_UCS4*)self->ob_item) + old_size, + Py_UCS4 *u = PyUnicode_AsUCS4(ustr, ((Py_UCS4*)array_items_ptr(self)) + old_size, ustr_length, 0); assert(u != NULL); (void)u; // Suppress unused_variable warning. @@ -1836,6 +2166,7 @@ array_array_fromunicode_impl(arrayobject *self, PyObject *ustr) } /*[clinic input] +@critical_section array.array.tounicode Extends this array with data from the unicode string ustr. @@ -1847,7 +2178,7 @@ unicode string from an array of some other type. static PyObject * array_array_tounicode_impl(arrayobject *self) -/*[clinic end generated code: output=08e442378336e1ef input=127242eebe70b66d]*/ +/*[clinic end generated code: output=08e442378336e1ef input=6c69dfe81a279b91]*/ { int typecode = self->ob_descr->typecode; if (typecode != 'u' && typecode != 'w') { @@ -1856,11 +2187,11 @@ array_array_tounicode_impl(arrayobject *self) return NULL; } if (typecode == 'u') { - return PyUnicode_FromWideChar((wchar_t *) self->ob_item, Py_SIZE(self)); + return PyUnicode_FromWideChar((wchar_t *) array_items_ptr(self), Py_SIZE(self)); } else { // typecode == 'w' int byteorder = 0; // native byteorder - return PyUnicode_DecodeUTF32((const char *) self->ob_item, Py_SIZE(self) * 4, + return PyUnicode_DecodeUTF32((const char *) array_items_ptr(self), Py_SIZE(self) * 4, NULL, &byteorder); } } @@ -1876,7 +2207,10 @@ array_array___sizeof___impl(arrayobject *self) /*[clinic end generated code: output=d8e1c61ebbe3eaed input=805586565bf2b3c6]*/ { size_t res = _PyObject_SIZE(Py_TYPE(self)); - res += (size_t)self->allocated * (size_t)self->ob_descr->itemsize; + arraydata *data = FT_ATOMIC_LOAD_PTR_RELAXED(self->data); + if (data != NULL) { + res += (size_t)data->allocated * (size_t)self->ob_descr->itemsize; + } return PyLong_FromSize_t(res); } @@ -2271,6 +2605,7 @@ array__array_reconstructor_impl(PyObject *module, PyTypeObject *arraytype, } /*[clinic input] +@critical_section array.array.__reduce_ex__ cls: defining_class @@ -2283,7 +2618,7 @@ Return state information for pickling. static PyObject * array_array___reduce_ex___impl(arrayobject *self, PyTypeObject *cls, PyObject *value) -/*[clinic end generated code: output=4958ee5d79452ad5 input=19968cf0f91d3eea]*/ +/*[clinic end generated code: output=4958ee5d79452ad5 input=18c90a4cad7ac527]*/ { PyObject *dict; PyObject *result; @@ -2295,10 +2630,11 @@ array_array___reduce_ex___impl(arrayobject *self, PyTypeObject *cls, array_state *state = get_array_state_by_class(cls); assert(state != NULL); - if (state->array_reconstructor == NULL) { - state->array_reconstructor = PyImport_ImportModuleAttrString( - "array", "_array_reconstructor"); - if (state->array_reconstructor == NULL) { + if (FT_ATOMIC_LOAD_PTR_RELAXED(state->array_reconstructor) == NULL) { + PyObject *array_reconstructor = PyImport_ImportModuleAttrString( + "array", "_array_reconstructor"); + FT_ATOMIC_STORE_PTR_RELAXED(state->array_reconstructor, array_reconstructor); + if (array_reconstructor == NULL) { return NULL; } } @@ -2411,8 +2747,9 @@ static PyMethodDef array_methods[] = { }; static PyObject * -array_repr(PyObject *op) +array_repr_lock_held(PyObject *op) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op); char typecode; PyObject *s, *v = NULL; Py_ssize_t len; @@ -2438,22 +2775,24 @@ array_repr(PyObject *op) return s; } +static PyObject * +array_repr(PyObject *op) +{ + PyObject *ret; + Py_BEGIN_CRITICAL_SECTION(op); + ret = array_repr_lock_held(op); + Py_END_CRITICAL_SECTION(); + return ret; +} + static PyObject* -array_subscr(PyObject *op, PyObject *item) +array_subscr_slice_lock_held(PyObject *op, PyObject *item) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op); arrayobject *self = arrayobject_CAST(op); array_state *state = find_array_state_by_type(Py_TYPE(self)); - if (PyIndex_Check(item)) { - Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); - if (i==-1 && PyErr_Occurred()) { - return NULL; - } - if (i < 0) - i += Py_SIZE(self); - return array_item(op, i); - } - else if (PySlice_Check(item)) { + if (PySlice_Check(item)) { Py_ssize_t start, stop, step, slicelength, i; size_t cur; PyObject* result; @@ -2474,8 +2813,8 @@ array_subscr(PyObject *op, PyObject *item) slicelength, self->ob_descr); if (result == NULL) return NULL; - memcpy(((arrayobject *)result)->ob_item, - self->ob_item + start * itemsize, + memcpy(((arrayobject *)result)->data->items, + array_items_ptr(self) + start * itemsize, slicelength * itemsize); return result; } @@ -2487,8 +2826,8 @@ array_subscr(PyObject *op, PyObject *item) for (cur = start, i = 0; i < slicelength; cur += step, i++) { - memcpy(ar->ob_item + i*itemsize, - self->ob_item + cur*itemsize, + memcpy(ar->data->items + i*itemsize, + array_items_ptr(self) + cur*itemsize, itemsize); } @@ -2502,12 +2841,40 @@ array_subscr(PyObject *op, PyObject *item) } } +static PyObject * +array_subscr(PyObject *op, PyObject *item) +{ + if (PyIndex_Check(item)) { + Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i==-1 && PyErr_Occurred()) { + return NULL; + } + Py_ssize_t size = PyArray_GET_SIZE(op); + if (i < 0) { + i += size; + } + return array_item(op, i); + } + + PyObject *ret; + Py_BEGIN_CRITICAL_SECTION(op); + ret = array_subscr_slice_lock_held(op, item); + Py_END_CRITICAL_SECTION(); + return ret; +} + static int -array_ass_subscr(PyObject *op, PyObject *item, PyObject *value) +array_ass_subscr_lock_held(PyObject *op, PyObject* item, PyObject* value) { - Py_ssize_t start, stop, step, slicelength, needed; + array_state* state = find_array_state_by_type(Py_TYPE(op)); + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op); +#ifdef Py_DEBUG + if (value != NULL && array_Check(value, state)) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(value); + } +#endif arrayobject *self = arrayobject_CAST(op); - array_state* state = find_array_state_by_type(Py_TYPE(self)); + Py_ssize_t start, stop, step, slicelength, needed; arrayobject* other; int itemsize; @@ -2531,7 +2898,7 @@ array_ass_subscr(PyObject *op, PyObject *item, PyObject *value) slicelength = 1; } else - return (*self->ob_descr->setitem)(self, i, value); + return setarrayitem(self, i, value, self->data); } else if (PySlice_Check(item)) { if (PySlice_Unpack(item, &start, &stop, &step) < 0) { @@ -2558,7 +2925,7 @@ array_ass_subscr(PyObject *op, PyObject *item, PyObject *value) value = array_slice(other, 0, needed); if (value == NULL) return -1; - ret = array_ass_subscr(op, item, value); + ret = array_ass_subscr_lock_held(op, item, value); Py_DECREF(value); return ret; } @@ -2590,8 +2957,8 @@ array_ass_subscr(PyObject *op, PyObject *item, PyObject *value) if (step == 1) { if (slicelength > needed) { - memmove(self->ob_item + (start + needed) * itemsize, - self->ob_item + stop * itemsize, + memmove(array_items_ptr(self) + (start + needed) * itemsize, + array_items_ptr(self) + stop * itemsize, (Py_SIZE(self) - stop) * itemsize); if (array_resize(self, Py_SIZE(self) + needed - slicelength) < 0) @@ -2601,13 +2968,13 @@ array_ass_subscr(PyObject *op, PyObject *item, PyObject *value) if (array_resize(self, Py_SIZE(self) + needed - slicelength) < 0) return -1; - memmove(self->ob_item + (start + needed) * itemsize, - self->ob_item + stop * itemsize, + memmove(array_items_ptr(self) + (start + needed) * itemsize, + array_items_ptr(self) + stop * itemsize, (Py_SIZE(self) - start - needed) * itemsize); } if (needed > 0) - memcpy(self->ob_item + start * itemsize, - other->ob_item, needed * itemsize); + memcpy(array_items_ptr(self) + start * itemsize, + other->data->items, needed * itemsize); return 0; } else if (needed == 0) { @@ -2626,14 +2993,14 @@ array_ass_subscr(PyObject *op, PyObject *item, PyObject *value) if (cur + step >= (size_t)Py_SIZE(self)) lim = Py_SIZE(self) - cur - 1; - memmove(self->ob_item + (cur - i) * itemsize, - self->ob_item + (cur + 1) * itemsize, + memmove(array_items_ptr(self) + (cur - i) * itemsize, + array_items_ptr(self) + (cur + 1) * itemsize, lim * itemsize); } cur = start + (size_t)slicelength * step; if (cur < (size_t)Py_SIZE(self)) { - memmove(self->ob_item + (cur-slicelength) * itemsize, - self->ob_item + cur * itemsize, + memmove(array_items_ptr(self) + (cur-slicelength) * itemsize, + array_items_ptr(self) + cur * itemsize, (Py_SIZE(self) - cur) * itemsize); } if (array_resize(self, Py_SIZE(self) - slicelength) < 0) @@ -2653,28 +3020,58 @@ array_ass_subscr(PyObject *op, PyObject *item, PyObject *value) } for (cur = start, i = 0; i < slicelength; cur += step, i++) { - memcpy(self->ob_item + cur * itemsize, - other->ob_item + i * itemsize, + memcpy(array_items_ptr(self) + cur * itemsize, + other->data->items + i * itemsize, itemsize); } return 0; } } +static int +array_ass_subscr(PyObject *op, PyObject* item, PyObject* value) +{ + int ret; + + if (value != NULL) { + array_state* state = find_array_state_by_type(Py_TYPE(op)); + if (array_Check(value, state)) { + Py_BEGIN_CRITICAL_SECTION2(op, value); + ret = array_ass_subscr_lock_held(op, item, value); + Py_END_CRITICAL_SECTION2(); + return ret; + } + if (PyIndex_Check(item)) { + Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return -1; + if (i < 0) + i += PyArray_GET_SIZE(op); + return setarrayitem_threadsafe(op, i, value); + } + } + + Py_BEGIN_CRITICAL_SECTION(op); + ret = array_ass_subscr_lock_held(op, item, value); + Py_END_CRITICAL_SECTION(); + return ret; +} + static const void *emptybuf = ""; static int -array_buffer_getbuf(PyObject *op, Py_buffer *view, int flags) +array_buffer_getbuf_lock_held(PyObject *op, Py_buffer *view, int flags) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op); + arrayobject *self = arrayobject_CAST(op); if (view == NULL) { PyErr_SetString(PyExc_BufferError, "array_buffer_getbuf: view==NULL argument is obsolete"); return -1; } - arrayobject *self = arrayobject_CAST(op); - view->buf = (void *)self->ob_item; + view->buf = (void *)array_items_ptr(self); view->obj = Py_NewRef(self); if (view->buf == NULL) view->buf = (void *)emptybuf; @@ -2705,61 +3102,39 @@ array_buffer_getbuf(PyObject *op, Py_buffer *view, int flags) return 0; } +static int +array_buffer_getbuf(PyObject *op, Py_buffer *view, int flags) +{ + int ret; + Py_BEGIN_CRITICAL_SECTION(op); + ret = array_buffer_getbuf_lock_held(op, view, flags); + Py_END_CRITICAL_SECTION(); + return ret; +} + static void array_buffer_relbuf(PyObject *op, Py_buffer *Py_UNUSED(view)) { + Py_BEGIN_CRITICAL_SECTION(op); arrayobject *self = arrayobject_CAST(op); self->ob_exports--; + assert(self->ob_exports >= 0); + Py_END_CRITICAL_SECTION(); } static PyObject * -array_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +array_new_internal_lock_held(PyTypeObject *type, PyObject *initial, int c) { +#ifdef Py_DEBUG + if (initial != NULL) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(initial); + } +#endif array_state *state = find_array_state_by_type(type); - int c; - PyObject *initial = NULL, *it = NULL; + PyObject *it = NULL; const struct arraydescr *descr; - - if ((type == state->ArrayType || - type->tp_init == state->ArrayType->tp_init) && - !_PyArg_NoKeywords("array.array", kwds)) - return NULL; - - if (!PyArg_ParseTuple(args, "C|O:array", &c, &initial)) - return NULL; - - if (PySys_Audit("array.__new__", "CO", - c, initial ? initial : Py_None) < 0) { - return NULL; - } - - if (c == 'u') { - if (PyErr_WarnEx(PyExc_DeprecationWarning, - "The 'u' type code is deprecated and " - "will be removed in Python 3.16", - 1)) { - return NULL; - } - } - bool is_unicode = c == 'u' || c == 'w'; - if (initial && !is_unicode) { - if (PyUnicode_Check(initial)) { - PyErr_Format(PyExc_TypeError, "cannot use a str to initialize " - "an array with typecode '%c'", c); - return NULL; - } - else if (array_Check(initial, state)) { - int ic = ((arrayobject*)initial)->ob_descr->typecode; - if (ic == 'u' || ic == 'w') { - PyErr_Format(PyExc_TypeError, "cannot use a unicode array to " - "initialize an array with typecode '%c'", c); - return NULL; - } - } - } - if (!(initial == NULL || PyList_Check(initial) || PyByteArray_Check(initial) || PyBytes_Check(initial) @@ -2797,6 +3172,7 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds) if (len > 0 && !array_Check(initial, state)) { Py_ssize_t i; + arrayobject *ap = arrayobject_CAST(a); for (i = 0; i < len; i++) { PyObject *v = PySequence_GetItem(initial, i); @@ -2804,7 +3180,7 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds) Py_DECREF(a); return NULL; } - if (setarrayitem(a, i, v) != 0) { + if (setarrayitem(ap, i, v, ap->data) != 0) { Py_DECREF(v); Py_DECREF(a); return NULL; @@ -2833,11 +3209,17 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds) if (n > 0) { arrayobject *self = (arrayobject *)a; - // self->ob_item may be NULL but it is safe. - PyMem_Free(self->ob_item); - self->ob_item = (char *)ustr; + assert(self->data == NULL); + self->data = arraydata_alloc(n, sizeof(wchar_t)); + if (self->data == NULL) { + PyMem_Free(ustr); + Py_DECREF(a); + PyErr_NoMemory(); + return NULL; + } + memcpy(self->data->items, (char *)ustr, n * sizeof(wchar_t)); + PyMem_Free(ustr); Py_SET_SIZE(self, n); - self->allocated = n; } } else { // c == 'w' @@ -2849,17 +3231,23 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds) } arrayobject *self = (arrayobject *)a; - // self->ob_item may be NULL but it is safe. - PyMem_Free(self->ob_item); - self->ob_item = (char *)ustr; + assert(self->data == NULL); + self->data = arraydata_alloc(n, sizeof(Py_UCS4)); + if (self->data == NULL) { + PyMem_Free(ustr); + Py_DECREF(a); + PyErr_NoMemory(); + return NULL; + } + memcpy(self->data->items, (char *)ustr, n * sizeof(Py_UCS4)); + PyMem_Free(ustr); Py_SET_SIZE(self, n); - self->allocated = n; } } else if (initial != NULL && array_Check(initial, state) && len > 0) { arrayobject *self = (arrayobject *)a; arrayobject *other = (arrayobject *)initial; - memcpy(self->ob_item, other->ob_item, len * other->ob_descr->itemsize); + memcpy(array_items_ptr(self), other->data->items, len * other->ob_descr->itemsize); } if (it != NULL) { if (array_iter_extend((arrayobject *)a, it) == -1) { @@ -2877,6 +3265,69 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return NULL; } +static PyObject * +array_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + array_state *state = find_array_state_by_type(type); + int c; + PyObject *initial = NULL; + + if ((type == state->ArrayType || + type->tp_init == state->ArrayType->tp_init) && + !_PyArg_NoKeywords("array.array", kwds)) { + return NULL; + } + + if (!PyArg_ParseTuple(args, "C|O:array", &c, &initial)) { + return NULL; + } + + if (PySys_Audit("array.__new__", "CO", + c, initial ? initial : Py_None) < 0) { + return NULL; + } + + if (c == 'u') { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "The 'u' type code is deprecated and " + "will be removed in Python 3.16", + 1)) { + return NULL; + } + } + + bool is_unicode = c == 'u' || c == 'w'; + + if (initial && !is_unicode) { + if (PyUnicode_Check(initial)) { + PyErr_Format(PyExc_TypeError, "cannot use a str to initialize " + "an array with typecode '%c'", c); + return NULL; + } + else if (array_Check(initial, state)) { + int ic = ((arrayobject*)initial)->ob_descr->typecode; + if (ic == 'u' || ic == 'w') { + PyErr_Format(PyExc_TypeError, "cannot use a unicode array to " + "initialize an array with typecode '%c'", c); + return NULL; + } + } + } + + PyObject *ret; + + if (initial == NULL) { + ret = array_new_internal_lock_held(type, initial, c); + } + else { + Py_BEGIN_CRITICAL_SECTION(initial); + ret = array_new_internal_lock_held(type, initial, c); + Py_END_CRITICAL_SECTION(); + } + + return ret; +} + PyDoc_STRVAR(module_doc, "This module defines an object type which can efficiently represent\n\ @@ -3019,8 +3470,7 @@ array_iter(PyObject *op) return NULL; it->ao = (arrayobject*)Py_NewRef(ao); - it->index = 0; - it->getitem = ao->ob_descr->getitem; + it->index = 0; // -1 indicates exhausted PyObject_GC_Track(it); return (PyObject *)it; } @@ -3030,23 +3480,27 @@ arrayiter_next(PyObject *op) { arrayiterobject *it = arrayiterobject_CAST(op); assert(it != NULL); + Py_ssize_t index = FT_ATOMIC_LOAD_SSIZE_RELAXED(it->index); + if (index < 0) { + return NULL; + } + arrayobject *ao = it->ao; #ifndef NDEBUG array_state *state = find_array_state_by_type(Py_TYPE(it)); assert(PyObject_TypeCheck(it, state->ArrayIterType)); + assert(array_Check(ao, state)); #endif - arrayobject *ao = it->ao; - if (ao == NULL) { - return NULL; + PyObject *ret = getarrayitem_threadsafe((PyObject *)ao, index); + if (ret != NULL) { + FT_ATOMIC_STORE_SSIZE_RELAXED(it->index, index + 1); } -#ifndef NDEBUG - assert(array_Check(ao, state)); + else { + FT_ATOMIC_STORE_SSIZE_RELAXED(it->index, -1); +#ifndef Py_GIL_DISABLED + Py_CLEAR(it->ao); #endif - if (it->index < Py_SIZE(ao)) { - return (*it->getitem)(ao, it->index++); } - it->ao = NULL; - Py_DECREF(ao); - return NULL; + return ret; } static void @@ -3082,14 +3536,14 @@ static PyObject * array_arrayiterator___reduce___impl(arrayiterobject *self, PyTypeObject *cls) /*[clinic end generated code: output=4b032417a2c8f5e6 input=ac64e65a87ad452e]*/ { - array_state *state = get_array_state_by_class(cls); assert(state != NULL); PyObject *func = _PyEval_GetBuiltin(state->str_iter); - if (self->ao == NULL) { - return Py_BuildValue("N(())", func); + Py_ssize_t index = FT_ATOMIC_LOAD_SSIZE_RELAXED(self->index); + if (index >= 0) { + return Py_BuildValue("N(O)n", func, self->ao, index); } - return Py_BuildValue("N(O)n", func, self->ao, self->index); + return Py_BuildValue("N(())", func); } /*[clinic input] @@ -3106,17 +3560,20 @@ array_arrayiterator___setstate___impl(arrayiterobject *self, PyObject *state) /*[clinic end generated code: output=d7837ae4ac1fd8b9 input=f47d5ceda19e787b]*/ { Py_ssize_t index = PyLong_AsSsize_t(state); - if (index == -1 && PyErr_Occurred()) + if (index == -1 && PyErr_Occurred()) { return NULL; - arrayobject *ao = self->ao; - if (ao != NULL) { - if (index < 0) { - index = 0; + } + if (FT_ATOMIC_LOAD_SSIZE_RELAXED(self->index) >= 0) { + if (index < -1) { + index = -1; } - else if (index > Py_SIZE(ao)) { - index = Py_SIZE(ao); /* iterator exhausted */ + else { + Py_ssize_t size = PyArray_GET_SIZE(self->ao); + if (index > size) { + index = size; /* iterator at end */ + } } - self->index = index; + FT_ATOMIC_STORE_SSIZE_RELAXED(self->index, index); } Py_RETURN_NONE; } @@ -3149,7 +3606,7 @@ static PyType_Spec arrayiter_spec = { /*********************** Install Module **************************/ static int -array_traverse(PyObject *module, visitproc visit, void *arg) +arraymodule_traverse(PyObject *module, visitproc visit, void *arg) { array_state *state = get_array_state(module); Py_VISIT(state->ArrayType); @@ -3159,7 +3616,7 @@ array_traverse(PyObject *module, visitproc visit, void *arg) } static int -array_clear(PyObject *module) +arraymodule_clear(PyObject *module) { array_state *state = get_array_state(module); Py_CLEAR(state->ArrayType); @@ -3173,9 +3630,9 @@ array_clear(PyObject *module) } static void -array_free(void *module) +arraymodule_free(void *module) { - (void)array_clear((PyObject *)module); + (void)arraymodule_clear((PyObject *)module); } /* No functions in array module. */ @@ -3202,7 +3659,7 @@ do { \ } while (0) static int -array_modexec(PyObject *m) +arraymodule_modexec(PyObject *m) { array_state *state = get_array_state(m); char buffer[Py_ARRAY_LENGTH(descriptors)], *p; @@ -3257,7 +3714,7 @@ array_modexec(PyObject *m) } static PyModuleDef_Slot arrayslots[] = { - {Py_mod_exec, array_modexec}, + {Py_mod_exec, arraymodule_modexec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} @@ -3271,9 +3728,9 @@ static struct PyModuleDef arraymodule = { .m_doc = module_doc, .m_methods = a_methods, .m_slots = arrayslots, - .m_traverse = array_traverse, - .m_clear = array_clear, - .m_free = array_free, + .m_traverse = arraymodule_traverse, + .m_clear = arraymodule_clear, + .m_free = arraymodule_free, }; diff --git a/Modules/clinic/arraymodule.c.h b/Modules/clinic/arraymodule.c.h index 97e5ca771f3a90..569c116ca7266c 100644 --- a/Modules/clinic/arraymodule.c.h +++ b/Modules/clinic/arraymodule.c.h @@ -6,6 +6,7 @@ preserve # include "pycore_runtime.h" // _Py_SINGLETON() #endif #include "pycore_abstract.h" // _PyNumber_Index() +#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() #include "pycore_modsupport.h" // _PyArg_CheckPositional() PyDoc_STRVAR(array_array_clear__doc__, @@ -23,7 +24,13 @@ array_array_clear_impl(arrayobject *self); static PyObject * array_array_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) { - return array_array_clear_impl((arrayobject *)self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = array_array_clear_impl((arrayobject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(array_array___copy____doc__, @@ -41,7 +48,13 @@ array_array___copy___impl(arrayobject *self); static PyObject * array_array___copy__(PyObject *self, PyObject *Py_UNUSED(ignored)) { - return array_array___copy___impl((arrayobject *)self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = array_array___copy___impl((arrayobject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(array_array___deepcopy____doc__, @@ -61,7 +74,9 @@ array_array___deepcopy__(PyObject *self, PyObject *unused) { PyObject *return_value = NULL; + Py_BEGIN_CRITICAL_SECTION(self); return_value = array_array___deepcopy___impl((arrayobject *)self, unused); + Py_END_CRITICAL_SECTION(); return return_value; } @@ -83,7 +98,9 @@ array_array_count(PyObject *self, PyObject *v) { PyObject *return_value = NULL; + Py_BEGIN_CRITICAL_SECTION(self); return_value = array_array_count_impl((arrayobject *)self, v); + Py_END_CRITICAL_SECTION(); return return_value; } @@ -128,7 +145,9 @@ array_array_index(PyObject *self, PyObject *const *args, Py_ssize_t nargs) goto exit; } skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); return_value = array_array_index_impl((arrayobject *)self, v, start, stop); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -151,7 +170,9 @@ array_array_remove(PyObject *self, PyObject *v) { PyObject *return_value = NULL; + Py_BEGIN_CRITICAL_SECTION(self); return_value = array_array_remove_impl((arrayobject *)self, v); + Py_END_CRITICAL_SECTION(); return return_value; } @@ -195,7 +216,9 @@ array_array_pop(PyObject *self, PyObject *const *args, Py_ssize_t nargs) i = ival; } skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); return_value = array_array_pop_impl((arrayobject *)self, i); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -280,7 +303,9 @@ array_array_insert(PyObject *self, PyObject *const *args, Py_ssize_t nargs) i = ival; } v = args[1]; + Py_BEGIN_CRITICAL_SECTION(self); return_value = array_array_insert_impl((arrayobject *)self, i, v); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -304,7 +329,13 @@ array_array_buffer_info_impl(arrayobject *self); static PyObject * array_array_buffer_info(PyObject *self, PyObject *Py_UNUSED(ignored)) { - return array_array_buffer_info_impl((arrayobject *)self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = array_array_buffer_info_impl((arrayobject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(array_array_append__doc__, @@ -324,7 +355,9 @@ array_array_append(PyObject *self, PyObject *v) { PyObject *return_value = NULL; + Py_BEGIN_CRITICAL_SECTION(self); return_value = array_array_append_impl((arrayobject *)self, v); + Py_END_CRITICAL_SECTION(); return return_value; } @@ -347,7 +380,13 @@ array_array_byteswap_impl(arrayobject *self); static PyObject * array_array_byteswap(PyObject *self, PyObject *Py_UNUSED(ignored)) { - return array_array_byteswap_impl((arrayobject *)self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = array_array_byteswap_impl((arrayobject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(array_array_reverse__doc__, @@ -365,7 +404,13 @@ array_array_reverse_impl(arrayobject *self); static PyObject * array_array_reverse(PyObject *self, PyObject *Py_UNUSED(ignored)) { - return array_array_reverse_impl((arrayobject *)self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = array_array_reverse_impl((arrayobject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(array_array_fromfile__doc__, @@ -464,7 +509,9 @@ array_array_tofile(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ goto exit; } f = args[0]; + Py_BEGIN_CRITICAL_SECTION(self); return_value = array_array_tofile_impl((arrayobject *)self, cls, f); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -487,7 +534,9 @@ array_array_fromlist(PyObject *self, PyObject *list) { PyObject *return_value = NULL; + Py_BEGIN_CRITICAL_SECTION2(self, list); return_value = array_array_fromlist_impl((arrayobject *)self, list); + Py_END_CRITICAL_SECTION2(); return return_value; } @@ -507,7 +556,13 @@ array_array_tolist_impl(arrayobject *self); static PyObject * array_array_tolist(PyObject *self, PyObject *Py_UNUSED(ignored)) { - return array_array_tolist_impl((arrayobject *)self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = array_array_tolist_impl((arrayobject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(array_array_frombytes__doc__, @@ -531,7 +586,9 @@ array_array_frombytes(PyObject *self, PyObject *arg) if (PyObject_GetBuffer(arg, &buffer, PyBUF_SIMPLE) != 0) { goto exit; } + Py_BEGIN_CRITICAL_SECTION(self); return_value = array_array_frombytes_impl((arrayobject *)self, &buffer); + Py_END_CRITICAL_SECTION(); exit: /* Cleanup for buffer */ @@ -557,7 +614,13 @@ array_array_tobytes_impl(arrayobject *self); static PyObject * array_array_tobytes(PyObject *self, PyObject *Py_UNUSED(ignored)) { - return array_array_tobytes_impl((arrayobject *)self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = array_array_tobytes_impl((arrayobject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(array_array_fromunicode__doc__, @@ -587,7 +650,9 @@ array_array_fromunicode(PyObject *self, PyObject *arg) goto exit; } ustr = arg; + Py_BEGIN_CRITICAL_SECTION(self); return_value = array_array_fromunicode_impl((arrayobject *)self, ustr); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -612,7 +677,13 @@ array_array_tounicode_impl(arrayobject *self); static PyObject * array_array_tounicode(PyObject *self, PyObject *Py_UNUSED(ignored)) { - return array_array_tounicode_impl((arrayobject *)self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = array_array_tounicode_impl((arrayobject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(array_array___sizeof____doc__, @@ -724,7 +795,9 @@ array_array___reduce_ex__(PyObject *self, PyTypeObject *cls, PyObject *const *ar goto exit; } value = args[0]; + Py_BEGIN_CRITICAL_SECTION(self); return_value = array_array___reduce_ex___impl((arrayobject *)self, cls, value); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -773,4 +846,4 @@ array_arrayiterator___setstate__(PyObject *self, PyObject *state) return return_value; } -/*[clinic end generated code: output=dd49451ac1cc3f39 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=46ca729af0fdb7cd input=a9049054013a1b77]*/ diff --git a/Tools/c-analyzer/c_parser/parser/_regexes.py b/Tools/c-analyzer/c_parser/parser/_regexes.py index c1a8ab3ad2f15d..76f0f71a2f7724 100644 --- a/Tools/c-analyzer/c_parser/parser/_regexes.py +++ b/Tools/c-analyzer/c_parser/parser/_regexes.py @@ -59,6 +59,8 @@ def _ind(text, level=1, edges='both'): register | static | _Thread_local | + _Alignas | + _Alignof | typedef | const | @@ -154,6 +156,17 @@ def _ind(text, level=1, edges='both'): TYPE_QUALIFIER = r'(?: \b (?: const | volatile ) \b )' PTR_QUALIFIER = rf'(?: [*] (?: \s* {TYPE_QUALIFIER} )? )' +ALIGNMENT_SPECIFIER = textwrap.dedent(r''' + # alignment specifier + (?: + _Alignas + \s* [(] + [^)]* + [)] + ) + # end alignment specifier + ''') + TYPE_SPEC = textwrap.dedent(rf''' # type spec (?: @@ -318,6 +331,9 @@ def _ind(text, level=1, edges='both'): (?: # typed member (?: + (?: # + \s* {ALIGNMENT_SPECIFIER} \s* + )? # Technically it doesn't have to have a type... (?: # (?: {TYPE_QUALIFIER} \s* )?