fix: force cast for null args in method invoke (temp fix for #724)
This commit is contained in:
@@ -769,7 +769,7 @@ public class InsnGen {
|
||||
if (!firstArg) {
|
||||
code.add(", ");
|
||||
}
|
||||
boolean cast = overloaded && processOverloadedArg(code, insn, callMth, arg, i - startArgNum);
|
||||
boolean cast = addArgCast(code, insn, callMth, arg, i - startArgNum, overloaded);
|
||||
if (!cast && i == argsCount - 1 && processVarArg(code, callMth, arg)) {
|
||||
continue;
|
||||
}
|
||||
@@ -781,42 +781,47 @@ public class InsnGen {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add additional cast for overloaded method argument.
|
||||
* Add additional cast for method argument.
|
||||
*/
|
||||
private boolean processOverloadedArg(CodeWriter code, InsnNode insn, MethodNode callMth, InsnArg arg, int origPos) {
|
||||
List<ArgType> argTypes = callMth.getArgTypes();
|
||||
ArgType origType = argTypes.get(origPos);
|
||||
if (origType.isGenericType() && !callMth.getParentClass().equals(mth.getParentClass())) {
|
||||
// cancel cast
|
||||
return false;
|
||||
}
|
||||
private boolean addArgCast(CodeWriter code, InsnNode insn, @Nullable MethodNode callMth,
|
||||
InsnArg arg, int origPos, boolean overloaded) {
|
||||
ArgType castType = null;
|
||||
if (insn instanceof CallMthInterface && origType.containsGenericType()) {
|
||||
ArgType clsType;
|
||||
CallMthInterface mthCall = (CallMthInterface) insn;
|
||||
RegisterArg instanceArg = mthCall.getInstanceArg();
|
||||
if (instanceArg != null) {
|
||||
clsType = instanceArg.getType();
|
||||
} else {
|
||||
clsType = mthCall.getCallMth().getDeclClass().getType();
|
||||
if (callMth != null) {
|
||||
List<ArgType> argTypes = callMth.getArgTypes();
|
||||
ArgType origType = argTypes.get(origPos);
|
||||
if (origType.isGenericType() && !callMth.getParentClass().equals(mth.getParentClass())) {
|
||||
// cancel cast
|
||||
return false;
|
||||
}
|
||||
ArgType replacedType = TypeUtils.replaceClassGenerics(root, clsType, origType);
|
||||
if (replacedType != null) {
|
||||
castType = replacedType;
|
||||
}
|
||||
if (castType == null) {
|
||||
ArgType invReplType = TypeUtils.replaceMethodGenerics(root, insn, origType);
|
||||
if (invReplType != null) {
|
||||
castType = invReplType;
|
||||
if (insn instanceof CallMthInterface && origType.containsGenericType()) {
|
||||
ArgType clsType;
|
||||
CallMthInterface mthCall = (CallMthInterface) insn;
|
||||
RegisterArg instanceArg = mthCall.getInstanceArg();
|
||||
if (instanceArg != null) {
|
||||
clsType = instanceArg.getType();
|
||||
} else {
|
||||
clsType = mthCall.getCallMth().getDeclClass().getType();
|
||||
}
|
||||
ArgType replacedType = TypeUtils.replaceClassGenerics(root, clsType, origType);
|
||||
if (replacedType != null) {
|
||||
castType = replacedType;
|
||||
}
|
||||
if (castType == null) {
|
||||
ArgType invReplType = TypeUtils.replaceMethodGenerics(root, insn, origType);
|
||||
if (invReplType != null) {
|
||||
castType = invReplType;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (castType == null) {
|
||||
castType = origType;
|
||||
if (castType == null) {
|
||||
castType = origType;
|
||||
}
|
||||
} else {
|
||||
castType = arg.getType();
|
||||
}
|
||||
// TODO: check castType for left type variables
|
||||
|
||||
if (isCastNeeded(arg, castType)) {
|
||||
if (isCastNeeded(arg, castType, overloaded)) {
|
||||
code.add('(');
|
||||
useType(code, castType);
|
||||
code.add(") ");
|
||||
@@ -825,7 +830,7 @@ public class InsnGen {
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isCastNeeded(InsnArg arg, ArgType origType) {
|
||||
private boolean isCastNeeded(InsnArg arg, ArgType origType, boolean overloaded) {
|
||||
ArgType argType = arg.getType();
|
||||
if (arg.isLiteral() && ((LiteralArg) arg).getLiteral() == 0
|
||||
&& (argType.isObject() || argType.isArray())) {
|
||||
@@ -834,7 +839,7 @@ public class InsnGen {
|
||||
if (argType.equals(origType)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return overloaded;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package jadx.tests.integration.invoke;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.tests.api.SmaliTest;
|
||||
|
||||
import static jadx.tests.api.utils.JadxMatchers.containsOne;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
public class TestCastInOverloadedInvoke2 extends SmaliTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
disableCompilation();
|
||||
|
||||
ClassNode cls = getClassNodeFromSmali();
|
||||
String code = cls.getCode().toString();
|
||||
|
||||
assertThat(code, containsOne("new Intent().putExtra(\"param\", (Parcelable) null);"));
|
||||
}
|
||||
}
|
||||
@@ -39,11 +39,10 @@ public class TestDeboxing2 extends IntegrationTest {
|
||||
assertThat(code, containsOne("l = 0L;"));
|
||||
|
||||
// checks for 'check' method
|
||||
assertThat(code, containsOne("test(null)"));
|
||||
assertThat(code, containsOne("test((Long) null)")); // TODO: cast not needed
|
||||
assertThat(code, containsOne("test(0L)"));
|
||||
assertThat(code, countString(2, "is(0L)"));
|
||||
assertThat(code, containsOne("test(7L)"));
|
||||
assertThat(code, containsOne("is(7L)"));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
.class public Linvoke/TestCastInOverloadedInvoke2;
|
||||
.super Ljava/lang/Object;
|
||||
|
||||
.method public test()V
|
||||
.locals 3
|
||||
|
||||
new-instance v0, Landroid/content/Intent;
|
||||
|
||||
invoke-direct {v0}, Landroid/content/Intent;-><init>()V
|
||||
|
||||
const-string v1, "param"
|
||||
|
||||
const/4 v2, 0x0
|
||||
|
||||
invoke-virtual {v0, v1, v2}, Landroid/content/Intent;->putExtra(Ljava/lang/String;Landroid/os/Parcelable;)Landroid/content/Intent;
|
||||
|
||||
return-void
|
||||
.end method
|
||||
Reference in New Issue
Block a user