不是必须加 -fsanitize=address,undefined,但不加会漏检内存类漏洞;AFL++ 依赖崩溃信号识别异常,需确保程序触发非零退出码或 SIGSEGV/SIGABRT;输入应通过 @@ 或 -f 正确传递至 std::cin/ifstream;复现失败常因随机性、多线程或 sanitizer 干扰。

编译时必须加 -fsanitize=address,undefined 吗?
不是必须,但不加就大概率漏掉内存类漏洞。AFL++ 本身不检测越界或未定义行为,它只负责变异输入、观察程序崩溃——而很多 C++ 漏洞(比如 std::vector::at 越界、use-after-free、signed integer overflow)默认不触发信号,进程照常退出,AFL++ 就当“正常执行”跳过了。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 用
clang++ -g -O2 -fsanitize=address,undefined -fno-omit-frame-pointer编译目标程序,这是最实用的组合;AddressSanitizer捕获堆/栈越界、UndefinedBehaviorSanitizer捕获整数溢出、空指针解引用等; - 避免同时启用
ThreadSanitizer,它会显著拖慢执行速度,且 AFL++ 并发 fuzz 时容易误报; - 如果程序依赖某些内联汇编或禁用 sanitizer 的第三方库,可对特定文件加
-fno-sanitize=all,但得清楚放弃哪部分检测能力。
afl-fuzz 启动时卡在 “Spinning up…” 不进 fuzz 循环?
常见原因是 AFL++ 没看到目标程序的首次崩溃或异常退出——它需要至少一次“非零退出码”或 SIGSEGV/SIGABRT 才认为 instrument 成功。C++ 程序若没做任何错误处理,可能静默吞掉异常、返回 0,AFL++ 就一直等。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 先手动运行一次:
./afl-showmap -o /dev/null -- ./target_program @@,确认是否能拿到覆盖率反馈;如果报Unable to execute target或输出全是 0,说明插桩失败或路径不对; - C++ 中抛出但未捕获的异常,默认调用
std::terminate(),它通常触发SIGABRT,AFL++ 能捕获;但如果用了set_terminate自定义处理器且没 abort/exit,就得改回来; - 确保目标程序从
main()开始执行,不要用LD_PRELOAD或 wrapper 隐藏入口;AFL++ 的LLVM插桩只作用于编译期可见的函数调用链。
如何让 AFL++ 正确传递输入到 C++ 程序的 std::cin 或 std::ifstream?
AFL++ 默认把测试用例作为命令行参数传入,但多数 C++ 程序从 stdin 读输入。不匹配就会导致程序卡住、读空、或直接退出,AFL++ 认为“hang”,反复重试。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 启动命令里加
@@占位符,并确保程序用它打开文件:例如afl-fuzz -i in/ -o out/ -- ./target @@,然后在代码里写std::ifstream f(argv[1]);; - 如果坚持用 stdin,必须加
-f参数:afl-fuzz -i in/ -o out/ -f input_file -- ./target,AFL++ 会把测试用例内容写入input_file再启动程序;注意该文件路径需有写权限,且不能是只读挂载; - 避免在 C++ 里混合使用
std::cin和fread(stdin, ...),C 标准库缓冲和 C++ 流缓冲可能不同步,导致读取错位;统一用std::cin或全用 C 风格。
为什么 AFL++ 找到的崩溃复现不了?
典型原因是 C++ 对象生命周期、全局状态或随机性干扰。比如 std::string 构造时依赖堆分配器行为,ASan 开启后内存布局变化,同一输入在不同运行中触发不同路径;又或者程序里用了 time(0)、rand()、std::random_device,导致每次行为不一致。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 复现前先关掉 ASan/UBSan:用原始未插桩二进制 + 相同输入文件跑,看是否还崩;如果只在插桩版崩,说明是 sanitizer 本身引发的 crash(如 OOM),不是原漏洞;
- 在
main()开头加srand(0);和std::srand(0),禁用所有随机源; - 检查是否用了多线程:AFL++ 默认单线程 fuzz,若程序自己开 thread 且没同步,崩溃不可复现;加
-D__AFL_HAVE_MANUAL_CONTROL编译,配合__AFL_INIT()手动控制 forkserver,能提升稳定性。
真正难的是那些依赖精确内存布局、竞争条件或硬件特性(如 AVX 指令异常)的漏洞——它们在 AFL++ 下出现概率低,复现窗口窄,得靠更定向的策略,比如把崩溃样本喂给 afl-tmin 缩减后再人工看堆栈。
















