Page 268 - 《软件学报》2024年第4期
P. 268
1846 软件学报 2024 年第 35 卷第 4 期
码变换的内容, 提取此补丁的标准操作路径, 并人为地构建缺陷程序包含的其他操作路径. 在训练时, 人为构建得
到的操作路径为噪音信息, 而通过抽象语法树差分技术得到的标准操作路径为神经网络的预期输出. 在完成数据
预处理后, 开始对模型进行训练. 我们首先对每条输入的操作路径进行编码, 将路径中的信息映射到高维数字向量
空间. 随后我们采用指针神经网络从多个特征中筛选出所需的特征, 帮助我们从众多输入的操作路径中筛选出标
准操作路径, 即修复该缺陷所对应的操作路径. 从该路径中我们便可获取到细粒度的缺陷代码令牌信息以及对其
进行修复所需操作.
第 2 阶段为预测阶段, 对于给定的缺陷函数, 我们将其转化为对应的抽象语法树并抽取出所有的抽象语法树
路径. 随后人为地将每条抽象语法树路径与 3 种代码更改原子操作结合, 构建出该缺陷代码片段所有可能的操作
路径. 我们将得到的一组操作路径送入上一阶段已训练好的模型当中, 输出按照可能性从高到低排列的操作路径
序列, 也即 BEEP 的预测结果. 通过解析操作路径中包含的代码令牌和变换操作, 可以得知缺陷函数可能的缺陷令
牌及修复该缺陷所需的代码变换操作.
3.1 数据预处理
我们使用历史补丁作为训练数据集. 对于数据集中的每个补丁, 我们使用 GumTree [52] 抽象语法树差分技术来
计算缺陷程序与正确补丁之间在抽象语法树层面的代码变更差异. 通过得到的差异, 我们可以识别到抽象语法树
路径 (即从根节点到被修改的叶子节点的路径) 以及操作路径 (即抽象语法树路径、代码令牌和代码变换操作). 需
要注意的是, 如果补丁中代码变换操作为插入, 则对应的操作路径内容应包括插入位置前一处未被更改的代码令
牌 (即前一条未被更改的语句的最后一个代码令牌)、其相应的抽象语法树路径以及 INSERT 操作. 通过抽象语法
树差分得到的操作路径仅是这个补丁所对应的正样例. 我们考虑每个缺陷方法中所有指向非缺陷叶子节点的抽象
语法树路径, 交替为其填补上 3 个更改操作中的每一个, 使一条抽象语法树路径衍生出 3 条操作路径, 这些新得到
的操作路径在训练过程中被标记为负样例, 因为它们代表着不应被预测为有缺陷的路径.
此外, 在数据预处理中, 我们收集每条抽象语法树叶子节点所对应的代码令牌信息, 它们在模型训练中能够一
定程度上提供程序语义信息. 一些近期的研究工作表明, 将代码令牌拆分成代码子令牌 (code sub-tokens) 能够显著
降低模型中词表的大小并更加有效地捕获语义信息 [13,44] , 因此我们也进行了类似的操作. 具体而言, 代码令牌依据
驼峰命名法和下划线命名规约 [53,54] 被拆分为代码子令牌, 得到的代码子令牌被进一步转化为小写形式.
3.2 模型训练
图 4 展示了我们提出的 BEEP 训练-预测模型的整体结构. 我们的深度神经网络主要由编码器-解码器结构和
指针网络组成. 编码器-解码器结构已经大大提升了解决自然语言中出现的语法错误的能力 [55,56] , 同时受软件自然
性 [57] 的启发, 程序中的缺陷部分也应该能够利用大数据的深度学习检测出来. 指针网络是注意力模型的一个简单
变种, 给定一条输入的序列, 序列中各元素是离散的 (即不存在顺序关系), 指针网络能够学习到输出序列的概率条
件. 近期研究表明, 当输出的元素是从输入的元素中进行选择时, 指针网络具有非常好的效果 [58,59] . 在定位细粒度
的缺陷代码令牌的场景下, 预测结果 (即操作路径) 是离散元素, 因此我们采用指针网络作为模型预测缺陷代码令
牌及相关的代码变换操作的框架.
i i i t i 是代
• 操作路径编码. 对于一条操作路径 op =< t i , p i ,o i > , 其中 p i = {n ,n ,...,n } 是对应的抽象语法树路径,
i 1 2 l i
o i 是代码令牌修改操作. 我们首先对其中的代码子令牌、抽象语法树路径以及代码变换操作进行编码, 这
码令牌,
一过程被已有的代码表示技术 (如 code2seq [13] ) 广泛采用. 我们利用不同编码矩阵分别对拆分后的代码子令牌和
修改操作进行编码, 这一过程可以表示为:
∑
V t = E t (t s ),
t s ∈T s
V o = E o (o),
t
其中, E t (·) 和 E o (·) 分别代表针对子令牌和修改操作的不同编码矩阵. T s 是代码令牌 的子令牌流, V t 代表令牌 t
的向量表示, V o 代表更改操作 o 的向量表示.