Skip to content

Commit 25243b1

Browse files
pitroucorona10
andauthored
[3.12] gh-112536: Add TSAN build on Github Actions (GH-116872)
(cherry picked from commit 20578a1) Co-authored-by: Donghee Na <[email protected]>
1 parent fcb2301 commit 25243b1

File tree

5 files changed

+74
-0
lines changed

5 files changed

+74
-0
lines changed

.github/workflows/build.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,15 @@ jobs:
471471
- name: Tests
472472
run: xvfb-run make buildbottest TESTOPTS="-j4 -uall,-cpu"
473473

474+
build_tsan:
475+
name: 'Thread sanitizer'
476+
needs: check_source
477+
if: needs.check_source.outputs.run_tests == 'true'
478+
uses: ./.github/workflows/reusable-tsan.yml
479+
with:
480+
config_hash: ${{ needs.check_source.outputs.config_hash }}
481+
options: ./configure --config-cache --with-thread-sanitizer --with-pydebug
482+
474483
all-required-green: # This job does nothing and is only used for the branch protection
475484
name: All required checks pass
476485
if: always()
@@ -485,6 +494,7 @@ jobs:
485494
- build_windows
486495
- test_hypothesis
487496
- build_asan
497+
- build_tsan
488498

489499
runs-on: ubuntu-latest
490500

@@ -513,6 +523,7 @@ jobs:
513523
build_ubuntu_ssltests,
514524
build_windows,
515525
build_asan,
526+
build_tsan,
516527
'
517528
|| ''
518529
}}

.github/workflows/reusable-tsan.yml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
on:
2+
workflow_call:
3+
inputs:
4+
config_hash:
5+
required: true
6+
type: string
7+
options:
8+
required: true
9+
type: string
10+
11+
jobs:
12+
build_tsan_reusable:
13+
name: 'Thread sanitizer'
14+
runs-on: ubuntu-22.04
15+
timeout-minutes: 60
16+
steps:
17+
- uses: actions/checkout@v4
18+
- name: Runner image version
19+
run: echo "IMAGE_VERSION=${ImageVersion}" >> $GITHUB_ENV
20+
- name: Restore config.cache
21+
uses: actions/cache@v4
22+
with:
23+
path: config.cache
24+
key: ${{ github.job }}-${{ runner.os }}-${{ env.IMAGE_VERSION }}-${{ inputs.config_hash }}
25+
- name: Install Dependencies
26+
run: |
27+
sudo ./.github/workflows/posix-deps-apt.sh
28+
sudo apt install -y clang
29+
# Reduce ASLR to avoid TSAN crashing
30+
sudo sysctl -w vm.mmap_rnd_bits=28
31+
- name: TSAN Option Setup
32+
run: |
33+
echo "TSAN_OPTIONS=suppressions=${GITHUB_WORKSPACE}/Tools/tsan/supressions.txt" >> $GITHUB_ENV
34+
echo "CC=clang" >> $GITHUB_ENV
35+
echo "CXX=clang++" >> $GITHUB_ENV
36+
- name: Add ccache to PATH
37+
run: |
38+
echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV
39+
- name: Configure ccache action
40+
uses: hendrikmuhs/[email protected]
41+
with:
42+
save: ${{ github.event_name == 'push' }}
43+
max-size: "200M"
44+
- name: Configure CPython
45+
run: ${{ inputs.options }}
46+
- name: Build CPython
47+
run: make -j4
48+
- name: Display build info
49+
run: make pythoninfo
50+
- name: Tests
51+
run: ./python -m test --tsan -j4

Lib/test/test_concurrent_futures/util.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ def get_context(self):
8585
self.skipTest("ProcessPoolExecutor unavailable on this system")
8686
if sys.platform == "win32":
8787
self.skipTest("require unix system")
88+
if support.check_sanitizer(thread=True):
89+
self.skipTest("TSAN doesn't support threads after fork")
8890
return super().get_context()
8991

9092

@@ -111,6 +113,8 @@ def get_context(self):
111113
self.skipTest("ProcessPoolExecutor unavailable on this system")
112114
if sys.platform == "win32":
113115
self.skipTest("require unix system")
116+
if support.check_sanitizer(thread=True):
117+
self.skipTest("TSAN doesn't support threads after fork")
114118
return super().get_context()
115119

116120

Lib/test/test_logging.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@
8080
skip_if_asan_fork = unittest.skipIf(
8181
support.HAVE_ASAN_FORK_BUG,
8282
"libasan has a pthread_create() dead lock related to thread+fork")
83+
skip_if_tsan_fork = unittest.skipIf(
84+
support.check_sanitizer(thread=True),
85+
"TSAN doesn't support threads after fork")
8386

8487

8588
class BaseTest(unittest.TestCase):
@@ -737,6 +740,7 @@ def remove_loop(fname, tries):
737740
@support.requires_fork()
738741
@threading_helper.requires_working_threading()
739742
@skip_if_asan_fork
743+
@skip_if_tsan_fork
740744
def test_post_fork_child_no_deadlock(self):
741745
"""Ensure child logging locks are not held; bpo-6721 & bpo-36533."""
742746
class _OurHandler(logging.Handler):

Python/thread_pthread.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@
9191
#endif
9292
#endif
9393

94+
/* Thread sanitizer doesn't currently support sem_clockwait */
95+
#ifdef _Py_THREAD_SANITIZER
96+
#undef HAVE_SEM_CLOCKWAIT
97+
#endif
9498

9599
/* Whether or not to use semaphores directly rather than emulating them with
96100
* mutexes and condition variables:

0 commit comments

Comments
 (0)