SearchGEM5:使用基于搜索的软件测试和大语言模型实现可靠的Gem5

互联不一般哥 2024-05-03 11:38:33

SearchGEM5: Towards Reliable Gem5 with Search Based Software Testing and Large Language Models

Aidan Dakhama, Karine even - mendoz ,W.B. Langdon,Hector Menendez1,Justyna Petke2

引用

Dakhama, A., Even-Mendoza, K., Langdon, W., Menendez, H., Petke, J. (2024). SearchGEM5: Towards Reliable Gem5 with Search Based Software Testing and Large Language Models. In: Arcaini, P., Yue, T., Fredericks, E.M. (eds) Search-Based Software Engineering. SSBSE 2023. Lecture Notes in Computer Science, vol 14415. Springer, Cham. https://doi.org/10.1007/978-3-031-48796-5_14

论文:https://doi.org/10.1007/978-3-031-48796-5_14

仓库:https://github.com/karineek/SearchGEM5/

摘要

本文介绍了一种新的自动化测试技术SearchGEM5,它结合了大语言模型和基于搜索的模糊测试,并对AFL++ 模糊器进行了扩展,加入了定制的新突变操作符。作者使用ChatGPT来参数化C程序,再将通过编译的代码片段提供给SearchGEM5进行测试。SearchGEM5生成了4005个二进制文件,作者测试了这些二进制文件,发现它的覆盖范围增加了1000余行,并发现了244个实例。最后得出结论:gem5对二进制文件的模拟与二进制文件本身的的预期行为不一致。

1 引言

测试在软件生命周期中起着关键作用。如今的测试生成通常昂贵而繁琐,为此,作者提出通过结合大语言模型(LLMs,Large Language Models)和基于搜索的(search-based)技术来自动化软件测试,并在gem5上进行演示。

gem5模拟器是一个用于计算机系统架构研究的模块化平台,涵盖系统级架构(system-level architectures)以及处理器微架构(processor micro-architectures)。gem5 最初是为学术界的计算机体系结构研究而设计的,但现在它已发展到用于学术界的计算机系统设计、工业界的研究和教学。目前它已经被ARM Research、AMD Research、Google、Micron、Metempsy、HP和Samsung等公司用于学术研究和工业领域。Arm 为使用 gem5 的开发人员开发了名为 Streamline 的进一步软件,旨在呈现“系统执行的图形视图”。Gem5具有多种执行模式。包括:全系统模拟(模拟整个操作系统)和系统调用模拟(仅模拟用户空间)、多种ISA(Alpha、ARM、SPARC、MIPS、POWER、RISC-V和x86 ISA)、支持自定义一致性协议的完整缓存层次结构的时序模型、从检查点进行序列化/反序列化等。

gem5代码量极大(134万行),它在不同的体系结构上模拟软件执行,如处理器微架构或系统级架构。同时,gem5的测试输入集是模拟的体系结构和在该模拟结构中运行的程序的组合,因此测试时可能的输入空间会呈指数级增长,这导致人们很难为gem5创建一个测试套件。

为此,作者提出了一种新颖的gem5测试方法。首先,以行业标准的C编译器测试套件(industry-standard C compiler test suites)和教程程序(tutorial programs)的混合集合为输入,ChatGPT(GPT 3.5)自动生成一组参数化的C程序,并提供了能使该程序正常终止参数和参数数据类型。通过编译LLM生成的参数化C程序,作者构建了一个测试输入语料库。语料库内包含了一些二进制文件及其如何执行的信息。其次,作者扩展了AFL++,一个基于覆盖率的模糊测试工具。为了生成新的测试输入,作者引入了自定义变异器(custom mutators)。这些变异器可以将二进制文件内的位翻转,或者变异该二进制文件的参数及其数据类型(例如,将0:INT32变异为55:INT32)。

为了检查生成的测试输入是否导致了gem5中的错误,作者使用AFL++的反馈(崩溃测试,crash testing)并在其他体系结构上运行二进制文件作为自动测试预测:如果gem5产生相同的结果,便认为测试运行成功。否则将其视为潜在的错误。作者生成了4005个独特的测试输入,其中244个导致gem5产生了不同于其他体系结构上运行观察到的行为。

2 技术介绍

