From 3fcbca94568b6ca75354e82fbece7539fc3eb862 Mon Sep 17 00:00:00 2001 From: Skylot Date: Thu, 2 May 2013 18:18:15 +0400 Subject: [PATCH] Fix try/catch/finally block processing --- .../jadx/dex/trycatch/ExceptionHandler.java | 18 +++++-- .../java/jadx/dex/trycatch/TryCatchBlock.java | 51 +++++++++++++++++-- .../java/jadx/dex/visitors/ModVisitor.java | 23 +-------- .../java/jadx/samples/TestTryCatch.java | 32 ++++++++++++ 4 files changed, 95 insertions(+), 29 deletions(-) diff --git a/src/main/java/jadx/dex/trycatch/ExceptionHandler.java b/src/main/java/jadx/dex/trycatch/ExceptionHandler.java index 88c2065c3..72dcc25e5 100644 --- a/src/main/java/jadx/dex/trycatch/ExceptionHandler.java +++ b/src/main/java/jadx/dex/trycatch/ExceptionHandler.java @@ -2,7 +2,7 @@ package jadx.dex.trycatch; import jadx.Consts; import jadx.dex.info.ClassInfo; -import jadx.dex.instructions.args.InsnArg; +import jadx.dex.instructions.args.RegisterArg; import jadx.dex.nodes.BlockNode; import jadx.dex.nodes.IContainer; import jadx.utils.InsnUtils; @@ -18,7 +18,9 @@ public class ExceptionHandler { private BlockNode handleBlock; private final List blocks = new ArrayList(); private IContainer handlerRegion; - private InsnArg arg; + private RegisterArg arg; + + private TryCatchBlock tryBlock; public ExceptionHandler(int addr, ClassInfo type) { this.handleOffset = addr; @@ -61,14 +63,22 @@ public class ExceptionHandler { this.handlerRegion = handlerRegion; } - public InsnArg getArg() { + public RegisterArg getArg() { return arg; } - public void setArg(InsnArg arg) { + public void setArg(RegisterArg arg) { this.arg = arg; } + public void setTryBlock(TryCatchBlock tryBlock) { + this.tryBlock = tryBlock; + } + + public TryCatchBlock getTryBlock() { + return tryBlock; + } + @Override public int hashCode() { return (catchType == null ? 0 : 31 * catchType.hashCode()) + handleOffset; diff --git a/src/main/java/jadx/dex/trycatch/TryCatchBlock.java b/src/main/java/jadx/dex/trycatch/TryCatchBlock.java index ab0bd9189..059a8661a 100644 --- a/src/main/java/jadx/dex/trycatch/TryCatchBlock.java +++ b/src/main/java/jadx/dex/trycatch/TryCatchBlock.java @@ -1,11 +1,15 @@ package jadx.dex.trycatch; import jadx.dex.attributes.AttributeType; +import jadx.dex.attributes.IAttribute; import jadx.dex.info.ClassInfo; import jadx.dex.nodes.BlockNode; +import jadx.dex.nodes.IBlock; import jadx.dex.nodes.IContainer; +import jadx.dex.nodes.InsnContainer; import jadx.dex.nodes.InsnNode; import jadx.dex.nodes.MethodNode; +import jadx.dex.visitors.InstructionRemover; import jadx.utils.Utils; import java.util.ArrayList; @@ -36,6 +40,7 @@ public class TryCatchBlock { ExceptionHandler handler = new ExceptionHandler(addr, type); handler = mth.addExceptionHandler(handler); handlers.add(handler); + handler.setTryBlock(this); return handler; } @@ -52,14 +57,29 @@ public class TryCatchBlock { } private void removeWholeBlock(MethodNode mth) { + if (finalBlock != null) { + // search catch attr + for (BlockNode block : mth.getBasicBlocks()) { + CatchAttr cb = (CatchAttr) block.getAttributes().get(AttributeType.CATCH_BLOCK); + if (cb == attr) { + for (ExceptionHandler eh : mth.getExceptionHandlers()) { + if (eh.getBlocks().contains(block)) { + TryCatchBlock tb = eh.getTryBlock(); + tb.setFinalBlockFromInsns(mth, ((IBlock) finalBlock).getInstructions()); + } + } + } + } + return; + } + // self destruction for (InsnNode insn : insns) - insn.getAttributes().remove(AttributeType.CATCH_BLOCK); + insn.getAttributes().remove(attr); insns.clear(); - for (BlockNode block : mth.getBasicBlocks()) { - block.getAttributes().remove(AttributeType.CATCH_BLOCK); - } + for (BlockNode block : mth.getBasicBlocks()) + block.getAttributes().remove(attr); } public void addInsn(InsnNode insn) { @@ -92,11 +112,34 @@ public class TryCatchBlock { this.finalBlock = finalBlock; } + public void setFinalBlockFromInsns(MethodNode mth, List insns) { + InsnContainer cont = new InsnContainer(); + List finalBlockInsns = new ArrayList(insns); + cont.setInstructions(finalBlockInsns); + setFinalBlock(cont); + + InstructionRemover.unbindInsnList(finalBlockInsns); + + // remove these instructions from other handlers + for (ExceptionHandler h : getHandlers()) { + for (BlockNode ehb : h.getBlocks()) + ehb.getInstructions().removeAll(finalBlockInsns); + } + // remove from blocks with this catch + for (BlockNode b : mth.getBasicBlocks()) { + IAttribute ca = b.getAttributes().get(AttributeType.CATCH_BLOCK); + if (attr == ca) + b.getInstructions().removeAll(finalBlockInsns); + } + } + public void merge(MethodNode mth, TryCatchBlock tryBlock) { for (InsnNode insn : tryBlock.getInsns()) this.addInsn(insn); this.handlers.addAll(tryBlock.getHandlers()); + for (ExceptionHandler eh : handlers) + eh.setTryBlock(this); // clear tryBlock.handlers.clear(); diff --git a/src/main/java/jadx/dex/visitors/ModVisitor.java b/src/main/java/jadx/dex/visitors/ModVisitor.java index c9bbae85d..3f7f92c7f 100644 --- a/src/main/java/jadx/dex/visitors/ModVisitor.java +++ b/src/main/java/jadx/dex/visitors/ModVisitor.java @@ -2,7 +2,6 @@ package jadx.dex.visitors; import jadx.Consts; import jadx.dex.attributes.AttributeType; -import jadx.dex.attributes.IAttribute; import jadx.dex.info.MethodInfo; import jadx.dex.instructions.IndexInsnNode; import jadx.dex.instructions.InsnType; @@ -12,7 +11,6 @@ import jadx.dex.instructions.args.RegisterArg; import jadx.dex.instructions.mods.ConstructorInsn; import jadx.dex.nodes.BlockNode; import jadx.dex.nodes.FieldNode; -import jadx.dex.nodes.InsnContainer; import jadx.dex.nodes.InsnNode; import jadx.dex.nodes.MethodNode; import jadx.dex.trycatch.ExcHandlerAttr; @@ -21,7 +19,6 @@ import jadx.dex.trycatch.TryCatchBlock; import jadx.utils.BlockUtils; import jadx.utils.exceptions.JadxRuntimeException; -import java.util.ArrayList; import java.util.List; import org.slf4j.Logger; @@ -195,24 +192,8 @@ public class ModVisitor extends AbstractVisitor { // move not removed instructions to 'finally' block if (size != 0) { - InsnContainer cont = new InsnContainer(); - List finalBlockInsns = new ArrayList(insns); - cont.setInstructions(finalBlockInsns); - tryBlock.setFinalBlock(cont); - - InstructionRemover.unbindInsnList(finalBlockInsns); - - // remove these instructions from other handlers - for (ExceptionHandler h : tryBlock.getHandlers()) { - for (BlockNode ehb : h.getBlocks()) - ehb.getInstructions().removeAll(finalBlockInsns); - } - // remove from blocks with this catch - for (BlockNode b : mth.getBasicBlocks()) { - IAttribute ca = b.getAttributes().get(AttributeType.CATCH_BLOCK); - if (tryBlock.getCatchAttr() == ca) - b.getInstructions().removeAll(finalBlockInsns); - } + // TODO: support instructions from several blocks + tryBlock.setFinalBlockFromInsns(mth, insns); size = insns.size(); } } diff --git a/src/samples/java/jadx/samples/TestTryCatch.java b/src/samples/java/jadx/samples/TestTryCatch.java index 455cce7f1..a556181d4 100644 --- a/src/samples/java/jadx/samples/TestTryCatch.java +++ b/src/samples/java/jadx/samples/TestTryCatch.java @@ -118,6 +118,31 @@ public class TestTryCatch extends AbstractTest { } } + private boolean test8(Object obj) { + this.mDiscovering = false; + try { + exc(obj); + } catch (Exception e) { + e.toString(); + } finally { + mDiscovering = true; + } + return mDiscovering; + } + + private boolean test8a(Object obj) { + this.mDiscovering = false; + try { + exc(obj); + } catch (Exception e) { + e.toString(); + } finally { + if (!mDiscovering) + mDiscovering = true; + } + return mDiscovering; + } + private static boolean testSynchronize(Object obj) throws InterruptedException { synchronized (obj) { if (obj instanceof String) @@ -127,6 +152,7 @@ public class TestTryCatch extends AbstractTest { return true; } + // TODO: remove 'synchronized(TestTryCatch.class)' block in decompiled version private synchronized static boolean testSynchronize2(Object obj) throws InterruptedException { return obj.toString() != null; } @@ -159,6 +185,12 @@ public class TestTryCatch extends AbstractTest { assertTrue(testSynchronize2("str")); assertTrue(testSynchronize3()); + + assertTrue(test8("a")); + assertTrue(test8(null)); + + assertTrue(test8a("a")); + assertTrue(test8a(null)); return true; }