/ justapi / scripts / sanitize.sh
swadhinbiswas πŸš€ release: 2.0.8 final β€” multi-thread server (ADR-085), free-threaded support (ADR-084), async handler fix (ADR-083) Β· 8/7/2026
f5b3f46
75 lines Β· 3.0 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#!/usr/bin/env bash
# scripts/sanitize.sh β€” fast memory-safety gate (replaces the full-suite Miri run).
#
# Why not full Miri: Miri interprets every instruction (100-1000x slower); the
# full justapi-core suite takes 20+ minutes and most of it is safe Rust. Only
# ONE production file has `unsafe` (memory.rs, 3 mentions, with SAFETY
# comments). The practical gate is:
#
#   1. AddressSanitizer on the full core suite (near-native speed, catches
#      use-after-free / buffer overflow / leaks).
#   2. A targeted Miri run on just memory.rs's unsafe (via its #[cfg(miri)]
#      test) β€” covers the only UB-sensitive code path.
#
# Prereqs: rustup nightly with miri + rust-src (added automatically below).
# ASan needs `-Zbuild-std` (builds std instrumented) because of proc-macro
# crates (time) that break under blanket RUSTFLAGS sanitizer.
#
# Usage:
#   bash scripts/sanitize.sh            # ASan + targeted miri
#   bash scripts/sanitize.sh --asan     # ASan only
#   bash scripts/sanitize.sh --miri     # targeted miri only

set -euo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT"

MODE="${1:-all}"
ASAN_TARGET_DIR="${ASAN_TARGET_DIR:-/tmp/justapi-asan-target}"
MIRI_TARGET_DIR="${MIRI_TARGET_DIR:-/tmp/justapi-miri-target}"
ASAN_LOG="$(mktemp /tmp/justapi-asan.XXXXXX.log)"
MIRI_LOG="$(mktemp /tmp/justapi-miri.XXXXXX.log)"

# -Zbuild-std needs the std source for the target. Idempotent; harmless if
# already installed.
rustup component add rust-src --toolchain nightly >/dev/null 2>&1 || true

run_step() {
    local name="$1" log="$2"; shift 2
    echo "[sanitize] $name..."
    if ! "$@" >"$log" 2>&1; then
        echo "[sanitize] $name FAILED (exit $?) β€” last 25 lines:" >&2
        tail -25 "$log" >&2
        exit 1
    fi
    # Surface the summary line if present, then confirm pass.
    grep -E "test result:" "$log" | tail -1 || true
    echo "[sanitize] $name: PASS"
}

if [[ "$MODE" == "all" || "$MODE" == "--asan" ]]; then
    # Exclude benchmark-gate tests: they assert on wall-clock timing and fail
    # under sanitizer instrumentation (~2x slowdown). Benchmarks are for
    # release builds; sanitizers are for memory safety.
    run_step "AddressSanitizer on justapi-core (lib, features=db)" "$ASAN_LOG" \
        env PATH="$HOME/.cargo/bin:$PATH" \
        CARGO_TARGET_DIR="$ASAN_TARGET_DIR" \
        RUSTFLAGS="-Zsanitizer=address" \
        rustup run nightly cargo test -p justapi-core --lib --features db \
            -Zbuild-std --target x86_64-unknown-linux-gnu \
            -- --skip bench_
fi

if [[ "$MODE" == "all" || "$MODE" == "--miri" ]]; then
    # The #[cfg(miri)] test in memory.rs exercises the arena's
    # from_utf8_unchecked under stacked-borrows provenance rules.
    run_step "Miri on the only unsafe module (memory.rs, targeted)" "$MIRI_LOG" \
        env PATH="$HOME/.cargo/bin:$PATH" \
        CARGO_TARGET_DIR="$MIRI_TARGET_DIR" \
        MIRIFLAGS="-Zmiri-disable-isolation" \
        rustup run nightly cargo miri test -p justapi-core --lib memory
fi

echo "[sanitize] done β€” memory-safety gate green"