|
| 1 | +name: Run with compiled Python |
| 2 | + |
| 3 | +on: |
| 4 | + workflow_call: |
| 5 | + inputs: |
| 6 | + sanitize: |
| 7 | + required: false |
| 8 | + default: |
| 9 | + type: string |
| 10 | + compiler: |
| 11 | + required: false |
| 12 | + default: |
| 13 | + type: string |
| 14 | + cpp_compiler: |
| 15 | + required: false |
| 16 | + default: |
| 17 | + type: string |
| 18 | + name: |
| 19 | + required: true |
| 20 | + type: string |
| 21 | + |
| 22 | +jobs: |
| 23 | + do_run: |
| 24 | + name: ${{inputs.name}} |
| 25 | + runs-on: ubuntu-latest |
| 26 | + |
| 27 | + env: |
| 28 | + BACKEND: c,cpp |
| 29 | + PYTHON_VERSION: 3.x-dev |
| 30 | + CONFIGURE_ARGS: --with-pydebug |
| 31 | + SANITIZER_CFLAGS: "" |
| 32 | + |
| 33 | + steps: |
| 34 | + - name: Checkout repo |
| 35 | + uses: actions/checkout@v5 |
| 36 | + |
| 37 | + - name: Set compiler |
| 38 | + if: ${{inputs.compiler}} |
| 39 | + run: | |
| 40 | + CC=${{inputs.compiler}} |
| 41 | + CXX=${{inputs.cpp_compiler}} |
| 42 | + echo EXTERNAL_OVERRIDE_CC=1 >> $GITHUB_ENV |
| 43 | + clangv=$($CC -v 2> >(grep "clang version")) |
| 44 | + echo $clangv |
| 45 | + if [[ $clangv == *"version 18"* && "${{inputs.sanitize}}" == *"thread"* ]]; then |
| 46 | + # Python uses clang-17 instead of 18 because of bugs so do the same |
| 47 | + CC=clang-17 |
| 48 | + CXX=clang-17 |
| 49 | + fi |
| 50 | + echo "CC=$CC" >> $GITHUB_ENV |
| 51 | + echo "CXX=$CXX" >> $GITHUB_ENV |
| 52 | + |
| 53 | +
|
| 54 | + - name: Set up sanitizer args |
| 55 | + if: ${{inputs.sanitize}} |
| 56 | + run: | |
| 57 | + SANITIZER_CFLAGS="" |
| 58 | + CONFIGURE_ARGS="" |
| 59 | + EXTRA_CONFIGURE_CFLAGS="" |
| 60 | + EXCLUDE="run[.] memoryview[.] --no-examples" |
| 61 | + if [[ "${{inputs.sanitize}}" == *"address"* ]]; then |
| 62 | + CONFIGURE_ARGS="$CONFIGURE_ARGS --with-address-sanitizer --without-pymalloc" |
| 63 | + SANITIZER_CFLAGS="$SANITIZER_CFLAGS -fsanitize=address" |
| 64 | + echo "ASAN_OPTIONS=detect_leaks=false log_path=${{ github.workspace }}/san_log" >> $GITHUB_ENV |
| 65 | + fi |
| 66 | + # TODO - memory sanitizer requires rebuilding almost all of CPython's dependencies |
| 67 | + # with memory sanitizer too, so isn't really usable for us. |
| 68 | + if [[ "${{inputs.sanitize}}" == *"memory"* ]]; then |
| 69 | + CONFIGURE_ARGS="$CONFIGURE_ARGS --with-memory-sanitizer" |
| 70 | + SANITIZER_CFLAGS="$SANITIZER_CFLAGS -fsanitize=memory" |
| 71 | + fi |
| 72 | + if [[ "${{inputs.sanitize}}" == *"undefined"* ]]; then |
| 73 | + CONFIGURE_ARGS="$CONFIGURE_ARGS --with-undefined-behavior-sanitizer" |
| 74 | + # We call functions through slightly incorrect pointer types a lot so disable this check for now for now |
| 75 | + EXTRA_CONFIGURE_CFLAGS="$EXTRA_CONFIGURE_CFLAGS -fno-sanitize=function" |
| 76 | + # omit vptr because it's largely C++-only and requires linking with clang++ (which breaks other things) |
| 77 | + SANITIZER_CFLAGS="$SANITIZER_CFLAGS -fsanitize=undefined -fno-sanitize=function -fno-sanitize=vptr -fno-omit-frame-pointer" |
| 78 | + echo "print_stacktrace=1" >> $GITHUB_ENV |
| 79 | + EXCLUDE="$EXCLUDE --excludefile tests/ubsan_bugs.txt" |
| 80 | + echo "UBSAN_OPTIONS=log_path=${{ github.workspace }}/san_log" >> $GITHUB_ENV |
| 81 | + fi |
| 82 | + if [[ "${{inputs.sanitize}}" == *"thread"* ]]; then |
| 83 | + CONFIGURE_ARGS="$CONFIGURE_ARGS --with-thread-sanitizer" |
| 84 | + SANITIZER_CFLAGS="$SANITIZER_CFLAGS -fsanitize=thread" |
| 85 | + if [[ "${{inputs.sanitize}}" == *"ft"* ]]; then |
| 86 | + echo "PYTHON_VERSION=3.xt-dev" >> $GITHUB_ENV |
| 87 | + CONFIGURE_ARGS="$CONFIGURE_ARGS --disable-gil" |
| 88 | + TSAN_SUPPRESSIONS="${GITHUB_WORKSPACE}/cpython_main/Tools/tsan/suppressions_free_threading.txt" |
| 89 | + else |
| 90 | + TSAN_SUPPRESSIONS="${GITHUB_WORKSPACE}/cpython_main/Tools/tsan/suppressions.txt" |
| 91 | + fi |
| 92 | + if [[ "${{github.event.label.name}}" != "full_sanitizers" ]]; then |
| 93 | + # For thread sanitizer run on a much smaller list of tests |
| 94 | + EXCLUDE="tag:threads" |
| 95 | + fi |
| 96 | + EXCLUDE="$EXCLUDE --excludefile tests/tsan_bugs.txt" |
| 97 | + echo "TSAN_OPTIONS=suppressions=$TSAN_SUPPRESSIONS log_path=${{ github.workspace }}/san_log" >> $GITHUB_ENV |
| 98 | + # Having too many workers seems to lead to an exit without a diagnostic message - possibly memory? |
| 99 | + echo "TEST_PARALLELISM=-j3" >> $GITHUB_ENV |
| 100 | + fi |
| 101 | + # Even running Python like this is slow, so only run a subset of tests |
| 102 | + # (i.e. compile-only tests tell us nothing) |
| 103 | + echo "EXCLUDE=$EXCLUDE --no-refnanny" >> $GITHUB_ENV |
| 104 | + # https://github.com/google/sanitizers/issues/934 |
| 105 | + echo "LD_PRELOAD=$(realpath "$(clang -print-file-name=libstdc++.so)")" >> $GITHUB_ENV |
| 106 | + echo "CONFIGURE_ARGS=$CONFIGURE_ARGS" >> $GITHUB_ENV |
| 107 | + echo "SANITIZER_CFLAGS=$SANITIZER_CFLAGS" >> $GITHUB_ENV |
| 108 | + echo "EXTRA_CONFIGURE_CFLAGS=$EXTRA_CONFIGURE_CFLAGS" >> $GITHUB_ENV |
| 109 | +
|
| 110 | + - name: Install build dependencies |
| 111 | + run: | |
| 112 | + sudo apt-get update -y -q |
| 113 | + sudo apt-get install -y -q libbz2-dev lzma-dev libreadline-dev libgmp-dev |
| 114 | +
|
| 115 | + - name: Build Python |
| 116 | + run: | |
| 117 | + git clone https://github.com/python/cpython/ cpython_main |
| 118 | + cd cpython_main |
| 119 | + ./configure ${CONFIGURE_ARGS} --prefix=${GITHUB_WORKSPACE}/cpython_install CFLAGS="-O2 $EXTRA_CONFIGURE_CFLAGS" |
| 120 | + make -j8 |
| 121 | + make install |
| 122 | + ${GITHUB_WORKSPACE}/cpython_install/bin/python3 -m venv ${GITHUB_WORKSPACE}/venv_pydebug |
| 123 | +
|
| 124 | + - name: Run CI |
| 125 | + run: | |
| 126 | + cd "${GITHUB_WORKSPACE}/" |
| 127 | + source venv_pydebug/bin/activate |
| 128 | + bash ./Tools/ci-run.sh |
| 129 | +
|
| 130 | + - name: Archive logs |
| 131 | + if: ${{ inputs.sanitize && always() }} |
| 132 | + uses: actions/upload-artifact@v4 |
| 133 | + with: |
| 134 | + name: ${{inputs.sanitize}}-logs |
| 135 | + path: san_log.* |
| 136 | + if-no-files-found: ignore |
| 137 | + |
| 138 | + # The check of the sanitizer logs does a bit of filtering of unwanted diagnostics |
| 139 | + # and finishes with an error code if anything bad is found. |
| 140 | + - name: Check logs |
| 141 | + if: ${{ inputs.sanitize && always() }} |
| 142 | + run: | |
| 143 | + cd "${GITHUB_WORKSPACE}/" |
| 144 | + source venv_pydebug/bin/activate |
| 145 | + python Tools/examine_sanitizer_logs.py san_log.* |
0 commit comments