前文 简单介绍了项目,根据熊英飞的这篇 An Empirical Study of Fault Localization Families and Their Combinations 开展实验。
Our experiments use the JavaSlicer dynamic slicing tool. JavaSlicer is based on the dynamic slicing algorithm of Wang and Roychoudhury, with extensions for object-oriented programs. The JavaSlicer implementation attaches to the program as a Java agent and re-writes classes as they are loaded into the Java VM.
A test fails by throwing an exception, either because of a violated assertion or a runtime crash. If there is only a single failed test, we use the execution of the statement that throws the exception as the slicing criterion. The slice then contains all statements that may have affected the statement that throws the exception.
If there are multiple failed tests, our experiments apply three strategies from a previous study to utilize multiple slices: union, intersection, and frequency . The first two strategies calculate the union or the intersection of the slices and report a set of statements as results. The frequency strategy calculates the inclusion frequency for each statement and reports a ranked list of statements based on the frequency. The more frequently a statement is included in the slice of a failed test, the more suspicious the statement is.
简单来说:单个失败测试,使用抛出异常的语句的执行作为切片准则。多个失败测试,采用并集、交集和频率的策略。
1.实验环境搭建
使用 b046ed3
的 Master 分支,运行环境与说明一致:
> ubuntu@VM-0-8-ubuntu:~$ javac -version
javac 1.6.0_20
> ubuntu@VM-0-8-ubuntu:~$ mvn -version
Apache Maven 2.2.0 (r788681; 2009-06-26 21:04:01+0800)
执行 assemble.sh
,报错 Plugin requires Maven version 2.2.1
。
配置换成 javac 1.8.0_281 / Apache Maven 3.3.9
则可以正常使用。
搭建 Defect4J 环境的相关内容不再赘述。
2.项目准备工作
以 Lang-61 为例,首先执行 Checkout:
defects4j checkout -p Lang -v 61b -w /home/ubuntu/lang_61_buggy
然后编译,可以借助 test
命令:
defects4j test
# 结果
Running ant (compile.tests)................................................ OK
Running ant (run.dev.tests)................................................ OK
Failing tests: 2
- org.apache.commons.lang.text.StrBuilderTest::testIndexOfLang294
- org.apache.commons.lang.text.StrBuilderTest::testLang294
同时获得了错误测试名称。然后执行单元测试,获得 Exception 信息:
java
-cp <classpath>
org.junit.runner.JUnitCore
<test class name>
# 示例
java
-cp /home/ubuntu/lib/junit-4.12.jar: # Junit jar包
/home/ubuntu/lib/hamcrest-core-1.3.jar: # hamcrest jar包
/home/ubuntu/lang_61_buggy/target/classes: # defects4j export -p dir.bin.classes 获得
/home/ubuntu/lang_61_buggy/target/tests # defects4j export -p dir.bin.tests 获得
org.junit.runner.JUnitCore
org.apache.commons.lang.text.StrBuilderTest # 删去失败测试::号后面具体方法
# 结果
JUnit version 4.12
......E........
Time: 0.061
There were 2 failures:
1) testIndexOfLang294(org.apache.commons.lang.text.StrBuilderTest)
junit.framework.AssertionFailedError: expected:<-1> but was:<6>
at junit.framework.Assert.fail(Assert.java:57) # -> junit.framework.Assert.fail:57
at junit.framework.Assert.failNotEquals(Assert.java:329)
..
2) testLang294(org.apache.commons.lang.text.StrBuilderTest)
java.lang.ArrayIndexOutOfBoundsException
at java.lang.System.arraycopy(Native Method) # 本地方法,跳过
at org.apache.commons.lang.text.StrBuilder.deleteImpl(StrBuilder.java:1114) # -> org.apache.commons.lang.text.StrBuilder.deleteImpl:1114
at org.apache.commons.lang.text.StrBuilder.deleteAll(StrBuilder.java:1188)
..
FAILURES!!!
Tests run: 73, Failures: 2
这部分信息,通过 test
自动生成的 failing_tests 文件也可以获得,或者直接从 D4J 项目中 framework/projects/Lang/trigger_tests
中获取。
3.生成跟踪文件
依据以下说明,生成 trace 文件。
You can also trace JUnit tests :
java -javaagent:... org.junit.runner.JUnitCore <test class name>
java
-javaagent:<tracer.jar>=tracefile:<trace file>
-cp <classpath>
org.junit.runner.JUnitCore
<test class name>
# 示例
java
-javaagent:/home/ubuntu/javaslicer/assembly/tracer.jar=tracefile:/home/ubuntu/trace/lang_61_1.trace
-cp /home/ubuntu/lib/junit-4.12.jar:
/home/ubuntu/lib/hamcrest-core-1.3.jar:
/home/ubuntu/lang_61_buggy/target/classes:
/home/ubuntu/lang_61_buggy/target/tests
org.junit.runner.JUnitCore
org.apache.commons.lang.text.StrBuilderTest
4.执行动态切片
对跟踪文件执行动态切片:
java
-Xmx <memory>
-jar <slicer.jar>
-p <trace file> <criterion/local>
>> <result file>
# 示例
java
-Xmx2g
-jar /home/ubuntu/javaslicer/assembly/slicer.jar
-p /home/ubuntu/trace/lang_61_1.trace
junit.framework.Assert.fail:57
>> /home/ubuntu/sliceRes/lang_61_1
输出结果:
0.0% done, time left: unknown
..
100.0% done, time left: 0:00:00
finished
The dynamic slice for criterion [junit.framework.Assert.fail:57]:
# 想要的结果
com.sun.proxy.$Proxy0.<init>:-1 ALOAD 0
com.sun.proxy.$Proxy0.<init>:-1 ALOAD 1
..
# 错误行
org.apache.commons.lang.text.StrBuilder.indexOf:1776 ALOAD 4
org.apache.commons.lang.text.StrBuilder.indexOf:1776 ARRAYLENGTH
org.apache.commons.lang.text.StrBuilder.indexOf:1776 ILOAD 3
org.apache.commons.lang.text.StrBuilder.indexOf:1776 ISUB
org.apache.commons.lang.text.StrBuilder.indexOf:1776 ISTORE 5
..
sun.reflect.generics.visitor.Reifier.visitClassTypeSignature:130 ALOAD 0
sun.reflect.generics.visitor.Reifier.visitClassTypeSignature:130 ALOAD 7
sun.reflect.generics.visitor.Reifier.visitClassTypeSignature:130 PUTFIELD sun/reflect/generics/visitor/Reifier.resultType Ljava/lang/reflect/Type;
Slice consists of 6178 bytecode instructions.
Computation took 15.12 seconds.
5.最终数据处理
只保留 org.apache.commons.lang 开头的项目行:
- 错误测试用例1:剩 132 行,错误行分布在 79 - 83。
- 错误测试用例2:剩 416 行,错误行分布在 248 - 252。
而使用 GZoltar 工具统计的 Spectra 有 973 行,切片可以显著缩减可疑语句数量。
附录:Shell脚本
# 写好了发我,谢谢~