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 61ec24d58163a1cb8dc1d268478147bf6cc89cc2..3bab513354f9a462d47a80ca17f880280011242f 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 f858cb7700d917a3b3f774e063631b08732a021c..6902db9764afbe5ec4a7deeb5dcf4da57ff29c12 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,5 +1,20 @@ package jadx.core.dex.visitors.blocksmaker; +import java.util.ArrayList; +import java.util.BitSet; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.jetbrains.annotations.NotNull; +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; @@ -14,26 +29,15 @@ 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 java.util.ArrayList; -import java.util.BitSet; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - 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);