首页 > 最新动态 > 【RISC-V 论文解读】PathFuzz:基于足迹内存的处理器覆盖率引导模糊测试
最新动态
【RISC-V 论文解读】PathFuzz:基于足迹内存的处理器覆盖率引导模糊测试
2026-05-2028

近些年来,覆盖率引导模糊测试(Coverage-Guided Fuzzing, CGF)逐步引入到 RISC-V 处理器验证。其基本思路是从一组初始测试出发,依据覆盖率反馈持续生成新输入,并通过待测处理器与参考模型的协同仿真发现行为不一致的情况

对于软件系统,这一方法已经较为成熟;但在 RISC-V 处理器场景中,其有效性明显受到了种子语料、输入表示和变异策略的制约

我们发表于第 61 届 ACM/IEEE 设计自动化会议(61st ACM/IEEE Design Automation Conference,DAC 2024)的 PathFuzz: Broadening Fuzzing Horizons with Footprint Memory for CPUs 正是针对这一问题展开研究。该工作认为,RISC-V 处理器模糊测试的瓶颈主要来自两个方面:

1. 种子语料的来源较为有限;

2. 输入表示方式与 CPU 的动态执行过程并不一致。

围绕这两个问题,PathFuzz 提出了足迹内存(footprint memory)这一输入格式,并实现了一套能够与现有开源验证基础设施协同工作的 RISC-V 处理器模糊测试框架。

一、问题背景:处理器模糊测试的探索能力为什么受限?

对 RISC-V CPU 而言,覆盖率引导模糊测试的一般流程如下:从初始种子语料出发构造输入,根据覆盖率反馈对输入持续变异,再将变异后的输入送入待测处理器执行,并通过参考模型比对执行行为以发现潜在功能错误。

在概念上来说这一流程相对直接,但是,处理器与普通软件程序有明显差异。CPU 执行时同时受指令集体系结构语义、特权级、地址翻译、异常机制和微结构状态等影响,许多行为只有在满足较强上下文约束时才会被触发。基于此,覆盖率引导模糊测试在 RISC-V 处理器验证中的效果,很大程度上取决于两个因素:

1.初始种子能否将执行带入具有代表性的状态空间

2.变异能否作用于真正影响执行路径的输入字节

首先,实验结果说明了现有流程的局限性。以三类常见处理器测试作为种子,在约 10 小时、100 万次变异过程中,覆盖率虽然持续上升,但相对初始覆盖率的增量并不大。riscv-tests 的基线覆盖率为 56.0%,增量为 12.6%;riscv-arch-test 的基线覆盖率为 44.2%,增量为 15.7%;riscv-dv 的基线覆盖率为 72.6%,增量仅为 9.9%。

这说明一个关键现象:在处理器验证场景中,如果不对变异算法进行面向场景的专门设计,而是直接采用通用的变异策略,那么覆盖率变化往往更受初始种子影响。换言之,在不引入针对 RISC-V 指令语义、特权状态或访存行为的特化变异机制时,像 havoc 这类通用变异策略对覆盖率的影响,可能明显弱于种子本身带来的影响。

图 1:不同种子下的覆盖率曲线
图 1:不同种子下的覆盖率曲线

二、现有方法的主要限制:种子来源少,输入表示低效

1. 种子来源受限

现有 RISC-V 处理器模糊测试器的种子通常来自几类常见来源,包括:手写定向测试,例如 riscv-tests;指令序列生成器,例如 riscv-dv;以及形式化工具导出的测试。这些测试在 RISC-V 处理器验证中都很常用,但仍然存在覆盖范围上的局限。特别是真实大程序上包含更复杂的控制流、访存模式和特权状态切换,能够覆盖更丰富的处理器行为,但是却很少被直接纳入现有模糊测试流程。原因是这类程序的运行时间更长、状态空间更大、所需内存镜像也更庞大,直接作为模糊测试输入会带来明显的时间与空间开销。

