diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 00d64b3df7e9654..21e4124c24cb0d7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -481,53 +481,6 @@ jobs: if: fromJSON(needs.build-context.outputs.run-tests) uses: ./.github/workflows/reusable-test-lazy-imports-all.yml - build-asan: - name: 'Address sanitizer' - runs-on: ${{ matrix.os }} - timeout-minutes: 60 - needs: build-context - if: needs.build-context.outputs.run-ubuntu == 'true' - strategy: - fail-fast: false - matrix: - os: [ubuntu-26.04] - env: - OPENSSL_VER: 3.5.9 - PYTHONSTRICTEXTENSIONBUILD: 1 - ASAN_OPTIONS: detect_leaks=0:allocator_may_return_null=1:handle_segv=0 - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - persist-credentials: false - - name: Runner image version - run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV" - - name: Register gcc problem matcher - run: echo "::add-matcher::.github/problem-matchers/gcc.json" - - name: Install dependencies - run: sudo ./.github/workflows/posix-deps-apt.sh - - name: Configure OpenSSL env vars - run: | - echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> "$GITHUB_ENV" - echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> "$GITHUB_ENV" - echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> "$GITHUB_ENV" - - name: 'Restore OpenSSL build' - id: cache-openssl - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 - with: - path: ./multissl/openssl/${{ env.OPENSSL_VER }} - key: ${{ matrix.os }}-multissl-openssl-${{ env.OPENSSL_VER }} - - name: Install OpenSSL - if: steps.cache-openssl.outputs.cache-hit != 'true' - run: python3 Tools/ssl/multissltests.py --steps=library --base-directory "$MULTISSL_DIR" --openssl "$OPENSSL_VER" --system Linux - - name: Configure CPython - run: ./configure --config-cache --with-address-sanitizer --without-pymalloc --with-openssl="$OPENSSL_DIR" - - name: Build CPython - run: make -j4 - - name: Display build info - run: make pythoninfo - - name: Tests - run: xvfb-run make ci - build-san: # ${{ '' } is a hack to nest jobs under the same sidebar category. name: Sanitizers${{ '' }} # zizmor: ignore[obfuscation] @@ -544,6 +497,9 @@ jobs: sanitizer: - TSan include: + - check-name: Address + sanitizer: ASan + free-threading: false - check-name: Undefined behavior sanitizer: UBSan free-threading: false @@ -657,7 +613,6 @@ jobs: - build-wasi - test-hypothesis - test-lazy-imports-all - - build-asan - build-san - cross-build-linux - cifuzz @@ -704,7 +659,6 @@ jobs: build-ubuntu-installed, build-ubuntu-ssltests, test-hypothesis, - build-asan, build-san, cross-build-linux, ' diff --git a/.github/workflows/reusable-san.yml b/.github/workflows/reusable-san.yml index f63c2b89134aca9..9c31241498a75e9 100644 --- a/.github/workflows/reusable-san.yml +++ b/.github/workflows/reusable-san.yml @@ -43,6 +43,15 @@ jobs: # please update the versions in `Tools/pixi-packages/variants.yaml` too. echo "CC=clang" >> "$GITHUB_ENV" echo "CXX=clang++" >> "$GITHUB_ENV" + - name: ASan option setup + if: inputs.sanitizer == 'ASan' + run: | + echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> "$GITHUB_ENV" + echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> "$GITHUB_ENV" + echo "ASAN_OPTIONS=${SAN_LOG_OPTION} detect_leaks=0 allocator_may_return_null=1 handle_segv=0" >> "$GITHUB_ENV" + echo "PYTHONSTRICTEXTENSIONBUILD=1" >> "$GITHUB_ENV" + env: + SAN_LOG_OPTION: log_path=${{ github.workspace }}/san_log - name: TSan option setup if: inputs.sanitizer == 'TSan' run: | @@ -88,16 +97,19 @@ jobs: - name: Add ccache to PATH run: | echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV" - - name: 'Restore OpenSSL build (TSan)' + - name: 'Restore OpenSSL build' id: cache-openssl - if: inputs.sanitizer == 'TSan' + if: inputs.sanitizer == 'TSan' || inputs.sanitizer == 'ASan' uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ./multissl/openssl/${{ env.OPENSSL_VER }} - key: ${{ env.IMAGE_OS_VERSION }}-multissl-openssl-tsan-${{ env.OPENSSL_VER }} - - name: Install OpenSSL (TSan) + key: >- + ${{ env.IMAGE_OS_VERSION }}-multissl-openssl-${{ + inputs.sanitizer == 'TSan' && 'tsan-' || '' + }}${{ env.OPENSSL_VER }} + - name: Install OpenSSL if: >- - inputs.sanitizer == 'TSan' + (inputs.sanitizer == 'TSan' || inputs.sanitizer == 'ASan') && steps.cache-openssl.outputs.cache-hit != 'true' run: >- python3 Tools/ssl/multissltests.py @@ -105,7 +117,7 @@ jobs: --base-directory="${MULTISSL_DIR}" --openssl="${OPENSSL_VER}" --system=Linux - --tsan + ${{ inputs.sanitizer == 'TSan' && '--tsan' || '' }} # gh-157958: -O2 instead of the pydebug default -Og to avoid a clang 21 # compile-time blowup on some interpreter files. # (https://github.com/llvm/llvm-project/issues/179695) @@ -117,14 +129,20 @@ jobs: --config-cache OPT="-O2 -g" ${{ - inputs.sanitizer == 'TSan' + inputs.sanitizer == 'ASan' + && '--with-address-sanitizer --without-pymalloc' + || inputs.sanitizer == 'TSan' && '--with-thread-sanitizer' || inputs.sanitizer == 'MSan' && '--with-memory-sanitizer' || '--with-undefined-behavior-sanitizer --with-strict-overflow' }} ${{ inputs.sanitizer == 'MSan' && '--with-assertions' || '--with-pydebug' }} - ${{ inputs.sanitizer == 'TSan' && '--with-openssl="$OPENSSL_DIR" --with-openssl-rpath=auto' || '' }} + ${{ + (inputs.sanitizer == 'TSan' || inputs.sanitizer == 'ASan') + && '--with-openssl="$OPENSSL_DIR" --with-openssl-rpath=auto' + || '' + }} ${{ inputs.free-threading && '--disable-gil' || '' }} - name: Build CPython run: make -j4 diff --git a/Lib/test/test_capi/test_mem.py b/Lib/test/test_capi/test_mem.py index 21b51d133447da7..7e35fabdd276086 100644 --- a/Lib/test/test_capi/test_mem.py +++ b/Lib/test/test_capi/test_mem.py @@ -1,3 +1,4 @@ +import os import re import textwrap import unittest @@ -188,10 +189,12 @@ class PyMemDefaultTests(PyMemDebugTests): 'need address sanitizer') class AddressSanitizerTests(unittest.TestCase): def test_buffer_overflow(self): + asan_options = os.environ.get('ASAN_OPTIONS', '') with support.SuppressCrashReport(): out = assert_python_failure( '-c', 'import _testcapi; _testcapi.pymem_buffer_overflow()', PYTHONMALLOC='malloc', + ASAN_OPTIONS=f'{asan_options}:log_path=stderr', ) self.assertIn(b'AddressSanitizer', out.err)