diff --git a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java index efc2a958879..f3def9bafee 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java @@ -467,7 +467,9 @@ private void makeInsnBody(CodeWriter code, InsnNode insn, Set state) thro case MONITOR_EXIT: if (isFallback()) { code.add("monitor-exit("); - addArg(code, insn.getArg(0)); + if (insn.getArgsCount() == 1) { + addArg(code, insn.getArg(0)); + } code.add(')'); } break; diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/IfMakerHelper.java b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/IfMakerHelper.java index 8525b48f569..413ca6c8a66 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/IfMakerHelper.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/IfMakerHelper.java @@ -155,6 +155,10 @@ static IfInfo mergeNestedIfNodes(IfInfo currentIf) { if (curThen == curElse) { return null; } + if (BlockUtils.isFollowBackEdge(curThen) + || BlockUtils.isFollowBackEdge(curElse)) { + return null; + } boolean followThenBranch; IfInfo nextIf = getNextIf(currentIf, curThen); if (nextIf != null) { @@ -380,6 +384,9 @@ private static IfInfo getNextIfNodeInfo(IfInfo info, BlockNode block) { if (next.getPredecessors().size() != 1) { return null; } + if (next.contains(AFlag.ADDED_TO_REGION)) { + return null; + } List insns = block.getInstructions(); boolean pass = true; List forceInlineInsns = new ArrayList<>(); diff --git a/jadx-core/src/main/java/jadx/core/utils/BlockUtils.java b/jadx-core/src/main/java/jadx/core/utils/BlockUtils.java index 569dd5c0772..256a594fdb8 100644 --- a/jadx-core/src/main/java/jadx/core/utils/BlockUtils.java +++ b/jadx-core/src/main/java/jadx/core/utils/BlockUtils.java @@ -14,6 +14,7 @@ import jadx.core.dex.attributes.AFlag; import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.nodes.IgnoreEdgeAttr; +import jadx.core.dex.attributes.nodes.LoopInfo; import jadx.core.dex.attributes.nodes.PhiListAttr; import jadx.core.dex.instructions.IfNode; import jadx.core.dex.instructions.InsnType; @@ -137,6 +138,27 @@ public static boolean isBackEdge(BlockNode from, BlockNode to) { return from.getSuccessors().contains(to); } + public static boolean isFollowBackEdge(BlockNode block) { + if (block == null) { + return false; + } + if (block.contains(AFlag.LOOP_START)) { + List predecessors = block.getPredecessors(); + if (predecessors.size() == 1) { + BlockNode loopEndBlock = predecessors.get(0); + if (loopEndBlock.contains(AFlag.LOOP_END)) { + List loops = loopEndBlock.getAll(AType.LOOP); + for (LoopInfo loop : loops) { + if (loop.getStart().equals(block) && loop.getEnd().equals(loopEndBlock)) { + return true; + } + } + } + } + } + return false; + } + /** * Check if instruction contains in block (use == for comparison, not equals) */ diff --git a/jadx-core/src/test/java/jadx/tests/integration/loops/TestDoWhileBreak2.java b/jadx-core/src/test/java/jadx/tests/integration/loops/TestDoWhileBreak2.java new file mode 100644 index 00000000000..f1d302630f7 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/loops/TestDoWhileBreak2.java @@ -0,0 +1,47 @@ +package jadx.tests.integration.loops; + +import java.util.Arrays; +import java.util.Iterator; + +import org.junit.jupiter.api.Test; + +import jadx.tests.api.IntegrationTest; + +import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat; + +public class TestDoWhileBreak2 extends IntegrationTest { + + public static class TestCls { + Iterator it; + + @SuppressWarnings("ConstantConditions") + public Object test() { + String obj; + do { + obj = this.it.next(); + if (obj == null) { + return obj; // 'return null' works + } + } while (this.it.hasNext()); + return obj; + } + + public void check() { + this.it = Arrays.asList("a", "b").iterator(); + assertThat(test()).isEqualTo("b"); + + this.it = Arrays.asList("a", "b", null).iterator(); + assertThat(test()).isEqualTo(null); + } + } + + @Test + public void test() { + assertThat(getClassNode(TestCls.class)) + .code() + .containsLine(2, "do {") + .containsLine(3, "obj = this.it.next();") + .containsLine(3, "if (obj == null) {") + .containsLine(2, "} while (this.it.hasNext());"); + } +} diff --git a/jadx-core/src/test/java/jadx/tests/integration/loops/TestDoWhileBreak3.java b/jadx-core/src/test/java/jadx/tests/integration/loops/TestDoWhileBreak3.java new file mode 100644 index 00000000000..786d0e9bf91 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/loops/TestDoWhileBreak3.java @@ -0,0 +1,33 @@ +package jadx.tests.integration.loops; + +import java.util.Iterator; + +import org.junit.jupiter.api.Test; + +import jadx.NotYetImplemented; +import jadx.tests.api.IntegrationTest; + +import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat; + +public class TestDoWhileBreak3 extends IntegrationTest { + + public static class TestCls { + Iterator it; + + public void test() { + do { + if (!it.hasNext()) { + break; + } + } while (it.next() != null); + } + } + + @NotYetImplemented + @Test + public void test() { + assertThat(getClassNode(TestCls.class)) + .code() + .containsOnlyOnce("while"); + } +}