2. 线性内存输入与 CPU 执行过程不匹配

通常情况下,现有工作将 CPU 的输入表示为线性内存(linear memory)。无论是按地址组织的数据镜像,还是指令和数据混合的内存布局,本质上都是静态地址到数据的映射。这种表示方式虽然通用,但在处理器模糊测试中存在两个典型问题。首先,大量输入内容在执行过程中根本不会被访问。实验统计发现,对于三类典型种子,执行过程中真正被 CPU 使用的输入字节比例平均仅为 18.9%、22.0% 和 6.2%,这意味着变异器修改的大量字节实际上对当前执行路径没有影响。其次,CPU 在执行过程中可能访问输入中并不存在的地址,例如:页表遍历、跨界取指和异常路径都可能导致额外访存请求。在线性内存表示下,这些地址往往只能由零值或随机值填充,因而无法被纳入覆盖率反馈驱动的变异过程。该工作将前一问题概括为输入内容的未充分利用,将后一问题概括为执行过程中对输入外地址的额外访问。两者共同降低了处理器模糊测试的效率,使变异空间被大量无效字节稀释,也使部分与执行相关的输入脱离了覆盖率引导机制。

三、核心思路:用足迹内存直接描述执行足迹

为了解决上述问题,PathFuzz 提出了足迹内存这一新的输入格式。与按地址组织内容的线性内存相比,足迹内存不再记录完整内存镜像,而是按照 CPU 执行过程中首次访问各地址的时间顺序,依次记录真正被访问到的字节内容,并将这些按时间顺序收集的字节拼接成新的模糊测试输入。

这一设计的关键在于,输入表示直接对应执行过程中实际发生的访存足迹。其生成方式是先从线性内存输入启动 CPU 执行,在 CPU 首次访问某个地址范围时按访问顺序记录对应字节,并将这些字节连接成足迹内存形式的新输入。在后续执行中,如果 CPU 首次访问某个地址并请求 N 个字节,就从足迹内存输入中顺序取出 N 个字节返回。采用这一表示方式后,未被访问的输入内容不会被保留下来,因而能够从源头减少无效变异目标;执行过程中首次出现的新访存请求也可以继续由足迹内存动态提供数据,从而降低越界访问带来的随机性;同时,输入规模显著缩小,更大、更复杂的程序状态也具备了被引入种子池的可能。

图 2:PathFuzz 的整体流程
图 2:PathFuzz 的整体流程

四、系统设计:PathFuzz 如何接入现有处理器验证流程

PathFuzz 建立在现有开源基础设施之上,其实现主要结合了 LibAFL 和 DiffTest。整体流程可以分为:种子生成、覆盖率引导模糊测试和协同仿真三个阶段。

1. 种子生成与格式转换

由于足迹内存的语义依赖于 CPU 的动态执行行为,同一个足迹内存输入离开具体执行过程后并不天然具备稳定含义。因此,PathFuzz 在长期存储种子时仍采用线性格式,在进入某次模糊测试迭代前再将线性种子转换为足迹内存形式,执行结束后则根据需要回写或保存线性形式的种子。通过这一转换机制,种子的语义稳定性得以保留,而实际变异阶段仍可使用更适合 CPU 模糊测试的输入格式。

2. 覆盖率反馈接口

PathFuzz 为处理器验证场景设计了标准化的覆盖率收集接口,覆盖来源包括基于硬件插桩的结构或功能覆盖率、基于仿真器生成 C++ 模型的软件插桩覆盖率,以及利用参考模型执行反馈得到的指令集体系结构行为覆盖指标。借助这一接口设计,该框架能够适配不同处理器设计和不同验证环境,而不受限于单一覆盖率实现方式。

3. 协同仿真的按需同步

