# QA3 实测复现脚本

[`docs/Architecture_QA3.md`](../../docs/Architecture_QA3.md) 中**表内列出的已脚本化实测**
由这里的脚本产出。§4.3–§4.6 的合成 magic/长度/checksum 实验目前只有文中命令和结果，
尚无独立 driver；历史 `/tmp` 语料与已提交 CSV 也不由本目录重新生成。

所有脚本默认把工作目录放在 `${WORK:-/tmp/symcc_qa3}`，不污染仓库。

## 前置条件

- 已构建的 SymCC：`build/symcc`、`build/SymCCRuntime-prefix/src/SymCCRuntime-build/libsymcc-rt.so`
- AFL++（`afl-fuzz`、`afl-showmap`、`afl-clang-fast` 在 `PATH` 里）
- 已构建的公开目标：`benchmark/public/bin/`（见 `benchmark/compile_public_benchmarks.sh`）
- `mpirun` + `mpi4py`（仅 `funnel.sh` 需要）

## 脚本

| 脚本 | 对应章节 | 产出 |
|---|---|---|
| `measure_strategy.sh` | §3.3 求解策略占比 | 各目标的 nominal / optimistic / fast / group 产出计数 + telemetry |
| `landing.py` | §3.4 | 各策略产出相对种子的"落地率" |
| `landing2.py` | §3.4 | 各策略的**独有新边**与"边/产出"，即互补性 |
| `iterate.py` | §3.5 | 单一策略下的嵌套深度迭代（前沿 FIFO） |
| `iterate2.py` | §3.5 | **FIFO vs 覆盖率制导**对照——本文最关键的一组对照 |
| `funnel.sh` | §1.6 | 端到端漏斗（generated → reported → accepted）+ worker 相位计时 + master PROF |
| `persab.sh` | §6.6 | 持久模式 A/B：同一二进制带/不带 `@@` 的 execs/s 与 bitmap 覆盖率 |
| `trace_base64.sh` | §4.9 | 真实 LAVA-M base64 的两类种子 DSE 遥测、策略产出与内容去重 |
| `inject_test.sh` | §1.10 | 受控对照：运行中的 afl-fuzz 会不会捡走直接丢进它自己 `queue/` 的文件（结论：不会） |

## 用法

```bash
cd <symcc 根目录>

# §3.3 求解策略占比（默认配置）——对每个目标各跑一次
W=/tmp/symcc_qa3/strategy && mkdir -p $W
benchmark/qa3_repro/measure_strategy.sh $W xml \
    benchmark/public/bin/google-fts/xml_read_fuzzer \
    benchmark/public/seeds/google-fts/xml_read_fuzzer
# 打开开关看占比怎么变：把 SYMCC_FAST_SOLVE=1 / SYMCC_OPTIMISTIC_FIRST=1 /
# SYMCC_MULTI_SOLVE=1 作为第 5 个参数传进去

# §3.4 各策略的边贡献互补性
python3 benchmark/qa3_repro/landing2.py \
    benchmark/public/bin/google-fts-afl/xml_read_fuzzer \
    $W/xml/out \
    benchmark/public/seeds/google-fts/xml_read_fuzzer/seed_01.xml

# §3.5 嵌套深度：FIFO vs 覆盖率制导（需先生成嵌套目标，见下）
python3 benchmark/qa3_repro/iterate2.py ./nested32 ./nested32_afl 32 60 fifo 64
python3 benchmark/qa3_repro/iterate2.py ./nested32 ./nested32_afl 32 60 cov  64

# §1.6 端到端漏斗 + 相位计时（约 4 分钟）
WARMUP=25 DUR=180 benchmark/qa3_repro/funnel.sh

# §6.6 持久模式 A/B（约 4 分钟）
DUR=60 benchmark/qa3_repro/persab.sh

# §4.9 真实目标的两类种子追踪（产物写入唯一的 /tmp 子目录）
benchmark/qa3_repro/trace_base64.sh

# §1.10 直注是否有效的受控对照（约 3 分钟）
benchmark/qa3_repro/inject_test.sh
```

### 生成 §3.5 用的嵌套目标

```bash
python3 - <<'PY'
for d in (4, 8, 16, 32):
    conds = "\n".join(f"  if (b[{i}] != (char)({0x41+i})) return {i};" for i in range(d))
    open(f"nested{d}.c", "w").write(f"""#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {{
  char b[64] = {{0}};
  FILE *f = fopen(argv[1], "rb");
  if (!f) return 100;
  if (fread(b, 1, {d}, f) != {d}) {{ fclose(f); return 101; }}
  fclose(f);
{conds}
  printf("DEPTH{d} SOLVED\\n");
  return 200;
}}
""")
PY
for d in 4 8 16 32; do
  build/symcc      -O0 -o nested$d      nested$d.c
  afl-clang-fast   -O0 -o nested${d}_afl nested$d.c
done
```

## 注意事项

- **持久模式目标不能带 `@@`。** 先用 `grep -a '##SIG_AFL_PERSISTENT##' <bin>` 判断；带错了
  AFL 会跑得飞快但 bitmap 覆盖率接近 0（`persab.sh` 就是量化这一点的）。
- `funnel.sh` 需要 `SYMCC_WORKER_PROFILE=1`（脚本内已设）才会写 `redun_*.csv` /
  `phase_timing_rank*.csv`。
- 当前 `_snap` 已改为读取 worker 的 AFL coverage 副本，并按 `(edge_id,count)` 的
  `edge_id` 比较；旧实现读 QSYM 图且会触发 `tuple >= int`。复现实验必须记录所用 commit/
  dirty diff，不能把修复前后的 `redun_*.csv` 混合。
- 结果随目标、种子、机器负载变化。文档里的数字是单次运行，**不是等 CPU 多轮确认性结果**
  （评级规则见 `docs/README.md`）。
- 正式复现还应记录主仓库/子模块提交、dirty diff 摘要、LLVM/AFL++/Z3 版本、seed manifest
  和结果文件哈希。当前脚本默认写 `/tmp`，不会自动生成这份 immutable manifest。
