From c410914208a30471884357a4f6e42e95f371f287 Mon Sep 17 00:00:00 2001 From: Skylot Date: Sun, 4 Mar 2018 19:18:53 +0300 Subject: [PATCH] core: skip finally extract visitor on error --- .../core/dex/visitors/DepthTraversal.java | 3 + .../blocksmaker/BlockFinallyExtract.java | 103 ++++++++++++------ 2 files changed, 70 insertions(+), 36 deletions(-) diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/DepthTraversal.java b/jadx-core/src/main/java/jadx/core/dex/visitors/DepthTraversal.java index 61ec24d58..3bab51335 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/DepthTraversal.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/DepthTraversal.java @@ -34,4 +34,7 @@ public class DepthTraversal { e.getClass().getSimpleName() + " in pass: " + visitor.getClass().getSimpleName(), e); } } + + private DepthTraversal() { + } } 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 f858cb770..6902db976 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 @@ -1,25 +1,5 @@ package jadx.core.dex.visitors.blocksmaker; -import jadx.core.dex.attributes.AFlag; -import jadx.core.dex.attributes.AType; -import jadx.core.dex.attributes.nodes.IgnoreEdgeAttr; -import jadx.core.dex.instructions.InsnType; -import jadx.core.dex.instructions.args.InsnArg; -import jadx.core.dex.instructions.args.RegisterArg; -import jadx.core.dex.nodes.BlockNode; -import jadx.core.dex.nodes.InsnNode; -import jadx.core.dex.nodes.MethodNode; -import jadx.core.dex.trycatch.CatchAttr; -import jadx.core.dex.trycatch.ExceptionHandler; -import jadx.core.dex.trycatch.SplitterBlockAttr; -import jadx.core.dex.trycatch.TryCatchBlock; -import jadx.core.dex.visitors.AbstractVisitor; -import jadx.core.dex.visitors.blocksmaker.helpers.BlocksPair; -import jadx.core.dex.visitors.blocksmaker.helpers.BlocksRemoveInfo; -import jadx.core.dex.visitors.ssa.LiveVarAnalysis; -import jadx.core.utils.BlockUtils; -import jadx.core.utils.exceptions.JadxRuntimeException; - import java.util.ArrayList; import java.util.BitSet; import java.util.HashSet; @@ -34,6 +14,30 @@ import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import jadx.core.Jadx; +import jadx.core.dex.attributes.AFlag; +import jadx.core.dex.attributes.AType; +import jadx.core.dex.attributes.nodes.IgnoreEdgeAttr; +import jadx.core.dex.instructions.InsnType; +import jadx.core.dex.instructions.args.InsnArg; +import jadx.core.dex.instructions.args.RegisterArg; +import jadx.core.dex.nodes.BlockNode; +import jadx.core.dex.nodes.InsnNode; +import jadx.core.dex.nodes.MethodNode; +import jadx.core.dex.trycatch.CatchAttr; +import jadx.core.dex.trycatch.ExceptionHandler; +import jadx.core.dex.trycatch.SplitterBlockAttr; +import jadx.core.dex.trycatch.TryCatchBlock; +import jadx.core.dex.visitors.AbstractVisitor; +import jadx.core.dex.visitors.DepthTraversal; +import jadx.core.dex.visitors.IDexTreeVisitor; +import jadx.core.dex.visitors.blocksmaker.helpers.BlocksPair; +import jadx.core.dex.visitors.blocksmaker.helpers.BlocksRemoveInfo; +import jadx.core.dex.visitors.ssa.LiveVarAnalysis; +import jadx.core.utils.BlockUtils; +import jadx.core.utils.ErrorsCounter; +import jadx.core.utils.exceptions.JadxRuntimeException; + import static jadx.core.dex.visitors.blocksmaker.BlockSplitter.connect; import static jadx.core.dex.visitors.blocksmaker.BlockSplitter.insertBlockBetween; import static jadx.core.dex.visitors.blocksmaker.BlockSplitter.removeConnection; @@ -46,16 +50,34 @@ public class BlockFinallyExtract extends AbstractVisitor { if (mth.isNoCode() || mth.isNoExceptionHandlers()) { return; } - - boolean reloadBlocks = false; - for (ExceptionHandler excHandler : mth.getExceptionHandlers()) { - if (processExceptionHandler(mth, excHandler)) { - reloadBlocks = true; + try { + boolean reloadBlocks = false; + for (ExceptionHandler excHandler : mth.getExceptionHandlers()) { + if (processExceptionHandler(mth, excHandler)) { + reloadBlocks = true; + } + } + if (reloadBlocks) { + mergeReturnBlocks(mth); + BlockProcessor.rerun(mth); + } + } catch (Exception e) { + LOG.warn("Undo finally extract visitor, mth: {}", mth, e); + try { + // reload method without applying this visitor + // TODO: make more common and less hacky + mth.unload(); + mth.load(); + List passes = Jadx.getPassesList(mth.root().getArgs()); + for (IDexTreeVisitor visitor : passes) { + if (visitor instanceof BlockFinallyExtract) { + break; + } + DepthTraversal.visit(visitor, mth); + } + } catch (Exception ee) { + LOG.error("Undo finally extract failed, mth: {}", mth, e); } - } - if (reloadBlocks) { - mergeReturnBlocks(mth); - BlockProcessor.rerun(mth); } } @@ -221,7 +243,7 @@ public class BlockFinallyExtract extends AbstractVisitor { } private static void performVariablesReMap(MethodNode mth, List removes, - LiveVarAnalysis laBefore, LiveVarAnalysis laAfter) { + LiveVarAnalysis laBefore, LiveVarAnalysis laAfter) { BitSet processed = new BitSet(mth.getRegsCount()); for (BlocksRemoveInfo removeInfo : removes) { processed.clear(); @@ -390,7 +412,7 @@ public class BlockFinallyExtract extends AbstractVisitor { } private static boolean checkInsns(List remInsns, List startInsns, int delta, - @Nullable BlocksRemoveInfo removeInfo) { + @Nullable BlocksRemoveInfo removeInfo) { for (int i = startInsns.size() - 1; i >= 0; i--) { InsnNode startInsn = startInsns.get(i); InsnNode remInsn = remInsns.get(delta + i); @@ -402,7 +424,7 @@ public class BlockFinallyExtract extends AbstractVisitor { } private static boolean checkBlocksTree(BlockNode remBlock, BlockNode startBlock, - @NotNull BlocksRemoveInfo removeInfo, BitSet bs) { + @NotNull BlocksRemoveInfo removeInfo, BitSet bs) { // skip check on start block if (!removeInfo.getProcessed().isEmpty() && !sameBlocks(remBlock, startBlock, removeInfo)) { @@ -436,7 +458,7 @@ public class BlockFinallyExtract extends AbstractVisitor { } private static boolean sameBlocks(BlockNode remBlock, BlockNode finallyBlock, - @NotNull BlocksRemoveInfo removeInfo) { + @NotNull BlocksRemoveInfo removeInfo) { List first = remBlock.getInstructions(); List second = finallyBlock.getInstructions(); if (first.size() < second.size()) { @@ -495,6 +517,12 @@ public class BlockFinallyExtract extends AbstractVisitor { LOG.warn("Finally extract failed: remBlock pred: {}, {}, method: {}", remBlock, remBlock.getPredecessors(), mth); return false; } + if (removeInfo.getOuts().isEmpty()) { + ErrorsCounter.methodError(mth, "Failed to extract finally block: empty outs"); + return false; + } + // safe checks finished, altering blocks tree + // all error must throw exception to undo changes BlockNode remBlockPred = remBlock.getPredecessors().get(0); removeInfo.setStartPredecessor(remBlockPred); @@ -534,7 +562,11 @@ public class BlockFinallyExtract extends AbstractVisitor { } } - BlocksPair out = removeInfo.getOuts().iterator().next(); + Set outs = removeInfo.getOuts(); + if (outs.isEmpty()) { + throw new JadxRuntimeException("Failed to extract finally block: all outs is deleted"); + } + BlocksPair out = outs.iterator().next(); BlockNode rOut = out.getFirst(); BlockNode sOut = out.getSecond(); @@ -556,8 +588,7 @@ public class BlockFinallyExtract extends AbstractVisitor { BlockNode pred = filtPreds.get(0); BlockNode repl = removeInfo.getBySecond(pred); if (repl == null) { - LOG.error("Block not found by {}, in {}, method: {}", pred, removeInfo, mth); - return false; + throw new JadxRuntimeException("Block not found by " + pred + ", in " + removeInfo); } removeConnection(pred, rOut); addIgnoredEdge(repl, rOut);