足迹内存还会影响参考模型与待测处理器之间的内存同步方式。在传统 DiffTest 流程中,待测处理器(Design Under Test, DUT)和参考模型(Reference Model, REF)在复位时通常会拿到同一份完整内存镜像。但在足迹内存下,输入字节与实际地址的对应关系只有在执行过程中才能确定,因此初始化阶段无法一次性完成完整同步。PathFuzz 采用按需拷贝(copy-on-demand)机制,即只在 DUT 首次访问某段输入数据时,才将相应内容同步给 REF。由于 REF 不进行推测执行,其执行进度通常落后于 DUT,因此这种延迟同步在语义上是成立的。与此同时,未被访问的输入无需复制到 REF,也减少了不必要的同步开销。

4. 用检查点(checkpoint)引入真实程序种子

PathFuzz 的另一个关键设计,是将 RISC-V 体系结构检查点(architectural checkpoint)与足迹内存结合,用于引入真实大程序作为种子。

这里的检查点,可以理解为程序执行到某一时刻时的体系结构状态快照。它通常包含寄存器状态、控制状态以及恢复执行所需的内存内容,使得仿真能够从该时刻继续向后运行,而不必从程序起点重新执行。对处理器模糊测试而言,检查点的价值在于,它能够把一个真实大程序在复杂执行过程中已经形成的状态直接带入测试过程。PathFuzz 从真实程序运行过程中截取检查点,再将其对应的线性状态转换为足迹内存。这样既保留了真实程序所处的复杂执行状态,又避免了直接处理完整内存镜像带来的代价。

五、实验结果:覆盖率、输入效率与缺陷发现能力

实验主要使用 Rocket 作为待测 RISC-V 处理器,Spike 作为 RISC-V 参考模型,覆盖率指标采用 Rocket 的翻转覆盖率(toggle coverage)。除特别说明外,每组实验运行 100 万个变异输入,并重复 16 次取平均。为方便比较,文中将不同种子集合分别记为 S#1 到 S#6:其中,S#1 对应 riscv-tests,S#2 对应 riscv-arch-test,S#3 对应 riscv-dv,S#4 对应 force-riscv,S#5 对应每个 SPEC CPU2006 benchmark 选取一个样例形成的检查点集合,S#6 对应规模更大的 SPEC CPU2006 检查点集合。由于线性内存规模过大,S#4、S#5 和 S#6 仅在足迹内存下使用。

1. 足迹内存提升了覆盖率增幅和收敛效率

将 S#1 到 S#3 从线性内存转换为足迹内存后,覆盖率增幅分别达到 13.8%、16.5% 和 12.7%,相对线性内存分别提升 1.10 倍、1.05 倍和 1.28 倍。如果比较达到相同覆盖率所需时间,足迹内存对应的速度提升则分别为 2.79 倍、1.96 倍和 11.90 倍。这说明足迹内存既提高了最终覆盖率增量,也显著改善了单位时间内的探索效率。

图 3:线性内存与足迹内存的覆盖率、
未使用输入比例和越界访问次数对比
图 3:线性内存与足迹内存的覆盖率、
 未使用输入比例和越界访问次数对比

从图 3 还可以看到,足迹内存明显降低了未使用输入比例和越界访问次数。以 S#3 为例,线性内存下平均有 96.8% 的变异字节未被 CPU 使用,并伴随平均 60.3 次越界访问;切换到足迹内存后,这两个数字分别下降到 76.3% 和 9.3。该结果与 PathFuzz 的设计目标一致,说明其收益直接来自输入表示的改变。

2. 真实程序种子显著提高最终覆盖率

引入真实程序种子后,PathFuzz 在 SPEC CPU2006 上取得了更高的覆盖率上限,其中 S#5 的最终覆盖率达到 93.1%,S#6 的最终覆盖率达到95.3%。

图 4:不同种子集合下的覆盖率结果
图 4:不同种子集合下的覆盖率结果

这一结果说明,处理器模糊测试的探索上限与种子来源密切相关。相比传统定向测试或随机生成测试,真实程序在控制流、访存行为和状态复杂度上都更接近实际负载,因此能够为 CGF 提供更高的起点和更大的搜索空间。

