Files
ConformalLabpp/scripts/quality/sanitizers.sh
Tarik Moussa a2eee9c279
Some checks failed
C++ Tests / test-fast (pull_request) Successful in 1m56s
API Docs / doc-build (pull_request) Successful in 58s
Markdown link check / check (pull_request) Successful in 45s
C++ Tests / test-cgal (pull_request) Failing after 13m14s
ci+quality: structural gates (CI: 3 new; local: 7 new + .clang-tidy)
CI gates (active on every PR via .gitea/workflows/)
───────────────────────────────────────────────────
1. test-count consistency
   cpp-tests.yml gains a step after test-cgal that runs
   `scripts/check-test-counts.sh` against the just-built ./build dir
   (reuse via new BUILD_DIR env var, ~5 s overhead).  Drift between
   `doc/api/tests.md` and ctest reality now fails the PR.

2. End-to-end smoke
   `scripts/try_it.sh` (the documented user quick-start) is now part of
   the CGAL job, so README quick-start regressions fail the PR rather
   than silently breaking when users land.

3. Internal markdown link checker
   New `.gitea/workflows/markdown-links.yml` + `scripts/check-markdown
   -links.py`.  PRs that touch any *.md file run the check; main pushes
   trigger it too; a weekly cron catches external link rot.  Pure
   Python, no third-party action.  Validated against the current tree:
   122 internal links across 37 *.md files, 0 broken.

Local quality scripts (`scripts/quality/`, not in CI)
─────────────────────────────────────────────────────
* `license-headers.sh`   — `SPDX-License-Identifier: MIT` audit over
                            code/{include,src,tests}/.  Currently
                            reports 60/66 files missing it — that's
                            a follow-up; the script captures the
                            structural gap.
* `sanitizers.sh`        — ASan + UBSan over the fast test suite.
* `coverage.sh`          — gcov/lcov line + branch coverage of
                            code/include/, HTML report under
                            build-coverage/lcov-html/.
* `clang-tidy.sh`        — runs the curated `.clang-tidy` policy over
                            every public header.
* `multi-compiler.sh`    — sequential build + test against every
                            detected g++/clang++ (auto-discovery or
                            explicit list).
* `cgal-version-matrix.sh`— sequential build + CGAL test suite against
                            every CGAL tree under `~/cgal/<ver>/` (or
                            via `CGAL_ROOTS=...` env var).
* `reproducible-build.sh`— two `Release -j1` builds, fail if any test
                            executable byte-differs.
* `run-all.sh`           — driver: `--fast` for the ~5-min subset,
                            no arg for the ~25–40 min full sweep;
                            captures per-gate logs to
                            build-quality-logs/.

+ `.clang-tidy`          — curated, deliberately-small policy (only
                            checks that fire on OUR code, never on
                            transitive CGAL/Eigen/Boost headers).

+ `scripts/quality/README.md` — explains the structure, lists each
                            gate's wall-time + prereqs, and codifies
                            the promotion path: a gate moves into CI
                            only when it's green on the dev machine
                            AND has a recovery-instructions paragraph
                            in `doc/release-policy.md`.

Doc updates
───────────
`doc/architecture/locked-vs-flexible.md` (reviewer-facing) gains 4
"closed" rows in the limitations table — the 3 CI gates above and the
local quality-script suite.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 08:25:09 +02:00

89 lines
3.7 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# scripts/quality/sanitizers.sh
#
# Build the fast test suite with AddressSanitizer + UndefinedBehaviorSanitizer
# and run it. Catches:
# * use-after-free, double-free, heap-buffer-overflow (ASan)
# * signed integer overflow, NaN propagation, alignment violations (UBSan)
# * Eigen / CGAL template-induced UB that escapes the regular build
#
# Local-only (not in CI): the sanitizer build is ~3× slower and brittle
# against system libraries. Run it before every release tag, after
# touching any Newton/Hessian code, or when investigating intermittent
# test failures.
#
# Usage:
# bash scripts/quality/sanitizers.sh # default: ASan + UBSan
# ASAN_OPTIONS=... UBSAN_OPTIONS=... bash scripts/quality/sanitizers.sh
#
# Exit codes:
# 0 every test passes under sanitizer instrumentation
# 1 a sanitizer report was triggered (test failure or runtime error)
# 2 prerequisite missing (no clang/gcc with sanitizer support)
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$ROOT"
BUILD_DIR="build-sanitizers"
SAN_FLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer -O1 -g"
# Default ASan/UBSan runtime options — print stack on first error,
# abort on first issue (so CI logs make the cause obvious).
export ASAN_OPTIONS="${ASAN_OPTIONS:-detect_leaks=1:abort_on_error=1:print_stacktrace=1}"
export UBSAN_OPTIONS="${UBSAN_OPTIONS:-print_stacktrace=1:halt_on_error=1}"
echo "========================================"
echo " Sanitizer build (ASan + UBSan)"
echo " flags : $SAN_FLAGS"
echo " ASAN : $ASAN_OPTIONS"
echo " UBSAN : $UBSAN_OPTIONS"
echo "========================================"
# ── Pick a compiler with sanitizer support ──────────────────────────────────
# Prefer clang (better diagnostics); fall back to gcc.
CXX_BIN=""
for cand in clang++-17 clang++-16 clang++-15 clang++ g++; do
if command -v "$cand" >/dev/null 2>&1; then
CXX_BIN="$cand"
break
fi
done
if [ -z "$CXX_BIN" ]; then
echo "FAIL: no clang++ / g++ found in PATH" >&2
exit 2
fi
echo "Using CXX = $CXX_BIN ($("$CXX_BIN" --version | head -1))"
echo
# ── Configure ────────────────────────────────────────────────────────────────
cmake -S code -B "$BUILD_DIR" \
-DCMAKE_CXX_COMPILER="$CXX_BIN" \
-DCMAKE_CXX_FLAGS="$SAN_FLAGS" \
-DCMAKE_EXE_LINKER_FLAGS="$SAN_FLAGS" \
-DCMAKE_BUILD_TYPE=Debug \
-Wno-dev
# ── Build the fast (non-CGAL) tests only ────────────────────────────────────
# CGAL tests would 45× the build time under sanitizers and have a
# higher false-positive surface (CGAL's expression-template trickery).
# Use the fast suite as the sanitizer canary; full coverage of the CGAL
# layer is covered by coverage.sh + the regular Release build.
nice -n 19 cmake --build "$BUILD_DIR" --target conformallab_tests \
-j"$(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || echo 2)"
# ── Run ──────────────────────────────────────────────────────────────────────
cd "$BUILD_DIR"
if ctest -E "^cgal\." --output-on-failure --output-junit san-results.xml; then
cd "$ROOT"
echo
echo "OK: all sanitizer-instrumented tests passed."
exit 0
else
cd "$ROOT"
echo
echo "FAIL: sanitizer-instrumented tests reported issues."
echo " See: $BUILD_DIR/Testing/Temporary/LastTest.log"
exit 1
fi