diff --git a/src/main/java/soot/JimpleBodyPack.java b/src/main/java/soot/JimpleBodyPack.java index 7767c20e639..b2a25a56f2f 100644 --- a/src/main/java/soot/JimpleBodyPack.java +++ b/src/main/java/soot/JimpleBodyPack.java @@ -92,6 +92,7 @@ private void applyPhaseOptions(JimpleBody b, Map opts) { pacman.getTransform("jb.lp").apply(b); // LocalPacker pacman.getTransform("jb.ne").apply(b); // NopEliminator pacman.getTransform("jb.uce").apply(b); // UnreachableCodeEliminator: Again, we might have new dead code + pacman.getTransform("jb.cp").apply(b); // CopyPropagator // LocalNameStandardizer: After all these changes, some locals // may end up being eliminated. If we want a stable local iteration diff --git a/src/test/java/soot/portedtest/RedundantJimpleStatementsTest.java b/src/test/java/soot/portedtest/RedundantJimpleStatementsTest.java index ab51952a5f7..1027b68433a 100644 --- a/src/test/java/soot/portedtest/RedundantJimpleStatementsTest.java +++ b/src/test/java/soot/portedtest/RedundantJimpleStatementsTest.java @@ -22,6 +22,7 @@ * #L% */ +import com.google.common.base.Joiner; import org.junit.Ignore; import org.junit.Test; import soot.*; @@ -58,23 +59,28 @@ public void loadClasses(String first, String... more) { Options.v().set_output_format(Options.output_format_jimple); Options.v().set_allow_phantom_refs(true); Options.v().set_ignore_resolving_levels(true); + PhaseOptions.v().setPhaseOption("jb", "stabilize-local-names:true"); + Scene.v().loadNecessaryClasses(); } - private List bodyStmtsAsStrings(Body body) { - List contentList = new ArrayList<>(); - for (Unit stmt : body.getUnits()) { - contentList.add(stmt.toString()); - } - return contentList; + private String bodyStmtsAsString(Body body) { + return Joiner.on('\n').join(body.getUnits()); } private void assertJimpleStmts(SootMethod method, List expectedStmts) { Body body = method.retrieveActiveBody(); assertNotNull(body); - List actualStmts = bodyStmtsAsStrings(body); + String actualStmts = bodyStmtsAsString(body); + + String exp = Joiner.on('\n').join(expectedStmts); + if (!exp.equals(actualStmts)) { + //Use a custom error message which is nicely readable; + //JUnits assertEquals mangles with the text, which makes it harder to retrieve the ground truth + throw new AssertionError(String.format("Expected:\n%s\n\nWas:\n%s", exp, actualStmts)); + } - assertEquals(expectedStmts, actualStmts); +} } @Test @@ -82,28 +88,28 @@ public void test01() { loadClasses(resourcePath, "java8", "bin"); SootMethod method = Scene.v().getMethod(""); List expectedBodyStmts = Stream.of( - "r6 := @this: MethodAcceptingLamExpr", - "r0 = staticinvoke ()", - "$r2 = ", - "$r1 = new java.lang.StringBuilder", - "specialinvoke $r1.()>()", - "$r3 = virtualinvoke $r1.(\"Percentage : \")", - "$d0 = interfaceinvoke r0.(45.0)", - "$r4 = virtualinvoke $r3.($d0)", - "$r5 = virtualinvoke $r4.()", - "virtualinvoke $r2.($r5)", - "return").collect(Collectors.toCollection(ArrayList::new)); + "r0 := @this: MethodAcceptingLamExpr", + "r1 = staticinvoke ()", + "$r2 = ", + "$r4 = new java.lang.StringBuilder", + "specialinvoke $r4.()>()", + "$r5 = virtualinvoke $r4.(\"Percentage : \")", + "$d0 = interfaceinvoke r1.(45.0)", + "$r6 = virtualinvoke $r5.($d0)", + "$r3 = virtualinvoke $r6.()", + "virtualinvoke $r2.($r3)", + "return" + ).collect(Collectors.toCollection(ArrayList::new)); assertJimpleStmts(method, expectedBodyStmts); } @Test public void test02() { loadClasses(resourcePath, "java9", "bin"); - List expectedBodyStmts = Stream.of( - "r1 = dynamicinvoke \"makeConcatWithConstants\" (\"This test\") (\"\\u0001 is cool\")", - "$r0 = ", - "virtualinvoke $r0.(r1)", - "return").collect(Collectors.toCollection(ArrayList::new)); + List expectedBodyStmts = Stream.of("r1 = dynamicinvoke \"makeConcatWithConstants\" (\"This test\") (\"\\u0001 is cool\")", + "$r0 = ", + "virtualinvoke $r0.(r1)", + "return").collect(Collectors.toCollection(ArrayList::new)); SootMethod method = Scene.v().getMethod(""); assertJimpleStmts(method, expectedBodyStmts); } @@ -112,14 +118,14 @@ public void test02() { public void test03() { loadClasses(resourcePath, "java11", "bin"); List expectedBodyStmts = Stream.of( - "r5 := @this: TypeInferenceLambda", - "r0 = staticinvoke ()", - "$r2 = staticinvoke (2)", - "$r1 = staticinvoke (3)", - "$r3 = interfaceinvoke r0.($r2, $r1)", - "$r4 = (java.lang.Integer) $r3", - "virtualinvoke $r4.()", - "return").collect(Collectors.toCollection(ArrayList::new)); + "r0 := @this: TypeInferenceLambda", + "r5 = staticinvoke ()", + "$r1 = staticinvoke (2)", + "$r2 = staticinvoke (3)", + "$r4 = interfaceinvoke r5.($r1, $r2)", + "$r3 = (java.lang.Integer) $r4", + "virtualinvoke $r3.()", + "return").collect(Collectors.toCollection(ArrayList::new)); SootMethod method = Scene.v().getMethod(""); assertJimpleStmts(method, expectedBodyStmts); } @@ -129,9 +135,9 @@ public void test04() { loadClasses(resourcePath, "java6", "bin"); List expectedBodyStmts = Stream.of( - "r0 := @this: Autoboxing", - "staticinvoke (6)", - "return").collect(Collectors.toCollection(ArrayList::new)); + "r0 := @this: Autoboxing", + "staticinvoke (6)", + "return").collect(Collectors.toCollection(ArrayList::new)); SootMethod method = Scene.v().getMethod(""); assertJimpleStmts(method, expectedBodyStmts); } @@ -141,54 +147,54 @@ public void test05() { loadClasses(resourcePath, "java6", "bin"); List expectedBodyStmts = Stream.of( - "r12 := @this: GenTypeParam", - "$r0 = new java.util.ArrayList", - "specialinvoke $r0.(int)>(3)", - "$r1 = newarray (java.lang.Integer)[3]", - "$r2 = staticinvoke (1)", - "$r1[0] = $r2", - "$r3 = staticinvoke (2)", - "$r1[1] = $r3", - "$r4 = staticinvoke (3)", - "$r1[2] = $r4", - "r5 = staticinvoke ($r1)", - "$r6 = new GenTypeParam", - "specialinvoke $r6.()>()", - "virtualinvoke $r6.($r0, r5)", - "$r7 = ", - "$r10 = staticinvoke (2)", - "$r9 = staticinvoke (8)", - "$r8 = staticinvoke (3)", - "$r11 = virtualinvoke $r6.($r10, $r9, $r8)", - "virtualinvoke $r7.($r11)", - "return").collect(Collectors.toCollection(ArrayList::new)); + "r00 := @this: GenTypeParam", + "$r11 = new java.util.ArrayList", + "specialinvoke $r11.(int)>(3)", + "$r09 = newarray (java.lang.Integer)[3]", + "$r03 = staticinvoke (1)", + "$r09[0] = $r03", + "$r04 = staticinvoke (2)", + "$r09[1] = $r04", + "$r05 = staticinvoke (3)", + "$r09[2] = $r05", + "r12 = staticinvoke ($r09)", + "$r01 = new GenTypeParam", + "specialinvoke $r01.()>()", + "virtualinvoke $r01.($r11, r12)", + "$r02 = ", + "$r06 = staticinvoke (2)", + "$r07 = staticinvoke (8)", + "$r08 = staticinvoke (3)", + "$r10 = virtualinvoke $r01.($r06, $r07, $r08)", + "virtualinvoke $r02.($r10)", + "return").collect(Collectors.toCollection(ArrayList::new)); SootMethod method = Scene.v().getMethod(""); assertJimpleStmts(method, expectedBodyStmts); } @Test - @Ignore("The variable names r10 and r11 may be used in swapped order") public void test06() { loadClasses(resourcePath, "java6", "bin"); List expectedBodyStmts = Stream.of( - "r9 := @this: Reflection", - "$r0 = new Reflection", - "specialinvoke $r0.()>()", - "r1 = class \"LReflection;\"", - "r11 = class \"LReflection;\"", - "r10 = class \"LReflection;\"", - "$r2 = ", - "virtualinvoke $r2.(class \"LReflection;\")", - "$r3 = newarray (java.lang.Class)[0]", - "r4 = virtualinvoke r11.($r3)", - "$r5 = ", - "$r6 = virtualinvoke r4.()", - "virtualinvoke $r5.($r6)", - "$r7 = ", - "$r8 = virtualinvoke r10.()", - "$i0 = lengthof $r8", - "virtualinvoke $r7.($i0)", - "return").collect(Collectors.toCollection(ArrayList::new)); + "r00 := @this: Reflection", + "$r01 = new Reflection", + "specialinvoke $r01.()>()", + "r05 = class \"LReflection;\"", + "r06 = class \"LReflection;\"", + "r07 = class \"LReflection;\"", + "$r02 = ", + "virtualinvoke $r02.(class \"LReflection;\")", + "$r08 = newarray (java.lang.Class)[0]", + "r10 = virtualinvoke r06.($r08)", + "$r03 = ", + "$r09 = virtualinvoke r10.()", + "virtualinvoke $r03.($r09)", + "$r04 = ", + "$r11 = virtualinvoke r07.()", + "$i00 = lengthof $r11", + "virtualinvoke $r04.($i00)", + "return" + ).collect(Collectors.toCollection(ArrayList::new)); SootMethod method = Scene.v().getMethod(""); assertJimpleStmts(method, expectedBodyStmts); } @@ -197,20 +203,20 @@ public void test06() { public void test07() { loadClasses(resourcePath, "java6", "bin"); List expectedBodyStmts = Stream.of( - "r7 := @this: UncheckedCast", - "$r0 = newarray (java.lang.Integer)[4]", - "$r1 = staticinvoke (5)", - "$r0[0] = $r1", - "$r2 = staticinvoke (8)", - "$r0[1] = $r2", - "$r3 = staticinvoke (9)", - "$r0[2] = $r3", - "$r4 = staticinvoke (6)", - "$r0[3] = $r4", - "r5 = staticinvoke ($r0)", - "$r6 = ", - "virtualinvoke $r6.(r5)", - "return").collect(Collectors.toCollection(ArrayList::new)); + "r0 := @this: UncheckedCast", + "$r6 = newarray (java.lang.Integer)[4]", + "$r2 = staticinvoke (5)", + "$r6[0] = $r2", + "$r3 = staticinvoke (8)", + "$r6[1] = $r3", + "$r4 = staticinvoke (9)", + "$r6[2] = $r4", + "$r5 = staticinvoke (6)", + "$r6[3] = $r5", + "r7 = staticinvoke ($r6)", + "$r1 = ", + "virtualinvoke $r1.(r7)", + "return").collect(Collectors.toCollection(ArrayList::new)); SootMethod method = Scene.v().getMethod(""); assertJimpleStmts(method, expectedBodyStmts); } @@ -219,14 +225,14 @@ public void test07() { public void test08() { loadClasses(resourcePath, "java11", "bin"); List expectedBodyStmts = Stream.of( - "r5 := @this: TypeInferenceLambda", - "r0 = staticinvoke ()", - "$r2 = staticinvoke (2)", - "$r1 = staticinvoke (3)", - "$r3 = interfaceinvoke r0.($r2, $r1)", - "$r4 = (java.lang.Integer) $r3", - "virtualinvoke $r4.()", - "return").collect(Collectors.toCollection(ArrayList::new)); + "r0 := @this: TypeInferenceLambda", + "r5 = staticinvoke ()", + "$r1 = staticinvoke (2)", + "$r2 = staticinvoke (3)", + "$r4 = interfaceinvoke r5.($r1, $r2)", + "$r3 = (java.lang.Integer) $r4", + "virtualinvoke $r3.()", + "return").collect(Collectors.toCollection(ArrayList::new)); SootMethod method = Scene.v().getMethod(""); assertJimpleStmts(method, expectedBodyStmts); @@ -237,16 +243,17 @@ public void test08() { public void test09() { loadClasses(resourcePath, "java9", "bin"); List expectedBodyStmts = Stream.of( - "r1 := @this: AnonymousDiamondOperator", - "$r6 = new AnonymousDiamondOperator$1", - "specialinvoke $r6.(AnonymousDiamondOperator)>(r1)", - "$r3 = staticinvoke (22)", - "$r2 = staticinvoke (23)", - "$r7 = (MyClass) $r6", - "$r4 = virtualinvoke $r7.($r3, $r2)", - "r5 = (java.lang.Integer) $r4", - "$i0 = virtualinvoke r5.()", - "return $i0").collect(Collectors.toCollection(ArrayList::new)); + "r0 := @this: AnonymousDiamondOperator", + "$r1 = new AnonymousDiamondOperator$1", + "specialinvoke $r1.(AnonymousDiamondOperator)>(r0)", + "$r3 = staticinvoke (22)", + "$r4 = staticinvoke (23)", + "$r2 = (MyClass) $r1", + "$r7 = virtualinvoke $r2.($r3, $r4)", + "$r5 = (java.lang.Integer) $r7", + "r6 = $r5", + "$i0 = virtualinvoke r6.()", + "return $i0").collect(Collectors.toCollection(ArrayList::new)); SootMethod method = Scene.v().getMethod(""); assertJimpleStmts(method, expectedBodyStmts); } @@ -255,17 +262,17 @@ public void test09() { public void test10() { loadClasses(resourcePath, "java6", "bin"); List expectedBodyStmts = Stream.of( - "r3 := @this: DeclareEnum", - "r0 = staticinvoke ()", - "i0 = lengthof r0", - "i1 = 0", - "if i1 >= i0 goto return", - "r1 = r0[i1]", - "$r2 = ", - "virtualinvoke $r2.(r1)", - "i1 = i1 + 1", - "goto [?= (branch)]", - "return").collect(Collectors.toCollection(ArrayList::new)); + "r0 := @this: DeclareEnum", + "r2 = staticinvoke ()", + "i0 = lengthof r2", + "i1 = 0", + "if i1 >= i0 goto return", + "r1 = r2[i1]", + "$r3 = ", + "virtualinvoke $r3.(r1)", + "i1 = i1 + 1", + "goto [?= (branch)]", + "return").collect(Collectors.toCollection(ArrayList::new)); SootMethod method = Scene.v().getMethod(""); assertJimpleStmts(method, expectedBodyStmts); } @@ -274,15 +281,15 @@ public void test10() { public void test11() { loadClasses(resourcePath, "java6", "bin"); List expectedBodyStmts = Stream.of( - "r1 := @this: GenericTypeParamOnClass", - "$r0 = new GenericTypeParamOnClass$A", - "specialinvoke $r0.(GenericTypeParamOnClass)>(r1)", - "$r2 = staticinvoke (5)", - "staticinvoke ($r0, $r2)", - "$r3 = virtualinvoke $r0.()", - "$r4 = (java.lang.Integer) $r3", - "virtualinvoke $r4.()", - "return").collect(Collectors.toCollection(ArrayList::new)); + "r0 := @this: GenericTypeParamOnClass", + "$r1 = new GenericTypeParamOnClass$A", + "specialinvoke $r1.(GenericTypeParamOnClass)>(r0)", + "$r2 = staticinvoke (5)", + "staticinvoke ($r1, $r2)", + "$r4 = virtualinvoke $r1.()", + "$r3 = (java.lang.Integer) $r4", + "virtualinvoke $r3.()", + "return").collect(Collectors.toCollection(ArrayList::new)); SootMethod method = Scene.v().getMethod(""); assertJimpleStmts(method, expectedBodyStmts); }