Skip to content

Commit 4783206

Browse files
authored
gh-117657: Add TSAN suppressions for the free-threaded build (#117736)
Additionally, reduce the iterations for a few weakref tests that would otherwise take a prohibitively long amount of time (> 1 hour) when TSAN is enabled and the GIL is disabled.
1 parent 0823f43 commit 4783206

File tree

5 files changed

+69
-7
lines changed

5 files changed

+69
-7
lines changed

.github/workflows/build.yml

+2
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,7 @@ jobs:
492492
with:
493493
config_hash: ${{ needs.check_source.outputs.config_hash }}
494494
options: ./configure --config-cache --with-thread-sanitizer --with-pydebug
495+
suppressions_path: Tools/tsan/supressions.txt
495496

496497
build_tsan_free_threading:
497498
name: 'Thread sanitizer (free-threading)'
@@ -501,6 +502,7 @@ jobs:
501502
with:
502503
config_hash: ${{ needs.check_source.outputs.config_hash }}
503504
options: ./configure --config-cache --disable-gil --with-thread-sanitizer --with-pydebug
505+
suppressions_path: Tools/tsan/suppressions_free_threading.txt
504506

505507
# CIFuzz job based on https://google.github.io/oss-fuzz/getting-started/continuous-integration/
506508
cifuzz:

.github/workflows/reusable-tsan.yml

+5-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ on:
77
options:
88
required: true
99
type: string
10+
suppressions_path:
11+
description: 'A repo relative path to the suppressions file'
12+
required: true
13+
type: string
1014

1115
jobs:
1216
build_tsan_reusable:
@@ -30,7 +34,7 @@ jobs:
3034
sudo sysctl -w vm.mmap_rnd_bits=28
3135
- name: TSAN Option Setup
3236
run: |
33-
echo "TSAN_OPTIONS=suppressions=${GITHUB_WORKSPACE}/Tools/tsan/supressions.txt" >> $GITHUB_ENV
37+
echo "TSAN_OPTIONS=suppressions=${GITHUB_WORKSPACE}/${{ inputs.suppressions_path }}" >> $GITHUB_ENV
3438
echo "CC=clang" >> $GITHUB_ENV
3539
echo "CXX=clang++" >> $GITHUB_ENV
3640
- name: Add ccache to PATH

Lib/test/test_weakref.py

+9-3
Original file line numberDiff line numberDiff line change
@@ -1255,6 +1255,12 @@ class MappingTestCase(TestBase):
12551255

12561256
COUNT = 10
12571257

1258+
if support.check_sanitizer(thread=True) and support.Py_GIL_DISABLED:
1259+
# Reduce iteration count to get acceptable latency
1260+
NUM_THREADED_ITERATIONS = 1000
1261+
else:
1262+
NUM_THREADED_ITERATIONS = 100000
1263+
12581264
def check_len_cycles(self, dict_type, cons):
12591265
N = 20
12601266
items = [RefCycle() for i in range(N)]
@@ -1880,7 +1886,7 @@ def test_make_weak_keyed_dict_repr(self):
18801886
def test_threaded_weak_valued_setdefault(self):
18811887
d = weakref.WeakValueDictionary()
18821888
with collect_in_thread():
1883-
for i in range(100000):
1889+
for i in range(self.NUM_THREADED_ITERATIONS):
18841890
x = d.setdefault(10, RefCycle())
18851891
self.assertIsNot(x, None) # we never put None in there!
18861892
del x
@@ -1889,7 +1895,7 @@ def test_threaded_weak_valued_setdefault(self):
18891895
def test_threaded_weak_valued_pop(self):
18901896
d = weakref.WeakValueDictionary()
18911897
with collect_in_thread():
1892-
for i in range(100000):
1898+
for i in range(self.NUM_THREADED_ITERATIONS):
18931899
d[10] = RefCycle()
18941900
x = d.pop(10, 10)
18951901
self.assertIsNot(x, None) # we never put None in there!
@@ -1900,7 +1906,7 @@ def test_threaded_weak_valued_consistency(self):
19001906
# WeakValueDictionary when collecting from another thread.
19011907
d = weakref.WeakValueDictionary()
19021908
with collect_in_thread():
1903-
for i in range(200000):
1909+
for i in range(2 * self.NUM_THREADED_ITERATIONS):
19041910
o = RefCycle()
19051911
d[10] = o
19061912
# o is still alive, so the dict can't be empty
+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# This file contains suppressions for the free-threaded build. It contains the
2+
# suppressions for the default build and additional suppressions needed only in
3+
# the free-threaded build.
4+
#
5+
# reference: https://github.com/google/sanitizers/wiki/ThreadSanitizerSuppressions
6+
7+
## Default build suppresssions
8+
9+
race:get_allocator_unlocked
10+
race:set_allocator_unlocked
11+
12+
## Free-threaded suppressions
13+
14+
race:_add_to_weak_set
15+
race:_in_weak_set
16+
race:_mi_heap_delayed_free_partial
17+
race:_Py_IsImmortal
18+
race:_Py_IsOwnedByCurrentThread
19+
race:_PyEval_EvalFrameDefault
20+
race:_PyFunction_SetVersion
21+
race:_PyImport_AcquireLock
22+
race:_PyImport_ReleaseLock
23+
race:_PyInterpreterState_SetNotRunningMain
24+
race:_PyInterpreterState_IsRunningMain
25+
race:_PyObject_GC_IS_SHARED
26+
race:_PyObject_GC_SET_SHARED
27+
race:_PyObject_GC_TRACK
28+
race:_PyType_HasFeature
29+
race:_PyType_Lookup
30+
race:assign_version_tag
31+
race:compare_unicode_unicode
32+
race:delitem_common
33+
race:dictkeys_decref
34+
race:dictkeys_incref
35+
race:dictresize
36+
race:gc_collect_main
37+
race:gc_restore_tid
38+
race:initialize_new_array
39+
race:insertdict
40+
race:lookup_tp_dict
41+
race:mi_heap_visit_pages
42+
race:PyMember_GetOne
43+
race:PyMember_SetOne
44+
race:new_reference
45+
race:set_contains_key
46+
race:set_inheritable
47+
race:start_the_world
48+
race:tstate_set_detached
49+
race:unicode_hash
50+
race:update_cache
51+
race:update_cache_gil_disabled

Tools/tsan/supressions.txt

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
## reference: https://github.com/google/sanitizers/wiki/ThreadSanitizerSuppressions
1+
# This file contains suppressions for the default (with GIL) build.
2+
# reference: https://github.com/google/sanitizers/wiki/ThreadSanitizerSuppressions
23
race:get_allocator_unlocked
34
race:set_allocator_unlocked
4-
race:mi_heap_visit_pages
5-
race:_mi_heap_delayed_free_partial

0 commit comments

Comments
 (0)