diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/SwitchNode.java b/jadx-core/src/main/java/jadx/core/dex/instructions/SwitchNode.java index ed4f79076..374ddd412 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/SwitchNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/SwitchNode.java @@ -119,14 +119,23 @@ public class SwitchNode extends TargetInsnNode { public String toString() { StringBuilder sb = new StringBuilder(); sb.append(super.toString()); - for (int i = 0; i < targets.length; i++) { - sb.append(CodeWriter.NL); - sb.append(" case ").append(keys[i]); - sb.append(": goto ").append(InsnUtils.formatOffset(targets[i])); - } - if (def != -1) { - sb.append(CodeWriter.NL); - sb.append(" default: goto ").append(InsnUtils.formatOffset(def)); + if (targetBlocks == null) { + for (int i = 0; i < keys.length; i++) { + sb.append(CodeWriter.NL); + sb.append(" case ").append(keys[i]).append(": goto ").append(InsnUtils.formatOffset(targets[i])); + } + if (def != -1) { + sb.append(CodeWriter.NL); + sb.append(" default: goto ").append(InsnUtils.formatOffset(def)); + } + } else { + for (int i = 0; i < keys.length; i++) { + sb.append(CodeWriter.NL); + sb.append(" case ").append(keys[i]).append(": goto ").append(targetBlocks[i]); + } + if (def != -1) { + sb.append(CodeWriter.NL).append(" default: goto ").append(defTargetBlock); + } } return sb.toString(); } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/RegionMaker.java b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/RegionMaker.java index 832b8123a..da956201e 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/RegionMaker.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/RegionMaker.java @@ -761,14 +761,30 @@ public class RegionMaker { out = calcPostDomOut(mth, block, mth.getExitBlocks()); } else { BlockNode loopEnd = loop.getEnd(); - // treat 'continue' as exit - out = calcPostDomOut(mth, block, loopEnd.getPredecessors()); - if (out != null) { - insertContinueInSwitch(block, out, loopEnd); + stack.addExit(loop.getStart()); + if (stack.containsExit(block) + || block == loopEnd + || loopEnd.getPredecessors().contains(block)) { + // in exits or last insn in loop => no 'out' block + out = null; } else { - // no 'continue' - out = calcPostDomOut(mth, block, Collections.singletonList(loopEnd)); + // treat 'continue' as exit + out = calcPostDomOut(mth, block, loopEnd.getPredecessors()); + if (out != null) { + insertContinueInSwitch(block, out, loopEnd); + } else { + // no 'continue' + out = calcPostDomOut(mth, block, Collections.singletonList(loopEnd)); + } } + if (out == loop.getStart()) { + // no other outs instead back edge to loop start + out = null; + } + } + if (out != null && processedBlocks.get(out.getId())) { + // out block already processed, prevent endless loop + throw new JadxRuntimeException("Failed to find switch 'out' block"); } SwitchRegion sw = new SwitchRegion(currentRegion, block); diff --git a/jadx-core/src/main/java/jadx/core/utils/ErrorsCounter.java b/jadx-core/src/main/java/jadx/core/utils/ErrorsCounter.java index fc88a662e..304c38267 100644 --- a/jadx-core/src/main/java/jadx/core/utils/ErrorsCounter.java +++ b/jadx-core/src/main/java/jadx/core/utils/ErrorsCounter.java @@ -21,6 +21,7 @@ import jadx.core.utils.exceptions.JadxOverflowException; public class ErrorsCounter { private static final Logger LOG = LoggerFactory.getLogger(ErrorsCounter.class); + private static final boolean PRINT_MTH_SIZE = true; private final Set errorNodes = new HashSet<>(); private int errorsCount; @@ -40,6 +41,10 @@ public class ErrorsCounter { errorsCount++; String msg = formatMsg(node, error); + if (PRINT_MTH_SIZE && node instanceof MethodNode) { + long insnsCount = ((MethodNode) node).countInsns(); + msg = "[" + insnsCount + "] " + msg; + } if (e == null) { LOG.error(msg); } else if (e instanceof JadxOverflowException) { diff --git a/jadx-core/src/test/java/jadx/tests/integration/switches/TestSwitchInLoop2.java b/jadx-core/src/test/java/jadx/tests/integration/switches/TestSwitchInLoop2.java new file mode 100644 index 000000000..e0fa866c2 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/switches/TestSwitchInLoop2.java @@ -0,0 +1,34 @@ +package jadx.tests.integration.switches; + +import org.junit.jupiter.api.Test; + +import jadx.tests.api.IntegrationTest; + +import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat; + +public class TestSwitchInLoop2 extends IntegrationTest { + public static class TestCls { + public boolean test() { + while (true) { + switch (call()) { + case 0: + return false; + case 1: + return true; + } + } + } + + private int call() { + return 0; + } + } + + @Test + public void test() { + assertThat(getClassNode(TestCls.class)) + .code() + .containsOne("while (true) {") + .containsOne("switch (call()) {"); + } +}