#!/usr/bin/env bash # Run every fold detector against yams' release compile DB. # # Outputs per-detector SARIF + Markdown + stderr to $OUT. # Usage: # tools/audit-yams.sh [out-dir] # # Defaults match the audit plan; override OUT_DIR for clean runs. set -uo pipefail # Don't `-e`: a detector exiting 1 (findings emitted) is success here. HERE="$(cd "$(dirname "$0")" && pwd)" FOLD="${FOLD:-$HERE/../build/release/src/cli/fold}" DB="${DB:-/Users/trevon/work/tools/yams/build/release/compile_commands.json}" OUT="${1:-/tmp/yams-audit-2026-05-14}" mkdir -p "$OUT" run_one() { local name="$1" shift local extra_args=("$@") echo "=== $name ===" local t0 t1 t0="$(date +%s)" # SARIF + Markdown — fold needs two invocations because --format takes one value. # --quarantine-dir lets fold record per-TU crashes (signal isolation) into # $OUT/quarantine.txt and skip them on the second invocation. "$FOLD" scan --compile-db "$DB" --detectors "$name" \ --quarantine-dir "$OUT" \ --format sarif --output "$OUT/$name.sarif" \ "${extra_args[@]}" 2> "$OUT/$name.stderr" local rc_sarif=$? "$FOLD" scan --compile-db "$DB" --detectors "$name" \ --quarantine-dir "$OUT" \ --format markdown --output "$OUT/$name.md" \ "${extra_args[@]}" 2>> "$OUT/$name.stderr" local rc_md=$? t1="$(date +%s)" local count count="$(grep -c '^### ' "$OUT/$name.md" 2>/dev/null || echo 0)" printf " rc(sarif=%d md=%d) findings=%s elapsed=%ss\n" \ "$rc_sarif" "$rc_md" "$count" "$((t1 - t0))" } # Redundancy run_one clone --min-body-stmts 8 --processes 1 run_one equiv --min-body-stmts 4 --processes 4 --budget-seconds 600 --per-query-ms 2000 # `dead` goes through the symbolic encoder and is vulnerable to a Clang # `getTypeInfoImpl` infinite-recursion bug on one yams TU # (storage_backend_factory.cpp). `--processes >=4` keeps the crash # isolated to one worker shard so the audit completes. run_one dead --min-body-stmts 4 --processes 4 --budget-seconds 900 --per-query-ms 2000 run_one class-dup --processes 1 --budget-seconds 600 --per-query-ms 2000 # CFG/call-graph (M16/M17 — non-symbolic, no Z3 budget needed) run_one dead-statement --processes 1 run_one unused-function --processes 1 run_one static-ptr-asymmetry --processes 1 # Security (M7 + M18 interval pre-pass + M15 stdlib-sink hook). # All four go through the symbolic encoder → use parallel mode so a # single-TU Clang crash doesn't sink the detector. run_one null-deref --processes 4 run_one div-by-zero --processes 4 --budget-seconds 600 --per-query-ms 2000 run_one int-overflow --processes 4 --budget-seconds 600 --per-query-ms 2000 run_one oob --processes 4 --budget-seconds 600 --per-query-ms 2000 echo echo "=== summary ===" for d in clone equiv dead class-dup dead-statement unused-function \ static-ptr-asymmetry null-deref div-by-zero int-overflow oob; do count="$(grep -c '^### ' "$OUT/$d.md" 2>/dev/null || echo 0)" printf " %-16s %s findings\n" "$d" "$count" done echo "outputs in: $OUT"