Commit 3fcbca94 authored by Skylot's avatar Skylot

Fix try/catch/finally block processing

parent 56eac437
...@@ -2,7 +2,7 @@ package jadx.dex.trycatch; ...@@ -2,7 +2,7 @@ package jadx.dex.trycatch;
import jadx.Consts; import jadx.Consts;
import jadx.dex.info.ClassInfo; 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.BlockNode;
import jadx.dex.nodes.IContainer; import jadx.dex.nodes.IContainer;
import jadx.utils.InsnUtils; import jadx.utils.InsnUtils;
...@@ -18,7 +18,9 @@ public class ExceptionHandler { ...@@ -18,7 +18,9 @@ public class ExceptionHandler {
private BlockNode handleBlock; private BlockNode handleBlock;
private final List<BlockNode> blocks = new ArrayList<BlockNode>(); private final List<BlockNode> blocks = new ArrayList<BlockNode>();
private IContainer handlerRegion; private IContainer handlerRegion;
private InsnArg arg; private RegisterArg arg;
private TryCatchBlock tryBlock;
public ExceptionHandler(int addr, ClassInfo type) { public ExceptionHandler(int addr, ClassInfo type) {
this.handleOffset = addr; this.handleOffset = addr;
...@@ -61,14 +63,22 @@ public class ExceptionHandler { ...@@ -61,14 +63,22 @@ public class ExceptionHandler {
this.handlerRegion = handlerRegion; this.handlerRegion = handlerRegion;
} }
public InsnArg getArg() { public RegisterArg getArg() {
return arg; return arg;
} }
public void setArg(InsnArg arg) { public void setArg(RegisterArg arg) {
this.arg = arg; this.arg = arg;
} }
public void setTryBlock(TryCatchBlock tryBlock) {
this.tryBlock = tryBlock;
}
public TryCatchBlock getTryBlock() {
return tryBlock;
}
@Override @Override
public int hashCode() { public int hashCode() {
return (catchType == null ? 0 : 31 * catchType.hashCode()) + handleOffset; return (catchType == null ? 0 : 31 * catchType.hashCode()) + handleOffset;
......
package jadx.dex.trycatch; package jadx.dex.trycatch;
import jadx.dex.attributes.AttributeType; import jadx.dex.attributes.AttributeType;
import jadx.dex.attributes.IAttribute;
import jadx.dex.info.ClassInfo; import jadx.dex.info.ClassInfo;
import jadx.dex.nodes.BlockNode; import jadx.dex.nodes.BlockNode;
import jadx.dex.nodes.IBlock;
import jadx.dex.nodes.IContainer; import jadx.dex.nodes.IContainer;
import jadx.dex.nodes.InsnContainer;
import jadx.dex.nodes.InsnNode; import jadx.dex.nodes.InsnNode;
import jadx.dex.nodes.MethodNode; import jadx.dex.nodes.MethodNode;
import jadx.dex.visitors.InstructionRemover;
import jadx.utils.Utils; import jadx.utils.Utils;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -36,6 +40,7 @@ public class TryCatchBlock { ...@@ -36,6 +40,7 @@ public class TryCatchBlock {
ExceptionHandler handler = new ExceptionHandler(addr, type); ExceptionHandler handler = new ExceptionHandler(addr, type);
handler = mth.addExceptionHandler(handler); handler = mth.addExceptionHandler(handler);
handlers.add(handler); handlers.add(handler);
handler.setTryBlock(this);
return handler; return handler;
} }
...@@ -52,14 +57,29 @@ public class TryCatchBlock { ...@@ -52,14 +57,29 @@ public class TryCatchBlock {
} }
private void removeWholeBlock(MethodNode mth) { 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 // self destruction
for (InsnNode insn : insns) for (InsnNode insn : insns)
insn.getAttributes().remove(AttributeType.CATCH_BLOCK); insn.getAttributes().remove(attr);
insns.clear(); insns.clear();
for (BlockNode block : mth.getBasicBlocks()) { for (BlockNode block : mth.getBasicBlocks())
block.getAttributes().remove(AttributeType.CATCH_BLOCK); block.getAttributes().remove(attr);
}
} }
public void addInsn(InsnNode insn) { public void addInsn(InsnNode insn) {
...@@ -92,11 +112,34 @@ public class TryCatchBlock { ...@@ -92,11 +112,34 @@ public class TryCatchBlock {
this.finalBlock = finalBlock; this.finalBlock = finalBlock;
} }
public void setFinalBlockFromInsns(MethodNode mth, List<InsnNode> insns) {
InsnContainer cont = new InsnContainer();
List<InsnNode> finalBlockInsns = new ArrayList<InsnNode>(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) { public void merge(MethodNode mth, TryCatchBlock tryBlock) {
for (InsnNode insn : tryBlock.getInsns()) for (InsnNode insn : tryBlock.getInsns())
this.addInsn(insn); this.addInsn(insn);
this.handlers.addAll(tryBlock.getHandlers()); this.handlers.addAll(tryBlock.getHandlers());
for (ExceptionHandler eh : handlers)
eh.setTryBlock(this);
// clear // clear
tryBlock.handlers.clear(); tryBlock.handlers.clear();
......
...@@ -2,7 +2,6 @@ package jadx.dex.visitors; ...@@ -2,7 +2,6 @@ package jadx.dex.visitors;
import jadx.Consts; import jadx.Consts;
import jadx.dex.attributes.AttributeType; import jadx.dex.attributes.AttributeType;
import jadx.dex.attributes.IAttribute;
import jadx.dex.info.MethodInfo; import jadx.dex.info.MethodInfo;
import jadx.dex.instructions.IndexInsnNode; import jadx.dex.instructions.IndexInsnNode;
import jadx.dex.instructions.InsnType; import jadx.dex.instructions.InsnType;
...@@ -12,7 +11,6 @@ import jadx.dex.instructions.args.RegisterArg; ...@@ -12,7 +11,6 @@ import jadx.dex.instructions.args.RegisterArg;
import jadx.dex.instructions.mods.ConstructorInsn; import jadx.dex.instructions.mods.ConstructorInsn;
import jadx.dex.nodes.BlockNode; import jadx.dex.nodes.BlockNode;
import jadx.dex.nodes.FieldNode; import jadx.dex.nodes.FieldNode;
import jadx.dex.nodes.InsnContainer;
import jadx.dex.nodes.InsnNode; import jadx.dex.nodes.InsnNode;
import jadx.dex.nodes.MethodNode; import jadx.dex.nodes.MethodNode;
import jadx.dex.trycatch.ExcHandlerAttr; import jadx.dex.trycatch.ExcHandlerAttr;
...@@ -21,7 +19,6 @@ import jadx.dex.trycatch.TryCatchBlock; ...@@ -21,7 +19,6 @@ import jadx.dex.trycatch.TryCatchBlock;
import jadx.utils.BlockUtils; import jadx.utils.BlockUtils;
import jadx.utils.exceptions.JadxRuntimeException; import jadx.utils.exceptions.JadxRuntimeException;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.slf4j.Logger; import org.slf4j.Logger;
...@@ -195,24 +192,8 @@ public class ModVisitor extends AbstractVisitor { ...@@ -195,24 +192,8 @@ public class ModVisitor extends AbstractVisitor {
// move not removed instructions to 'finally' block // move not removed instructions to 'finally' block
if (size != 0) { if (size != 0) {
InsnContainer cont = new InsnContainer(); // TODO: support instructions from several blocks
List<InsnNode> finalBlockInsns = new ArrayList<InsnNode>(insns); tryBlock.setFinalBlockFromInsns(mth, 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);
}
size = insns.size(); size = insns.size();
} }
} }
......
...@@ -118,6 +118,31 @@ public class TestTryCatch extends AbstractTest { ...@@ -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 { private static boolean testSynchronize(Object obj) throws InterruptedException {
synchronized (obj) { synchronized (obj) {
if (obj instanceof String) if (obj instanceof String)
...@@ -127,6 +152,7 @@ public class TestTryCatch extends AbstractTest { ...@@ -127,6 +152,7 @@ public class TestTryCatch extends AbstractTest {
return true; return true;
} }
// TODO: remove 'synchronized(TestTryCatch.class)' block in decompiled version
private synchronized static boolean testSynchronize2(Object obj) throws InterruptedException { private synchronized static boolean testSynchronize2(Object obj) throws InterruptedException {
return obj.toString() != null; return obj.toString() != null;
} }
...@@ -159,6 +185,12 @@ public class TestTryCatch extends AbstractTest { ...@@ -159,6 +185,12 @@ public class TestTryCatch extends AbstractTest {
assertTrue(testSynchronize2("str")); assertTrue(testSynchronize2("str"));
assertTrue(testSynchronize3()); assertTrue(testSynchronize3());
assertTrue(test8("a"));
assertTrue(test8(null));
assertTrue(test8a("a"));
assertTrue(test8a(null));
return true; return true;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment