Skip to content

Commit

Permalink
fix: force cast for null args in method invoke (temp fix for #724)
Browse files Browse the repository at this point in the history
  • Loading branch information
skylot committed Oct 27, 2019
1 parent 9f06d67 commit 08f9a90
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 32 deletions.
65 changes: 35 additions & 30 deletions jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
Original file line number Diff line number Diff line change
Expand Up @@ -769,7 +769,7 @@ void generateMethodArguments(CodeWriter code, InsnNode insn, int startArgNum,
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;
}
Expand All @@ -781,42 +781,47 @@ void generateMethodArguments(CodeWriter code, InsnNode insn, int startArgNum,
}

/**
* 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 (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) {
ArgType invReplType = TypeUtils.replaceMethodGenerics(root, insn, origType);
if (invReplType != null) {
castType = invReplType;
}
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(") ");
Expand All @@ -825,7 +830,7 @@ private boolean processOverloadedArg(CodeWriter code, InsnNode insn, MethodNode
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())) {
Expand All @@ -834,7 +839,7 @@ private boolean isCastNeeded(InsnArg arg, ArgType origType) {
if (argType.equals(origType)) {
return false;
}
return true;
return overloaded;
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -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);"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,10 @@ public void test() {
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)"));

}
}
18 changes: 18 additions & 0 deletions jadx-core/src/test/smali/invoke/TestCastInOverloadedInvoke2.smali
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 08f9a90

Please sign in to comment.