| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent dc7a2b6 commit 3926842
3 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,30 @@ | |||
| 1 | + import unittest | ||
| 2 | + | ||
| 3 | + from threading import Thread | ||
| 4 | + from unittest import TestCase | ||
| 5 | + | ||
| 6 | + from test.support import threading_helper | ||
| 7 | + | ||
| 8 | + @threading_helper.requires_working_threading() | ||
| 9 | + class TestCode(TestCase): | ||
| 10 | + def test_code_attrs(self): | ||
| 11 | + """Test concurrent accesses to lazily initialized code attributes""" | ||
| 12 | + code_objects = [] | ||
| 13 | + for _ in range(1000): | ||
| 14 | + code_objects.append(compile("a + b", "<string>", "eval")) | ||
| 15 | + | ||
| 16 | + def run_in_thread(): | ||
| 17 | + for code in code_objects: | ||
| 18 | + self.assertIsInstance(code.co_code, bytes) | ||
| 19 | + self.assertIsInstance(code.co_freevars, tuple) | ||
| 20 | + self.assertIsInstance(code.co_varnames, tuple) | ||
| 21 | + | ||
| 22 | + threads = [Thread(target=run_in_thread) for _ in range(2)] | ||
| 23 | + for thread in threads: | ||
| 24 | + thread.start() | ||
| 25 | + for thread in threads: | ||
| 26 | + thread.join() | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + if __name__ == "__main__": | ||
| 30 | + unittest.main() | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,4 @@ | |||
| 1 | + Fix a crash in the free threading build when :c:func:`PyCode_GetCode`, | ||
| 2 | + :c:func:`PyCode_GetVarnames`, :c:func:`PyCode_GetCellvars`, or | ||
| 3 | + :c:func:`PyCode_GetFreevars` were called from multiple threads at the same | ||
| 4 | + time. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -302,21 +302,32 @@ validate_and_copy_tuple(PyObject *tup) | |||
| 302 | 302 | } | |
| 303 | 303 | ||
| 304 | 304 | static int | |
| 305 | - init_co_cached(PyCodeObject *self) { | ||
| 306 | - if (self->_co_cached == NULL) { | ||
| 307 | - self->_co_cached = PyMem_New(_PyCoCached, 1); | ||
| 308 | - if (self->_co_cached == NULL) { | ||
| 305 | + init_co_cached(PyCodeObject *self) | ||
| 306 | + { | ||
| 307 | + _PyCoCached *cached = FT_ATOMIC_LOAD_PTR(self->_co_cached); | ||
| 308 | + if (cached != NULL) { | ||
| 309 | + return 0; | ||
| 310 | + } | ||
| 311 | + | ||
| 312 | + Py_BEGIN_CRITICAL_SECTION(self); | ||
| 313 | + cached = self->_co_cached; | ||
| 314 | + if (cached == NULL) { | ||
| 315 | + cached = PyMem_New(_PyCoCached, 1); | ||
| 316 | + if (cached == NULL) { | ||
| 309 | 317 | PyErr_NoMemory(); | |
| 310 | - return -1; | ||
| 311 | 318 | } | |
| 312 | - self->_co_cached->_co_code = NULL; | ||
| 313 | - self->_co_cached->_co_cellvars = NULL; | ||
| 314 | - self->_co_cached->_co_freevars = NULL; | ||
| 315 | - self->_co_cached->_co_varnames = NULL; | ||
| 319 | + else { | ||
| 320 | + cached->_co_code = NULL; | ||
| 321 | + cached->_co_cellvars = NULL; | ||
| 322 | + cached->_co_freevars = NULL; | ||
| 323 | + cached->_co_varnames = NULL; | ||
| 324 | + FT_ATOMIC_STORE_PTR(self->_co_cached, cached); | ||
| 325 | + } | ||
| 316 | 326 | } | |
| 317 | - return 0; | ||
| 318 | - | ||
| 327 | + Py_END_CRITICAL_SECTION(); | ||
| 328 | + return cached != NULL ? 0 : -1; | ||
| 319 | 329 | } | |
| 330 | + | ||
| 320 | 331 | /****************** | |
| 321 | 332 | * _PyCode_New() | |
| 322 | 333 | ******************/ | |
@@ -1571,16 +1582,21 @@ get_cached_locals(PyCodeObject *co, PyObject **cached_field, | |||
| 1571 | 1582 | { | |
| 1572 | 1583 | assert(cached_field != NULL); | |
| 1573 | 1584 | assert(co->_co_cached != NULL); | |
| 1574 | - if (*cached_field != NULL) { | ||
| 1575 | - return Py_NewRef(*cached_field); | ||
| 1585 | + PyObject *varnames = FT_ATOMIC_LOAD_PTR(*cached_field); | ||
| 1586 | + if (varnames != NULL) { | ||
| 1587 | + return Py_NewRef(varnames); | ||
| 1576 | 1588 | } | |
| 1577 | - assert(*cached_field == NULL); | ||
| 1578 | - PyObject *varnames = get_localsplus_names(co, kind, num); | ||
| 1589 | + | ||
| 1590 | + Py_BEGIN_CRITICAL_SECTION(co); | ||
| 1591 | + varnames = *cached_field; | ||
| 1579 | 1592 | if (varnames == NULL) { | |
| 1580 | - return NULL; | ||
| 1593 | + varnames = get_localsplus_names(co, kind, num); | ||
| 1594 | + if (varnames != NULL) { | ||
| 1595 | + FT_ATOMIC_STORE_PTR(*cached_field, varnames); | ||
| 1596 | + } | ||
| 1581 | 1597 | } | |
| 1582 | - *cached_field = Py_NewRef(varnames); | ||
| 1583 | - return varnames; | ||
| 1598 | + Py_END_CRITICAL_SECTION(); | ||
| 1599 | + return Py_XNewRef(varnames); | ||
| 1584 | 1600 | } | |
| 1585 | 1601 | ||
| 1586 | 1602 | PyObject * | |
@@ -1674,18 +1690,26 @@ _PyCode_GetCode(PyCodeObject *co) | |||
| 1674 | 1690 | if (init_co_cached(co)) { | |
| 1675 | 1691 | return NULL; | |
| 1676 | 1692 | } | |
| 1677 | - if (co->_co_cached->_co_code != NULL) { | ||
| 1678 | - return Py_NewRef(co->_co_cached->_co_code); | ||
| 1693 | + | ||
| 1694 | + _PyCoCached *cached = co->_co_cached; | ||
| 1695 | + PyObject *code = FT_ATOMIC_LOAD_PTR(cached->_co_code); | ||
| 1696 | + if (code != NULL) { | ||
| 1697 | + return Py_NewRef(code); | ||
| 1679 | 1698 | } | |
| 1680 | - PyObject *code = PyBytes_FromStringAndSize((const char *)_PyCode_CODE(co), | ||
| 1681 | - _PyCode_NBYTES(co)); | ||
| 1699 | + | ||
| 1700 | + Py_BEGIN_CRITICAL_SECTION(co); | ||
| 1701 | + code = cached->_co_code; | ||
| 1682 | 1702 | if (code == NULL) { | |
| 1683 | - return NULL; | ||
| 1703 | + code = PyBytes_FromStringAndSize((const char *)_PyCode_CODE(co), | ||
| 1704 | + _PyCode_NBYTES(co)); | ||
| 1705 | + if (code != NULL) { | ||
| 1706 | + deopt_code(co, (_Py_CODEUNIT *)PyBytes_AS_STRING(code)); | ||
| 1707 | + assert(cached->_co_code == NULL); | ||
| 1708 | + FT_ATOMIC_STORE_PTR(cached->_co_code, code); | ||
| 1709 | + } | ||
| 1684 | 1710 | } | |
| 1685 | - deopt_code(co, (_Py_CODEUNIT *)PyBytes_AS_STRING(code)); | ||
| 1686 | - assert(co->_co_cached->_co_code == NULL); | ||
| 1687 | - co->_co_cached->_co_code = Py_NewRef(code); | ||
| 1688 | - return code; | ||
| 1711 | + Py_END_CRITICAL_SECTION(); | ||
| 1712 | + return Py_XNewRef(code); | ||
| 1689 | 1713 | } | |
| 1690 | 1714 | ||
| 1691 | 1715 | PyObject * | |
| Back | FazBrowse Home | New Git URL |
0 commit comments