Fix try/catch/finally block processing
This commit is contained in:
@@ -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<BlockNode> blocks = new ArrayList<BlockNode>();
|
||||
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;
|
||||
|
||||
@@ -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<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) {
|
||||
for (InsnNode insn : tryBlock.getInsns())
|
||||
this.addInsn(insn);
|
||||
|
||||
this.handlers.addAll(tryBlock.getHandlers());
|
||||
for (ExceptionHandler eh : handlers)
|
||||
eh.setTryBlock(this);
|
||||
|
||||
// clear
|
||||
tryBlock.handlers.clear();
|
||||
|
||||
@@ -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<InsnNode> finalBlockInsns = new ArrayList<InsnNode>(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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user