From f0a73b329e1023897d1f20cebc0a01e5988acc62 Mon Sep 17 00:00:00 2001 From: Skylot Date: Wed, 6 Aug 2014 22:28:29 +0400 Subject: [PATCH] core: fix processing conditions in loop --- .../java/jadx/core/dex/nodes/BlockNode.java | 5 ++ .../dex/visitors/regions/IfMakerHelper.java | 13 ++++- .../dex/visitors/regions/RegionMaker.java | 3 +- .../main/java/jadx/core/utils/BlockUtils.java | 21 ++++++++ .../tests/internal/others/TestLoopInTry.java | 54 +++++++++++++++++++ 5 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 jadx-core/src/test/java/jadx/tests/internal/others/TestLoopInTry.java diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/BlockNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/BlockNode.java index 446648ac..44ed06fb 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/BlockNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/BlockNode.java @@ -86,6 +86,11 @@ public class BlockNode extends AttrNode implements IBlock { for (BlockNode b : sucList) { if (b.contains(AType.EXC_HANDLER)) { toRemove.add(b); + } else if (b.contains(AFlag.SYNTHETIC)) { + List s = b.getSuccessors(); + if (s.size() == 1 && s.get(0).contains(AType.EXC_HANDLER)) { + toRemove.add(b); + } } } if (block.contains(AFlag.LOOP_END)) { 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 703447ec..d8e8ffb0 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 @@ -18,9 +18,13 @@ import java.util.Collection; import java.util.List; import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import static jadx.core.utils.BlockUtils.isPathExists; public class IfMakerHelper { + private static final Logger LOG = LoggerFactory.getLogger(IfMakerHelper.class); private IfMakerHelper() { } @@ -59,10 +63,12 @@ public class IfMakerHelper { } else if (badElse) { info = new IfInfo(info.getCondition(), thenBlock, null); info.setOutBlock(null); + LOG.debug("Stop processing blocks after bad 'else' in 'if': {}, method: {}", info, mth); } else { info = IfInfo.invert(info); info = new IfInfo(info.getCondition(), info.getThenBlock(), null); info.setOutBlock(null); + LOG.debug("Stop processing blocks after bad 'then' in 'if': {}, method: {}", info, mth); } } else { List thenSC = thenBlock.getCleanSuccessors(); @@ -93,7 +99,12 @@ public class IfMakerHelper { private static boolean allPathsFromIf(BlockNode block, IfInfo info) { List preds = block.getPredecessors(); Set ifBlocks = info.getMergedBlocks(); - return ifBlocks.containsAll(preds); + for (BlockNode pred : preds) { + if (!ifBlocks.contains(pred) && !pred.contains(AFlag.LOOP_END)) { + return false; + } + } + return true; } private static boolean sameElements(Collection c1, Collection c2) { 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 f8924aaa..169c7302 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 @@ -231,7 +231,8 @@ public class RegionMaker { } LoopRegion loopRegion = new LoopRegion(curRegion, block, block == loop.getEnd()); boolean found; - if (block == loop.getStart() || block == loop.getEnd()) { + if (block == loop.getStart() || block == loop.getEnd() + || BlockUtils.isEmptySimplePath(loop.getStart(), block)) { found = true; } else if (block.getPredecessors().contains(loop.getStart())) { loopRegion.setPreCondition(loop.getStart()); 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 799d5bda..34a9f8fe 100644 --- a/jadx-core/src/main/java/jadx/core/utils/BlockUtils.java +++ b/jadx-core/src/main/java/jadx/core/utils/BlockUtils.java @@ -301,4 +301,25 @@ public class BlockUtils { } return list.isEmpty() ? Collections.emptyList() : list; } + + /** + * Return true if on path from start to end no instructions and no branches. + */ + public static boolean isEmptySimplePath(BlockNode start, BlockNode end) { + if (start == end && start.getInstructions().isEmpty()) { + return true; + } + if (!start.getInstructions().isEmpty() || start.getCleanSuccessors().size() != 1) { + return false; + } + BlockNode block = getNextBlock(start); + while (block != null + && block != end + && block.getCleanSuccessors().size() < 2 + && block.getPredecessors().size() == 1 + && block.getInstructions().isEmpty()) { + block = getNextBlock(block); + } + return block == end; + } } diff --git a/jadx-core/src/test/java/jadx/tests/internal/others/TestLoopInTry.java b/jadx-core/src/test/java/jadx/tests/internal/others/TestLoopInTry.java new file mode 100644 index 00000000..b25690cc --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/internal/others/TestLoopInTry.java @@ -0,0 +1,54 @@ +package jadx.tests.internal.others; + +import jadx.api.InternalJadxTest; +import jadx.core.dex.nodes.ClassNode; + +import org.junit.Test; + +import static jadx.tests.utils.JadxMatchers.containsOne; +import static org.junit.Assert.assertThat; + +public class TestLoopInTry extends InternalJadxTest { + + public static class TestCls { + private static boolean b = true; + + public int test() { + try { + if (b) { + throw new Exception(); + } + while (f()) { + s(); + } + } catch (Exception e) { + System.out.println("exception"); + return 1; + } + return 0; + } + + private static void s() { + } + + private static boolean f() { + return false; + } + } + + @Test + public void test() { + ClassNode cls = getClassNode(TestCls.class); + String code = cls.getCode().toString(); + System.out.println(code); + + assertThat(code, containsOne("try {")); + assertThat(code, containsOne("if (b) {")); + assertThat(code, containsOne("throw new Exception();")); + assertThat(code, containsOne("while (f()) {")); + assertThat(code, containsOne("s();")); + assertThat(code, containsOne("} catch (Exception e) {")); + assertThat(code, containsOne("return 1;")); + assertThat(code, containsOne("return 0;")); + } +} -- GitLab