Page 48 - 《软件学报》2021年第9期
P. 48
2672 Journal of Software 软件学报 Vol.32, No.9, September 2021
缺陷代码可能出错位置,然后依赖测试在正确代码上的运行结果推断代码规约,最后基于该规约为缺陷代码生
成修复代码骨架(sketch),并通过枚举所有的可能填充代码骨架产生修复代码.该方法与上述方法的不同在于其
中包含了代码重构部分,使得语义相近的代码尽可能在结构上相似,方便之后的代码匹配.但其应用的场景是针
对学生提交的作业,要求相同功能的代码存在不同的实现.在工业开发环境中,相同功能代码并不一定总是存
在,使得其应用范围受到了一定限制.
(4) 本节小结
基于启发式搜索的自动修复方法是到目前为止研究最为广泛的一类方法.该类方法的优点是具有较强的
通用性,适用于不同种类的程序缺陷.然而,其缺点是容易产生似真补丁而降低补丁的准确率.因此,其核心是如
何定义合适的补丁搜索空间以提升补丁的质量.如前所述,修复方法的召回率和准确率是两个相互制约的指标,
在保证准确率达到一定指标要求的情况下提升自动方法的修复数量,是搜索空间定义的重大挑战.
2.2 基于人工修复模板
(1) 利用模板生成补丁
基于人工模板的补丁生成,指根据开发者或研究人员的经验预定义一些补丁模板或者补丁生成策略用于
指导修复的过程,2013 年被提出来的 PAR [30] 是其中的代表性研究.通过分析人工修复补丁的特征,Kim 等人为
PAR 人工定义了 10 个修复模板,涵盖 6 大类的代码修改,例如替换函数的参数、替换变量初始化等.PAR 中包含
了每个修复模板的实现逻辑,当给定一个缺陷代码位置,PAR 按照一定的顺序逐一实例化预定义的修复模板产
生修复补丁.由于补丁生成的模板由人工定义和编写,生成补丁的质量相比随机产生会有较大提升.对开发者的
调查问卷表明,PAR 产生的补丁具有较好的可读性.在此之后,2019 年,Koyuncu 等人 [53] 将 PAR 定义的修复模板
用来修复缺陷报告中的缺陷,并提出了修复工具 iFixR.然而,该方法的缺点也是比较明显的.人工定义模板负担
重且难以覆盖所有类型的程序缺陷,适合于分布较广泛的特定类型缺陷.比如,2019 年,Marginean 等人 [54] 提出的
修复工具 SapFix 主要针对面向对象语言中的空指针缺陷等.
2017 年,Tian 等人 [55] 提出了一种针对 C 语言错误的自动修复方法 ErrDoc,该方法主要针对静态分析工具检
测出来的不正确条件检查(error check)和资源释放(resource release)以及值的错误传播(error propagation)和输
出错误(error output)这 4 种常见错误进行修复.类似地,ErrDoc 针对每种特定的缺陷定义了对应的修复模板.当
检测到对应的程序缺陷时,即应用对应的修复模板.例如,函数的返回值出错的一种修复模板,是直接将返回值
替换成为对应的期望值.相比于 PAR 以及 SapFix,该方法的主要不同点在于:通过静态分析在程序的控制流图上
检测出错路径和未出错路径,通过对比差异为修复提供指导.
类似 ErrDoc,很多基于模板的自动修复技术主要是针对一些特定类型的缺陷.原因是缺陷的修复方式相对
比较固定,数量有限,方便人工定义.比如:早在 2016 年,Gao 等人 [56] 通过定义 3 种修复模板来修复缓冲区溢出
(buffer overflow)缺陷,实现了修复工具 BovInspector;Gao 等人 [57] 和 Yan 等人 [58] 分别在 2013 年和 2016 年提出了
LeakFix 和 AutoFix,通过预定义的修复模板(插入 free 语句),借助静态分析技术修复内存泄漏缺陷;再比如:2019
年,Xu 等人 [59] 通过添加空指针检查等模板,修复静态分析技术检测出来的空指针异常错误.
2018 年,Liu 等人 [60] 首先使用代码修改提取工具 GumTree [61] 从 Stack Overflow 上的缺陷代码修复中提取代
码修改操作,然后由人工总结成修复模板.该方法相比上述定义模板的好处在于:一些常用的变量或常量在问答
网站上可能经常出现,这些数据可以包含到修复模板中,在生成修复补丁时可以起辅助作用.与此类似,Tan 等
人 [62] 通过分析安卓(Android)应用软件崩溃的常见原因,总结了 8 个修复模板并用于自动化修复安卓缺陷.
2018 年,Hua 等人 [31] 提出了基于模板的自动修复技术 SketchFix,该方法主要关注的是缺陷修复技术中的效
率问题.根据之前的介绍,通常情况下补丁生成是一个不断迭代过程,每次生成新的修复补丁都需要对程序进行
重新编译.因此,修复的一部分时间开销在于重复编译.SketchFix 使用辅助函数替换待修复的代码,辅助函数内
部的具体实现根据预定义的补丁模板生成.这样做的好处是:程序只需要编译一次即可,修复过程每次只修改辅
助函数内的代码,因此只有非常有限的代码需要每次更新编译,从而避免了由于编译整个项目所带来的时间开
销,可以有效提升修复的效率.与 SketchFix 类似,2017 年,Durieux 等人 [63] 提出了 NPEfix,通过元编程避免不同补