亚历克斯是一名软件开发人员,最近在她梦寐以求的公司工作。她终于准备将一个备受期待的新特性推向共享代码存储库,这是她作为开发人员职业生涯中的一个重要里程碑。在开发实践中越来越常见,这种推送触发了代码在对公司的每个人可见之前必须通过的无数测试。Alex已经对新功能进行了大量的测试,并相信它会通过所有由推送自动触发的测试。不幸的是,Alex得知构建系统拒绝了提交。持续集成系统报告了与完全不同的团队开发的软件包相关的失败测试。Alex现在必须理解这个问题并手动修复这个特性。
如果不是简单地通知Alex测试失败,而是构建系统还建议对提交的代码进行一到两个可能的补丁呢?虽然这个通用的用例仍然是虚构的,但是越来越多的研究人员正在研究自动程序修复的新技术,从而使它成为现实。Monperrus编写了一份自动程序修复研究的参考书目。17
本质上,自动修复技术试图自动识别特定bug的补丁,一个这些技术可以在很少,甚至可能没有人类干预的情况下应用。这种类型的工作开始在某些受限的实际领域被采用。静态bug查找工具越来越多地提供“快速修复”建议,帮助开发者解决标记的bug或糟糕的代码模式,Facebook最近宣布了一个工具,它可以自动修复通过Android应用程序自动测试工具发现的bug。15
bug的问题激发了大量自动识别它们的工作。正式验证的进展已经显示出完全可靠的软件的前景。然而,现代软件开发的速度和规模通常排除了这种技术的应用,除了最安全的关键系统。在许多公司中,最常依赖于语法模式匹配或不那么复杂的静态分析的轻量级静态方法作为质量检验关越来越受欢迎。7,23在系统抽象的多个层次上进行测试,在实践中仍然是最常见的bug检测技术。
虽然检测bug是改进软件的必要步骤,但它却没有解决更困难的修复bug的任务。在实践中,程序修复是具有挑战性的几个原因。开发人员首先必须了解问题,并在源代码中定位其根源。接下来,她必须思考可能解决问题的策略。对于这些策略中的一些,开发人员将通过应用它并评估相关的测试用例是否通过来评估一个潜在的补丁;如果不是,她可能会使用失败的测试用例来进行额外的调试活动。最后,开发人员必须选择一个补丁并将其应用于代码库。复杂的软件项目往往包含遗留代码、组织中其他成员编写的代码,甚至是由第三方编写的代码,这一事实使所有这些任务的难度变得更加复杂。
自动程序修复的承诺是通过为软件错误提供可能的修正补丁来减少这些任务的负担。在较高的层次上,这种技术将一个程序和一些正确标准的说明作为输入,这些标准是固定程序应该满足的。大多数研究技术都将测试套件用于此目的:一个或多个失败的测试表明需要修复的bug,而通过的测试表明不应该更改的行为。最终目标是一组程序更改(通常是对源代码),使所有测试通过,在不破坏其他行为的情况下修复bug。
当今自动化程序修复研究的最大挑战是规范薄弱的问题。由于预期的程序行为的详细的形式化规范通常是不可用的,程序修复是由弱的正确性标准驱动的,比如测试套件。因此,生成的补丁可能会过度适合给定的测试套件,并且可能无法推广到测试套件之外的测试。29
在本文的其余部分中,我们将讨论自动化程序修复中的一些技术进展,包括对过拟合问题的说明。我们首先概述一些自动化程序修复的用例。
本节讨论自动修复的四个实际用例,并报告基于当前修复技术的初步经验。
在开发过程中修复bug。现有的持续集成(CI)管道,如Jenkins,是将修复集成到开发过程中的重要跳板。通过定期构建、测试和部署代码库,CI为使用测试套件作为正确性规范的修复工具提供了先决条件。修复可以成为CI系统中的一个活动,它建议补丁来响应回归测试失败,例如对于我们假设的程序员Alex。
当今自动化程序修复研究的最大挑战是规范薄弱的问题。
我们到了吗?自动化修复正确性错误的现有技术通常使用开源项目中的错误来评估其有效性。因为许多技术需要输入测试来触发修复中的bug并评估技术,这样的程序和bug必须与一个或多个失败的测试用例相关联。这些错误通常是通过回溯代码历史来系统地收集的,以确定错误修复提交以及与之相关的回归测试。以这种方式研究bug的开源项目包括流行的Java项目,例如各种Apache库、Log4J和Rhino JavaScript解释器,以及流行的C项目,例如PHP和Python解释器、Wireshark网络协议分析器和libtiff库。
最近,修理工项目33提出了一个机器人,它可以监控软件错误,并使用修复工具自动查找修复。Facebook最近的另一项研究15描述将修复集成为持续集成的一部分的经验修复工具监视测试失败、重新生成它们并自动查找补丁。一旦找到补丁,它们将被提交给开发人员进行验证。目前,这项工作的重点是自动修复Android应用程序的崩溃,然而,该项目计划将这项工作扩展到通用修复。
修复安全漏洞。许多安全漏洞是可利用的内存错误或编程错误,因此是自动修复的相关目标。关键软件,包括处理文件格式的流行库或操作系统实用程序,都被定期严格地检查漏洞,以响应频繁的更新,使用灰盒模糊测试工具,如美国的Fuzzy Lop (AFL)b).微软最近宣布了Springfield项目;谷歌同样宣布了OSS-Fuzz项目。这种连续的模糊工作流程为自动程序修复生成用例。特别是修复工具可以接收AFL等灰盒模糊测试工具产生的测试。
我们到了吗?现有的修复技术可以有效地修复某些类型的安全漏洞,特别是整数和缓冲区溢出。对OSS Fuzz主题进行的实证研究c表明整型溢出错误是可接受的一行补丁,这是很容易产生的修复工具。例如,这些更改添加了变量或常量的显式类型转换、修改条件检查以防止溢出或更改类型声明。现有的维修工具16也被证明可以自动为臭名昭著的“心脏出血”(Heartbleed)漏洞生成补丁:
if (hbtype == TLS1_ hb_ REQUEST)
/*下面添加的检查是修复*/
&& payload + 18 < s->s3->rre .length) {
...
memcpy (bp, pl、载荷);
...
}
它在功能上等同于开发者提供的补丁:
/*下面添加的检查是修复*/
如果(1 + 2 + payload + 16
...
if (hbtype == TLS1_ hb_ REQUEST) {
...
}
智能辅导。计算机编程学习社区正在迅速发展。
这种增长导致了越来越大的潜在学习者群体,但往往没有足够的教学支持。自动化修复可以作为智能辅导系统的一个关键组成部分,为学习者解决编程作业提供提示,并通过比较模型解决方案自动化学生的编程作业评分。
我们到了吗?虽然基于修复的智能辅导目前仍是一个公开的挑战,但初步证据表明,使用程序修复之类的过程向学生提供反馈28或者学生作业的自动评分40已经获得。自动化作业评分可以受益于学生的bug解决方案和教师的模型解决方案之间的“语义距离”的计算。未来的一个重要挑战是,编程教育需要对今天的程序修复工作流程进行细微的改变,因为教学主要集中在指导学生找到解决方案,而不是修复他们破碎的解决方案。
性能瓶颈的自愈。随着用于智能设备、无人机和其他网络物理或自主系统的各种物联网(IoT)软件的出现,对在线程序修复的需求越来越大,特别是对能源消耗等非功能性属性的需求。考虑一下用于灾难恢复的无人机,比如洪水或火控。无人机软件可能会遇到意外或危险的输入,因为可能会遇到不可预见的物理环境,这可能会耗尽设备的电池。存在无人机软件在线自愈的需求。针对非功能性问题(如性能瓶颈)的自动修复可以提供这种自修复能力。
我们到了吗?目前针对非功能性物业的修复技术已经证明了它们在改善现实软件方面的有效性。考虑两个与性能相关的修复工具的例子。首先是MemoizeIt工具31建议执行应用程序级缓存的代码,它允许程序避免不必要的重复计算。第二,焦糖工具19对广泛使用的Java和C/ c++程序(如Lucene、Chromium和MySQL)中总共150个未知的性能问题提出了补丁,这些问题现在已经根据建议修复得到了修复。虽然这些例子令人鼓舞,但如何将非功能性修复应用于完全自动化的自我修复仍然是一个问题。
在这里,我们将描述一个简单的例子来说明程序修复中的各种最先进的技术。这个例子是为教学目的而选择的,而不是为了说明修复技术的所有能力。正如我们前面所描述的,今天的技术适用于更加复杂的程序。
考虑这样一个函数,它将给定的三角形分类为不等边三角形、等腰三角形或等边三角形(图1).从中学学到的等腰三角形的定义可以看出,第6行的情况需要纠正为
(a == b || b == c || a == c)
这种修复并非微不足道;它不仅仅是简单地改变条件中的一个操作符。
中的测试套件图2捕获函数考虑的各种三角形类别:INVALID、EQUILATERAL、ISOSCELES和SCALENE。因为代码包含一个bug,所以有几个测试失败了。自动化程序修复的目标是获得一个有bug的程序和一个测试套件,比如这些,并生成一个修复程序的补丁。在这种情况下,测试套件提供了正确性标准,指导修复到一个有效的补丁。一般来说,对于任何特定的bug,可能存在任意数量的补丁,甚至人类也可以为真实世界的bug找到不同的补丁。
图2。中的函数的测试套件图1.
在较高的层次上,程序修复问题可以这样看:给定一个有bug的程序P和一个测试套件T,使得P通过了T中的一个或多个测试,找到P的一个“小”修改,使修改后的程序P通过了T。术语“小”只是指这样一个事实:比起复杂的补丁,开发人员通常更喜欢更简单的补丁。有些技术甚至试图找到一个最小的补丁。另一些人则在补丁大小与其他目标之间进行权衡,比如高效地找到补丁。在自动修复中,一个特别的风险是一个“补丁”,它导致所提供的测试用例通过,但它并没有泛化到完整的,通常不可用的规范。即通过自动修复方法产生的补丁可以对测试数据进行过拟合。这是一个极端的例子,在测试中过度修理图2如下:
如果(a==-1 && b==-1 && c==-1)
返回无效;
If (a==1 && b==1 && c==1)
返回等边三角形;
If (a==2 && b==2 && c==3)
返回等腰;
...
当然,这样一个“修复”的程序是没有用的,因为它没有通过所提供的测试套件之外的任何测试。这个例子是故意的极端。更常见的是,当前修复技术产生的补丁通过禁用(或删除)未被测试的功能,倾向于过度匹配所提供的测试套件。29
自动修复错误包括(隐式地)搜索输入源代码的更改空间。构建这样的补丁的技术可以分为大类,根据构建的补丁类型,以及如何进行搜索。图3给出了技术的概述。这些技术的输入是一个有bug的程序和一个正确性标准(正确性标准通常作为一个测试套件给出)。大多数技术都从一个常见的预处理步骤开始,该步骤识别那些可能有bug的代码位置。这种故障定位过程,例如,由Jones等人,8提供代码位置的排序,以指示其潜在的缺陷。在高层次上,主要有两种方法:启发式修复而且基于修复。这些技术有时可以通过机器学习来增强,我们称之为learning-aided修复。
启发式修复。启发式搜索方法,如图左侧所示图3采用生成和测试方法,构造和迭代语法程序修改的搜索空间。这些技术可以简单地解释如下:
for cand SearchSpace做
验证cand // break,如果成功完成
与SearchSpace表示考虑过的程序修改的集合。验证包括计算应用建议的补丁时通过的测试数。这相当于遗传规划或其他随机搜索方法中的适应度函数评估。
启发式修复通过生成补丁来转换程序抽象语法树(AST)。AST是一种基于树的程序源代码表示,它捕获重要的程序构造,同时抽象出括号或分号等语法细节。给定错误定位信息,定位代码在程序中最可能出现错误的位置,语法技术通过沿着三个轴中的一个进行选择来使搜索变得易于跟踪:突变选择、测试执行和遍历策略。
突变的选择。由于可能突变的组合爆炸,可以生成和编译的程序变体的数量通常非常大。因此,技术必须限制修复候选对象所考虑的编辑的类型和种类。这又定义了搜索空间,因此基于搜索的修复算法具有很大的灵活性。但是,这种灵活性也有风险:如果搜索空间太小,所需的修复甚至可能不在搜索空间中。对于我们的三角形例子(图1),回想一下,最自然的补丁替换第6行为(a == b || b == c || a == c)
.如果我们只考虑修改二元运算符的突变,修复算法的单编辑搜索空间将不包含开发者提供的修复,这需要用新的条件来扩充分支条件。另一方面,如果搜索空间太大,搜索就会变得棘手,导致算法在合理的时间内无法找到修复。
为了解决这个问题,一些技术将编辑限制为只在语句级或块级删除、插入或替换代码。对于代码插入或替换,常见的方法是从同一程序或模块的其他地方提取代码,遵循整形手术假设(正确的代码可以从同一程序的其他地方导入)。6或者是有能力的程序员假设(程序员大多是有能力的,虽然他们可能在程序的某个部分出错,但他们很可能在其他地方正确地编写了类似的逻辑)。因此,这种技术将只考虑移动整个代码块或代码行,例如,在语义上类似于中所示的整个if条件图1.由于源代码是重复的,这通常可以工作。22
其他技术也得益于使用表达性更强的转换模板,例如使用空指针检查来保护去引用操作。这样的转换模板在修复空间大小和结果补丁的可读性和“自然性”之间进行了权衡。从语句级编辑转移到表达式级编辑会增加搜索空间,增加的数量取决于用于构造搜索空间的转换模板。
然而,即使搜索空间很大,变异操作符也可能不支持程序所需的行为变化,或者可能以不同于人类建议的方式影响期望的变化。修改操作符或插入条件(从程序的其他地方复制)的技术在这个小程序上仍然会遇到困难,因为(= = c)
在我们的例子中从不逐字出现。如此缺乏正确的代码片段会导致提供很少修复材料的较小程序的退化行为。它还推动了智能扩大搜索空间的研究,例如,通过考虑一个程序的过去版本。
测试执行。通过在提供的测试用例集上运行修改后的程序来评估修复候选。测试执行通常是最昂贵的步骤,因为测试套件可能很大,技术可能需要多次重新运行它们。人们提出了各种策略来减少这种成本,包括选择测试套件和确定优先级。不需要适应度函数的搜索策略,例如,基于随机或确定性搜索的搜索策略,可以通过早期失败(在第一次测试失败时)来降低测试成本。此外,这样的技术可能会以启发式的顺序运行测试用例,这样设计是为了最大限度地增加机会,如果一个测试用例将失败,那么它会在验证过程的早期运行。
遍历策略。最后,技术在如何选择探索哪些补丁以及以何种顺序方面有所不同。GenProg,37该领域提出了一种基于补丁程序通过的测试用例数量的适应度函数的遗传规划算法。后续技术,如PAR9在变异算子(PAR)或适应度函数中有所变化。其他技术只是随机抽样,通常将自己限制在单一编辑的补丁中,21或者像GenProg AE那样以启发式、确定性的顺序。36
基于修复。与启发式修复技术相比,基于约束的技术通过构建修补代码应该满足的修复约束来进行,如下面所示图3.将生成的patch code作为一个待合成的函数。符号执行或其他方法提取要合成函数的属性;这些属性构成了修复约束。修复约束的解可以通过约束求解或其他搜索技术得到。在这些方法中,制定修复约束是关键,而不是解决修复约束的机制。这类技术可以通过下面的示意图来获取:
测试集t
计算修复约束t
合成e作为V的溶液tt
在这种情况下,T是作为正确性标准指导修复的测试套件。约束t将通过符号执行来计算10测试所经过的路径的tT。约束t是经常的形式吗
tt输出=预期
在哪里t测试所经过的路径是否为路径条件t, output是在执行过程中捕获输出变量的符号表达式t而expected指的是神谕或者说预期。程序路径的路径条件是一个公式,对于那些遍历该路径的输入是成立的。10
计算修复约束和angelix值。为了说明基于约束的修复,请重新考虑前面的运行示例。SemFix,18哪个是基于约束的技术的代表,用一个抽象函数替换第6行中的故障条件f(一个,b,c)。在这个例子中,f是一个接受整数值的谓词吗一个,b,c并返回true / false。然后,该技术象征性地执行给定测试套件中的测试,以推断关于未知函数的属性f。这些性质对于合成合适的化合物至关重要f它可以通过所有给定的测试用例。
我们的测试套件中的前两个测试甚至没有达到第6行。因此,SemFix不会推断函数的任何属性f从他们。从最后四个测试中,可以推断出修复约束
f(2、2、3)f(3、2、2)f(2、3、2)f(2、3、4)
这是因为对程序的分析显示,对于输入,执行第6行iff为true,程序返回等腰
和其他方面不等边三角形
.
推断详细的约束规范可能是困难的,有时会带来重大的可伸缩性问题。这促使对基于价值的规范进行更有效的推断。16特别是,天使的值对补丁位置进行推断,其中固定位置的天使值是使失败的测试用例通过的值。一旦确定了每个失败测试的天使值(集合),就可以使用程序合成来生成符合这种基于值的规范的补丁代码。这就是Angelix工具所体现的哲学16天使值是通过符号执行获得的(而不是直接通过符号执行以SMT约束的形式产生修复规范)。这种将修复任务分为天使值确定和补丁代码生成以满足天使值的方法是语义修复方法的表征。
不是通过符号执行和约束求解来获得天使值,它们也可以通过搜索来获得,特别是对于条件语句。这是因为每个条件语句的出现只有两个可能的返回值:true和false。不采用符号执行的枚举可能天使值的技术13,39通常尝试专门修复条件语句,其中天使值被详尽地枚举,直到所有失败的测试用例通过。这些技术采用语义修复技术的工作流程(规范推理后生成补丁),用枚举步骤完全或部分替代符号程序分析。基于符号分析的方法,如Mechtaev等。16另一方面,避免详尽列举可能的天使价值。
解决约束找到一个补丁。这些技术一旦得到待修复语句的修复约束或天使值,就必须生成一个补丁来实现天使值。找到修复约束的解会得到抽象函数的定义f,对应于修补过的代码。这通常是通过搜索或约束求解实现的,其中允许在尚未合成的函数中出现操作符f是受限制的。在这个例子中,如果我们限制允许出现的操作符f作为关系运算符,大多数搜索或求解技术都会找到表达式A == b || b == c || A == c
高效的程序合成技术(参见Alur等。2为了说明程序合成的一些最新进展)经常被用来构造函数f.
上优于修复。最近在高级机器学习,尤其是深度学习方面的改进,以及大量补丁的可用性,使基于学习的修复成为可能。目前的方法大致分为三类,它们在修复过程中利用学习的程度不同。一条工作路线14从代码语料库中学习正确代码的模型,这表明给定的代码片段相对于代码语料库的可能性有多大。然后,该方法使用该模型对一组候选补丁进行排序,首先提出最真实的补丁。另一行工作是从提交历史中的成功补丁推断代码转换模板。3.,12特别是Long等人。12推断ast - ast转换模板,总结补丁如何将有缺陷的代码修改为正确的代码。然后可以使用这些转换模板来生成修复候选。
第三行不仅通过学习改进部分修复流程,还可以训练模型进行端到端修复。这样的模型预测给定的一段有缺陷的代码的修复代码,而不依赖任何其他显式提供的信息。特别地,与前面讨论的修复技术相比,这样的模型不依赖于测试套件或约束求解器。DeepFix5训练修复编译错误的神经网络,例如,缺少右括号、不兼容的操作符或缺少声明。该方法使用编译器作为oracle,在向用户推荐候选补丁之前验证它们。图法诺等。32提出一个模型来预测任意修复,并使用从版本历史中提取的bug修复来训练这个模型。根据他们的初始结果,该模型在9%的情况下对真实的缺陷产生了bug修复补丁。这两种方法都是在将代码输入神经网络之前对其进行抽象。中的运行示例图1,这种抽象将用通用占位符(如VAR1和VAR2)替换应用程序特定的标识符triangle和EQUILATERAL。在这种抽象之后,两种方法都使用基于rnn的序列对序列网络,该网络可以预测如何修改抽象代码。
鉴于人们对基于学习的方法解决软件工程问题越来越感兴趣,我们可能会在未来几年看到更多基于学习的修复的进展。实现有效解决方案的关键挑战包括找到源代码更改的适当表示,以及获取大量高质量的人类补丁作为训练数据。
修复非功能性属性。为了帮助开发人员提高软件效率,几种方法确定了优化机会,并就如何重构代码以提高性能提出了建议。这些方法通常专注于特定类型的性能问题,例如,不必要的循环执行19或者重复执行相同的计算。31另一项工作是从一组功能相同的数据结构中选择最可能为给定程序提供最佳性能的数据结构。26所有这些方法都建议修改代码,但将是否应用优化的最终决定权留给开发人员。
为了减轻安全威胁,人们提出了各种在运行时修复程序的技术。这些方法会自动重写代码,以添加执行某种安全策略的运行时机制。例如,这种修复技术可以加强控制流的完整性,1防止代码注入,30.自动插入不可信输入的杀毒程序,或强制执行自动推断的安全属性。20.
我们注意到,修复非功能属性的现有技术通常专注于特定类型的问题,例如,一种性能反模式或攻击。这将它们与修复正确性错误的核心修复文献区别开来,后者通常旨在修复更大的错误集。
尽管过去十年在程序修复方面取得了巨大的进步,但未来的工作仍有各种各样的开放挑战需要解决。我们确定了三个核心挑战:提高和确保维修质量;扩大维修所解决问题的范围;并将修复集成到开发过程中。
质量。质量方面的挑战在于增加自动识别的修复提供正确修复、易于长期维护的机会。解决这一挑战可能是实现程序修复在现实生活中的应用的最重要的一步。
措施的正确性。修复质量的一个重要方面是该修复是否确实纠正了错误。在实践中,程序修复依赖于正确性的度量。找到这样的度量方法是一个困难且未解决的问题,这既适用于人工生成的补丁,也适用于机器生成的补丁。到目前为止,研究人员已经通过人工判断、众包评估、与开发人员修补的历史bug进行比较,或者在指示性程序工作负载或测试案例中修补程序的性能进行了评估。Xiong等人的近期工作。38提供了一种基于修补程序相对于原始程序在通过和失败测试时的行为来过滤修补程序的新颖展望。
替代的神谕。现有的大部分文献集中在基于测试的修复上,正确性标准是作为一个测试套件给出的。更丰富的正确性属性,例如断言或契约,可用时可用于指导修复。34其他方法考虑替代oracle,例如从动态执行推断出的潜在不变量。20.这种方法可以遵循“bug作为偏差行为”的原则,即观察并避免执行与“正常”执行的偏差。特别是Weimer等人。35提供可用于修复的各种(部分)神谕的概述。
保证正确性。目前的修复技术很少能保证生成的补丁的正确性,这可能会阻碍自动修复的应用,特别是对安全关键的软件。如果正确性保证作为属性可用,例如前置条件、后置条件和对象不变量,这些可以用来指导程序修复。Logozzo和Ball的作品11报告了修复尝试增加保留财产执行的数量,同时减少违反执行的数量的努力。然而,这种正式的技术取决于驱动修复可用的属性。
可维护性。一旦检测到正确的修复并将其应用到代码库中,修复后的代码应该像人工修复一样易于维护。该领域的初步工作研究了自动生成补丁对人类维护行为的影响。4需要更多的研究来发展对变化质量的基本理解,特别是关于将与修改后的系统交互的人类开发人员。
这些技术一旦得到待修复语句的修复约束或天使值,就生成一个patch来实现天使值。
解决质量挑战的一个有希望的途径是利用从其他开发工件中获得的信息,包括文档或正式规范、语言规范和类型系统,或者正在修复的程序的源代码控制历史,或者自由获得的开源软件的广泛语料库。这些附加信息可以通过对潜在的程序修改施加新的约束(例如,根据类型系统的建议)来减少修复搜索空间,并增加生成的补丁是人类可以接受的概率。
范围。范围上的挑战是进一步扩展自动修复所适用的bug和程序的种类。
通用的修复。长期以来,程序分析的研究一直集中在针对特定类型错误(如缓冲区溢出错误)的专用修复工具上,20.或者领域特定语言中的bug。24如前所述,最近的工作集中在通用修复工具上,这些工具不需要对所考虑的bug进行任何假设。虽然在可预见的未来,自动修复所有bug似乎是遥不可及的,但针对广泛的bug仍然是一个重要的挑战。
复杂的程序和补丁。在程序修复的最初研究中,许多关键的创新都涉及到复杂程序的可扩展性技术。例如,基于搜索的技术从对程序ast的种群进行推理转移到对小编辑程序(补丁本身)的种群进行推理,并开发了其他有效限制搜索空间的技术。基于约束的修复策略已经从对整个方法的语义进行推理,转变为只对期望的行为变化进行推理。这些努力使大规模的项目和多线修复成为可能。16我们预计,随着程序修复技术涉及更复杂的推理,可伸缩性将周期性地回到前台。我们在这里强调,对于大型程序和大型搜索空间(复杂的变化),程序修复技术应该保持可伸缩性。
开发过程。最后的挑战是将修复工具集成到开发过程中。
与bug检测集成。错误检测是程序修复之前的自然步骤。通过将修复视为使程序通过给定测试的最小更改,可以将调试和修复融合到一个步骤中。我们设想未来的工作是将修复与bug检测技术(如静态分析工具)集成在一起。这样做可以使修复技术从静态分析中获得关于可能修复的额外信息,除了现在使用的测试用例。作为这个方向的第一步,谷歌上使用的静态分析基础设施建议对其警告的子集进行修复。23一个有希望的未来方向可能是扩展静态分析工具,以生成不希望的行为的动态见证或场景。
IDE集成。现在的大多数修理工具都是研究原型。将这些工具以用户友好的方式提供给开发人员需要努力将修复集成到集成开发环境(ide)中。例如,集成ide的修复工具可以响应失败的单元或系统测试或开发人员的提示。据我们所知,这种应用还没有得到广泛的探索。适当的交互响应时间是这种方法的先决条件。该研究方向将受益于与开发人员工具和人机交互方面的专家的交流,以确保工具的设计和有效评估。
自动化程序修复仍然是一种诱人的可行的方法,它可以提高程序质量,同时改善程序员的开发体验。
交互性。随着程序修复被集成到开发环境中,在修复期间与开发人员交互是很重要的。虽然过去十年的重点一直是完全自动化的修复,但是将开发人员重新投入到循环中是必要的,特别是由于通常用于指导程序修复的薄弱规范(测试套件)。可能需要用户交互来产生额外测试输入的预期输出,从而加强测试套件驱动修复。27当然,我们有可能过滤那些看似合理但可能不正确的补丁,例如,通过偏爱较小的补丁或偏爱与人类补丁“相似”的补丁。尽管如此,开发人员仍然需要探索剩下的大量补丁建议。
解释维修。与此相关的一个问题是解释修复建议。一个值得追求的想法是基于程序依赖关系和其他语义特征计算和表示补丁的相关性,这允许开发人员松散地将可信的补丁组合在一起。特别是在编程教育的应用中,需要解释修复。40修复工具不仅仅是将学生的错误程序修复到正确的模型程序中,它还可以生成提示,提示学生在修复过程中丢失了什么。这些提示可能采用捕捉修复效果的逻辑公式的形式,这是从基于约束的修复工具中收集的;这些暗示可能以自然语言的形式呈现,而不是以逻辑形式呈现,以便学习者理解。
自动化程序修复仍然是一种诱人的可行的方法,它可以提高程序质量,同时改善程序员的开发体验。
从技术上讲,自动修复涉及到定义、导航和确定补丁空间的优先级等方面的挑战。该领域受益于过去在软件测试中搜索空间定义和导航的经验教训,这体现在测试选择和优先级的大量文献中。GenProg工具37这只是基因搜索的一个例子,它对检测很有用,但也可能用于修复。与此同时,自动修复也带来了新的挑战,因为它可能会生成过度匹配给定测试的补丁。这是测试是不完整的正确性说明的一种表现。因此,有必要推断规范来指导修复,可能是通过程序分析。Semfix和Angelix工具16,18下面是几个例子,说明如何将修复问题设想为推断修复约束的一个例子,它们展示了这种基于约束的技术的可伸缩性。
从概念上讲,自动程序修复缩小了今天编写正确程序所花费的大量手工努力和通过学习方法自动生成程序的最终梦想之间的差距。考虑到在程序修复中生成多行程序修复的挑战,我们可以想象自动生成解释程序的难度。
实际地说,自动化程序修复也使我们敏锐地意识到在软件工程项目中管理变更的挑战,以及在这个领域中自动化的需要。今天,手工调试和维护经常占用软件项目中80%的资源,这促使实践者长期宣称存在遗留危机。25将来,程序修复可以通过修复软件项目中复杂变更的bug来提供工具支持。这可以帮助解决开发人员在管理程序更改时的困境:“我们的困境是,我们讨厌更改,但同时又喜欢它;我们真正想要的是事情保持不变,但变得更好。”d
致谢作者承认在Dagstuhl 17022自动化程序修复研讨会(2017年1月)上与研究人员进行了许多讨论。克莱尔·勒·古斯承认美国国家科学基金会的支持。ccf - 1750116和ccf - 1738253。Michael Pradel感谢BMWF/ heessen在CRISP项目中的支持,以及DFG在ConcSys和Perf4JS项目中的支持。Abhik Roychoudhury感谢新加坡国家研究基金会、国家网络安全研发项目的支持。NRF2014NCR-NCR001-21)。
数字观看作者对这部作品的独家讨论通信视频。//www.eqigeno.com/videos/automated-program-repair
1.Abadi, M., Budiu, M., Erlingsson, U.和Ligatti, J.控制流完整性。在第12届ACM计算机与通信安全会议论文集, 2005, acm, 340353。
2.Alur, R., Singh, R., Fisman, D.和Solar-Lezama, A.基于搜索的程序合成。Commun。ACM 61(2018), 8493。
3.Brown, d.b., Vaughn, M., Liblit, B. and rep, T.W.野生捕获突变体的照顾和喂养。在2017年会议论文集th软件工程基础联席会议, (Paderborn, Germany, 2017.9.48), 511522。
4.Fry, Z.P., Landau, B.和Weimer, W.补丁可维护性的人类研究。在《实习生录》。计算机协会。软件测试与分析, 2012, 177187。
5.Gupta, R., Pal, S., Kanade, A.和Shevade, S. DeepFix:通过深度学习修复常见的C语言错误。Assoc。人工智能的进步,2017。
6.自动化补丁技术:解决方案已经出台。Commun。ACM 53(2010), 108108。
7.Johnson, B., Song, Y., Murphy-Hill, E.和Bowdidge, Z.为什么软件开发人员不使用静态分析工具来发现bug ?在《实习生录》。关于软件工程的讨论, 2013, 672681。
8.Jones, j.a., harold, M.J.和Stasko, J.测试信息可视化辅助故障定位。在ACM/IEEE实习生论文集。关于软件工程的讨论9。
9.Kim, D., Nam, J., Song, J. and Kim, S.从人类编写的补丁学习的自动补丁生成。在ACM/IEEE软件工程国际会议论文集, 2013年。
10.符号执行和程序测试。Commun。ACM 19(1976)。
11.Logozzo, F.和Ball, T.模块化和验证自动程序修复。在面向对象编程系统语言与应用学报, 2012年。
12.Long, F., Amidon, P.和Rinard, M.用于补丁生成的代码转换的自动推理。在ACM SIGSOFT实习生会议记录。计算机协会。《软件工程基础,2017年。
13.Long, F.和Rinard, M.带条件合成的阶段性程序修复。在2015年会议论文集th软件工程基础联席会议, 2015年。
14.Long, F.和Rinard, M.通过学习正确的代码自动生成补丁。在ACM实习生会议记录。计算机协会。《程序设计语言原理, 2016年。
15.在《实习生录》。关于软件工程的讨论,软件工程实践轨道,2019年。
16.Mechtaev, S., Yi, J.和Roychoudhury, A. Angelix:通过符号分析的可扩展多线程序补丁合成。在ACM/IEEE实习生论文集。关于软件工程的讨论, 2016年。
17.自动软件修复:参考书目。ACM计算调查511(2017)。
18.Nguyen, H.D.T, Qi, D, Roychoudhury, A.和Chandra, S. SemFix:通过语义分析的程序修复。在ACM/IEEE实习生论文集。关于软件工程的讨论, 2013年。
19.尼斯托,A.,张,P-C。,Radoi, C. and Lu, S. Caramel: Detecting and fixing performance problems that have non-intrusive fixes. InICSE学报》, 2015年。
20.珀金斯,J.H.等人。自动修补已部署软件中的错误。在Symp的程序。论操作系统原理。ACM, 2009年。
21.齐勇,毛晓明,雷毅,戴振宇,王辰。随机搜索对程序自动修复的影响。在《实习生录》。关于软件工程的讨论,2014年。
22.Ray, B., Hellendoorn, V., Godhane, S., Tu, Z., Bacchelli, A.和Devanbu, P.谈bug代码的“自然性”。在三十八届立法会会议纪要th实习生。关于软件工程的讨论(美国德克萨斯州奥斯汀,2016年5月1422日),428439。
23.Sadowski, C., Aftandilian, E., Eagle, A., Miller-Cushon, L.和Jaspan, C.从谷歌构建静态分析工具的经验教训。Commun。ACM 61, 4(2018年4月),5866。
24.Samimi, H., Schäfer, M., Artzi, S., Millstein, T., Tip, F.和Hendren, L.使用字符串约束求解在PHP应用程序中自动修复HTML生成错误。在34年会议纪要th实习生。关于软件工程的讨论, 2012年。
25.Seacord, R., Plakosh, D.和Lewis, G.。使遗留系统现代化:软件技术、工程过程和业务实践。艾迪生韦斯利,2003年。
26.shachham, o.m., Vechev, M.T.和Yahav, E. Chameleon:适应性选择的集合。在程序设计语言设计与实现学报, 2009年。ACM, 408418年。
27.Shriver, D., Elbaum, S.和Stolee, K.T.在综合的最后:缩小项目候选人。在《实习生录》。关于软件工程的讨论,2017年。
28.Singh, R., Gulwani, S.和Solar-Lezama, A.介绍编程作业的自动反馈生成。在《实习生录》。关于程序设计语言的设计与实现, 2013年。
29.Smith, E.K, Barr, E, Le Goues, C.和Brun, Y.治疗比疾病更糟糕吗?程序自动修复中的过拟合。在软件工程基础国际研讨会论文集(FSE), 2015年。
30.Su, Z.和Wassermann, G. Web应用程序中命令注入攻击的本质。在计算机协会学报》上。《程序设计语言原理, 2006, 372382。
31.你可以解决的性能问题:记忆机会的动态分析。在面向对象编程,系统,语言和应用研讨会论文集, 2015年。
32.Tufano, M., Watson, C., Bavota, G., Di Penta, M., White, M.和Poshyvanyk, D.通过神经机器翻译在野外学习bug修复补丁的实证研究。在实习生学报》上。关于自动化软件工程的讨论, 2018年。
33.俞正宇,刘志勇,宋文杰,孟佩罗斯,M.,如何设计一个程序修复机器人?来自修理工项目的见解。在实习生学报》上。软件工程专业,跟踪软件工程实践, 2018年。
34.Wei, Y., Pei, Y., Furia, C.A, Silva, L.S., Buchholz, S., Meyer, B.和Zeller, A.合同程序的自动修正。在ACM实习生论文集。计算机协会。软件测试与分析, 2010年。
35.Weimer, W., Forrest, S., Kim, M., Le Goues, C.和Hurley, P.系统弹性的可信软件修复。在学报46th年度IEEE /联合会实习。可靠系统和网络研讨会, 2016年。
36.Weimer, W., Fry, Z和Forrest, S.利用自适应程序修复的程序等价:模型和第一个结果。在ACM/IEEE实习生论文集。关于自动化软件工程的讨论, 2013年。
37.Weimer, W., Nguyen, T.V., Le Goues, C.和Forrest, S.使用基因编程自动寻找补丁。在ACM/IEEE实习生论文集。关于软件工程的讨论, 2009年。
38.熊勇,刘霞,曾敏,张磊,黄光光,黄光光。基于测试的程序修复中的补丁正确性识别。在实习生学报》上。关于软件工程的讨论, 2018年。
39.Xuan, J., Martinez, M., Demarco, F., Clement, M., Marcote, s.l., Durieux, T., Le Berre, D.和Monperrusm . Nopol: Java程序中条件语句错误的自动修复。IEEE反式。软件工程43,(2017)。
40.Yi J., Ahmed U.Z., Karkare, A., Tan, S.H.和Roychoudhury, A.使用自动化程序修复入门编程作业的可行性研究。在ACM SIGSOFT实习生论文集。计算机协会。软件工程基础,2017年。
a.我们使用通俗术语“bug”来指代导致意外运行时行为的编程错误。
b。http://lcamtuf.coredump.cx/afl/
©2019 0001 - 0782/19/12 ACM
如果您不是为了盈利或商业利益而制作或分发本作品的部分或全部,并在第一页注明本通知和完整引用,则允许您免费制作本作品的部分或全部数字或纸质副本,供个人或课堂使用。本作品的组成部分必须由ACM以外的其他人享有版权。信用文摘是允许的。以其他方式复制、重新发布、在服务器上发布或重新分发到列表,需要事先获得特定的许可和/或费用。请求发布的权限permissions@acm.org或传真(212)869-0481。
数字图书馆是由计算机协会出版的。版权所有©2019 ACM股份有限公司
没有发现记录