summaryrefslogtreecommitdiffstats
path: root/Lib/test
diff options
context:
space:
mode:
authorDaniele Parmeggiani <8658291+dpdani@users.noreply.github.com>2024-12-03 14:41:53 (GMT)
committerGitHub <noreply@github.com>2024-12-03 14:41:53 (GMT)
commit979bf2489d0c59ae451b97d7e3c148f47e259f0b (patch)
treea95c98176fd1edc03127a6c847d5adba1a8669d4 /Lib/test
parent84ff1313d04e8cbeec7b2cbe4503d86f1f5b449d (diff)
downloadcpython-979bf2489d0c59ae451b97d7e3c148f47e259f0b.zip
cpython-979bf2489d0c59ae451b97d7e3c148f47e259f0b.tar.gz
cpython-979bf2489d0c59ae451b97d7e3c148f47e259f0b.tar.bz2
gh-117657: TSAN Fix races in `PyMember_Get` and `PyMember_Set` for C extensions (GH-123211)
Diffstat (limited to 'Lib/test')
-rw-r--r--Lib/test/libregrtest/tsan.py1
-rw-r--r--Lib/test/test_capi/test_structmembers.py13
-rw-r--r--Lib/test/test_free_threading/test_slots.py244
3 files changed, 258 insertions, 0 deletions
diff --git a/Lib/test/libregrtest/tsan.py b/Lib/test/libregrtest/tsan.py
index 822ac0f..00d5779 100644
--- a/Lib/test/libregrtest/tsan.py
+++ b/Lib/test/libregrtest/tsan.py
@@ -25,6 +25,7 @@ TSAN_TESTS = [
'test_threading_local',
'test_threadsignals',
'test_weakref',
+ 'test_free_threading.test_slots',
]
diff --git a/Lib/test/test_capi/test_structmembers.py b/Lib/test/test_capi/test_structmembers.py
index 6b27dc5..ae9168f 100644
--- a/Lib/test/test_capi/test_structmembers.py
+++ b/Lib/test/test_capi/test_structmembers.py
@@ -37,6 +37,9 @@ def _make_test_object(cls):
9.99999,# T_FLOAT
10.1010101010, # T_DOUBLE
"hi", # T_STRING_INPLACE
+ 12, # T_LONGLONG
+ 13, # T_ULONGLONG
+ "c", # T_CHAR
)
@@ -162,6 +165,16 @@ class ReadWriteTests:
self.assertRaises(TypeError, setattr, ts, "T_STRING_INPLACE", "s")
self.assertRaises(TypeError, delattr, ts, "T_STRING_INPLACE")
+ def test_char(self):
+ ts = self.ts
+ self.assertEqual(ts.T_CHAR, "c")
+ ts.T_CHAR = "z"
+ self.assertEqual(ts.T_CHAR, "z")
+ self.assertRaises(TypeError, setattr, ts, "T_CHAR", "")
+ self.assertRaises(TypeError, setattr, ts, "T_CHAR", b"a")
+ self.assertRaises(TypeError, setattr, ts, "T_CHAR", bytearray(b"b"))
+ self.assertRaises(TypeError, delattr, ts, "T_STRING_INPLACE")
+
class ReadWriteTests_OldAPI(ReadWriteTests, unittest.TestCase):
cls = _test_structmembersType_OldAPI
diff --git a/Lib/test/test_free_threading/test_slots.py b/Lib/test/test_free_threading/test_slots.py
index 758f74f..a3b9f4b 100644
--- a/Lib/test/test_free_threading/test_slots.py
+++ b/Lib/test/test_free_threading/test_slots.py
@@ -1,3 +1,4 @@
+import _testcapi
import threading
from test.support import threading_helper
from unittest import TestCase
@@ -41,3 +42,246 @@ class TestSlots(TestCase):
assert 0 <= eggs <= iters
run_in_threads([writer, reader, reader, reader])
+
+ def test_T_BOOL(self):
+ spam_old = _testcapi._test_structmembersType_OldAPI()
+ spam_new = _testcapi._test_structmembersType_NewAPI()
+
+ def writer():
+ for _ in range(1_000):
+ # different code paths for True and False
+ spam_old.T_BOOL = True
+ spam_new.T_BOOL = True
+ spam_old.T_BOOL = False
+ spam_new.T_BOOL = False
+
+ def reader():
+ for _ in range(1_000):
+ spam_old.T_BOOL
+ spam_new.T_BOOL
+
+ run_in_threads([writer, reader])
+
+ def test_T_BYTE(self):
+ spam_old = _testcapi._test_structmembersType_OldAPI()
+ spam_new = _testcapi._test_structmembersType_NewAPI()
+
+ def writer():
+ for _ in range(1_000):
+ spam_old.T_BYTE = 0
+ spam_new.T_BYTE = 0
+
+ def reader():
+ for _ in range(1_000):
+ spam_old.T_BYTE
+ spam_new.T_BYTE
+
+ run_in_threads([writer, reader])
+
+ def test_T_UBYTE(self):
+ spam_old = _testcapi._test_structmembersType_OldAPI()
+ spam_new = _testcapi._test_structmembersType_NewAPI()
+
+ def writer():
+ for _ in range(1_000):
+ spam_old.T_UBYTE = 0
+ spam_new.T_UBYTE = 0
+
+ def reader():
+ for _ in range(1_000):
+ spam_old.T_UBYTE
+ spam_new.T_UBYTE
+
+ run_in_threads([writer, reader])
+
+ def test_T_SHORT(self):
+ spam_old = _testcapi._test_structmembersType_OldAPI()
+ spam_new = _testcapi._test_structmembersType_NewAPI()
+
+ def writer():
+ for _ in range(1_000):
+ spam_old.T_SHORT = 0
+ spam_new.T_SHORT = 0
+
+ def reader():
+ for _ in range(1_000):
+ spam_old.T_SHORT
+ spam_new.T_SHORT
+
+ run_in_threads([writer, reader])
+
+ def test_T_USHORT(self):
+ spam_old = _testcapi._test_structmembersType_OldAPI()
+ spam_new = _testcapi._test_structmembersType_NewAPI()
+
+ def writer():
+ for _ in range(1_000):
+ spam_old.T_USHORT = 0
+ spam_new.T_USHORT = 0
+
+ def reader():
+ for _ in range(1_000):
+ spam_old.T_USHORT
+ spam_new.T_USHORT
+
+ run_in_threads([writer, reader])
+
+ def test_T_INT(self):
+ spam_old = _testcapi._test_structmembersType_OldAPI()
+ spam_new = _testcapi._test_structmembersType_NewAPI()
+
+ def writer():
+ for _ in range(1_000):
+ spam_old.T_INT = 0
+ spam_new.T_INT = 0
+
+ def reader():
+ for _ in range(1_000):
+ spam_old.T_INT
+ spam_new.T_INT
+
+ run_in_threads([writer, reader])
+
+ def test_T_UINT(self):
+ spam_old = _testcapi._test_structmembersType_OldAPI()
+ spam_new = _testcapi._test_structmembersType_NewAPI()
+
+ def writer():
+ for _ in range(1_000):
+ spam_old.T_UINT = 0
+ spam_new.T_UINT = 0
+
+ def reader():
+ for _ in range(1_000):
+ spam_old.T_UINT
+ spam_new.T_UINT
+
+ run_in_threads([writer, reader])
+
+ def test_T_LONG(self):
+ spam_old = _testcapi._test_structmembersType_OldAPI()
+ spam_new = _testcapi._test_structmembersType_NewAPI()
+
+ def writer():
+ for _ in range(1_000):
+ spam_old.T_LONG = 0
+ spam_new.T_LONG = 0
+
+ def reader():
+ for _ in range(1_000):
+ spam_old.T_LONG
+ spam_new.T_LONG
+
+ run_in_threads([writer, reader])
+
+ def test_T_ULONG(self):
+ spam_old = _testcapi._test_structmembersType_OldAPI()
+ spam_new = _testcapi._test_structmembersType_NewAPI()
+
+ def writer():
+ for _ in range(1_000):
+ spam_old.T_ULONG = 0
+ spam_new.T_ULONG = 0
+
+ def reader():
+ for _ in range(1_000):
+ spam_old.T_ULONG
+ spam_new.T_ULONG
+
+ run_in_threads([writer, reader])
+
+ def test_T_PYSSIZET(self):
+ spam_old = _testcapi._test_structmembersType_OldAPI()
+ spam_new = _testcapi._test_structmembersType_NewAPI()
+
+ def writer():
+ for _ in range(1_000):
+ spam_old.T_PYSSIZET = 0
+ spam_new.T_PYSSIZET = 0
+
+ def reader():
+ for _ in range(1_000):
+ spam_old.T_PYSSIZET
+ spam_new.T_PYSSIZET
+
+ run_in_threads([writer, reader])
+
+ def test_T_FLOAT(self):
+ spam_old = _testcapi._test_structmembersType_OldAPI()
+ spam_new = _testcapi._test_structmembersType_NewAPI()
+
+ def writer():
+ for _ in range(1_000):
+ spam_old.T_FLOAT = 0.0
+ spam_new.T_FLOAT = 0.0
+
+ def reader():
+ for _ in range(1_000):
+ spam_old.T_FLOAT
+ spam_new.T_FLOAT
+
+ run_in_threads([writer, reader])
+
+ def test_T_DOUBLE(self):
+ spam_old = _testcapi._test_structmembersType_OldAPI()
+ spam_new = _testcapi._test_structmembersType_NewAPI()
+
+ def writer():
+ for _ in range(1_000):
+ spam_old.T_DOUBLE = 0.0
+ spam_new.T_DOUBLE = 0.0
+
+ def reader():
+ for _ in range(1_000):
+ spam_old.T_DOUBLE
+ spam_new.T_DOUBLE
+
+ run_in_threads([writer, reader])
+
+ def test_T_LONGLONG(self):
+ spam_old = _testcapi._test_structmembersType_OldAPI()
+ spam_new = _testcapi._test_structmembersType_NewAPI()
+
+ def writer():
+ for _ in range(1_000):
+ spam_old.T_LONGLONG = 0
+ spam_new.T_LONGLONG = 0
+
+ def reader():
+ for _ in range(1_000):
+ spam_old.T_LONGLONG
+ spam_new.T_LONGLONG
+
+ run_in_threads([writer, reader])
+
+ def test_T_ULONGLONG(self):
+ spam_old = _testcapi._test_structmembersType_OldAPI()
+ spam_new = _testcapi._test_structmembersType_NewAPI()
+
+ def writer():
+ for _ in range(1_000):
+ spam_old.T_ULONGLONG = 0
+ spam_new.T_ULONGLONG = 0
+
+ def reader():
+ for _ in range(1_000):
+ spam_old.T_ULONGLONG
+ spam_new.T_ULONGLONG
+
+ run_in_threads([writer, reader])
+
+ def test_T_CHAR(self):
+ spam_old = _testcapi._test_structmembersType_OldAPI()
+ spam_new = _testcapi._test_structmembersType_NewAPI()
+
+ def writer():
+ for _ in range(1_000):
+ spam_old.T_CHAR = "c"
+ spam_new.T_CHAR = "c"
+
+ def reader():
+ for _ in range(1_000):
+ spam_old.T_CHAR
+ spam_new.T_CHAR
+
+ run_in_threads([writer, reader])