fix: support all-catch in multi-catch (#1510)
This commit is contained in:
@@ -14,9 +14,9 @@ import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.dex.instructions.args.InsnArg;
|
||||
import jadx.core.dex.nodes.BlockNode;
|
||||
import jadx.core.dex.nodes.IContainer;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.utils.InsnUtils;
|
||||
import jadx.core.utils.Utils;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
|
||||
public class ExceptionHandler {
|
||||
|
||||
@@ -33,9 +33,14 @@ public class ExceptionHandler {
|
||||
|
||||
private boolean removed = false;
|
||||
|
||||
public ExceptionHandler(int addr, @Nullable ClassInfo type) {
|
||||
public static ExceptionHandler build(MethodNode mth, int addr, @Nullable ClassInfo type) {
|
||||
ExceptionHandler eh = new ExceptionHandler(addr);
|
||||
eh.addCatchType(mth, type);
|
||||
return eh;
|
||||
}
|
||||
|
||||
private ExceptionHandler(int addr) {
|
||||
this.handlerOffset = addr;
|
||||
addCatchType(type);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,7 +48,7 @@ public class ExceptionHandler {
|
||||
*
|
||||
* @param type - null for 'all' or 'Throwable' handler
|
||||
*/
|
||||
public boolean addCatchType(@Nullable ClassInfo type) {
|
||||
public boolean addCatchType(MethodNode mth, @Nullable ClassInfo type) {
|
||||
if (type != null) {
|
||||
if (catchTypes.contains(type)) {
|
||||
return false;
|
||||
@@ -51,14 +56,16 @@ public class ExceptionHandler {
|
||||
return catchTypes.add(type);
|
||||
}
|
||||
if (!this.catchTypes.isEmpty()) {
|
||||
throw new JadxRuntimeException("Null type added to not empty exception handler: " + this);
|
||||
mth.addDebugComment("Throwable added to exception handler: '" + catchTypeStr() + "', keep only Throwable");
|
||||
catchTypes.clear();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void addCatchTypes(Collection<ClassInfo> types) {
|
||||
public void addCatchTypes(MethodNode mth, Collection<ClassInfo> types) {
|
||||
for (ClassInfo type : types) {
|
||||
addCatchType(type);
|
||||
addCatchType(mth, type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ public class AttachTryCatchVisitor extends AbstractVisitor {
|
||||
ExcHandlerAttr excHandlerAttr = insn.get(AType.EXC_HANDLER);
|
||||
if (excHandlerAttr != null) {
|
||||
ExceptionHandler handler = excHandlerAttr.getHandler();
|
||||
if (handler.addCatchType(type)) {
|
||||
if (handler.addCatchType(mth, type)) {
|
||||
// exist handler updated (assume from same try block) - don't add again
|
||||
return null;
|
||||
}
|
||||
@@ -143,7 +143,7 @@ public class AttachTryCatchVisitor extends AbstractVisitor {
|
||||
} else {
|
||||
insn = insertNOP(insnByOffset, handlerOffset);
|
||||
}
|
||||
ExceptionHandler handler = new ExceptionHandler(handlerOffset, type);
|
||||
ExceptionHandler handler = ExceptionHandler.build(mth, handlerOffset, type);
|
||||
mth.addExceptionHandler(handler);
|
||||
insn.addAttr(new ExcHandlerAttr(handler));
|
||||
return handler;
|
||||
|
||||
@@ -549,7 +549,7 @@ public class BlockExceptionHandler {
|
||||
if (handler == resultHandler) {
|
||||
return false;
|
||||
}
|
||||
resultHandler.addCatchTypes(handler.getCatchTypes());
|
||||
resultHandler.addCatchTypes(mth, handler.getCatchTypes());
|
||||
handler.markForRemove();
|
||||
return true;
|
||||
});
|
||||
|
||||
-2
@@ -25,8 +25,6 @@ public class TestTryCatchMultiException extends IntegrationTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
// printDisassemble();
|
||||
// setFallback();
|
||||
noDebugInfo();
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package jadx.tests.integration.trycatch;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.tests.api.SmaliTest;
|
||||
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
|
||||
@SuppressWarnings("CommentedOutCode")
|
||||
public class TestTryCatchMultiException2 extends SmaliTest {
|
||||
|
||||
// @formatter:off
|
||||
/*
|
||||
public static boolean test() {
|
||||
try {
|
||||
Class<?> cls = Class.forName("c");
|
||||
return ((Boolean) cls.getMethod("b", new Class[0]).invoke(cls, new Object[0])).booleanValue();
|
||||
} catch (ClassNotFoundException | NoSuchMethodException | Exception | Throwable unused) {
|
||||
// java compiler don't allow shadow subclasses in multi-catch
|
||||
// in this case leave only Throwable
|
||||
return false;
|
||||
}
|
||||
}
|
||||
*/
|
||||
// @formatter:on
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
assertThat(getClassNodeFromSmali())
|
||||
.code()
|
||||
.containsOne("} catch (Throwable unused) {");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
.class public Ltrycatch/TestTryCatchMultiException2;
|
||||
.super Ljava/lang/Object;
|
||||
|
||||
|
||||
.method public static test()Z
|
||||
.registers 5
|
||||
|
||||
:try_start_b
|
||||
const-string v0, "c"
|
||||
invoke-static {v0}, Ljava/lang/Class;->forName(Ljava/lang/String;)Ljava/lang/Class;
|
||||
move-result-object v1
|
||||
|
||||
const/4 v0, 0x0
|
||||
const-string v2, "b"
|
||||
new-array v3, v0, [Ljava/lang/Class;
|
||||
invoke-virtual {v1, v2, v3}, Ljava/lang/Class;->getMethod(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
|
||||
move-result-object v2
|
||||
|
||||
new-array v3, v0, [Ljava/lang/Object;
|
||||
invoke-virtual {v2, v1, v3}, Ljava/lang/reflect/Method;->invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;
|
||||
move-result-object v1
|
||||
|
||||
check-cast v1, Ljava/lang/Boolean;
|
||||
invoke-virtual {v1}, Ljava/lang/Boolean;->booleanValue()Z
|
||||
|
||||
move-result v1
|
||||
:try_end_2f
|
||||
.catch Ljava/lang/ClassNotFoundException; {:try_start_b .. :try_end_2f} :catch_30
|
||||
.catch Ljava/lang/NoSuchMethodException; {:try_start_b .. :try_end_2f} :catch_30
|
||||
.catch Ljava/lang/Exception; {:try_start_b .. :try_end_2f} :catch_30
|
||||
.catchall {:try_start_b .. :try_end_2f} :catchall_30
|
||||
|
||||
return v1
|
||||
|
||||
:catch_30
|
||||
:catchall_30
|
||||
return v0
|
||||
.end method
|
||||
Reference in New Issue
Block a user