From 52deb48aac643bbcd983fb04bb128b13b4879878 Mon Sep 17 00:00:00 2001 From: Skylot Date: Sat, 16 Mar 2019 20:51:25 +0300 Subject: [PATCH] fix: move instruction out of try/catch (#468) --- .../java/jadx/core/dex/nodes/InsnNode.java | 20 +++++++++ .../java/jadx/core/dex/nodes/MethodNode.java | 16 +++++-- .../trycatch/TestTryCatchStartOnMove.java | 33 ++++++++++++++ .../trycatch/TestTryCatchStartOnMove.smali | 45 +++++++++++++++++++ 4 files changed, 110 insertions(+), 4 deletions(-) create mode 100644 jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatchStartOnMove.java create mode 100644 jadx-core/src/test/smali/trycatch/TestTryCatchStartOnMove.smali diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java index 0d8348dce..f04dd9d12 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java @@ -316,4 +316,24 @@ public class InsnNode extends LineAttrNode { } return INSN_CLONER.deepClone(this); } + + public boolean canThrowException() { + switch (getType()) { + case RETURN: + case IF: + case GOTO: + case MOVE: + case MOVE_EXCEPTION: + case NEG: + case CONST: + case CONST_STR: + case CONST_CLASS: + case CMP_L: + case CMP_G: + return false; + + default: + return true; + } + } } diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java index 969ffd50d..b6067bdef 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java @@ -321,16 +321,24 @@ public class MethodNode extends LineAttrNode implements ILoadable, ICodeNode { int offset = aTry.getStartAddress(); int end = offset + aTry.getInstructionCount() - 1; - InsnNode insn = insnByOffset[offset]; - insn.add(AFlag.TRY_ENTER); + boolean tryBlockStarted = false; + InsnNode insn = null; while (offset <= end && offset >= 0) { insn = insnByOffset[offset]; - catchBlock.addInsn(insn); + if (insn != null) { + if (tryBlockStarted) { + catchBlock.addInsn(insn); + } else if (insn.canThrowException()) { + insn.add(AFlag.TRY_ENTER); + catchBlock.addInsn(insn); + tryBlockStarted = true; + } + } offset = InsnDecoder.getNextInsnOffset(insnByOffset, offset); } if (insnByOffset[end] != null) { insnByOffset[end].add(AFlag.TRY_LEAVE); - } else { + } else if (insn != null) { insn.add(AFlag.TRY_LEAVE); } } diff --git a/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatchStartOnMove.java b/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatchStartOnMove.java new file mode 100644 index 000000000..468a3a243 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatchStartOnMove.java @@ -0,0 +1,33 @@ +package jadx.tests.integration.trycatch; + +import org.junit.Test; + +import jadx.core.dex.nodes.ClassNode; +import jadx.tests.api.SmaliTest; + +import static jadx.tests.api.utils.JadxMatchers.containsOne; +import static org.junit.Assert.assertThat; + +public class TestTryCatchStartOnMove extends SmaliTest { + +// private static void test(String s) { +// try { +// call(s); +// } catch (Exception unused) { +// System.out.println("Failed call for " + s); +// } +// } +// +// private static void call(String s) { +// } + + @Test + public void test() { + ClassNode cls = getClassNodeFromSmaliWithPkg("trycatch", "TestTryCatchStartOnMove"); + String code = cls.getCode().toString(); + + assertThat(code, containsOne("try {")); + assertThat(code, containsOne("} catch (Exception e) {")); + assertThat(code, containsOne("System.out.println(\"Failed call for \" + str")); + } +} diff --git a/jadx-core/src/test/smali/trycatch/TestTryCatchStartOnMove.smali b/jadx-core/src/test/smali/trycatch/TestTryCatchStartOnMove.smali new file mode 100644 index 000000000..d09dffbee --- /dev/null +++ b/jadx-core/src/test/smali/trycatch/TestTryCatchStartOnMove.smali @@ -0,0 +1,45 @@ +.class public Ltrycatch/TestTryCatchStartOnMove; +.super Ljava/lang/Object; + + +# direct methods +.method private static test(Ljava/lang/String;)V + .registers 5 + + :try_start + move v3, p0 + invoke-static {v3}, Ltrycatch/TestTryCatchStartOnMove;->call(Ljava/lang/String;)V + :try_end + .catch Ljava/lang/Exception; {:try_start .. :try_end} :catch + + :goto_ret + return-void + + :catch + move-exception v0 + sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream; + new-instance v1, Ljava/lang/StringBuilder; + invoke-direct {v1}, Ljava/lang/StringBuilder;->()V + const-string v2, "Failed call for " + invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + move-result-object v1 + invoke-virtual {v1, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + move-result-object v1 + invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; + move-result-object v1 + invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V + goto :goto_ret +.end method + + +.method public constructor ()V + .registers 1 + invoke-direct {p0}, Ljadx/tests/api/SmaliTest;->()V + return-void +.end method + + +.method private static call(Ljava/lang/String;)V + .registers 1 + return-void +.end method