diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 750aa1ed87bca1..28d77ab11c98a9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -500,6 +500,7 @@ jobs: options: ./configure --config-cache --disable-gil --with-thread-sanitizer --with-pydebug suppressions_path: Tools/tsan/suppressions_free_threading.txt tsan_logs_artifact_name: tsan-logs-free-threading + os-matrix: '["ubuntu-22.04", "macos-14"]' # CIFuzz job based on https://google.github.io/oss-fuzz/getting-started/continuous-integration/ cifuzz: diff --git a/.github/workflows/reusable-tsan.yml b/.github/workflows/reusable-tsan.yml index b6d5d8fa1c7157..5ff0a9d0e23045 100644 --- a/.github/workflows/reusable-tsan.yml +++ b/.github/workflows/reusable-tsan.yml @@ -15,12 +15,19 @@ on: description: 'Name of the TSAN logs artifact. Must be unique for each job.' required: true type: string + os-matrix: + required: false + type: string + default: '["ubuntu-22.04"]' jobs: build_tsan_reusable: - name: 'Thread sanitizer' - runs-on: ubuntu-22.04 + name: 'Thread sanitizer (${{ matrix.os }})' + runs-on: ${{ matrix.os }} timeout-minutes: 60 + strategy: + matrix: + os: ${{fromJson(inputs.os-matrix)}} steps: - uses: actions/checkout@v4 - name: Runner image version @@ -31,6 +38,7 @@ jobs: path: config.cache key: ${{ github.job }}-${{ runner.os }}-${{ env.IMAGE_VERSION }}-${{ inputs.config_hash }} - name: Install Dependencies + if: ${{ startsWith(matrix.os, 'ubuntu') }} run: | sudo ./.github/workflows/posix-deps-apt.sh # Install clang-18 @@ -64,6 +72,10 @@ jobs: run: make pythoninfo - name: Tests run: ./python -m test --tsan -j4 + if: ${{ startsWith(matrix.os, 'ubuntu') }} + - name: Tests + run: ./python.exe -m test --tsan -j4 + if: ${{ startsWith(matrix.os, 'macos') }} - name: Display TSAN logs if: always() run: find ${GITHUB_WORKSPACE} -name 'tsan_log.*' | xargs head -n 1000 diff --git a/Lib/test/test_capi/test_mem.py b/Lib/test/test_capi/test_mem.py index 6ab7b685c2e18b..0c2963cf6fa8c6 100644 --- a/Lib/test/test_capi/test_mem.py +++ b/Lib/test/test_capi/test_mem.py @@ -1,8 +1,8 @@ import re +import sys import textwrap import unittest - from test import support from test.support import import_helper, requires_subprocess from test.support.script_helper import assert_python_failure, assert_python_ok @@ -75,12 +75,20 @@ def check_malloc_without_gil(self, code): def test_pymem_malloc_without_gil(self): # Debug hooks must raise an error if PyMem_Malloc() is called # without holding the GIL + if support.check_sanitizer(thread=True) and sys.platform == 'darwin': + # See: gh-120696 + raise unittest.SkipTest("this test will hang on macOS with TSAN") + code = 'import _testcapi; _testcapi.pymem_malloc_without_gil()' self.check_malloc_without_gil(code) def test_pyobject_malloc_without_gil(self): # Debug hooks must raise an error if PyObject_Malloc() is called # without holding the GIL + if support.check_sanitizer(thread=True) and sys.platform == 'darwin': + # See: gh-120696 + raise unittest.SkipTest("this test will hang on macOS with TSAN") + code = 'import _testcapi; _testcapi.pyobject_malloc_without_gil()' self.check_malloc_without_gil(code)