Automatic Software Repair: a Bibliography 自动软件修复概览(三)

原论文标题《Automatic Software Repair: a Bibliography》

原作者 Martin Monperrus,主页:https://www.monperrus.net/martin/

发表于 ACM Computing Surveys, 2017

原文链接:https://arxiv.org/pdf/1807.00515.pdf

此翻译已获得原作者授权

译者:ClarkC.

引用请注明出处

 

感谢原文作者Martin Monperrus教授提供翻译授权。鉴于原文较长,该翻译将分为四次上传。第一次为原文开头至第二节结尾,第二次为原文第三节,第三次为原文第四节,最后一次为原文第五、六、七节。原文中的参考文献可至原文中查看,原文链接附在开头与结尾。

 

 

4. 状态修复

状态修复是指在修复中更改程序的状态。 状态的意思范围很广,可以是更改输入,堆,栈或者环境。 例如,自动中断链表中的循环是一种状态修复。 与行为修复相反,状态修复必须在程序运行时进行。

      状态修复可以源于经典的容错技术[9]。在这个庞大的领域中,许多研究的目标都是 “恢复(recovery)”,Avizienis等人将其定义为:将包含一个或多个error和(可能的)fault的系统状态转换为没有检测到的error的状态[9]。在本文中使用“状态修复(state repair)”代替“恢复”。这个术语的改变使得我们有了一个概况性的术语“修复(repair)”,其涵盖了在本质相关概念(recovery、resilience等),也涵盖了行为和状态修复,详见参考文献[9]中的图5.1,展示了经典的恢复技术、error与fault处理技术的概貌。

       状态修复依赖bug的预期结果和不正确状态的预期结果。与行为修复相反,这些预期结果必须在生产中、运行时可使用。这排除了第3节中讨论的某些预期结果,例如测试套件和基于静态分析的预期结果。对于状态修复,有三个主要的bug 预期结果类型。首先,状态修复经常考虑违反非功能性约束。例如,因段错误或使用空指针导致崩溃,违反了“程序不应崩溃”这一非功能约束。 其次,状态修复还可以考虑在生产中验证的功能性约束,例如前置和后置条件。将在第4.7.1节中详细讨论。第三,有一些状态修复方法基于在运行时观察程序状态的规律性而获得的“推断约束(inferred contracts)”。在这种情况下,bug被定义为违反推断约束的程序状态或行为,而修复是对程序状态和执行进行异常检测的后续措施。

       在下文中所要叙述的方法按修复操作排序。这更符合该领域的历史,而不像行为修复那样按预期结果的种类排序。

      

4.1. 重新初始化与重启

      重启(restart或reboot)软件应用程序是最简单的修复操作。其在“软件复兴(software rejuvenation)” [64]的领域下已经有了很深的探索,但主要是理论探讨而不是实践探索。

       Candea及其同事[19,20,21]深入探讨了微重启(microreboot)的概念。微重启包括细粒度可重启组件的层次结构,以及在出现故障时从最小组件(EJB)开始尝试重启直到最大组件(物理机)(类似于分布式计算中的渐进式重试[184])。他们的实验表明,这可以显著提高系统的可用性。

 

      

4.2. 检查点与回滚
      检查点和回滚机制定期获取执行状态的快照,并能够在以后还原它们。这项技术的挑战首先是捕获状态的大小和边界,其次是检查点的时间点[85,76]。当系统配备了检查点和回滚机制时,回滚就是修复。尽管这是一项较老的技术,但在许多情况下还是很有价值的。

       Dira [164]是使用代码来检测通过恶意负载实施的控制劫持攻击(control-hijacking)并从中恢复的系统。其修复操作包括找到被攻击的函数和读取了有效负载的函数的最小共同来源。然后,执行过程恢复到该帧,并撤消所有状态更改。同样,Assure [159]也是一种基于检查点以提供自我修复功能的技术。最近的论文也将检查点和回滚作为修复的一部分,例如[23]。

 

