From e31fa6efd4efbc3f9fe4a2c85f83c8df1d475108 Mon Sep 17 00:00:00 2001 From: "M.Schmidt" Date: Wed, 9 Jul 2025 16:25:52 +0200 Subject: [PATCH 1/4] varreplacer draft --- .../scope/sootup/BoomerangPreInterceptor.java | 47 ++++++++++++++----- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/BoomerangPreInterceptor.java b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/BoomerangPreInterceptor.java index 87c0cc29..9dd606be 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/BoomerangPreInterceptor.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/BoomerangPreInterceptor.java @@ -18,6 +18,7 @@ import java.util.stream.Collectors; import org.jspecify.annotations.NonNull; import sootup.core.graph.MutableStmtGraph; +import sootup.core.graph.StmtGraph; import sootup.core.jimple.Jimple; import sootup.core.jimple.basic.*; import sootup.core.jimple.common.constant.ClassConstant; @@ -41,6 +42,8 @@ import sootup.core.types.ReferenceType; import sootup.core.views.View; +import javax.annotation.Nonnull; + public class BoomerangPreInterceptor implements BodyInterceptor { private final boolean TRANSFORM_CONSTANTS_SETTINGS; @@ -120,7 +123,7 @@ private void transformConstantsAtFieldWrites(Body.BodyBuilder body) { && rightOp instanceof Constant && !(rightOp instanceof ClassConstant)) { String label = LABEL + replaceCounter++; - Local local = Jimple.newLocal(label, rightOp.getType()); + Local local = new ReplacedLocal(label, leftOp, rightOp); JAssignStmt newAssignStmt = Jimple.newAssignStmt(local, rightOp, stmt.getPositionInfo()); body.addLocal(local); @@ -145,7 +148,7 @@ private void transformConstantsAtFieldWrites(Body.BodyBuilder body) { if (InvokeExprOpt.isPresent()) { if (filterTransformableInvokeExprs(stmt)) { - transformInInvokeExprs(body, stmt, InvokeExprOpt); + transformInInvokeExprs(body, stmt, InvokeExprOpt.get()); } } } @@ -178,9 +181,8 @@ protected boolean filterTransformableInvokeExprs(@NonNull Stmt stmt) { } private void transformInInvokeExprs( - Body.BodyBuilder body, Stmt stmt, Optional InvokeExprOpt) { + Body.BodyBuilder body, Stmt stmt, AbstractInvokeExpr invokeExpr) { List newArgs = new ArrayList<>(); - AbstractInvokeExpr invokeExpr = InvokeExprOpt.get(); for (int i = 0; i < invokeExpr.getArgCount(); i++) { Immediate arg = invokeExpr.getArg(i); @@ -304,11 +306,12 @@ private void addNullifiedFields(Body.BodyBuilder bodyBuilder, View view) { NullConstant.getInstance(), StmtPositionInfo.getNoStmtPositionInfo()); - Optional firstNonIdentityStmt = findFirstNonIdentityStmt(bodyBuilder); + MutableStmtGraph stmtGraph = bodyBuilder.getStmtGraph(); + Optional firstNonIdentityStmt = findFirstNonIdentityStmt(stmtGraph); if (firstNonIdentityStmt.isPresent()) { - bodyBuilder.getStmtGraph().insertBefore(firstNonIdentityStmt.get(), nullifiedFieldStmt); + stmtGraph.insertBefore(firstNonIdentityStmt.get(), nullifiedFieldStmt); } else { - bodyBuilder.getStmtGraph().addNode(nullifiedFieldStmt); + stmtGraph.addNode(nullifiedFieldStmt); } } } @@ -332,15 +335,33 @@ private Collection getDefinedFields(Body.BodyBuilder bodyBuilder return definedFields; } - private Optional findFirstNonIdentityStmt(Body.BodyBuilder bodyBuilder) { - for (Stmt stmt : bodyBuilder.getStmts()) { - if (stmt instanceof JIdentityStmt) { - continue; + private Optional findFirstNonIdentityStmt(StmtGraph stmtGraph) { + for (Stmt stmt : stmtGraph) { + if (stmt instanceof JIdentityStmt) { + continue; + } + return Optional.of(stmt); } + return Optional.empty(); + } - return Optional.of(stmt); + /** + * More expressive Local Replacement implementation with reference to the not replaced code Stmt + * */ + private static class ReplacedLocal extends Local { + + final Value lvalue; + + public ReplacedLocal(String label, Value lvalue, Value rvalue) { + super(label, rvalue.getType()); + this.lvalue = lvalue; } - return Optional.empty(); + @Nonnull + @Override + public String getName() { + return super.getName() + "_" + lvalue; + } } + } From 022915c7b06532bb2de017fd786c60ba9ad28a3f Mon Sep 17 00:00:00 2001 From: "M.Schmidt" Date: Thu, 10 Jul 2025 10:55:06 +0200 Subject: [PATCH 2/4] iterate / create less Lists --- .../scope/sootup/BoomerangPreInterceptor.java | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/BoomerangPreInterceptor.java b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/BoomerangPreInterceptor.java index 9dd606be..268887fb 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/BoomerangPreInterceptor.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/BoomerangPreInterceptor.java @@ -279,7 +279,8 @@ private void addNullifiedFields(Body.BodyBuilder bodyBuilder, View view) { sootClass.get().getFields().stream() .map(SootClassMember::getSignature) .collect(Collectors.toSet()); - Collection definedFields = getDefinedFields(bodyBuilder); + MutableStmtGraph graph = bodyBuilder.getStmtGraph(); + Collection definedFields = getDefinedFields(graph); for (FieldSignature fieldSignature : allFields) { if (definedFields.contains(fieldSignature)) { @@ -298,29 +299,31 @@ private void addNullifiedFields(Body.BodyBuilder bodyBuilder, View view) { // TODO Consider only Ref types or all types? if (field.get().getType() instanceof ReferenceType) { + // FIXME: don't build a body just for the this local! + Local thisLocal = bodyBuilder.build().getThisLocal(); JInstanceFieldRef nullifiedFieldRef = - Jimple.newInstanceFieldRef(bodyBuilder.build().getThisLocal(), fieldSignature); + Jimple.newInstanceFieldRef(thisLocal, fieldSignature); + JAssignStmt nullifiedFieldStmt = Jimple.newAssignStmt( nullifiedFieldRef, NullConstant.getInstance(), StmtPositionInfo.getNoStmtPositionInfo()); - MutableStmtGraph stmtGraph = bodyBuilder.getStmtGraph(); - Optional firstNonIdentityStmt = findFirstNonIdentityStmt(stmtGraph); + Optional firstNonIdentityStmt = findFirstNonIdentityStmt(graph); if (firstNonIdentityStmt.isPresent()) { - stmtGraph.insertBefore(firstNonIdentityStmt.get(), nullifiedFieldStmt); + graph.insertBefore(firstNonIdentityStmt.get(), nullifiedFieldStmt); } else { - stmtGraph.addNode(nullifiedFieldStmt); + graph.addNode(nullifiedFieldStmt); } } } } - private Collection getDefinedFields(Body.BodyBuilder bodyBuilder) { + private Collection getDefinedFields(StmtGraph stmtGraph) { Collection definedFields = new LinkedHashSet<>(); - for (Stmt stmt : bodyBuilder.getStmts()) { + for (Stmt stmt : stmtGraph) { if (stmt instanceof JAssignStmt) { LValue leftOp = ((JAssignStmt) stmt).getLeftOp(); From 6577c4809d1f99fe3574052f364f0df50ae92774 Mon Sep 17 00:00:00 2001 From: "M.Schmidt" Date: Thu, 10 Jul 2025 10:56:59 +0200 Subject: [PATCH 3/4] simpler way to create a new "this" Local --- .../java/boomerang/scope/sootup/BoomerangPreInterceptor.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/BoomerangPreInterceptor.java b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/BoomerangPreInterceptor.java index 268887fb..6d89fb45 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/BoomerangPreInterceptor.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/BoomerangPreInterceptor.java @@ -299,8 +299,7 @@ private void addNullifiedFields(Body.BodyBuilder bodyBuilder, View view) { // TODO Consider only Ref types or all types? if (field.get().getType() instanceof ReferenceType) { - // FIXME: don't build a body just for the this local! - Local thisLocal = bodyBuilder.build().getThisLocal(); + Local thisLocal = Jimple.newLocal("this", classType); JInstanceFieldRef nullifiedFieldRef = Jimple.newInstanceFieldRef(thisLocal, fieldSignature); From 457e87f9cc2d327034f5de66617a70c148e0eff9 Mon Sep 17 00:00:00 2001 From: "M.Schmidt" Date: Thu, 10 Jul 2025 14:21:40 +0200 Subject: [PATCH 4/4] improve interceptor performance --- .../scope/sootup/BoomerangPreInterceptor.java | 55 +++++++++---------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/BoomerangPreInterceptor.java b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/BoomerangPreInterceptor.java index 6d89fb45..aedf29bd 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/BoomerangPreInterceptor.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/scope/sootup/BoomerangPreInterceptor.java @@ -16,6 +16,8 @@ import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; + import org.jspecify.annotations.NonNull; import sootup.core.graph.MutableStmtGraph; import sootup.core.graph.StmtGraph; @@ -73,7 +75,7 @@ public void interceptBody(Body.@NonNull BodyBuilder bodyBuilder, @NonNull View v } } - private void addNopStatementsToMethod(Body.BodyBuilder body) { + private void addNopStatementsToMethod(Body.@NonNull BodyBuilder body) { // Initial nop statement JNopStmt initialNop = Jimple.newNopStmt(StmtPositionInfo.getNoStmtPositionInfo()); MutableStmtGraph stmtGraph = body.getStmtGraph(); @@ -105,9 +107,9 @@ private void addNopStatementsToMethod(Body.BodyBuilder body) { } private void transformConstantsAtFieldWrites(Body.BodyBuilder body) { - Collection stmtsWithConstants = getStatementsWithConstants(body); - for (Stmt stmt : stmtsWithConstants) { - if (stmt instanceof JAssignStmt) { + MutableStmtGraph stmtGraph = body.getStmtGraph(); + getStatementsWithConstants(body).forEach( stmt -> { + if (stmt instanceof JAssignStmt) { /* Transform simple assignments to two assignment steps: * - value = 10; * becomes @@ -122,20 +124,19 @@ private void transformConstantsAtFieldWrites(Body.BodyBuilder body) { if (isFieldRef(leftOp) && rightOp instanceof Constant && !(rightOp instanceof ClassConstant)) { + String label = LABEL + replaceCounter++; Local local = new ReplacedLocal(label, leftOp, rightOp); JAssignStmt newAssignStmt = Jimple.newAssignStmt(local, rightOp, stmt.getPositionInfo()); body.addLocal(local); - body.getStmtGraph().insertBefore(stmt, newAssignStmt); + stmtGraph.insertBefore(stmt, newAssignStmt); JAssignStmt updatedAssignStmt = Jimple.newAssignStmt(leftOp, local, stmt.getPositionInfo()); - body.getStmtGraph().replaceNode(stmt, updatedAssignStmt); + stmtGraph.replaceNode(stmt, updatedAssignStmt); } - } - - if (stmt.isInvokableStmt()) { + }else if (stmt.isInvokableStmt()) { /* Extract constant arguments to new assignments * - method(10) * becomes @@ -151,9 +152,8 @@ private void transformConstantsAtFieldWrites(Body.BodyBuilder body) { transformInInvokeExprs(body, stmt, InvokeExprOpt.get()); } } - } - if (stmt instanceof JReturnStmt) { + } else if (stmt instanceof JReturnStmt) { /* Transform return stmtsWithConstants into two stmtsWithConstants * - return 10 * becomes @@ -168,12 +168,13 @@ private void transformConstantsAtFieldWrites(Body.BodyBuilder body) { Jimple.newAssignStmt(local, returnStmt.getOp(), returnStmt.getPositionInfo()); body.addLocal(local); - body.getStmtGraph().insertBefore(stmt, assignStmt); + stmtGraph.insertBefore(stmt, assignStmt); JReturnStmt newReturnStmt = Jimple.newReturnStmt(local, returnStmt.getPositionInfo()); - body.getStmtGraph().replaceNode(stmt, newReturnStmt); + stmtGraph.replaceNode(stmt, newReturnStmt); } - } + }); + } protected boolean filterTransformableInvokeExprs(@NonNull Stmt stmt) { @@ -220,21 +221,20 @@ private void transformInInvokeExprs( } } - private Collection getStatementsWithConstants(Body.BodyBuilder body) { - Collection result = new HashSet<>(); + private Stream getStatementsWithConstants(Body.BodyBuilder body) { // Assign statements: If the right side is a constant // Consider arguments of invoke expressions // Check for constant return values - body.getStmts() - .forEach( + return body.getStmts().stream() + .filter( stmt -> { if (stmt instanceof JAssignStmt) { JAssignStmt assignStmt = (JAssignStmt) stmt; if (isFieldRef(assignStmt.getLeftOp()) && assignStmt.getRightOp() instanceof Constant) { - result.add(stmt); + return true; } } if (stmt.isInvokableStmt()) { @@ -244,7 +244,7 @@ private Collection getStatementsWithConstants(Body.BodyBuilder body) { if (invokeExpr.isPresent()) { for (Value arg : invokeExpr.get().getArgs()) { if (arg instanceof Constant) { - result.add(stmt); + return true; } } } @@ -253,12 +253,11 @@ private Collection getStatementsWithConstants(Body.BodyBuilder body) { if (stmt instanceof JReturnStmt) { JReturnStmt returnStmt = (JReturnStmt) stmt; if (returnStmt.getOp() instanceof Constant) { - result.add(stmt); + return true; } } + return false; }); - - return result; } private boolean isFieldRef(Value value) { @@ -267,7 +266,7 @@ private boolean isFieldRef(Value value) { || value instanceof JArrayRef; } - private void addNullifiedFields(Body.BodyBuilder bodyBuilder, View view) { + private void addNullifiedFields(Body.@NonNull BodyBuilder bodyBuilder, @NonNull View view) { ClassType classType = bodyBuilder.getMethodSignature().getDeclClassType(); Optional sootClass = view.getClass(classType); @@ -293,15 +292,15 @@ private void addNullifiedFields(Body.BodyBuilder bodyBuilder, View view) { continue; } - if (field.get().isStatic() || field.get().isFinal()) { + SootField sootField = field.get(); + if (sootField.isStatic() || sootField.isFinal()) { continue; } // TODO Consider only Ref types or all types? if (field.get().getType() instanceof ReferenceType) { - Local thisLocal = Jimple.newLocal("this", classType); - JInstanceFieldRef nullifiedFieldRef = - Jimple.newInstanceFieldRef(thisLocal, fieldSignature); + Local thisLocal = bodyBuilder.getLocals().stream().filter( l -> l.getName().equals("this")).findAny().orElseThrow(); + JInstanceFieldRef nullifiedFieldRef = Jimple.newInstanceFieldRef(thisLocal, fieldSignature); JAssignStmt nullifiedFieldStmt = Jimple.newAssignStmt(