core: prevent endless region processing (#340)

This commit is contained in:
Skylot
2018-08-23 20:56:32 +03:00
parent 0c041120f6
commit 7492889f4e
4 changed files with 34 additions and 15 deletions
@@ -1,5 +1,7 @@
package jadx.core.dex.instructions;
import java.util.List;
import com.android.dx.io.instructions.DecodedInstruction;
import jadx.core.dex.instructions.args.ArgType;
@@ -57,11 +59,12 @@ public class IfNode extends GotoNode {
@Override
public void initBlocks(BlockNode curBlock) {
thenBlock = getBlockByOffset(target, curBlock.getSuccessors());
if (curBlock.getSuccessors().size() == 1) {
List<BlockNode> successors = curBlock.getSuccessors();
thenBlock = getBlockByOffset(target, successors);
if (successors.size() == 1) {
elseBlock = thenBlock;
} else {
elseBlock = selectOther(thenBlock, curBlock.getSuccessors());
elseBlock = selectOther(thenBlock, successors);
}
}
@@ -2,6 +2,7 @@ package jadx.core.dex.visitors.regions;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import org.slf4j.Logger;
@@ -52,6 +53,12 @@ public class IfMakerHelper {
BlockNode thenBlock = info.getThenBlock();
BlockNode elseBlock = info.getElseBlock();
if (Objects.equals(thenBlock, elseBlock)) {
IfInfo ifInfo = new IfInfo(info, null, null);
ifInfo.setOutBlock(thenBlock);
return ifInfo;
}
// select 'then', 'else' and 'exit' blocks
if (thenBlock.contains(AFlag.RETURN) && elseBlock.contains(AFlag.RETURN)) {
info.setOutBlock(null);
@@ -60,21 +60,26 @@ public class RegionMaker {
private final MethodNode mth;
private int regionsCount;
private Region[] regionByBlock;
private BitSet processedBlocks;
public RegionMaker(MethodNode mth) {
this.mth = mth;
this.regionByBlock = new Region[mth.getBasicBlocks().size()];
this.processedBlocks = new BitSet(mth.getBasicBlocks().size());
}
public Region makeRegion(BlockNode startBlock, RegionStack stack) {
int startBlockId = startBlock.getId();
Region region = regionByBlock[startBlockId];
if (region != null) {
return region;
Region r = new Region(stack.peekRegion());
if (startBlock == null) {
return r;
}
Region r = new Region(stack.peekRegion());
int startBlockId = startBlock.getId();
if (processedBlocks.get(startBlockId)) {
mth.addWarn("Removed duplicated region for block: " + startBlock + " " + startBlock.getAttributesString());
return r;
}
processedBlocks.set(startBlockId);
BlockNode next = startBlock;
while (next != null) {
next = traverse(r, next, stack);
@@ -83,7 +88,6 @@ public class RegionMaker {
throw new JadxRuntimeException("Regions count limit reached");
}
}
regionByBlock[startBlockId] = r;
return r;
}
@@ -201,6 +205,7 @@ public class RegionMaker {
loopStart.remove(AType.LOOP);
loop.getEnd().add(AFlag.SKIP);
stack.addExit(loop.getEnd());
processedBlocks.clear(loopStart.getId());
Region body = makeRegion(loopStart, stack);
loopRegion.setBody(body);
loopStart.addAttr(AType.LOOP, loop);
@@ -296,6 +301,7 @@ public class RegionMaker {
curRegion.getSubBlocks().add(loopRegion);
loopStart.remove(AType.LOOP);
processedBlocks.clear(loopStart.getId());
stack.push(loopRegion);
BlockNode out = null;
@@ -850,7 +856,7 @@ public class RegionMaker {
}
private Map<BlockNode, List<Object>> reOrderSwitchCases(Map<BlockNode, List<Object>> blocksMap,
Map<BlockNode, BlockNode> fallThroughCases) {
Map<BlockNode, BlockNode> fallThroughCases) {
List<BlockNode> list = new ArrayList<>(blocksMap.size());
list.addAll(blocksMap.keySet());
list.sort((a, b) -> {
@@ -5,6 +5,7 @@ import org.junit.Test;
import jadx.core.dex.nodes.ClassNode;
import jadx.tests.api.IntegrationTest;
import static jadx.tests.api.utils.JadxMatchers.containsLines;
import static jadx.tests.api.utils.JadxMatchers.containsOne;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
@@ -18,10 +19,8 @@ public class TestWrongCode extends IntegrationTest {
return a.length;
}
@SuppressWarnings("empty")
private int test2(int a) {
if (a == 0) {
;
}
return a;
}
@@ -36,7 +35,11 @@ public class TestWrongCode extends IntegrationTest {
assertThat(code, containsOne("int[] a = null;"));
assertThat(code, containsOne("return a.length;"));
assertThat(code, containsString("return a == 0 ? a : a;"));
assertThat(code, containsLines(2,
"if (a == 0) {",
"}",
"return a;"
));
}
@Test