fold/tools/audit-yams.sh
trvon 0452353d2e
Implement walkSwitch: analyze case bodies in switch statements
Results: +86 TP across all CWEs (476:+3, 369:+18, 190:+51, 121:+14)
2026-05-15 18:32:45 -04:00

77 lines
3 KiB
Bash
Executable file

#!/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"