https://github.com/python/cpython/commit/9a8d75692950d1d2948672fbcbe88373c8ea7891
commit: 9a8d75692950d1d2948672fbcbe88373c8ea7891
branch: 3.14
author: Neil Schemenauer <[email protected]>
committer: nascheme <[email protected]>
date: 2026-07-17T13:08:26-07:00
summary:

[3.14] gh-144774: Add critical section in `BaseException.__setstate__` 
(GH-150578) (GH-153819)

(cherry picked from commit f586fd9e304e6747fdebe2477355beb059724571)

Co-authored-by: Brij Kapadia <[email protected]>

files:
A Lib/test/test_free_threading/test_exceptions.py
A 
Misc/NEWS.d/next/Core_and_Builtins/2026-05-29-17-51-11.gh-issue-144774.jPcixe.rst
M Objects/clinic/exceptions.c.h
M Objects/exceptions.c

diff --git a/Lib/test/test_free_threading/test_exceptions.py 
b/Lib/test/test_free_threading/test_exceptions.py
new file mode 100644
index 000000000000000..61146f29c7868e5
--- /dev/null
+++ b/Lib/test/test_free_threading/test_exceptions.py
@@ -0,0 +1,16 @@
+import unittest
+import copy
+
+from test.support import threading_helper
+
+threading_helper.requires_working_threading(module=True)
+class ExceptionTests(unittest.TestCase):
+    def test_setstate_data_race(self):
+        E = Exception()
+
+        def func():
+            for i in range(100):
+                setattr(E, 'x', i)
+                copy.copy(E)
+
+        threading_helper.run_concurrently(func, nthreads=4)
diff --git 
a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-29-17-51-11.gh-issue-144774.jPcixe.rst
 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-29-17-51-11.gh-issue-144774.jPcixe.rst
new file mode 100644
index 000000000000000..3dd117e7d3c3502
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-29-17-51-11.gh-issue-144774.jPcixe.rst
@@ -0,0 +1 @@
+Fix data race in :class:`BaseException` when an exception is copied while 
being mutated.
diff --git a/Objects/clinic/exceptions.c.h b/Objects/clinic/exceptions.c.h
index 9baac8b1cc660b0..5047a673e579c66 100644
--- a/Objects/clinic/exceptions.c.h
+++ b/Objects/clinic/exceptions.c.h
@@ -44,7 +44,7 @@ BaseException___setstate__(PyObject *self, PyObject *state)
 {
     PyObject *return_value = NULL;
 
-    Py_BEGIN_CRITICAL_SECTION(self);
+    Py_BEGIN_CRITICAL_SECTION(state);
     return_value = BaseException___setstate___impl((PyBaseExceptionObject 
*)self, state);
     Py_END_CRITICAL_SECTION();
 
@@ -380,4 +380,4 @@ BaseExceptionGroup_subgroup(PyObject *self, PyObject 
*matcher_value)
 
     return return_value;
 }
-/*[clinic end generated code: output=fcf70b3b71f3d14a input=a9049054013a1b77]*/
+/*[clinic end generated code: output=e63b88d0443b4f92 input=a9049054013a1b77]*/
diff --git a/Objects/exceptions.c b/Objects/exceptions.c
index e651b261686016e..833e283c17603c8 100644
--- a/Objects/exceptions.c
+++ b/Objects/exceptions.c
@@ -233,7 +233,7 @@ BaseException___reduce___impl(PyBaseExceptionObject *self)
  */
 
 /*[clinic input]
-@critical_section
+@critical_section state
 BaseException.__setstate__
     state: object
     /
@@ -241,7 +241,7 @@ BaseException.__setstate__
 
 static PyObject *
 BaseException___setstate___impl(PyBaseExceptionObject *self, PyObject *state)
-/*[clinic end generated code: output=f3834889950453ab input=5524b61cfe9b9856]*/
+/*[clinic end generated code: output=f3834889950453ab input=f9b1aea70382cdb6]*/
 {
     PyObject *d_key, *d_value;
     Py_ssize_t i = 0;

_______________________________________________
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