#!/usr/bin/env python3
"""探测 xml AFL 二进制在 afl-showmap -S 下是否【确定性】:同一内容多次 get_edges 是否一致。
若非确定 → 解释 microbench 的 264 vs 263 off-by-one(与我改动无关,是目标非确定性)。"""
import sys, os, glob, subprocess, tempfile, hashlib
sys.path.insert(0, "util")
import mpi_fuzzing_helper as m

ROOT = "/home/ubuntu/code/symcc"
SYMCC_BIN = os.path.join(ROOT, "benchmark/public/bin/google-fts/xml_read_fuzzer")
AFL_BIN = os.path.join(ROOT, "benchmark/public/bin/google-fts-afl/xml_read_fuzzer")
SEEDS = os.path.join(ROOT, "benchmark/public/seeds/google-fts/xml_read_fuzzer")

# 生成少量输出
od = tempfile.mkdtemp(prefix="dp_")
for s in sorted(glob.glob(os.path.join(SEEDS, "*")))[:4]:
    env = dict(os.environ, SYMCC_OUTPUT_DIR=od, SYMCC_ENABLE_LINEARIZATION="1", SYMCC_INPUT_FILE=s)
    try:
        subprocess.run([SYMCC_BIN, s], stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL,
                       stderr=subprocess.DEVNULL, env=env, timeout=60)
    except Exception:
        pass
# 取最小的几个输出(小 XML 解析快,不易撞 5s 超时)
allc = [(os.path.getsize(os.path.join(od, f)), os.path.join(od, f))
        for f in os.listdir(od) if os.path.isfile(os.path.join(od, f))]
allc.sort()
contents = [open(p, "rb").read() for _, p in allc[:5]]
print(f"取样 {len(contents)} 个最小输出做确定性探测")

def edges_key(e):
    return tuple(sorted(eid for eid, _ in e)) if e else ()

# 测试A:同一 forkserver 内,连续两次喂【同一内容】,边集是否一致(确定则应完全相同)
sm = m.StreamingShowmap("/usr/local/bin/afl-showmap", [AFL_BIN])
diff = 0
for i, c in enumerate(contents):
    e1 = edges_key(sm.get_edges(c))
    e2 = edges_key(sm.get_edges(c))
    same = (e1 == e2)
    if not same:
        diff += 1
    print(f"  样本{i}: 两次同内容边集一致={same} (|e1|={len(e1)},|e2|={len(e2)},对称差={len(set(e1)^set(e2))})")
sm.close()
print(f"→ 非确定样本 = {diff}/{len(contents)}  "
      f"{'⇒ 目标非确定(超时/持久态),off-by-one 与我的改动无关' if diff else '⇒ 确定'}")

import shutil; shutil.rmtree(od, ignore_errors=True)
