Skip to content

Commit b5087c2

Browse files
authored
Merge pull request #862 from rgommers/ci-fix-asan
CI: run the ASan/UBSan job in a container instead of on macOS
2 parents 074fac6 + 2c1ed83 commit b5087c2

1 file changed

Lines changed: 29 additions & 30 deletions

File tree

.github/workflows/tests.yml

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ env:
1919
FORCE_COLOR: 3
2020
# Some common environment variables for both GNU/Linux and macOS jobs
2121
MPLBACKEND: Agg
22-
CYTHON_TRACE: 1
23-
CYTHONSPEC: cython
2422
NUMPY_MIN: numpy==1.26.4
2523
CYTHON_MIN: cython==3.1.3
2624

@@ -246,37 +244,30 @@ jobs:
246244
247245
clang_ASan_UBSan:
248246
name: Test under ASan and UBSan
249-
runs-on: macos-latest
247+
runs-on: ubuntu-latest
248+
container:
249+
# Prebuilt ASan-instrumented CPython 3.14 + clang-21, from
250+
# https://github.com/nascheme/cpython_sanity. To refresh the digest:
251+
# docker pull ghcr.io/nascheme/cpython-asan:3.14 && \
252+
# docker inspect --format='{{index .RepoDigests 0}}' ghcr.io/nascheme/cpython-asan:3.14
253+
image: ghcr.io/nascheme/cpython-asan:3.14@sha256:5e7cfa58bbaff0a31efc199d7d39902b80f99ab526c9c74104cd909ff075fd0a
254+
options: --shm-size=2g
255+
env:
256+
# LeakSanitizer is on by default under ASan on Linux (unlike on macOS, where it is
257+
# unsupported). Without this, every Python subprocess spawned during the build exits
258+
# non-zero over small leaks in CPython's own startup/import code - which breaks meson's
259+
# `run_command(py, ..., check: true)` probe for numpy's include dir. Leak checking for
260+
# the test run itself is configured in the "Test" step below.
261+
ASAN_OPTIONS: detect_leaks=0
250262
steps:
251263
- uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v4.2.2
252264
with:
253265
submodules: recursive
254266
fetch-tags: true
255267
persist-credentials: false
256268

257-
- name: Set up pyenv
258-
run: |
259-
git clone https://github.com/pyenv/pyenv.git "$HOME/.pyenv"
260-
PYENV_ROOT="$HOME/.pyenv"
261-
PYENV_BIN="$PYENV_ROOT/bin"
262-
PYENV_SHIMS="$PYENV_ROOT/shims"
263-
echo "$PYENV_BIN" >> $GITHUB_PATH
264-
echo "$PYENV_SHIMS" >> $GITHUB_PATH
265-
echo "PYENV_ROOT=$PYENV_ROOT" >> $GITHUB_ENV
266-
267-
- name: Set up LLVM
268-
run: |
269-
brew install llvm@19
270-
LLVM_PREFIX=$(brew --prefix llvm@19)
271-
echo CC="$LLVM_PREFIX/bin/clang" >> $GITHUB_ENV
272-
echo CXX="$LLVM_PREFIX/bin/clang++" >> $GITHUB_ENV
273-
echo LDFLAGS="-L$LLVM_PREFIX/lib" >> $GITHUB_ENV
274-
echo CPPFLAGS="-I$LLVM_PREFIX/include" >> $GITHUB_ENV
275-
276-
- name: Build Python with AddressSanitizer
277-
run: |
278-
CONFIGURE_OPTS="--with-address-sanitizer" pyenv install 3.14
279-
pyenv global 3.14
269+
- name: Trust working directory
270+
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
280271

281272
- name: Install NumPy dependencies from PyPI
282273
run: |
@@ -285,6 +276,9 @@ jobs:
285276
- name: Build NumPy with ASan
286277
run: |
287278
pip install numpy --no-binary numpy --no-build-isolation -Csetup-args="-Db_sanitize=address" -v
279+
# pyenv only creates shims for newly installed scripts on rehash; without this
280+
# `numpy-config` is not on PATH and meson falls back to probing the interpreter
281+
pyenv rehash
288282
289283
- name: Install dependencies from PyPI
290284
run: |
@@ -293,11 +287,16 @@ jobs:
293287
- name: Build PyWavelets with ASan and UBSan
294288
run: |
295289
export CFLAGS=-fno-sanitize=function # suppressed upstream, see cython#7437
296-
spin build -- -Db_sanitize=address,undefined -Db_lundef=false
290+
# -j2 rather than -j4: ASan builds are memory-hungry and OOM in CI otherwise
291+
spin build -j2 -- -Db_sanitize=address,undefined -Db_lundef=false
297292
298293
- name: Test
299294
run: |
300295
# pass -s to pytest to see ASAN errors and warnings, otherwise pytest captures them
301-
ASAN_OPTIONS=detect_leaks=0:symbolize=1:strict_init_order=true:allocator_may_return_null=1:use_sigaltstack=0 \
302-
UBSAN_OPTIONS=halt_on_error=1 \
303-
spin test -- -v -s --timeout=600 --durations=10
296+
export ASAN_OPTIONS=detect_leaks=0:symbolize=1:strict_init_order=true:allocator_may_return_null=1:use_sigaltstack=0
297+
export UBSAN_OPTIONS=halt_on_error=1
298+
# test_swt2_iswt2_integration takes ~3.5 minutes under ASan and adds little here:
299+
# it loops swt2/iswt2 over every discrete wavelet, but the same C code is already
300+
# covered by test_swt2_iswt2_quick and test_swtn_iswtn_integration
301+
spin test -- -v -s --timeout=600 --durations=10 \
302+
-k "not test_swt2_iswt2_integration"

0 commit comments

Comments
 (0)