Skip to content

Commit 324bec7

Browse files
ASan+UBSan workflow lane Pt2 (#1728)
* Move gtest filter to env var * extract sanitizer gtest filter into shared script * set explicit ASAN options for sanitizer test lane * reproduction on failure * split sanitizer lane into build/test with core-vs-extended subsets, clang-18 pin, and runtime guardrails * caches files * add shared libs on path * lib path added * change name "test (core/extended subset)" to "(ASan+UBSan)" * moved runs to scripts * rem repro * readme change * removed cache as discussed with @elalish in meeting * testing by removing LD_LIBRARY_PATH * restore * only keep find and remove hardcoded paths * run path use origin cmake args * removed lib path
1 parent c463210 commit 324bec7

6 files changed

Lines changed: 131 additions & 28 deletions

File tree

.github/workflows/manifold.yml

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -457,43 +457,46 @@ jobs:
457457
ASAN_OPTIONS=detect_container_overflow=0 cmake --build build
458458
459459
build_sanitizer:
460-
name: Sanitizer (ASan+UBSan)
460+
name: Sanitizer build (ASan+UBSan)
461461
timeout-minutes: 30
462462
runs-on: ubuntu-24.04
463463
steps:
464464
- uses: actions/checkout@v6
465465
- name: Install apt packages
466466
uses: awalsh128/cache-apt-pkgs-action@v1.6.0
467467
with:
468-
packages: libgtest-dev libtbb-dev clang cmake
468+
packages: libgtest-dev libtbb-dev clang-18 cmake
469469
version: 1
470470
- *clone-clipper2
471-
- name: Build (clang + asan/ubsan)
472-
run: |
473-
cmake \
474-
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
475-
-DBUILD_SHARED_LIBS=ON \
476-
-DMANIFOLD_STRICT=ON \
477-
-DMANIFOLD_PYBIND=OFF \
478-
-DMANIFOLD_DEBUG=ON \
479-
-DMANIFOLD_ASSERT=ON \
480-
-DMANIFOLD_CROSS_SECTION=ON \
481-
-DMANIFOLD_PAR=OFF \
482-
-DCMAKE_C_COMPILER=clang \
483-
-DCMAKE_CXX_COMPILER=clang++ \
484-
-DCMAKE_C_FLAGS="-fsanitize=address,undefined" \
485-
-DCMAKE_CXX_FLAGS="-fsanitize=address,undefined" \
486-
-DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address,undefined" \
487-
-DCMAKE_SHARED_LINKER_FLAGS="-fsanitize=address,undefined" \
488-
-DFETCHCONTENT_SOURCE_DIR_CLIPPER2=clipper2 \
489-
. -B build
490-
cmake --build build
491-
- name: Test (small sanitizer subset)
492-
env:
493-
ASAN_OPTIONS: detect_container_overflow=0
494-
UBSAN_OPTIONS: print_stacktrace=1
495-
run: |
496-
./build/test/manifold_test --gtest_filter="Boolean.DeterminismSimpleSubtract:Boolean.DeterminismSimpleUnion:Boolean.DeterminismSimpleIntersect:Boolean.MultiCoplanar:Boolean.NonIntersecting:Manifold.MeshDeterminism"
471+
- name: Build (clang-18 + asan/ubsan)
472+
run: bash ./scripts/ci/sanitizer_build.sh
473+
- name: Upload sanitizer build artifacts
474+
uses: actions/upload-artifact@v4
475+
with:
476+
name: sanitizer-build
477+
path: build/
478+
retention-days: 5
479+
480+
test_sanitizer:
481+
name: Sanitizer (ASan+UBSan)
482+
needs: build_sanitizer
483+
timeout-minutes: 30
484+
runs-on: ubuntu-24.04
485+
env:
486+
ASAN_OPTIONS: detect_container_overflow=0:strict_init_order=1
487+
UBSAN_OPTIONS: print_stacktrace=1
488+
SANITIZER_TEST_TIMEOUT_SEC: 1200
489+
SANITIZER_SUBSET: ${{ (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && 'extended' || 'core' }}
490+
steps:
491+
- uses: actions/checkout@v6
492+
- name: Download sanitizer build artifacts
493+
uses: actions/download-artifact@v4
494+
with:
495+
name: sanitizer-build
496+
path: .
497+
- name: Test sanitizer subset
498+
shell: bash
499+
run: bash ./scripts/ci/sanitizer_test.sh
497500

498501
build_mxe:
499502
name: MXE (TBB:${{matrix.parallelization == 'ON'}})

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,4 +164,5 @@
164164
"--header-insertion=never"
165165
],
166166
"editor.defaultFormatter": "xaver.clang-format",
167+
"claudeCode.allowDangerouslySkipPermissions": true,
167168
}

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,18 @@ Offline building (with missing dependencies/dependency version override):
166166
167167
The build instructions used by our CI are in [manifold.yml](https://github.com/elalish/manifold/blob/master/.github/workflows/manifold.yml), which is a good source to check if something goes wrong and for instructions specific to other platforms, like Windows.
168168

169+
#### Sanitizer CI Reproduction
170+
171+
To reproduce the sanitizer CI test locally from repo root:
172+
173+
```bash
174+
bash ./scripts/ci/sanitizer_build.sh
175+
source ./scripts/sanitizer_cases.sh
176+
ASAN_OPTIONS=detect_container_overflow=0:strict_init_order=1 \
177+
UBSAN_OPTIONS=print_stacktrace=1 \
178+
./build/test/manifold_test --gtest_filter="${SANITIZER_GTEST_FILTER_CORE}"
179+
```
180+
169181
### WASM
170182

171183
> Note: While we support compiling with `MANIFOLD_PAR=ON` in recent emscripten

scripts/ci/sanitizer_build.sh

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
cmake \
5+
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
6+
-DBUILD_SHARED_LIBS=ON \
7+
-DMANIFOLD_STRICT=ON \
8+
-DMANIFOLD_PYBIND=OFF \
9+
-DMANIFOLD_DEBUG=ON \
10+
-DMANIFOLD_ASSERT=ON \
11+
-DMANIFOLD_CROSS_SECTION=ON \
12+
-DMANIFOLD_PAR=OFF \
13+
-DCMAKE_C_COMPILER=clang-18 \
14+
-DCMAKE_CXX_COMPILER=clang++-18 \
15+
-DCMAKE_C_FLAGS="-fsanitize=address,undefined" \
16+
-DCMAKE_CXX_FLAGS="-fsanitize=address,undefined" \
17+
-DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address,undefined" \
18+
-DCMAKE_SHARED_LINKER_FLAGS="-fsanitize=address,undefined" \
19+
-DCMAKE_BUILD_RPATH_USE_ORIGIN=ON \
20+
-DFETCHCONTENT_SOURCE_DIR_CLIPPER2=clipper2 \
21+
. -B build
22+
23+
cmake --build build

scripts/ci/sanitizer_test.sh

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
source ./scripts/sanitizer_cases.sh
5+
6+
case "${SANITIZER_SUBSET}" in
7+
core)
8+
SANITIZER_GTEST_FILTER="${SANITIZER_GTEST_FILTER_CORE}"
9+
;;
10+
extended)
11+
SANITIZER_GTEST_FILTER="${SANITIZER_GTEST_FILTER_EXTENDED}"
12+
;;
13+
*)
14+
echo "::warning::Unknown SANITIZER_SUBSET=${SANITIZER_SUBSET}, falling back to core."
15+
SANITIZER_GTEST_FILTER="${SANITIZER_GTEST_FILTER_CORE}"
16+
;;
17+
esac
18+
19+
SANITIZER_TEST_BIN=""
20+
for CANDIDATE in \
21+
./build/test/manifold_test \
22+
./test/manifold_test \
23+
./sanitizer-build/test/manifold_test \
24+
./sanitizer-build/build/test/manifold_test; do
25+
if [ -f "${CANDIDATE}" ]; then
26+
SANITIZER_TEST_BIN="${CANDIDATE}"
27+
break
28+
fi
29+
done
30+
31+
if [ -z "${SANITIZER_TEST_BIN}" ]; then
32+
SANITIZER_TEST_BIN="$(find . -type f -name manifold_test | head -n 1)"
33+
fi
34+
if [ -z "${SANITIZER_TEST_BIN}" ]; then
35+
echo "::error::Could not find manifold_test after downloading sanitizer artifacts."
36+
echo "::group::Artifact layout"
37+
find . -maxdepth 4 -type d | sort
38+
echo "::endgroup::"
39+
exit 127
40+
fi
41+
chmod +x "${SANITIZER_TEST_BIN}" || true
42+
43+
set +e
44+
timeout "${SANITIZER_TEST_TIMEOUT_SEC}" \
45+
"${SANITIZER_TEST_BIN}" --gtest_filter="${SANITIZER_GTEST_FILTER}"
46+
TEST_RC="$?"
47+
set -e
48+
if [ "${TEST_RC}" -eq 124 ]; then
49+
echo "::warning::Sanitizer test timed out after ${SANITIZER_TEST_TIMEOUT_SEC}s."
50+
fi
51+
52+
exit "${TEST_RC}"

scripts/sanitizer_cases.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/usr/bin/env bash
2+
3+
# Shared sanitizer test/filter definitions.
4+
# Keep core small for PR CI stability, and tune over time with runtime data.
5+
6+
SANITIZER_GTEST_FILTER_CORE="Boolean.DeterminismSimpleSubtract:Boolean.DeterminismSimpleUnion:Boolean.DeterminismSimpleIntersect:Boolean.MultiCoplanar:Boolean.NonIntersecting:Manifold.MeshDeterminism"
7+
8+
# Broader set for scheduled/manual runs.
9+
SANITIZER_GTEST_FILTER_EXTENDED="${SANITIZER_GTEST_FILTER_CORE}:Boolean.AlmostCoplanar"
10+
11+
# Default filter used by workflow/test helpers.
12+
SANITIZER_GTEST_FILTER="${SANITIZER_GTEST_FILTER_CORE}"

0 commit comments

Comments
 (0)