4.3. 备选方案

      容错的另一个经典概念是n版本编程。无论是使用投票[8]还是使用恢复块重试[142],都包括依靠可替代实现来从error中恢复。现在,使用自然的替代方案集(而不是被设计的)或自动创建的变体集来探索这一概念[16]。例如,Carzaniga等人[24]使用基于一组针对API的替代规则的修复策略来修复运行时的web应用程序,例如调用bar()而不是foo()。后来,他们用了相同的思想来恢复Java的运行中异常[23]。Hosek和Cadar [62]使用了另一种自然多样性:出现failure时,他们用同一应用程序的旧版本或更新版本来替换当前版本。其关键思想是,错误并不是一成不变的:随着时间的流逝,某些bug会消失,而其他bug也会出现。

 

4.4. 重新配置

      重新配置应用程序也是一种恢复(recovery)[9],因此是一种状态修复。事实上,当“自我修复(self-healing)”还是一个热门术语时,人们对其进行了很多探索。例如,Cheng等人[26]使用三个核心的运行时重新配置操作(添加组件,移动组件,删除组件)来优化服务质量值。在相关的引用文献中[52,155]也可以找到同样的修复方法。在Web服务编排的环境中,Friedrich等人[135,46]的修复措施包括用另一个Web服务替换当前的(这就是一种重新配置)并重试服务调用。

 

4.5. 输入修改

      如果系统在某些输入上出错,则一种状态修复操作包括修改输入。拒绝引起错误的输入也是一种可能的选择,可以将其视为输入修改的极端情况。

       Ammann和Knight的“数据多样性(data diversity)” [3]旨在出现故障的情况下实现程序的计算。其思想是,当发生failure时,更改输入的数据,以使更改后的新输入不会导致failure。假设基于该人工输入的输出,通过一个逆变换,在所考虑的范围中仍然是可接受的。

       Long等人[107]提出了自动输入校正的思想:不拒绝异常输入,而是对其进行更改,以使其适合典型的可接受输入空间,这被称为“输入校正”。

       Liand和Sekar [98]通过研究崩溃输入特性之间的通用配置文件来修复缓冲区溢出。一旦识别出已确认的配置文件,崩溃的输入将被拒绝。尽管他们的研究涉及安全性,但可以将其视为一种运行时的用于修复缓冲区溢出形式的内存错误的技术。从修复的角度来看,缓冲区溢出是偶然的(由于bug)还是恶意触发的都无关紧要。与拒绝输入相同,Vigilante [29]是一种用于减轻恶意攻击的综合方法。应对蠕虫攻击的对策是过滤:一旦检测到无效或恶意输入,就将其过滤掉,并中止当前请求或任务。

 

4.6. 环境扰动

       如果系统在某些情况下发生故障,则可以通过更改运行时环境(例如内存,调度)或配置来获得下一个成功请求。

       Qin等人[141]的研究表明,通过在分配的内存块中填充额外的空间,可以避免内存错误。Berger和Zorn[13]使用了同样的方法,并添加了复制方法。但是,与Rx的不同之处在于他们的系统允许对由此产生的内存安全性进行概率推理。Novark等人[131]也探讨了同样的想法。不同的是,Nguyen和Rinard[129]通过循环内存分配来实现有界内存大小,其方式类似于故障忽略计算(已在第3.6节中介绍)。Garvin等人[53]解决了配置bug,并提出了“重新配置解决方案(reconfiguration workarounds)”,以更改导致failure的配置。

       Jula等人[72]提出了一种在运行时防御死锁的系统。系统首先检测死锁的同步模式,当检测到该模式时,系统会使用附加锁以避免死锁的再次出现。

       Tallam等人[174]将该技术领域命名为“执行扰动(execution perturbations)”。对于并发和内存bug,他们表明消除线程中断,填充内存分配以及拒绝请求是避免failure的一种方法。

 

4.7. 前滚

      前滚(rollforward或forward recovery)是指将当前系统状态转换为正确的状态。 有几种前滚技术:不变恢复(invariant restoration),错误虚拟化(error virtualization)等。

 

4.7.1 不变恢复 在某些情况下,状态正确性可以表示为不变式。因此,修复意味着在可能的情况下以与当前错误状态相比最小的变化来恢复不变量。

Demsky和Rinard [35]使用规范语言来表达数据结构的正确性。然后,在运行时使用该规范自动修复损坏的数据结构(运行时的具体实例,而不是抽象数据类型)。Elkarablieh等人[43]也在运行时自动修复数据结构,与Demsky和Rinard的区别在于他们是靠用普通Java代码编写的不变量(“repOK”布尔方法)。