gem5的单个测试输入由一个二进制文件和其参数组成。因此,在测试gem5时需要一组二进制文件。这些二进制文件可以通过两种方式生成:1)编译程序;2)变异现有的二进制文件。本文首先选择一组示例程序,并使用大语言模型(LLM)创建变体,将内部参数提取为程序参数。然后对它们进行编译,并使用AFL++和SearchGEM5内部自定义变异器使它们更加多样化。

作者使用LLM生成一组适用于测试gem5的C程序并使用一个BASH脚本来修正小错误。使用基于覆盖率的变异模糊测试器AFL++进行变异。此外对于每个测试用例,作者将gem5的结果与实际测试执行进行比较,最后创建了一组参数化的测试输入。为了在gem5中执行单个测试,需要:1.gem5模拟的程序二进制文件;2.二进制文件需要的参数;3.参数的类型(例如32位整数)。作者通过编译从LLM获取的程序来生成二进制文件,还向LLM提出需要一个包含程序参数及其类型的文件。

本文中有三种用于训练LLM生成测试输入的提示词:

1)一个包含了一段小的C代码和一段描述任务的文本的提示词;

2)一个给出了正确响应的例子的提示词;

3)一个给出了错误响应的例子的提示词,并简要解释了为什么是无效的。

然后使用这些提示词让LLM自动构造一个来自单个来源(例如,单个git存储库)的许多程序的提示词,比如

“I will give you a set of N programs from source X, can you generate a pair per program with an input sample and its type information for the second program ? These are the programs : (name : code , name : code , . . .”。

LLM会返回一些成对的程序,每一对程序包括原始的C程序及其参数化的对应程序,以及每个参数的一个有效参数示例(输入值)和类型。(原始程序用于检查程序是否完整,而类型用于SearchGEM5变异输入。)

LLM使用的程序来源包括:C-testsuite、LLVM测试套件和C示例。当遇到没有参数或无法编译的程序时,会尝试最多三次自动修复无效的程序,修复的方法是使用一个BASH脚本来处理已知问题(例如,缺少include文件),或者选择再次向LLM询问。

作者采用AFL的AFL++分支进行模糊测试。AFL++事先需要一组初始文件,这些初始文件都是对待测系统(SUT)的输入,之后AFL++对待测系统进行插装以测量测试覆盖率。在运行过程中,AFL++通过代码覆盖率来引导测试先前未经测试的代码。作者以AFL++的覆盖率选择为标准,重新实现变异操作符和部分变异策略来扩展了AFL++。这使得AFL++可以根据测试覆盖率数据从语料库中选择特定的测试输入,并对其二进制文件、参数或它们的类型进行变异。

作者为gem5的测试输入引入了两种变异操作符:1)位翻转操作符,用于编辑编译后的二进制文件;2)用于编辑参数值的操作符。它使用类型信息,以确保参数保持有效。

作者扩展了AFL++,实现了一个新工具SearchGEM5。SearchGEM5以二进制文件名、参数列表和类型的形式评估新的测试输入。然后,SearchGEM5使用这些信息直接对编译后的二进制文件或其参数进行变异操作。

3 实验评估

3.1 实验设置

数据来源。本文使用的C程序语料库是使用ChatGPT(2023年8月3日)GPT-3.5-turbo创建的。编译器采用了GCC-11,但由于gem5的要求,覆盖率测量使用了gcov-9。Python脚本是由SSBSE Challenge Track 2023组织者提供的示例文件,名为hello-custom-binary.py。SearchGEM5使用AFL++来进行模糊测试,使用默认参数。

实验方法。作者在一台单个虚拟机上运行了实验,该虚拟机配备了8个虚拟CPU核心和72GB RAM,运行的操作系统是Ubuntu 20.04.2 LTS x86_64。主机使用了一颗AMD EPYC 7313P CPU(单插槽,3.0 GHz,16个核心,每个CPU 2个线程)。

3.2 实验评估

作者对SearchGEM5进行了测试生成能力、覆盖率、漏洞发现以及重现结果所需的工作量的评估。为此提出了三个RQ:

GPT -3.5 turbo为gem5生成符合指定要求的参数化C程序的能力如何?LLM和AFL++生成的测试输入的覆盖率是多少?AFL++能否提高gem5中LLM生成的基本覆盖?SearchGEM5在发现错误方面有多有效?

3.2.1 测试生成能力

