基本信息
**原文名称:**Large Language Models are
Edge-Case Fuzzers: Testing Deep
Learning Libraries via FuzzGPT
**原文作者:**Yinlin Deng;Chunqiu Steven Xia;
Haoran Peng等
**原文链接:**https://doi.org/10.48550/arXiv.
2304.02014
**发表期刊:**International Conference on
Software Engineering (ICSE),2024
**开源代码:**暂未开源
一、引言
深度学习库中的漏洞可能会影响所有基于此的深度学习应用,所以因此确保此类系统的质量至关重要。生成用于模糊测试的深度学习库的有效输入程序具有挑战性,因为输入程序需要同时满足所支持语言(如 Python)的语法/语义以及用于构建有效的张量/操作符约束。先前的TitanFuzz表明,可以直接利用大语言模型来隐式学习所有语言和深度学习计算约束,从而生成用于模糊测试深度学习库的有效程序。然而,大语言模型倾向于按照其海量训练语料库(如 GitHub)中的典型程序的相似模式/符号生成普通程序,而模糊测试则更倾向于涵盖边缘情况或不太可能由人工生成的异常输入。
因此,为了弥补这一空白,作者提出了FuzzGPT,利用多个大语言模型提供素材以合成用于模糊处理的异常程序的技术。该技术基于以下两种假设:
**(1)**历史错误触发程序可能包含对错误查找非常重要的稀有或有价值代码成分[6,7]。
**(2)**大语言模型具有自动化生成语义语法有效的程序的能力。
二、概述
FuzzGPT的基本框架如图1所示,主要由两部分组成:
(1)历史错误信息收集:利用爬虫爬取历史错误信息;
(2)程序生成和变异:大语言模型从历史错误信息中生成初始程序,并进一步变异生成新的程序;
图1 FuzzGPT结构图
三**、历史错误信息的数据集构建**
1.从Github爬取历史错误信息
使用HTML 爬虫从 GitHub 问题跟踪系统中收集目标库的所有问题和拉取请求 (PR)。然后专注于从两个来源识别触发错误的代码片段:(1) 与已接受或待定 PR 相关的问题。我们在这些错误报告中搜索所有包含可重现错误的代码段的代码块,并将它们串联起来。(2) 提交信息中包含代码块的 PR。我们进一步考虑 PR,因为有些 PR 可能修复了错误,但没有相应的问题。对于每个提取出来的问题或 PR,也会提取其标题,并将其纳入提示中,以便进行少量学习和微调。在挖掘出触发错误的代码片段后,接下来将执行自动标注,进一步为每个代码片段标注相应的错误 API。
2.自动标识存在漏洞的API
数据集中的每个代码片段通常涉及多个API。因此,不能直接提取确切的错误API。为了注释有bug的API,提出了一种自训练方法,将少量提示(如图 2 所示)提供给 LLM,并使用模型完成其错误 API标注。我们首先为几个随机选择的错误触发代码片段提供错误 API 名称的手动注释。这些手动注释的对成为用作 LLM 输入的一部分的少样本示例。在图 2 中,few-shot示例使用选定的错误触发代码片段、相应问题/拉请求的提取标题(例如Tensor.apply_ Failed)构建的,最后,手动注释的错误 API 名称(例如,torch.Tensor.apply_)。接下来将少样本示例与目标错误触发代码片段相结合以创建提示,然后查询 LLM 以获得给定代码片段的预测错误 API 名称。因为由于现代 LLM 的上下文学习能力,只需要为目标库注释几个示例, 注释工作量很小。
图2 API自动化标注
即便可能标注错误的API,但“错误”的API和存在Bug的API中存在非严格映射,也就是说在生成包含“错误”的API的代码时,有可能会包含存在Bug的API。
**四、**上下文学习和微调
1.上下文学习
少量学习 在目标查询前添加来自注释错误触发代码片段数据集的示例。**图 3(1)**显示了少量学习提示是如何构建的。示例格式包括 API 名称(如 torch. Tensor. apply_)、从问题/PR 标题中获得的错误描述(如 Tensor.apply_ Failed)以及最后的触发错误的代码片段。这些示例有两个目的。首先,它们的目的是让 LLM 能够生成所需的输出格式。其次,使模型能够通过观察历史错误触发代码片段来学习生成类似的边缘案例代码片段,而无需修改模型参数。在少数几次学习过程中,每次提示都包含 括号示例(记为 括号-Shot)和实际查询(目标 API 和错误描述标题)。然后,LLM 可以根据提示生成新的预测。
图3 微调、零知识和少量学习
思维链提示 少量学习的一个重要组成部分是所使用的提示。提示设计受到了思维链提示的启发,提示不是直接生成最终输出,而是要求模型逐步执行任务。按照上下文示例的格式,首先在查询中包含目标应用程序接口名称(例如,应用程序接口:torch.gather),在生成调用目标应用程序接口的实际 "触发错误 "代码段之前,要求模型生成可能的 "错误 "描述。预测的错误描述为 LLM 提供了额外的提示,表明生成的代码应尽量涵盖特定的潜在错误行为。
零知识学习 在这一部分中,输入仅由部分代码片段组成。部分代码片段是根据历史错误触发代码片段数据集创建的,在其中随机删除了部分后缀代码。图 3 (2) 展示了如何创建零知识补全输入。首先包含一个自然语言注释 # 下面的代码揭示了 {target_api} 中的一个错误,它允许对任意目标 API 应用零点学习。然后从数据集中随机抽取一个暴露漏洞的示例代码片段。之后随机移除部分被选中的触发错误的代码片段的后缀,只保留前缀行作为 LLM 的输入。
2.微调
微调通过在历史错误代码片段数据集上进行训练来直接修改模型参数。图3 ( 3 ) 显示了微调过程的工作原理,以及微调模型在推理过程中产生模糊输出的输入。 每个训练样本都由API名称、错误描述和触发错误的代码片段组成。从原始的预训练 LLM 开始,然后通过梯度下降训练更新模型权重,对每个训练样本进行自动回归预测。
**五、**实验设计及结果
(一)数据集建立及大模型参数设置
从GitHub仓库中关于PyTorch和TensorFlow的历史问题和PR中分别收集到 1750 和 633 个触发 bug 的代码片段。对提取的代码进行了额外的清理,以过滤掉错误信息,并删除仅包含执行的输入和输出的代码行。
在API 标识上手动注释了K=6个随机抽样示例,并将其作为上下文示例。对于每个未标注的示例,都查询 Codex 以完成 buggy API标识,即使是错误标注的示例,错误标注的 API 始终出现在代码中。
在生成式大模型上采用了Codex(code-davinci-002)和 CodeGen(350M/2B/6B-mono)。由于Codex未开源,所以只对CodeGen进行了微调。微调方案为batch_size=32 , learning rate=5e-5 并用AdamW优化器进行了10次训练。
(二)实验设置
本实验的测试目标为2种流行深度学习库,TensorFlow(v2.10)和PyTorch(v1.12),这两深度学习库在先前的测试工作中已经被广泛研究。
默认设置是为每个目标 API 生成 100 个程序。在“少量样本提示”方法中,对于每个目标 API,都用随机挑选的 6 次示例独立构建 10 个提示程序,并将每个提示程序交给 LLM,以采样 10 代程序。同样,在 "零知识 "方法中,从数据集中随机选择 10 个不同的示例,并使用部分/完整代码构建 10 个提示来执行完成/编辑。在微调方法中,使用固定的任务描述,并对模型进行 10 次查询,对每个目标API生成100个程序。在使用所有 LLMs 生成程序时,我们的默认设置为 top-p sampling,𝑝 = 0.95,𝑡𝑒𝑚𝑝𝑒𝑟𝑎𝑡𝑢𝑟𝑒 = 0.8,𝑚𝑎𝑥_𝑡𝑜𝑘𝑒𝑛 =256[5]。
(三)实验设备
64核心256GB内存的工作站, 4张RTX A6000GPU显卡,系统环境为Ubuntu20.04.5LTS。
(四)具体实验
1.实验一:FuzzGPT内不同模型变体的性能比较
比较了三种 FuzzGPT 变体(少量提示、零知识、微调),以了解它们的性能。
FuzzzzGPT 展示了利用上下文学习和微调技术生成模糊输入的能力。从图 4 中的覆盖率趋势中,我们观察到在所有三个变体中,即使生成了全部 100 个代码片段,覆盖率也不会达到饱和,这显示了 LLM 从历史错误触发数据集中学习的能力,可以持续生成有价值的模糊程序,从而获得更大的覆盖率。表1总结了最终3种变体生成的结果。
图4 API覆盖率增长趋势
表1 API覆盖率对比
2.实验二:与先前工作对比
在表2中总结了FuzzGPT与先前工作(FreeFuzz[1]、DeepREL[2]、▽Fuzz[3]、Muffin[4]、TitanFuzz[5])的对比,在代码覆盖率和API覆盖率上均有显著的提高。
表2 与先前工作的对比
并比较了FuzzGPT与TitanFuzz(两者均基于大模型)对Unique Crashes发现数量的比较,如图5所示。
图5 Unique Crash对比
3.实验三:关键环节消融实验
1)FuzzGPT中在不同模型参数的性能
该实验的测试了在使用上下文学习的LLM生成种子程序的过程中Prompt提示词工程的作用,分别对是否使用API签名(只提供函数名而不提供参数)、是否使用step-by-step(不提供图2中的Task1和Task2,只提供库的版本和函数名)的方式来生成种子。并测试了在不同temperature值下生成可用层序的数量。
图6 不同参数下生成的代码覆盖行数
随着模型参数的增加,从CodeGen350M 到 2B 再到 6B,覆盖率有了明显的提高,CodeGen-6B 在覆盖率方面已经可以达到与 Codex 相当的性能。
2)思维链提示
这部分实验检测了思维链提示的有效性,当包含错误信息的描述可以显著提高代码覆盖率,如表3所示
表3 采用(w)或不采用(w/o)思维链提示对生成程序的影响
3)思维链提示的数量对大模型的影响
提供少量示例可以增加LLM生成代码覆盖率,但随着提示增加,代码覆盖率反而会下降。如果示例过多,会限制LLM的创造性,从而影响生成的代码。
图7 不同提示示例数量对代码覆盖率的影响
4)零知识的不同提示词策略
给予LLM不同的提示词策略来比较生成的代码覆盖率。Editin为对已有程序进行编辑,completion-NL只给出自然语言的提示,Completion给出部分代码让LLM完成程序。给出部分代码并要求LLM进行补全生成的代码覆盖率最高。
表4 不同提示词策略下生成的程序及覆盖率对比
5)微调模型的参数对比
在微调时,模型越大并不总是越好。例如,2B模型拥有最多独特的有效程序。这可能可以用有效性与不寻常性的权衡来解释:当我们对 LLM 进行微调,使其偏向于不寻常性生成时,我们可能会失去一些有效性保护信息,而这两者都有助于提高代码覆盖率和最终的错误查找能力。同样的也进行了思维链提示对微调模型的效果对比,如图8所示
表5 不同参数微调模型对FuzzGPT的影响
图8 是否使用思维链对微调模型的影响
4.实验四:真实环境发现的Bug
TitanFuzz共检测到65个bug,已确认其中53 个(19个崩溃错误和34个计算错误)是有效的。53个bug中有41个是先前未发现的bug(其 8个已修复)。在这 53 个bug中,只有9个能被API级的fuzzer探测到,而模型级fuzzer没有探测到上述任何一个。值得注意的是,通过直接使用 Codex 生成的种子而不进行任何变异,就可以发现 10 个已知的bug。
表7 Bug的发现数量
六、总结
这是第一种利用历史错误触发程序为LLM 进行边缘案例模糊的方法。与十多年来研究的利用此类历史信息的传统模糊技术相比,FuzzGPT 是完全自动化、可通用的,适用于具有挑战性的领域,如 DL 库模糊。此外,FuzzGPT 还展示了 ChatGPT 在没有任何历史信息的情况下生成边缘案例程序的潜力。实验结果表明,FuzzGPT 的性能大大优于现有的 DL 库模糊器,并能检测出 PyTorch 和 TensorFlow 的各种错误。
参考文献
[1][1] WEI A, DENG Y, YANG C, et al. Free Lunch for Testing: Fuzzing Deep-Learning Libraries from Open Source[J].
[2]YINLIN D, YANG C, WEI A, et al. Fuzzing Deep-Learning Libraries via Automated Relational API Inference[J]. Cornell University - arXiv,Cornell University - arXiv, 2022.
[3]YANG C, DENG Y, YAO J, et al. Fuzzing Automatic Differentiation in Deep-Learning Libraries[J]. 2023.
[4]GU J, LUO X, ZHOU Y, et al. Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing[J]. 2022.
[5]DENG Y, XIA C, YANG C, et al. Large Language Models are Edge-Case Fuzzers: Testing Deep Learning Libraries via FuzzGPT[J]. 2023.
[6]CHEN J, WANG G, HAO D, et al. History-Guided Configuration Diversification for Compiler Test-Program Generation[C/OL]//2019 34th IEEE/ACM International Conference on Automated Software Engineering (ASE), San Diego, CA, USA. 2019. http://dx.doi.org/10.1109/ase.2019.00037. DOI:10.1109/ase.2019.00037.
[7]HOLLER C, HERZIG K, ZELLER A. Fuzzing with code fragments[J]. USENIX Security Symposium,USENIX Security Symposium, 2012.
—END—