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