3. 发现 4 个长期存在的公开项目缺陷

在评估过程中,PathFuzz 发现了 Rocket 中的 3 个缺陷和 Spike 中的 1 个缺陷。这 4 个问题分别自 2017 年、2021 年、2021 年和 2014 年起存在于对应开源项目中,但在此前相关模糊测试研究中并未被发现。几个代表性案例包括:Rocket 在访问越界页表项时错误抛出了页错误异常而非访问错误异常;Rocket 缺失 mconfigptr 控制与状态寄存器;Rocket 在未启用虚拟化扩展时,对 medeleg 控制与状态寄存器的可写掩码实现错误;Spike 在跨界取指场景下报告了错误的异常地址。上述缺陷在最佳情况下可以在 15 分钟内被触发。

实验结果还体现出缺陷与种子选择之间的强相关性。例如,mconfigptr 缺失这一问题很难依靠随机变异直接命中,但某类生成器种子的首条指令恰好会读取相邻 CSR 地址,因此只需较小幅度的变异就可能触发该问题。这表明,缺陷的可发现性既取决于变异策略,也与种子所处的状态邻域密切相关。

六、这项工作的意义:将处理器模糊测试的重点放回输入与种子

PathFuzz 的直接贡献体现在足迹内存这一输入格式及相应的 RISC-V 处理器模糊测试框架实现上。更重要的是,该工作从方法层面重新强调了三个问题:处理器模糊测试的效果不能仅从变异算法角度理解,输入表示方式会直接影响变异的有效性,种子来源则会显著影响最终覆盖率上限和缺陷发现能力。正因如此,PathFuzz 的目标是更有效地利用既有 RISC-V 处理器验证资产,使模糊测试与现有验证方法形成互补关系。手写测试、指令生成器和真实程序共同构成了处理器模糊测试的潜在种子来源,而 PathFuzz 的作用在于以更高效的方式组织这些种子,并使模糊测试器能够更直接地作用于与执行路径相关的数据。

此外,该工作对应的 xfuzz 环境已开源。它在 LibAFL 之上接入了开源覆盖率插桩能力和 DiffTest 协同仿真流程,为后续处理器模糊测试研究提供了可复用底座。这一点对开源处理器验证研究也具有现实意义。

七、未来展望

PathFuzz 的贡献主要体现在输入表示和种子构造这两个基础层面,但围绕处理器模糊测试,仍然有几条值得继续推进的方向。

首先,覆盖率并不能与验证质量直接对应。覆盖率只是验证过程中的可量化指标之一,用来间接反映测试活动是否触及了更多设计状态。学术论文中常用的翻转覆盖率、结构覆盖率,或者参考模型反馈得到的行为覆盖率,都有各自价值,但它们都难以直接表征实际验证效果。对工业级处理器验证而言,更关键的问题往往是测试是否覆盖到了高风险场景、关键控制状态、复杂异常路径以及真实软件负载下的交互行为。因此,PathFuzz 将覆盖率作为主要评估指标是合理的,因为这类指标便于量化、便于比较,也便于在研究阶段验证方法有效性;但如果进一步面向实际验证质量评估,仍然需要更贴近设计风险的指标体系,以及与 bug 发现能力、场景代表性相结合的综合判断。

其次,PathFuzz 并没有把研究重点放在场景特化的变异算法上,而是优先处理了输入表示和种子来源问题。放在当前背景下看,这一取舍具有一定前瞻性。近年来,大语言模型(Large Language Model, LLM)和相关 AI 方法在程序理解、约束生成和测试生成上的能力提升很快。对于处理器模糊测试而言,许多过去依赖人工设计的工作,例如针对 ISA 语义的变异规则、特权状态切换约束、页表与异常路径构造策略,未来都有可能由 AI 辅助完成。沿着这一路线发展,足迹内存和检查点机制更像是一个稳定的基础底座,它们先解决输入表示与种子来源问题,再为后续引入更强的自动化变异策略提供接口。换言之,PathFuzz 将基础设施和算法层适度解耦,使得未来无论是人工调优、规则驱动,还是 AI 驱动的测试生成方法,都更容易接入。

