diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/blocks/BlockExceptionHandler.java b/jadx-core/src/main/java/jadx/core/dex/visitors/blocks/BlockExceptionHandler.java index cb70bfa66725796c5657eeb2bf88685282f6fc39..362ac072f18f27010f88996226c049e1d5c45aaf 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/blocks/BlockExceptionHandler.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/blocks/BlockExceptionHandler.java @@ -323,23 +323,14 @@ public class BlockExceptionHandler { private static boolean wrapBlocksWithTryCatch(MethodNode mth, TryCatchBlockAttr tryCatchBlock) { List blocks = tryCatchBlock.getBlocks(); BlockNode top = searchTopBlock(mth, blocks); - if (top.getPredecessors().isEmpty()) { + if (top.getPredecessors().isEmpty() && top != mth.getEnterBlock()) { return false; } BlockNode bottom = searchBottomBlock(mth, blocks); - if (Consts.DEBUG_EXC_HANDLERS) { LOG.debug("TryCatch #{} split: top {}, bottom: {}", tryCatchBlock.id(), top, bottom); } - - BlockNode topSplitterBlock; - if (top == mth.getEnterBlock()) { - BlockNode fixedTop = mth.getEnterBlock().getSuccessors().get(0); - topSplitterBlock = BlockSplitter.blockSplitTop(mth, fixedTop); - } else { - BlockNode existTopSplitter = BlockUtils.getBlockWithFlag(top.getPredecessors(), AFlag.EXC_TOP_SPLITTER); - topSplitterBlock = existTopSplitter != null ? existTopSplitter : BlockSplitter.blockSplitTop(mth, top); - } + BlockNode topSplitterBlock = getTopSplitterBlock(mth, top); topSplitterBlock.add(AFlag.EXC_TOP_SPLITTER); topSplitterBlock.add(AFlag.SYNTHETIC); @@ -356,6 +347,10 @@ public class BlockExceptionHandler { BlockSplitter.connect(bottom, bottomSplitterBlock); } + if (Consts.DEBUG_EXC_HANDLERS) { + LOG.debug("TryCatch #{} result splitters: top {}, bottom: {}", + tryCatchBlock.id(), topSplitterBlock, bottomSplitterBlock); + } connectSplittersAndHandlers(tryCatchBlock, topSplitterBlock, bottomSplitterBlock); for (BlockNode block : blocks) { @@ -373,6 +368,25 @@ public class BlockExceptionHandler { return true; } + private static BlockNode getTopSplitterBlock(MethodNode mth, BlockNode top) { + if (top == mth.getEnterBlock()) { + BlockNode fixedTop = mth.getEnterBlock().getSuccessors().get(0); + return BlockSplitter.blockSplitTop(mth, fixedTop); + } + BlockNode existPredTopSplitter = BlockUtils.getBlockWithFlag(top.getPredecessors(), AFlag.EXC_TOP_SPLITTER); + if (existPredTopSplitter != null) { + return existPredTopSplitter; + } + // try to reuse exists splitter on empty simple path below top block + if (top.getCleanSuccessors().size() == 1 && top.getInstructions().isEmpty()) { + BlockNode otherTopSplitter = BlockUtils.getBlockWithFlag(top.getCleanSuccessors(), AFlag.EXC_TOP_SPLITTER); + if (otherTopSplitter != null && otherTopSplitter.getPredecessors().size() == 1) { + return otherTopSplitter; + } + } + return BlockSplitter.blockSplitTop(mth, top); + } + private static BlockNode searchTopBlock(MethodNode mth, List blocks) { BlockNode top = BlockUtils.getTopBlock(blocks); if (top != null) { 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 6235e4cacbe4a6463424452b2828d7edbebacc86..4091ad2b28d391d066a549c2e69a5e53b41b32a6 100644 --- a/jadx-core/src/main/java/jadx/core/utils/BlockUtils.java +++ b/jadx-core/src/main/java/jadx/core/utils/BlockUtils.java @@ -572,9 +572,9 @@ public class BlockUtils { return traverseSuccessorsUntil(start, end, new BitSet(), false); } - public static BlockNode getTopBlock(Collection blocks) { + public static BlockNode getTopBlock(List blocks) { if (blocks.size() == 1) { - return blocks.iterator().next(); + return blocks.get(0); } for (BlockNode from : blocks) { boolean top = true; @@ -594,9 +594,9 @@ public class BlockUtils { /** * Search last block in control flow graph from input set. */ - public static BlockNode getBottomBlock(Collection blocks) { + public static BlockNode getBottomBlock(List blocks) { if (blocks.size() == 1) { - return blocks.iterator().next(); + return blocks.get(0); } for (BlockNode bottomCandidate : blocks) { boolean bottom = true; diff --git a/jadx-core/src/main/java/jadx/core/utils/DebugUtils.java b/jadx-core/src/main/java/jadx/core/utils/DebugUtils.java index 2c96de9fcd8ff2c5c1118ad5ea545a60b950da08..ca71199710eeea442875524a6bc4130a7e74c6e1 100644 --- a/jadx-core/src/main/java/jadx/core/utils/DebugUtils.java +++ b/jadx-core/src/main/java/jadx/core/utils/DebugUtils.java @@ -59,6 +59,10 @@ public class DebugUtils { } } + public static void dumpRawTest(MethodNode mth, String desc) { + dumpRaw(mth, desc, method -> method.getName().equals("test")); + } + public static void dumpRaw(MethodNode mth, String desc) { File out = new File("test-graph-" + desc + "-tmp"); DotGraphVisitor.dumpRaw().save(out, mth); diff --git a/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatchFinally13.java b/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatchFinally13.java new file mode 100644 index 0000000000000000000000000000000000000000..24430a34e6d6548409a5e78ab457de7f34c5e652 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatchFinally13.java @@ -0,0 +1,52 @@ +package jadx.tests.integration.trycatch; + +import jadx.tests.api.IntegrationTest; +import jadx.tests.api.extensions.inputs.InputPlugin; +import jadx.tests.api.extensions.inputs.TestWithInputPlugins; + +import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat; + +public class TestTryCatchFinally13 extends IntegrationTest { + + public static class TestCls { + public void test(int i) { + try { + doSomething1(); + if (i == -12) { + return; + } + if (i > 10) { + doSomething2(); + } else if (i == -1) { + doSomething3(); + } + } catch (Exception ex) { + logError(); + } finally { + doSomething4(); + } + } + + private void logError() { + } + + private void doSomething1() { + } + + private void doSomething2() { + } + + private void doSomething3() { + } + + private void doSomething4() { + } + } + + @TestWithInputPlugins({ InputPlugin.DEX, InputPlugin.JAVA }) + public void test() { + assertThat(getClassNode(TestCls.class)) + .code() + .containsOne("} finally {"); + } +}