Page 169 - 《软件学报》2026年第7期
P. 169
2854 软件学报 2026 年第 37 卷第 7 期
查点植入 (如采用语句级粒度, 每个检查点的 Try 代码块仅包裹一条或多条程序语句), 则植入 Try 代码块的过程
需要考虑不同项目的代码逻辑和结构差异, 导致检查点的植入受到具体项目的限制, 这与 INSPECT 技术提高缺陷
定位泛化能力的目标不符; 另一方面, 仅当 Try 代码块所包裹的程序语句触发异常时, 检查点才能记录该次被触发
的信息, 若缩小 Try 代码块包裹的程序语句范围, 可能增加程序执行时所触发异常被遗漏的概率, 以函数为粒度
的 Try 代码块可以捕获所有当前函数中触发的异常, 因此能够更好地体现当前的程序执行状态.
(2) 植入规则. 检查点植入的规则包括植入 Try 代码块的具体形式、其判断异常是否触发的规则, 以及对被测
程序执行逻辑的影响. INSPECT 在函数上植入检查点的模板如图 2 所示. 其中, 第 1 行的“func”代表函数声明, 第
5 行的“Statements”代表函数体中的程序语句, 这两部分是待植入函数的原有内容. 第 4–6 行的 Try-catch 代码块包
裹了目标函数中的所有程序语句, 因此, 当函数中的任意语句触发异常时, 都可以被植入的 Try-catch 代码块捕获.
第 6 行的 catch 关键字指明了 Try 代码块将捕获的异常类型为 Exception, 意味着不限制具体的异常类型, 任意
Exception 的子类都将在被函数中的语句触发后由第 6 行的 catch 代码块捕获. 为了记录目标函数的异常触发信
息, 在第 2 行以“triggeredOrNot” (本文中形式化描述为 triggeredOrNot) 变量标识异常的触发情况, 该变量的初始
值为 0 (代表函数中没有异常被触发). 在执行函数的过程中, 若某条语句触发了异常, 该异常将导致函数执行跳转
至第 6 行的 catch 代码块, 从而使得第 7 行语句将“triggeredOrNot”变量的值修改为 1 (代表函数中有异常被触发).
检查点上具体的异常触发信息记录由第 3 行语句 (检查点开始) 和第 10 行语句 (检查点结束) 完成, 其中的
“Checkpoint#i” (本文中形式化描述为 Checkpoint#i) 是在不同函数上植入的以 i 为唯一标识的检查点.
1. func{
2. String triggeredOrNot = “0”;
3. System.out.println(“Begin:Checkpoint#i”);
4. try{
5. Statements;
6. } catch (Exception triggered){
7. triggeredOrNot = “1”;
8. throw triggered;
9. } finally {
10. System.out.println(“End:Checkpoint#i_” + triggeredOrNot); }}
图 2 检查点植入模板
值得注意的是, INSPECT 方法植入检查点是为了缓解现有基于异常信息的缺陷定位技术对程序自带异常处
理语句的依赖, 其只是对程序原有异常处理语句的临时性替代, 并非对程序异常处理语句设置的推荐或修改. 因
此, 植入的检查点不应对程序原有的执行逻辑产生影响. 在图 2 所示的检查点植入模板中, 若仅在原始函数上植
入 Try 代码块并设置捕获所有 Exception 子类的 catch 代码块, 可能导致函数中原本会向上层调用栈抛出的异常被
植入的检查点隐藏, 从而扰乱程序原有执行逻辑. 以 Java 中流行度较高的 Spring 框架 [42] 对异常处理机制的应用为
例, Spring 的关系型数据库事务管理往往会在捕获到异常时进行事务的回滚, 如果该异常被植入的 Try 代码块捕
获并隐藏, 可能导致原本需要回滚的事务被正常提交, 使得数据库操作出错. 为了避免这种情况, 方法在所植入检
查点的 catch 代码块中向上抛出捕获的异常, 如图 2 中的第 8 行所示. 这一处理使得植入的检查点不会影响程序原
有的执行逻辑, 且第 8 行的 throw 语句不会阻止第 10 行中检查点结束信息的记录, 因为在异常处理相关的语法规
则中, 一旦程序执行进入 Try 代码块, 任何 return 和 throw 语句的结果都将被暂时保存, 并在第 9 行的 finally 代码
块执行后返回.
(3) 植入密度. 检查点植入的密度是在被测程序中植入检查点的数量. 由于 INSPECT 方法以函数为粒度植入
Try 代码块, 检查点植入的密度实际上是待测程序中被选择植入 Try 代码块的函数数量占所有函数的比例. 开发人
员在程序中设置的异常处理代码反映了其对程序的理解, 这些异常处理代码往往存在于程序中更可能出现错误执
行状态的位置, 因而能够以较低的密度有效检查程序执行状态. INSPECT 方法采用自动化、轻量级的手段植入临
时检查点作为对程序原有异常处理代码的替代, 因而难以完全覆盖可能出现错误执行状态的位置. 为此, 以相对于
一般程序中异常处理语句 (即开发者设置的 Try 代码块) 更高的密度植入检查点. 具体而言, 顺序扫描待测程序中