更进一步看,RISC-V 处理器验证本身就是一个高度依赖积累的领域。无论是手写测试、随机测试模板、参考模型、覆盖率点、缺陷库、软件负载,还是检查点,本质上都属于验证资产的一部分。随着处理器规模和软件栈复杂度持续上升,验证工作的重点也不应停留在自动化流程本身,而应进一步转向如何借助这些流程,更有效地组织、筛选、复用并放大长期沉淀下来的验证资产,从而更深入地逼近设计中的真实缺陷。从这个角度看,PathFuzz 的意义不仅在于提出了一种新的输入格式,也在于给出了一个更适合承接既有 RISC-V 验证资产的框架。

真实程序种子的引入还可以继续向前推进。当前工作已经证明,真实程序和检查点能够显著提高覆盖率上限,并帮助发现长期存在的缺陷。进一步看,后续工作还可以探索更细粒度的检查点选择策略,例如围绕特定特权状态、页表行为、异常路径、设备交互或操作系统关键阶段筛选检查点,而不是仅仅扩大检查点数量。这样做有望在不显著增加测试开销的前提下,提高种子与目标场景之间的匹配程度。

最后,更值得关注的是这类基础设施的可扩展性。足迹内存强调输入表示与动态执行过程对齐,检查点强调把真实程序状态有效引入测试流程,这两点都不依赖于某一种特定覆盖率指标,也不天然局限于某一个处理器模型。后续工作既可以继续探索与更多覆盖率指标、更多参考模型和更多变异策略的结合,也可以将这一思路推广到更复杂的处理器配置、更完整的软件栈环境,乃至 SoC 级验证场景。对于开源处理器验证研究而言,这种能够持续承接新方法、新资产和新场景的基础设施,其长期价值往往比某一组具体实验结果更加重要。

八、总结

PathFuzz 针对处理器覆盖率引导模糊测试中的两个基础问题给出了系统性回答,即种子语料来源过窄,以及传统线性内存输入与 CPU 动态执行过程不匹配。围绕这两个问题,该工作提出了足迹内存,并结合检查点机制将真实大程序引入处理器模糊测试。

从实验结果看,这一设计带来的改进主要体现在三个方面:覆盖率增幅得到提高,无效输入和越界访问造成的变异浪费得到降低,真实程序种子能够显著提升覆盖率上限,并帮助发现长期存在的 RISC-V 处理器缺陷。对于处理器验证场景而言,这项工作的启发并不只在于提出了足迹内存这一技术点,更在于强调了验证资产积累的重要性。处理器验证长期依赖测试、模型、软件负载、状态快照和人工经验的持续沉淀,而模糊测试能否发挥作用,很大程度上取决于这些沉淀能否被有效组织和利用。沿着这一思路看,覆盖率引导模糊测试的有效性不仅取决于变异策略本身,也取决于输入表示方式和种子构造方式,更取决于能否将已有验证资产转化为自动化探索的真实起点。我们也期待,在开源芯片生态持续发展的背景下,LLM 等 AI 技术能够进一步激活处理器验证长期积累下来的资产价值。

附:论文与项目链接

  • 论文题目:PathFuzz: Broadening Fuzzing Horizons with Footprint Memory for CPUs
  • 会议:第 61 届 ACM/IEEE 设计自动化会议(61st ACM/IEEE Design Automation Conference,DAC 2024)
  • 作者:Yinan Xu,Sa Wang,Dan Tang,Ninghui Sun,Yungang Bao
  • 单位:中国科学院计算技术研究所处理器芯片全国重点实验室;中国科学院大学;北京开源芯片研究院
  • DOI:10.1145/3649329.3655911
  • 开源项目:https://github.com/OpenXiangShan/xfuzz

点我访问原文链接