Perkins等人[134]提出了ClearView系统,该系统可以自动修复产品中的error。该系统在低级x86二进制文件上运行,通过监视系统执行来学习不变式。然后监视这些不变量,并在其违规之后强制恢复。修复是在CPU寄存器和内存位置改变的级别上进行。

Lewis和Whitehead[97]通过定义一个运行时故障监视器,为基于事件的系统提供了一种通用的修复方法,但其核心思想是相同的:当一个不变量被破坏时,修复系统会自动恢复它。游戏领域的例子很有趣:如果马里奥因为特定的动作和操作顺序而被吊在空中,他就会被强行放回地面。除了数据结构和游戏之外,在现实的系统中,复杂的事件和交互链可能会导致许多奇怪和不希望出现的系统状态,但通常可以通过声明简单的不变量来指导运行时修复。

 

4.7.2 错误虚拟化 错误虚拟化包括使用系统中已经存在,但用于处理其他错误的错误处理代码,来处理未知且不可恢复的error。

哥伦比亚大学已经深入探索了这个思想。例如,Sidiroglou等人[160]在模仿生物免疫的系统中进行错误虚拟化。他们将错误虚拟化与选择性事务仿真相结合,选择性事务仿真是一种通过事务解释器仿真本机代码执行的技术。当仿真部分中发生failure时,所有状态更改都将被撤消(一种在功能级别上的微回滚)。在Assure[159]中,错误虚拟化的思想与模糊化相结合,以提前发现和测试有价值的错误虚拟化点,称为救援点。

 

4.7.3 其他前向恢复 Carbin等人[22]引入了一种监视程序的系统,以检测无限循环并跳出循环。该系统使用二进制代码检测工具,并在不改变内存状态的情况下中断在执行过程中检测到的循环。同样,“循环穿孔(loop perforation)” [157] 的概念也是如此。Sidiroglou等人[157]的研究已经表明,有可能在某些应用程序域中跳过循环迭代的执行。例如,在视频解码算法(编解码器)中,跳过某些循环迭代只会对某些像素或轮廓产生影响,而不会完全降低画质或使软件崩溃。另一方面,跳过循环迭代是性能方面的关键。换句话说,要在性能和准确性之间进行权衡。这种权衡可以设置为离线(例如,任意跳过每两个循环中的一个)或根据计算机的当前负载动态设置。

Dobilyi和Weimer [40]的目标是修复空指针异常。 他们使用代码转换将钩子函数(hooks)引入恢复框架。此框架负责用创建适当类型的默认对象以替换空值或跳过指令的形式来进行向前恢复。

Long等人[111]介绍了“恢复牧羊(recovery shepherding)”的思想。对于某些特定的错误(空引用和零除),恢复牧羊包括返回一个生成的值,就像故障忽略计算一样。但是,恢复牧羊的关键思想是跟踪这个生成的值,以便观察1其是否被传递给了系统调用或文件,以及2其是否消失。在1的情况下,如果系统调用和文件写入涉及了虚假的生成值,则将其禁用,以限制错误传播。当生成值不再被使用和引用时,意味着error已以某种方式消失了,该文献中的实验表明通常是这种情况。

 

4.8. 协同修复

运行时修复的一个交叉关注点是在同一个应用程序的所有实例上共享修复。这种方法已经以“应用程序社区”的名义进行了研究。Locasto等人[104]使用应用程序社区来查找和分发对堆栈操作形式的修复。Rinard等人[144]还报告了关于在应用程序社区中监控信息的集中化和修复行为的分布的实验。

(未完待续)

 其余部分:(一):https://blog.csdn.net/ClarkCC/article/details/106029615

                   (二):https://blog.csdn.net/ClarkCC/article/details/106108728

                   (四):https://blog.csdn.net/ClarkCC/article/details/106178322

若发现翻译问题,可直接评论或与我联系:cheng.yifan@qq.com

原论文标题《Automatic Software Repair: a Bibliography》

原作者 Martin Monperrus,主页https://www.monperrus.net/martin/

发表于 ACM Computing Surveys, 2017

原文链接:https://arxiv.org/pdf/1807.00515.pdf

此翻译已获得原作者授权

译者ClarkC. 

引用请注明出处

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值