You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让AFL++模糊测试生成有效的代码覆盖数据?

AFL++模糊测试中覆盖配置文件为空的解决方案

问题背景

使用AFL++ 4.0c对应用程序进行模糊测试,通过clang包装器添加模糊插桩,编译时使用的覆盖标记:

--coverage -g -fprofile-instr-generate -fcoverage-mapping

启动模糊测试的命令:

env PARAM=paramstuff                 \ # 设置环境变量
afl-fuzz -x dicts/dicts -f file.txt  \ # AFL配置参数
-i input -o output                   \ # 输入输出目录
--                                   \
./myapp --flag --flag2 --flag3        # 目标应用参数

遇到的问题:

  • 模糊测试运行正常,但生成的覆盖配置文件为空
  • 配置错误导致模糊测试无法启动时,覆盖配置文件及.gcda文件不为空
  • 直接启动应用程序(不通过AFL++)时,能正常生成覆盖配置文件
  • 模糊测试及应用程序均通过CTRL+C停止

核心原因

AFL++自身的插桩机制会接管代码的覆盖追踪逻辑,与clang的-fprofile-instr-generate系列覆盖率收集标记存在冲突,导致正常模糊测试时clang的覆盖率数据无法被正确捕获和写入。

解决步骤

1. 分离插桩与覆盖率编译流程

不要在同一编译过程中同时启用AFL++插桩和clang覆盖率标记:

  • 若仅需模糊测试:使用AFL++的编译包装器(如afl-clang-fast)编译,无需添加覆盖率标记。
  • 若需收集模糊测试期间的覆盖率:直接用clang编译,仅添加覆盖率标记(--coverage -g -fprofile-instr-generate -fcoverage-mapping),不使用AFL++的编译工具。

2. 强制触发覆盖率数据写入

CTRL+C终止时,AFL++可能直接杀死子进程,导致应用程序来不及将覆盖率数据刷入文件:

  • 在目标应用代码中添加信号处理逻辑,捕获SIGINT信号,在退出前调用__llvm_profile_write_file()函数手动写入覆盖率数据:
    #include <signal.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include "llvm-c/profile.h"
    
    void sigint_handler(int sig) {
      __llvm_profile_write_file();
      exit(0);
    }
    
    int main() {
      signal(SIGINT, sigint_handler);
      // 原有应用逻辑
      return 0;
    }
    
  • 或者设置环境变量强制实时刷新:
    env LLVM_PROFILE_FILE="coverage.profraw" LLVM_PROFILE_FLAGS="flush=1" \
    afl-fuzz -x dicts/dicts -f file.txt \
    -i input -o output \
    -- \
    ./myapp --flag --flag2 --flag3
    
    注意:实时刷新会降低模糊测试性能,仅用于调试阶段。

3. 调整AFL++运行参数

  • 使用-d参数启用debug模式,避免AFL++对子进程的快速终止优化:
    env PARAM=paramstuff \
    afl-fuzz -d -x dicts/dicts -f file.txt \
    -i input -o output \
    -- \
    ./myapp --flag --flag2 --flag3
    
  • 增加-t参数调整超时时间,确保子进程有足够时间完成数据写入:
    env PARAM=paramstuff \
    afl-fuzz -t 1000+ -x dicts/dicts -f file.txt \
    -i input -o output \
    -- \
    ./myapp --flag --flag2 --flag3
    

4. 独立生成每个子进程的覆盖率文件

设置LLVM_PROFILE_FILE为带进程ID的路径,避免多个子进程的覆盖率文件互相覆盖:

env LLVM_PROFILE_FILE="coverage-%p.profraw" PARAM=paramstuff \
afl-fuzz -x dicts/dicts -f file.txt \
-i input -o output \
-- \
./myapp --flag --flag2 --flag3

之后可以用llvm-profdata merge命令将多个.profraw文件合并为一个完整的覆盖率文件:

llvm-profdata merge -sparse coverage-*.profraw -o merged.profdata

内容的提问来源于stack exchange,提问作者Sugar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 21:25:21