Commit d20cd43a authored by Skylot's avatar Skylot

core: fix loop handling

parent 7b4321ec
...@@ -21,6 +21,7 @@ import jadx.core.dex.nodes.MethodNode; ...@@ -21,6 +21,7 @@ import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.trycatch.CatchAttr; import jadx.core.dex.trycatch.CatchAttr;
import jadx.core.dex.visitors.AbstractVisitor; import jadx.core.dex.visitors.AbstractVisitor;
import jadx.core.utils.BlockUtils; import jadx.core.utils.BlockUtils;
import jadx.core.utils.exceptions.JadxOverflowException;
import jadx.core.utils.exceptions.JadxRuntimeException; import jadx.core.utils.exceptions.JadxRuntimeException;
import static jadx.core.dex.visitors.blocksmaker.BlockSplitter.connect; import static jadx.core.dex.visitors.blocksmaker.BlockSplitter.connect;
...@@ -68,11 +69,16 @@ public class BlockProcessor extends AbstractVisitor { ...@@ -68,11 +69,16 @@ public class BlockProcessor extends AbstractVisitor {
processNestedLoops(mth); processNestedLoops(mth);
} }
private static boolean removeEmptyBlock(MethodNode mth, BlockNode block) { private static boolean canRemoveBlock(BlockNode block) {
if (block.getInstructions().isEmpty() return block.getInstructions().isEmpty()
&& !block.isSynthetic() && !block.isSynthetic()
&& block.isAttrStorageEmpty() && block.isAttrStorageEmpty()
&& block.getSuccessors().size() <= 1) { && block.getSuccessors().size() <= 1
&& !block.getPredecessors().isEmpty();
}
private static boolean removeEmptyBlock(BlockNode block) {
if (canRemoveBlock(block)) {
LOG.debug("Removing empty block: {}", block); LOG.debug("Removing empty block: {}", block);
if (block.getSuccessors().size() == 1) { if (block.getSuccessors().size() == 1) {
BlockNode successor = block.getSuccessors().get(0); BlockNode successor = block.getSuccessors().get(0);
...@@ -245,7 +251,13 @@ public class BlockProcessor extends AbstractVisitor { ...@@ -245,7 +251,13 @@ public class BlockProcessor extends AbstractVisitor {
exit.setDomFrontier(EMPTY); exit.setDomFrontier(EMPTY);
} }
for (BlockNode block : mth.getBasicBlocks()) { for (BlockNode block : mth.getBasicBlocks()) {
try {
computeBlockDF(mth, block); computeBlockDF(mth, block);
} catch (StackOverflowError e) {
throw new JadxOverflowException("Failed compute block dominance frontier");
} catch (Exception e) {
throw new JadxRuntimeException("Failed compute block dominance frontier", e);
}
} }
} }
...@@ -253,7 +265,7 @@ public class BlockProcessor extends AbstractVisitor { ...@@ -253,7 +265,7 @@ public class BlockProcessor extends AbstractVisitor {
if (block.getDomFrontier() != null) { if (block.getDomFrontier() != null) {
return; return;
} }
block.getDominatesOn().forEach(c -> computeBlockDF(mth, c)); block.getDominatesOn().forEach(domBlock -> computeBlockDF(mth, domBlock));
List<BlockNode> blocks = mth.getBasicBlocks(); List<BlockNode> blocks = mth.getBasicBlocks();
BitSet domFrontier = null; BitSet domFrontier = null;
for (BlockNode s : block.getSuccessors()) { for (BlockNode s : block.getSuccessors()) {
...@@ -367,7 +379,7 @@ public class BlockProcessor extends AbstractVisitor { ...@@ -367,7 +379,7 @@ public class BlockProcessor extends AbstractVisitor {
} }
} }
for (BlockNode basicBlock : basicBlocks) { for (BlockNode basicBlock : basicBlocks) {
if (removeEmptyBlock(mth, basicBlock)) { if (removeEmptyBlock(basicBlock)) {
changed = true; changed = true;
} }
} }
......
package jadx.tests.integration.loops;
import org.junit.Test;
import jadx.core.dex.nodes.ClassNode;
import jadx.tests.api.SmaliTest;
import static jadx.tests.api.utils.JadxMatchers.containsOne;
import static jadx.tests.api.utils.JadxMatchers.countString;
import static org.hamcrest.Matchers.anyOf;
import static org.junit.Assert.assertThat;
public class TestLoopCondition5 extends SmaliTest {
public static class TestCls {
private static int lastIndexOf(int[] array, int target, int start, int end) {
for (int i = end - 1; i >= start; i--) {
if (array[i] == target) {
return i;
}
}
return -1;
}
}
@Test
public void test0() {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
assertThat(code, containsOne("for ("));
assertThat(code, containsOne("return -1;"));
assertThat(code, countString(2, "return "));
}
@Test
public void test1() {
ClassNode cls = getClassNodeFromSmaliWithPath("loops", "TestLoopCondition5");
String code = cls.getCode().toString();
assertThat(code, anyOf(containsOne("for ("), containsOne("while (true) {")));
assertThat(code, containsOne("return -1;"));
assertThat(code, countString(2, "return "));
}
}
.class public LTestLoopCondition5;
.super Ljava/lang/Object;
.source "TestLoopCondition5.java"
.method private static lastIndexOf([IIII)I
.locals 1
add-int/lit8 p3, p3, -0x1
:goto_0
const/4 v0, -0x1
if-lt p3, p2, :cond_1
.line 219
aget v0, p0, p3
if-ne v0, p1, :cond_0
return p3
:cond_0
add-int/lit8 p3, p3, -0x1
goto :goto_0
:cond_1
move p3, v0
return p3
.end method
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment