From f37c23db7ad6eabb31ceb931db7d5b056047dc87 Mon Sep 17 00:00:00 2001 From: Skylot Date: Mon, 13 Dec 2021 18:14:27 +0000 Subject: [PATCH] fix: use correct top block for try blocks with same start (#1304) --- .../blocks/BlockExceptionHandler.java | 36 +++++++++---- .../main/java/jadx/core/utils/BlockUtils.java | 8 +-- .../main/java/jadx/core/utils/DebugUtils.java | 4 ++ .../trycatch/TestTryCatchFinally13.java | 52 +++++++++++++++++++ 4 files changed, 85 insertions(+), 15 deletions(-) create mode 100644 jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatchFinally13.java 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 cb70bfa6..362ac072 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 6235e4ca..4091ad2b 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 2c96de9f..ca711997 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 00000000..24430a34 --- /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 {"); + } +} -- GitLab