为了评估GPT -3.5 turbo为gem5生成符合指定要求的参数化C程序的能力,除了基本提示词外,作者还向GPT-3.5-turbo提供了额外的示例:一个带有有效输入的C程序,以及一个带有无效输入的C程序。作者运行了25小时的GPT-3.5-turbo,生成了1869个C参数化文件:其中1086个通过了GCC-11 -O3编译,形成了AFL++的有效测试程序集。AFL++使用其中的744个进行变异(剩余342个测试输入通常因为参数无效被AFL++忽略)。在运行了10天后,AFL++生成了2136个独特的变异测试输入。综上,SearchGEM5生成了4005个独特的测试程序,其中3222个变成了二进制文件。

3.2.2 测试覆盖率

为了评估将LLMs与AFL++搜索相结合的方法与LLM生成的测试输入的整体覆盖率之间的差距,作者使用g++ 9.4 -O1和gcov构建了gem5,添加了gcov插装开销。作者分别使用了LLM生成的1086个二进制文件和AFL++生成的2136个二进制文件,测量了gem5代码库中与X86相关的部分。并使用基于gcov的工具gfauto为gem5代码库中的3380个文件(包括头文件和系统头文件)生成了可读的覆盖率结果。LLM生成的测试输入在gem5代码库上达到了39143行的覆盖。而AFL++的测试输入覆盖了40337行,多覆盖了1194行。

3.2.3 漏洞发现

为评估SearchGEM5在发现gem5中的漏洞的有效性,作者对gem漏洞进行了分析。作者在gem5中发现了紧急崩溃(panic crashes)、断言违规(assertion violations)、崩溃(crashes)、超时(hangs)和模拟错误(missimulation bugs)等问题,汇总在表1中。作者对所有崩溃进行了分类,确定了gem5代码库中两种不同类型的断言违规和10种不同类型的紧急崩溃。虽然挂起可能是由多种不同问题引起的,但它们在表中被分组在一起。

例如,表中第14行的测试输入是由GPT-3.5-turbo生成的。gem5错误模拟了它(在不模拟操作系统以及程序的情况下运行,SE模式),导致与原生X86运行产生不同的输出。在gem5模拟中,使用无效输入时,程序错误地以退出码0结束。然而,相同的程序和错误的输入组合,在原生X86上运行时达到第11行时,程序被以分段错误终止(LLM生成的程序执行为./00172.c.o 0;)。可能是因为gem5的地址空间会掩盖这些指针错误,类似于虚拟化混淆的情况,通常是由于操作系统的无效地址是进程地址空间的一部分。

表1:使用SearchGEM5生成的测试输入在gem5中发现的错误列表

3.2.4 可移植性

AFL++已经应用于各种目标程序,因此扩展不同的待测系统应该很容易。本文的自定义AFL++突变器可以被重用,因为这是与目标程序无关的位(bit)级突变。

GPT-3.5-turbo已经接受了来自许多编程语言(如Python和Java)的广泛代码的训练。通过调整LLM提示词和程序示例,本文的方法可以很容易地应用于在其他编程语言中生成测试输入。

总结

在像gem5这样的复杂仿真系统中发现漏洞需要将基于搜索的策略(如模糊测试)与像ChatGPT这样的LLM相结合,并通过重新定位和改进现有的测试程序基准来提供广泛的测试用例。在研究初期这些工作十分复杂,因为为反馈式模糊测试工具(如AFL++ )准备仿真系统需要对整个系统进行插装,这能够自动发现新的错误,这些错误不一定是灾难性的故障,例如模糊测试通常发现的分段错误,它可能是一些简单但由内部预言自动识别的输出差异。与差异测试配合使用,作者发现它可以找出掩盖的错误。作者的方法以一种非传统的方式使用AFL++,用更复杂的输入格式替换了测试输入的模糊化,正如前文所讨论的那样,这个想法被各个领域采用,例如编译器测试或网络协议分析。在gem5的测试中,虽然还难以完全验证其架构的合规性和代码的完整性,但像SearchGEM5深入到内部的gem5测试验证方法,对于验证许多可能的想法也是至关重要的。最后的可移植性讨论和表1量化了每个错误的测试输入实例,提供了部分再现bug的限制的见解,而这种限制俩源于随机测试和LLM的非确定性。作者也将进一步的分析推迟到未来的研究中。

转述:李顺

0 阅读:2

互联不一般哥

简介:感谢大家的关注