fix: use correct top block for try blocks with same start (#1304)

This commit is contained in:
Skylot
2021-12-13 18:14:27 +00:00
parent d2bde0be21
commit f37c23db7a
4 changed files with 85 additions and 15 deletions
@@ -323,23 +323,14 @@ public class BlockExceptionHandler {
private static boolean wrapBlocksWithTryCatch(MethodNode mth, TryCatchBlockAttr tryCatchBlock) {
List<BlockNode> 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<BlockNode> blocks) {
BlockNode top = BlockUtils.getTopBlock(blocks);
if (top != null) {
@@ -572,9 +572,9 @@ public class BlockUtils {
return traverseSuccessorsUntil(start, end, new BitSet(), false);
}
public static BlockNode getTopBlock(Collection<BlockNode> blocks) {
public static BlockNode getTopBlock(List<BlockNode> 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<BlockNode> blocks) {
public static BlockNode getBottomBlock(List<BlockNode> blocks) {
if (blocks.size() == 1) {
return blocks.iterator().next();
return blocks.get(0);
}
for (BlockNode bottomCandidate : blocks) {
boolean bottom = true;
@@ -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);
@@ -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 {");
}
}