Page 170 - 《软件学报》2026年第7期
P. 170

宋壹 等: 基于异常检查点植入的软件缺陷定位方法                                                        2855


                 的所有函数, 以固定间隔       4  为函数植入检查点, 最终为被测程序中           20%  的函数植入检查点      (检查点植入具体密度
                 值的选择将在第      4.3  节中进一步分析).
                    需要说明的是, INSPECT     方法为待测程序植入的检查点仅会临时存在于缺陷定位任务中, 其并不会被真实地
                 引入到程序本身, 因此植入检查点这一操作不会增加程序的运行开销.
                  2.2   伪正确版本生成
                    与  SBFL、MBFL  技术采用覆盖信息、突变信息开展缺陷定位一样, 采用异常信息开展缺陷定位同样通过对
                 失败执行和通过执行进行比对, 得到指向底层缺陷根因位置的线索. 根据                      PIE  模型, 揭露了待测程序中缺陷语句存
                 在的失败测试用例, 其实际输出与预期输出不符的原因在于这些测试用例执行通过了缺陷语句, 导致执行状态受
                 到感染. 相对地, 通过测试用例的实际输出与预期输出一致, 其执行状态在一定程度上体现了程序的“标准行为”,
                 因而具备与失败执行进行比对的潜力. 原始无缺陷程序在真实调试环境下并不存在, 通过执行因而难以获得, 前
                 期  EXPECT  方法通过生成伪正确版本, 来获得一条失败测试用例对应的通过执行, 以进行比对. 具体而言, 伪正确
                 版本是指与待测错误程序不同, 能够将待测错误程序上一条失败测试用例转变为通过的程序版本 (因为得到该版
                 本的目的仅是获得失败测试用例对应的通过执行, 以对二者进行比对, 而非对错误程序进行修复, 因此该版本称为
                 “伪正确版本”). EXPECT    方法已经证实, 在程序自身含有足量异常处理语句的情况下, 基于伪正确版本得到的通
                 过测试用例具有体现程序“标准行为”的能力, 能够有效和失败执行进行比对并定位缺陷. 在程序自带异常处理语
                 句缺失、INSPECT    方法自动植入检查点的情况下, 通过测试用例是否仍具有这一能力有待检验.
                    本文以    Math  项目  [41] 为例, 通过探索性实验验证了这一推测. 例如, 现有              Math  项目的一个错误版本
                 (ArithmeticUtils.java 文件第  479  行中存在一处缺陷: “==”运算符被误写为“!=”), 如图    3  所示. 由于该缺陷的存在,
                 测试用例“testLcm”的实际输出与预期输出不一致, 被判为失败测试用例. 采用基于突变的策略生成不同于待测错
                 误程序的版本, 尝试获取能够使得测试用例“testLcm”执行通过的伪正确版本. 结果发现, 将源文件                      ArithmeticUtils.java
                 中第  509  行代码的“==”运算符变为“!=”, 可将失败测试用例“testLcm”变为通过. 按照与待测程序相同的方法在该
                 伪正确版本上植入检查点, 并收集异常触发信息, 将所收集的信息与在原始无缺陷                         Math  项目上收集的信息进行对
                 比. 结果显示, 虽然伪正确版本中仍存在缺陷语句, 但测试用例“testLcm”在伪正确版本上执行和在原始无缺陷版本
                 上执行收集到的异常触发信息保持了一致. 这表明在                 INSPECT  的工作环境下, 伪正确版本可以有效代替原始无缺
                 陷版本来获取通过执行. 该例子中植入的检查点、失败测试用例、失败和通过执行下的异常触发流以及程序源代
                 码, 在本文开源仓库中予以提供.

                   475. public static int lcm(int a, int b) throws MathArithmeticException{
                   476.   if (a == 0 || b == 0){
                   477.      return 0;}
                   478.   int lcm = FastMath.abs(ArithmeticUtils.mulAndCheck(a / gcd(a, b), b));
                   479.   if (lcm != Integer.MIN_VALUE) {  // 缺陷语句: “!=” 应为 “==”
                   480.      throw new MathArithmeticException(LocalizedFormats.LCM_OVERFLOW_32_BITS, a, b);}
                   481.   return lcm;}

                                                图 3 Math  项目的一个错误版本

                    为了进一步验证这一现象, 基于突变策略为上述                Math  项目生成  40  个含有缺陷的错误版本, 尝试为每个错误
                 版本的失败测试用例生成能够提供其通过执行的伪正确版本, 并比对测试用例在伪正确版本和原始无缺陷程序上
                 收集到的异常触发信息. 结果显示, 对于           100%  的失败测试用例, 都能够容易地获取到其伪正确版本, 且测试用例
                 在伪正确版本上基于植入的检查点收集到的异常触发信息与在原始程序上收集到的一致. 该结果提示, 在基于植
                 入检查点收集异常触发信息的情况下, 伪正确版本仍可以作为原始无缺陷程序的有效替代, 用以获取通过执行. 上
                 述探索性研究中      40  个错误版本的失败测试用例数量, 以及其失败测试用例在伪正确版本、原始无缺陷版本上收
                 集到的异常触发信息和比对结果, 在本文开源仓库中予以提供.
                    以上介绍了伪正确版本用于          INSPECT  工作流的可行性, 下面具体介绍伪正确版本的获取方法. 伪正确版本的
   165   166   167   168   169   170   171   172   173   174   175