我已经在我的应用程序中发现了一个错误(使用soot处理字节码)只会出现在特定的字节码指令上。
我想为该特定案例创建一个测试。但是,我无法可靠地编写测试代码,这将编译为预期的字节码,然后会触发错误。
这是我尝试触发错误:
public void updateRhsOnIfEq() {
int x = 15;
int y = AircraftControl.readSensor(0);
// FIXME != in bytecode instead of ==
if (x == y) {
AircraftControl.readSensor(y);
}
else {
AircraftControl.readSensor(x);
}
}
问题是,编译器通过反转比较并切换两个分支来更改分支逻辑。正如您在下面的字节码中看到的那样,它会进行!=
比较,而不是==
。但是,我正在测试的错误仅由==
触发。
public void updateRhsOnIfEq();
0 bipush 15
2 istore_1 [x]
3 iconst_0
4 invokestatic AircraftControl.readSensor(int) : int [17]
7 istore_2 [y]
8 iload_1 [x]
9 iload_2 [y]
10 if_icmpne 21 <============================== Should be if_icmpeq
13 iload_2 [y]
14 invokestatic AircraftControl.readSensor(int) : int [17]
17 pop
18 goto 26
21 iload_1 [x]
22 invokestatic AircraftControl.readSensor(int) : int [17]
25 pop
26 return
有没有办法编写需要轻松生成可预测字节码的测试用例?鉴于存在不同的Java编译器,版本等,这是否可行?
答案 0 :(得分:2)
编译器不会更改分支逻辑。 这是编译器在这种情况下使用if_icmpne的自然行为(只是我的观点)要使(eclipse)编译器使用if_icmpeq
,只需按以下方式更改代码:
if (x != y) {
AircraftControl.readSensor(x);
}
else {
AircraftControl.readSensor(y);
}
此代码:
public static void main(String[] args) {
int x = (int) System.currentTimeMillis(), y = (int) System
.currentTimeMillis();
if (x != y) {
System.out.println("x != y");
} else {
System.out.println("x == y");
}
}
结果:
0: invokestatic #16 // Method java/lang/System.currentTimeMillis:()J
3: l2i
4: istore_1
5: invokestatic #16 // Method java/lang/System.currentTimeMillis:()J
8: l2i
9: istore_2
10: iload_1
11: iload_2
12: if_icmpeq 26
15: getstatic #22 // Field java/lang/System.out:Ljava/io/PrintStream;
18: ldc #26 // String x != y
20: invokevirtual #28 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
23: goto 34
26: getstatic #22 // Field java/lang/System.out:Ljava/io/PrintStream;
29: ldc #34 // String x == y
31: invokevirtual #28 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
34: return
答案 1 :(得分:2)
如果您需要特定的字节码指令,那么显而易见且最可靠的方法是直接在字节码中编写它。
我编写了一个可用的here开源汇编程序。对于简单的情况,你可以使用像Jasmin这样的东西,这可能会更好地记录下来。我也有一个反汇编程序,所以如果你只需要进行小的调整,你就可以编译一个Java类,反汇编,调整然后重新组装。
答案 2 :(得分:1)
解决如何生成测试用例的问题,你是对的。不同的Java编译器和同一编译器的不同版本可能会随着时间的推移产生不同的字节码。
您的替代方案是:
if_icmpne
更改为if_icmpeq
生成测试用例后,您需要捕获并将它们存储为类文件。不要依赖于能够在运行中重新生成它们。