From 9cea0163fa676cca038e7381c5493f0e9ef7dcee Mon Sep 17 00:00:00 2001 From: Skylot Date: Sat, 29 Nov 2014 14:26:36 +0300 Subject: [PATCH] core: fix BlockNode hashCode function --- .../dex/attributes/nodes/IgnoreEdgeAttr.java | 2 +- .../java/jadx/core/dex/nodes/BlockNode.java | 16 +---- .../core/dex/visitors/SimplifyVisitor.java | 11 ++++ .../blocksmaker/BlockFinallyExtract.java | 14 +---- .../visitors/blocksmaker/BlockProcessor.java | 60 ++++++++++--------- .../main/java/jadx/core/utils/BlockUtils.java | 20 +++++++ .../trycatch/TestFinallyExtract.java | 1 - .../trycatch/TestTryCatchFinally2.java | 60 +++++++++++++++++++ 8 files changed, 128 insertions(+), 56 deletions(-) create mode 100644 jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatchFinally2.java diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/IgnoreEdgeAttr.java b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/IgnoreEdgeAttr.java index 4cb147a3b..c43afa6f1 100644 --- a/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/IgnoreEdgeAttr.java +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/IgnoreEdgeAttr.java @@ -10,7 +10,7 @@ import java.util.Set; public class IgnoreEdgeAttr implements IAttribute { - private final Set blocks = new HashSet(); + private final Set blocks = new HashSet(3); public Set getBlocks() { return blocks; 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 e9c619834..5920d2f94 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 @@ -179,7 +179,7 @@ public class BlockNode extends AttrNode implements IBlock { @Override public int hashCode() { - return id; // TODO id can change during reindex + return startOffset; } @Override @@ -187,23 +187,11 @@ public class BlockNode extends AttrNode implements IBlock { if (this == obj) { return true; } - if (obj == null) { - return false; - } - if (hashCode() != obj.hashCode()) { - return false; - } if (!(obj instanceof BlockNode)) { return false; } BlockNode other = (BlockNode) obj; - if (id != other.id) { - return false; - } - if (startOffset != other.startOffset) { - return false; - } - return true; + return id == other.id && startOffset == other.startOffset; } @Override diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/SimplifyVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/SimplifyVisitor.java index 2607accaa..6ed8d4885 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/SimplifyVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/SimplifyVisitor.java @@ -86,6 +86,17 @@ public class SimplifyVisitor extends AbstractVisitor { } break; + case MOVE: + InsnArg firstArg = insn.getArg(0); + if (firstArg.isLiteral()) { + InsnNode constInsn = new InsnNode(InsnType.CONST, 1); + constInsn.setResult(insn.getResult()); + constInsn.addArg(firstArg); + constInsn.copyAttributesFrom(insn); + return constInsn; + } + break; + default: break; } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockFinallyExtract.java b/jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockFinallyExtract.java index b3510fd2e..c6ac58984 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockFinallyExtract.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockFinallyExtract.java @@ -359,7 +359,7 @@ public class BlockFinallyExtract extends AbstractVisitor { BlockNode sOut = out.getSecond(); // redirect out edges - List filtPreds = filterPredecessors(sOut); + List filtPreds = BlockUtils.filterPredecessors(sOut); if (filtPreds.size() > 1) { BlockNode pred = sOut.getPredecessors().get(0); BlockNode newPred = BlockSplitter.insertBlockBetween(mth, pred, sOut); @@ -446,18 +446,6 @@ public class BlockFinallyExtract extends AbstractVisitor { edgeAttr.getBlocks().add(toBlock); } - private static List filterPredecessors(BlockNode block) { - List predecessors = block.getPredecessors(); - List list = new ArrayList(predecessors.size()); - for (BlockNode pred : predecessors) { - IgnoreEdgeAttr edgeAttr = pred.get(AType.IGNORE_EDGE); - if (edgeAttr == null || !edgeAttr.contains(block)) { - list.add(pred); - } - } - return list; - } - private static int countInstructions(ExceptionHandler excHandler) { int totalSize = 0; for (BlockNode excBlock : excHandler.getBlocks()) { diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockProcessor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockProcessor.java index 97f75cc10..eb3baed9b 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockProcessor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockProcessor.java @@ -315,34 +315,40 @@ public class BlockProcessor extends AbstractVisitor { return false; } BlockNode exitBlock = mth.getExitBlocks().get(0); - if (exitBlock.getPredecessors().size() > 1 - && exitBlock.getInstructions().size() == 1 - && !exitBlock.contains(AFlag.SYNTHETIC)) { - InsnNode returnInsn = exitBlock.getInstructions().get(0); - List preds = new ArrayList(exitBlock.getPredecessors()); - if (returnInsn.getArgsCount() != 0 && !isReturnArgAssignInPred(preds, returnInsn)) { - return false; - } - boolean first = true; - for (BlockNode pred : preds) { - BlockNode newRetBlock = BlockSplitter.startNewBlock(mth, exitBlock.getStartOffset()); - newRetBlock.add(AFlag.SYNTHETIC); - InsnNode newRetInsn; - if (first) { - newRetInsn = returnInsn; - newRetBlock.add(AFlag.ORIG_RETURN); - first = false; - } else { - newRetInsn = duplicateReturnInsn(returnInsn); - } - newRetBlock.getInstructions().add(newRetInsn); - removeConnection(pred, exitBlock); - connect(pred, newRetBlock); - } - cleanExitNodes(mth); - return true; + if (exitBlock.getInstructions().size() != 1 + || exitBlock.contains(AFlag.SYNTHETIC)) { + return false; } - return false; + List preds = exitBlock.getPredecessors(); + if (preds.size() < 2) { + return false; + } + preds = BlockUtils.filterPredecessors(exitBlock); + if (preds.size() < 2) { + return false; + } + InsnNode returnInsn = exitBlock.getInstructions().get(0); + if (returnInsn.getArgsCount() != 0 && !isReturnArgAssignInPred(preds, returnInsn)) { + return false; + } + boolean first = true; + for (BlockNode pred : preds) { + BlockNode newRetBlock = BlockSplitter.startNewBlock(mth, exitBlock.getStartOffset()); + newRetBlock.add(AFlag.SYNTHETIC); + InsnNode newRetInsn; + if (first) { + newRetInsn = returnInsn; + newRetBlock.add(AFlag.ORIG_RETURN); + first = false; + } else { + newRetInsn = duplicateReturnInsn(returnInsn); + } + newRetBlock.getInstructions().add(newRetInsn); + removeConnection(pred, exitBlock); + connect(pred, newRetBlock); + } + cleanExitNodes(mth); + return true; } private static boolean isReturnArgAssignInPred(List preds, InsnNode returnInsn) { 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 172c793fb..b48f033f4 100644 --- a/jadx-core/src/main/java/jadx/core/utils/BlockUtils.java +++ b/jadx-core/src/main/java/jadx/core/utils/BlockUtils.java @@ -2,6 +2,7 @@ package jadx.core.utils; import jadx.core.dex.attributes.AFlag; import jadx.core.dex.attributes.AType; +import jadx.core.dex.attributes.nodes.IgnoreEdgeAttr; import jadx.core.dex.attributes.nodes.PhiListAttr; import jadx.core.dex.instructions.IfNode; import jadx.core.dex.instructions.InsnType; @@ -79,6 +80,25 @@ public class BlockUtils { return ret; } + /** + * Return predecessors list without blocks contains 'IGNORE_EDGE' attribute. + * + * @return new list of filtered predecessors + */ + public static List filterPredecessors(BlockNode block) { + List predecessors = block.getPredecessors(); + List list = new ArrayList(predecessors.size()); + for (BlockNode pred : predecessors) { + IgnoreEdgeAttr edgeAttr = pred.get(AType.IGNORE_EDGE); + if (edgeAttr == null) { + list.add(pred); + } else if (!edgeAttr.contains(block)) { + list.add(pred); + } + } + return list; + } + public static boolean isBackEdge(BlockNode from, BlockNode to) { if (to == null) { return false; diff --git a/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestFinallyExtract.java b/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestFinallyExtract.java index cc008d4f2..d1d02511d 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestFinallyExtract.java +++ b/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestFinallyExtract.java @@ -30,7 +30,6 @@ public class TestFinallyExtract extends IntegrationTest { @Test public void test() { - setOutputCFG(); ClassNode cls = getClassNode(TestCls.class); String code = cls.getCode().toString(); diff --git a/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatchFinally2.java b/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatchFinally2.java new file mode 100644 index 000000000..41527defa --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatchFinally2.java @@ -0,0 +1,60 @@ +package jadx.tests.integration.trycatch; + +import jadx.core.clsp.NClass; +import jadx.core.dex.nodes.ClassNode; +import jadx.tests.api.IntegrationTest; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import org.junit.Test; + +import static jadx.tests.api.utils.JadxMatchers.containsOne; +import static org.junit.Assert.assertThat; + +public class TestTryCatchFinally2 extends IntegrationTest { + + public static class TestCls { + private NClass[] classes; + + public void test(OutputStream output) throws IOException { + DataOutputStream out = new DataOutputStream(output); + try { + out.writeByte(1); + out.writeInt(classes.length); + for (NClass cls : classes) { + writeString(out, cls.getName()); + } + for (NClass cls : classes) { + NClass[] parents = cls.getParents(); + out.writeByte(parents.length); + for (NClass parent : parents) { + out.writeInt(parent.getId()); + } + } + } finally { + out.close(); + } + } + + private void writeString(DataOutputStream out, String name) { + } + } + + @Test + public void test() { + ClassNode cls = getClassNode(TestCls.class); + String code = cls.getCode().toString(); + + assertThat(code, containsOne("} finally {")); + assertThat(code, containsOne("out.close();")); + + assertThat(code, containsOne("for (NClass parent : parents) {")); + + // TODO +// assertThat(code, countString(2, "for (NClass cls : classes) {")); + assertThat(code, containsOne("for (NClass cls : this.classes) {")); + assertThat(code, containsOne("for (NClass cls2 : this.classes) {")); + } +}