diff --git a/src/main/java/jadx/dex/nodes/MethodNode.java b/src/main/java/jadx/dex/nodes/MethodNode.java index 351da71c4..dc9a53ff7 100644 --- a/src/main/java/jadx/dex/nodes/MethodNode.java +++ b/src/main/java/jadx/dex/nodes/MethodNode.java @@ -4,6 +4,7 @@ import jadx.Consts; import jadx.dex.attributes.AttrNode; import jadx.dex.attributes.AttributeFlag; import jadx.dex.attributes.JumpAttribute; +import jadx.dex.attributes.LoopAttr; import jadx.dex.attributes.annotations.Annotation; import jadx.dex.info.AccessInfo; import jadx.dex.info.AccessInfo.AFType; @@ -64,6 +65,7 @@ public class MethodNode extends AttrNode implements ILoadable { private IContainer region; private List exceptionHandlers; + private List loops = Collections.emptyList(); public MethodNode(ClassNode classNode, Method mthData) { this.mthInfo = MethodInfo.fromDex(classNode.dex(), mthData.getMethodIndex()); @@ -411,6 +413,21 @@ public class MethodNode extends AttrNode implements ILoadable { this.exitBlocks.add(exitBlock); } + public void registerLoop(LoopAttr loop) { + if(loops.isEmpty()) { + loops = new ArrayList(5); + } + loops.add(loop); + } + + public LoopAttr getLoopForBlock(BlockNode block) { + for (LoopAttr loop : loops) { + if(loop.getLoopBlocks().contains(block)) + return loop; + } + return null; + } + public ExceptionHandler addExceptionHandler(ExceptionHandler handler) { if (exceptionHandlers == null) { exceptionHandlers = new ArrayList(2); diff --git a/src/main/java/jadx/dex/visitors/BlockMakerVisitor.java b/src/main/java/jadx/dex/visitors/BlockMakerVisitor.java index c0ae7f59c..cd4ba6992 100644 --- a/src/main/java/jadx/dex/visitors/BlockMakerVisitor.java +++ b/src/main/java/jadx/dex/visitors/BlockMakerVisitor.java @@ -180,6 +180,8 @@ public class BlockMakerVisitor extends AbstractVisitor { if (i > 100) throw new AssertionError("Can't fix method cfg: " + mth); } + + registerLoops(mth); } private static BlockNode getBlock(int offset, Map blocksMap) { @@ -307,6 +309,16 @@ public class BlockMakerVisitor extends AbstractVisitor { } } + private static void registerLoops(MethodNode mth) { + for (BlockNode block : mth.getBasicBlocks()) { + AttributesList attributes = block.getAttributes(); + IAttribute loop = attributes.get(AttributeType.LOOP); + if(loop != null && attributes.contains(AttributeFlag.LOOP_START)) { + mth.registerLoop((LoopAttr) loop); + } + } + } + private static boolean modifyBlocksTree(MethodNode mth) { for (BlockNode block : mth.getBasicBlocks()) { if (block.getPredecessors().isEmpty() && block != mth.getEnterBlock()) { diff --git a/src/main/java/jadx/dex/visitors/regions/FinishRegions.java b/src/main/java/jadx/dex/visitors/regions/FinishRegions.java index 0874db3de..4de1aba56 100644 --- a/src/main/java/jadx/dex/visitors/regions/FinishRegions.java +++ b/src/main/java/jadx/dex/visitors/regions/FinishRegions.java @@ -1,33 +1,50 @@ package jadx.dex.visitors.regions; import jadx.dex.instructions.InsnType; +import jadx.dex.instructions.args.ArgType; +import jadx.dex.nodes.BlockNode; import jadx.dex.nodes.IBlock; import jadx.dex.nodes.IRegion; import jadx.dex.nodes.InsnNode; import jadx.dex.nodes.MethodNode; import jadx.dex.regions.LoopRegion; +import java.util.Iterator; import java.util.List; -public class FinishRegions implements IRegionVisitor { - +public class FinishRegions extends TracedRegionVisitor { @Override - public void processBlock(MethodNode mth, IBlock block) { + public void processBlockTraced(MethodNode mth, IBlock container, IRegion currentRegion) { + if (container.getClass() != BlockNode.class) + return; - // remove return from class init method - if (mth.getMethodInfo().isClassInit()) { + BlockNode block = (BlockNode) container; + + // remove last return in void functions + if (block.getCleanSuccessors().isEmpty() + && mth.getReturnType().equals(ArgType.VOID)) { List insns = block.getInstructions(); - if (insns.size() != 0) { - InsnNode last = insns.get(insns.size() - 1); - if (last.getType() == InsnType.RETURN) { - insns.remove(insns.size() - 1); + int lastIndex = insns.size() - 1; + if (lastIndex != -1) { + InsnNode last = insns.get(lastIndex); + if (last.getType() == InsnType.RETURN + && blockNotInLoop(mth, block)) { + insns.remove(lastIndex); } } } } - @Override - public void enterRegion(MethodNode mth, IRegion region) { + private boolean blockNotInLoop(MethodNode mth, BlockNode block) { + if (mth.getLoopForBlock(block) != null) + return false; + + for (Iterator it = regionStack.descendingIterator(); it.hasNext(); ) { + IRegion region = it.next(); + if (region.getClass() == LoopRegion.class) + return false; + } + return true; } @Override @@ -36,6 +53,6 @@ public class FinishRegions implements IRegionVisitor { LoopRegion loop = (LoopRegion) region; loop.mergePreCondition(); } + super.leaveRegion(mth, region); } - } diff --git a/src/main/java/jadx/dex/visitors/regions/TracedRegionVisitor.java b/src/main/java/jadx/dex/visitors/regions/TracedRegionVisitor.java index 4493c4800..1e71e2a42 100644 --- a/src/main/java/jadx/dex/visitors/regions/TracedRegionVisitor.java +++ b/src/main/java/jadx/dex/visitors/regions/TracedRegionVisitor.java @@ -4,11 +4,12 @@ import jadx.dex.nodes.IBlock; import jadx.dex.nodes.IRegion; import jadx.dex.nodes.MethodNode; -import java.util.Stack; +import java.util.ArrayDeque; +import java.util.Deque; public abstract class TracedRegionVisitor implements IRegionVisitor { - private final Stack regionStack = new Stack(); + protected final Deque regionStack = new ArrayDeque(); @Override public void enterRegion(MethodNode mth, IRegion region) { @@ -27,5 +28,4 @@ public abstract class TracedRegionVisitor implements IRegionVisitor { public void leaveRegion(MethodNode mth, IRegion region) { regionStack.pop(); } - }