https://github.com/python/cpython/commit/a6c4080aaa646d8d3a0e54a6de7557b230c09341
commit: a6c4080aaa646d8d3a0e54a6de7557b230c09341
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: zooba <[email protected]>
date: 2024-06-11T19:35:49Z
summary:

gh-120198: Fix race condition when editing __class__ with an audit hook active 
(GH-120195)

(cherry picked from commit 203565b2f9c74656ba519780049b46d4e5afcba1)

Co-authored-by: Ken Jin <[email protected]>

files:
A Misc/NEWS.d/next/Core and 
Builtins/2024-06-10-15-07-16.gh-issue-120198.WW_pjO.rst
M Lib/test/test_free_threading/test_type.py
M Lib/test/test_super.py
M Objects/typeobject.c

diff --git a/Lib/test/test_free_threading/test_type.py 
b/Lib/test/test_free_threading/test_type.py
index 6eead198deed46..786336fa0cddce 100644
--- a/Lib/test/test_free_threading/test_type.py
+++ b/Lib/test/test_free_threading/test_type.py
@@ -1,3 +1,4 @@
+import threading
 import unittest
 
 from concurrent.futures import ThreadPoolExecutor
diff --git a/Lib/test/test_super.py b/Lib/test/test_super.py
index 256b416caaa584..3ffbe03f0c2f11 100644
--- a/Lib/test/test_super.py
+++ b/Lib/test/test_super.py
@@ -1,9 +1,10 @@
 """Unit tests for zero-argument super() & related machinery."""
 
 import textwrap
+import threading
 import unittest
 from unittest.mock import patch
-from test.support import import_helper
+from test.support import import_helper, threading_helper
 
 
 ADAPTIVE_WARMUP_DELAY = 2
@@ -505,6 +506,38 @@ def some(cls):
         for _ in range(ADAPTIVE_WARMUP_DELAY):
             C.some(C)
 
+    @threading_helper.requires_working_threading()
+    def test___class___modification_multithreaded(self):
+        """ Note: this test isn't actually testing anything on its own.
+        It requires a sys audithook to be set to crash on older Python.
+        This should be the case anyways as our test suite sets
+        an audit hook.
+        """
+        class Foo:
+            pass
+
+        class Bar:
+            pass
+
+        thing = Foo()
+        def work():
+            foo = thing
+            for _ in range(5000):
+                foo.__class__ = Bar
+                type(foo)
+                foo.__class__ = Foo
+                type(foo)
+
+
+        threads = []
+        for _ in range(6):
+            thread = threading.Thread(target=work)
+            thread.start()
+            threads.append(thread)
+
+        for thread in threads:
+            thread.join()
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/Misc/NEWS.d/next/Core and 
Builtins/2024-06-10-15-07-16.gh-issue-120198.WW_pjO.rst b/Misc/NEWS.d/next/Core 
and Builtins/2024-06-10-15-07-16.gh-issue-120198.WW_pjO.rst
new file mode 100644
index 00000000000000..8dc8aec44d80c4
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and 
Builtins/2024-06-10-15-07-16.gh-issue-120198.WW_pjO.rst 
@@ -0,0 +1 @@
+Fix a crash when multiple threads read and write to the same ``__class__`` of 
an object concurrently.
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 18b7dfce3d8038..2d001b76e09775 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -6363,7 +6363,6 @@ compatible_for_assignment(PyTypeObject* oldto, 
PyTypeObject* newto, const char*
 static int
 object_set_class(PyObject *self, PyObject *value, void *closure)
 {
-    PyTypeObject *oldto = Py_TYPE(self);
 
     if (value == NULL) {
         PyErr_SetString(PyExc_TypeError,
@@ -6383,6 +6382,8 @@ object_set_class(PyObject *self, PyObject *value, void 
*closure)
         return -1;
     }
 
+    PyTypeObject *oldto = Py_TYPE(self);
+
     /* In versions of CPython prior to 3.5, the code in
        compatible_for_assignment was not set up to correctly check for memory
        layout / slot / etc. compatibility for non-HEAPTYPE classes, so we just

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]

Reply via email to