diff --git a/.github/workflows/compiler_sanitization.yml b/.github/workflows/compiler_sanitization.yml new file mode 100644 index 00000000..128dbd83 --- /dev/null +++ b/.github/workflows/compiler_sanitization.yml @@ -0,0 +1,136 @@ +name: Compiler Sanitizer Tests + +on: + push: + branches: + - main + pull_request: + workflow_dispatch: + +defaults: + run: + shell: bash + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + clang_ASAN_UBSAN: + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + fetch-tags: true + + - name: Install system dependencies + run: | + brew install mpfr fftw cmake + + - name: Set up LLVM + run: | + brew install llvm@19 + LLVM_PREFIX=$(brew --prefix llvm@19) + echo "CC=$LLVM_PREFIX/bin/clang" >> $GITHUB_ENV + echo "CXX=$LLVM_PREFIX/bin/clang++" >> $GITHUB_ENV + echo "LDFLAGS=-L$LLVM_PREFIX/lib" >> $GITHUB_ENV + echo "CPPFLAGS=-I$LLVM_PREFIX/include" >> $GITHUB_ENV + + - name: Set up pyenv + run: | + git clone https://github.com/pyenv/pyenv.git "$HOME/.pyenv" + PYENV_ROOT="$HOME/.pyenv" + PYENV_BIN="$PYENV_ROOT/bin" + PYENV_SHIMS="$PYENV_ROOT/shims" + echo "$PYENV_BIN" >> $GITHUB_PATH + echo "$PYENV_SHIMS" >> $GITHUB_PATH + echo "PYENV_ROOT=$PYENV_ROOT" >> $GITHUB_ENV + + - name: Check pyenv is working + run: pyenv --version + + - name: Build CPython with address sanitizer + run: | + CONFIGURE_OPTS="--with-address-sanitizer" pyenv install 3.14t + pyenv global 3.14t + + - name: Install Python build dependencies + run: | + pip install meson meson-python ninja cython pytest hypothesis wheel build patchelf pytest-timeout + + - name: Clone and build NumPy with ASan + run: | + git clone --depth 1 https://github.com/numpy/numpy.git numpy-asan + cd numpy-asan + git submodule update --init --recursive + # Build NumPy with address sanitizer using pip + pip install . -v --no-build-isolation \ + -Csetup-args=-Db_sanitize=address,undefined \ + -Csetup-args=-Db_lundef=false + + - name: Build and install quaddtype with ASan + working-directory: quaddtype + run: | + # Build with sanitizers - these flags propagate to subprojects (SLEEF, qblas) by default + pip install .[test] -v --no-build-isolation \ + -Csetup-args=-Db_sanitize=address,undefined \ + -Csetup-args=-Db_lundef=false + + - name: Run quaddtype tests with ASan + working-directory: quaddtype + run: | + # Create a directory for sanitizer logs + mkdir -p ${{ github.workspace }}/sanitizer_logs + + # Run tests with sanitizer output redirected to log files + # Note: UBSAN halt_on_error=0 because NumPy has some UBSAN issues that would abort tests + ASAN_OPTIONS=detect_leaks=0:symbolize=1:strict_init_order=true:allocator_may_return_null=1:log_path=${{ github.workspace }}/sanitizer_logs/asan \ + UBSAN_OPTIONS=halt_on_error=0:log_path=${{ github.workspace }}/sanitizer_logs/ubsan \ + pytest -vvv --color=yes --timeout=600 --durations=10 + + - name: Display quaddtype sanitizer warnings + if: always() + run: | + echo "" + echo "==========================================" + echo "ASAN LOGS" + echo "==========================================" + if ls ${{ github.workspace }}/sanitizer_logs/asan* 1> /dev/null 2>&1; then + cat ${{ github.workspace }}/sanitizer_logs/asan* 2>/dev/null || echo "No ASAN logs available." + else + echo "No ASAN log files found." + fi + + echo "" + echo "==========================================" + echo "UBSAN LOGS" + echo "==========================================" + if ls ${{ github.workspace }}/sanitizer_logs/ubsan* 1> /dev/null 2>&1; then + cat ${{ github.workspace }}/sanitizer_logs/ubsan* 2>/dev/null || echo "No UBSAN logs available." + else + echo "No UBSAN log files found." + fi + + - name: Check for quaddtype sanitizer issues + if: always() + run: | + # Fail if any quaddtype-related sanitizer issues are found + QUADDTYPE_ISSUES="" + if ls ${{ github.workspace }}/sanitizer_logs/* 1> /dev/null 2>&1; then + QUADDTYPE_ISSUES=$(cat ${{ github.workspace }}/sanitizer_logs/* 2>/dev/null | \ + grep -E "quaddtype|_quaddtype|numpy_quaddtype" || true) + fi + + if [ -n "$QUADDTYPE_ISSUES" ]; then + echo "==========================================" + echo "ERROR: Sanitizer issues found in quaddtype!" + echo "==========================================" + echo "$QUADDTYPE_ISSUES" + exit 1 + else + echo "No quaddtype-specific sanitizer issues found." + fi