Page 13 - 《软件学报》2026年第7期
P. 13
2698 软件学报 2026 年第 37 卷第 7 期
中多个与类型相关的编译器缺陷. Chen 等人 [15] 提出的 Java 测试程序变异方法 classfuzz, 其设计了一系列针对字
节码文件的变异规则, 例如, 修改变量类型及函数返回值类型等. 通过在种子程序上应用不同的变异规则生成新的
测试程序, 从而对 JVM 的启动阶段 (即加载、链接及初始化) 进行测试. 在此基础上, Chen 等人 [32] 进一步提出基
于活字节码 (live bytecode) 的测试程序生成方法 classming, 其首先获取已有测试程序中被执行的字节码序列, 随
后通过修改被执行字节码的控制流和数据流, 生成大量语义不同的变异体. 最后基于差分测试检测 JVM 执行引擎
中潜在的缺陷.
其他基于变异的 Java 测试程序生成方法均针对 JVM 中的 JIT 编译器进行测试. 例如, Wu 等人 [12] 提出了针
对 JVM 中 JIT 编译器的测试程序变异方法 JITFuzz, 其针对 JIT 编译器中不同的代码优化设计相应的变异规则,
例如, 函数内联及逃逸分析等. Jia 等人 [34] 提出从两个维度对 JIT 编译器进行测试的方法 JOpFuzzer, 其利用 TBar [35]
来对已有的测试程序进行变异, 涉及的变异规则包括修改数据类型以及函数调用等. 此外, JOpFuzzer 同时考虑生
成 JIT 编译器的不同优化选项配置, 通过打开或关闭不同的优化选项, 使得生成的测试程序能够覆盖更多的 JIT
编译器功能模块. Xie 等人 [13] 提出了基于优化交互的 JIT 编译器测试方法 MopFuzzer, 其同样基于 JIT 编译器的优
化功能设计不同的变异规则, 例如, 循环展开调用及锁消除调用等. 随后, 利用 JVM 的运行时数据引导生成触发不
同 JIT 优化组合的测试程序, 从而对 JIT 编译器不同优化的交互进行测试. Li 等人 [14] 提出了编译空间的概念, 并提
出基于变异的编译空间探索方法 Artemis, 其通过对测试程序中的函数调用进行修改, 改变其执行状态, 即解释执
行或 JIT 编译执行. 通过对比不同执行状态的执行结果, 从而检测 JIT 编译器中潜在的缺陷.
相似地, 现有基于变异的测试程序生成方法同样无法对新特性进行有效覆盖. 一方面, 现有工作的变异规则主
要围绕 JVM 中的特定组件 (例如, JIT 编译器) 而设计, 无法覆盖新特性 [12–14] ; 另一方面, 现有工作大多在字节码层
面直接生成 JVM 可以运行的测试程序 [15,32,34] . 然而, 语言新特性往往以语法糖的形式体现于 Java 源码层, 这导致
现有方法无法生成具备新特性触发条件的测试程序, 从而限制了其在新特性测试中的应用. 不同于上述方法, 本方
法一方面提升了对新特性行为的覆盖能力, 另一方面能够有效暴露 Java 编译器和 JVM 在支持新特性过程中可能
存在的实现缺陷, 弥补了语言新特性测试的不足.
2 动机示例
本节通过一个示例来展示 LumiX 的研究动机. 同时, 基于该示例分析为何现有研究方法无法对新特性进行有
效的测试.
图 1 展示了由 LumiX 生成的测试程序, 该测试程序成功检测出了 Java 编译器 ECJ 中关于 Java 8 新特性 Lambda
表达式的未知缺陷 (Bug #3792 [36] ). 具体来说, 该测试程序在第 1 行定义了一个值为 false 的布尔类型变量 DEBUG,
并在第 3 行定义了一个类型为 Object 的局部变量 o, 并在第 5 行为其重新赋值为一个新的 Object 类型对象. 随后
在第 6 行, 测试程序通过 if 语句判断 DEBUG 变量是否为 true, 若条件成立, 则执行 if 语句的代码体. 该代码体中
创建了一个新的线程, 并在线程中通过 Lambda 表达式指定了线程的执行逻辑. 然而, Lambda 表达式使用了局部
变量 o, 而 o 并未被声明为 final 变量, 且不满足 effectively final 条件 (即变量没有显式声明为 final, 但其值在初始
化后未被修改). 根据 Java 8 中 Lambda 的语法规范, 表达式中引用的局部变量必须是显式声明为 final 或者是
effectively final, 否则将被视为非法引用, 从而可能导致线程安全问题或内存泄漏等隐患. 在对该测试程序进行编
译时, javac 编译器能够成功检测到此类非法引用并抛出编译错误, 而 ECJ 编译器则未能识别出该错误, 并且生成
了一个错误的 class 文件.
需要注意的是, 图 1 中浅蓝色标记部分为 LumiX 向种子程序中插入的包含 Java 新特性的代码片段. 其中, Lambda
表达式是 Java 8 中引入的新特性, 用于简洁地表示匿名函数, 可作为参数传递给方法或赋值给变量, 是 Java 向函
数式编程迈出的关键一步. LumiX 首先利用程序分析工具识别出种子程序中可以复用的程序元素, 例如, 本示例中
的局部变量 o. 随后, 利用大模型生成 Lambda 表达式的代码片段, 并在生成的过程中复用了种子程序中的局部变
量 o, 如测试程序第 10 行所示. 该测试程序最终成功触发了 javac 编译器和 ECJ 编译器的不一致行为. 本工作随后

