From 08f9a90c95e6ca03e8ba51f5c71a8ae86cf4b7da Mon Sep 17 00:00:00 2001 From: Skylot Date: Sun, 27 Oct 2019 16:49:41 +0000 Subject: [PATCH] fix: force cast for null args in method invoke (temp fix for #724) --- .../main/java/jadx/core/codegen/InsnGen.java | 67 ++++++++++--------- .../invoke/TestCastInOverloadedInvoke2.java | 22 ++++++ .../integration/others/TestDeboxing2.java | 3 +- .../invoke/TestCastInOverloadedInvoke2.smali | 18 +++++ 4 files changed, 77 insertions(+), 33 deletions(-) create mode 100644 jadx-core/src/test/java/jadx/tests/integration/invoke/TestCastInOverloadedInvoke2.java create mode 100644 jadx-core/src/test/smali/invoke/TestCastInOverloadedInvoke2.smali diff --git a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java index b43b2de44..04e37da47 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java @@ -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 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 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; } /** diff --git a/jadx-core/src/test/java/jadx/tests/integration/invoke/TestCastInOverloadedInvoke2.java b/jadx-core/src/test/java/jadx/tests/integration/invoke/TestCastInOverloadedInvoke2.java new file mode 100644 index 000000000..30fa5fc00 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/invoke/TestCastInOverloadedInvoke2.java @@ -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);")); + } +} diff --git a/jadx-core/src/test/java/jadx/tests/integration/others/TestDeboxing2.java b/jadx-core/src/test/java/jadx/tests/integration/others/TestDeboxing2.java index 5a7247d56..7bdd21745 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/others/TestDeboxing2.java +++ b/jadx-core/src/test/java/jadx/tests/integration/others/TestDeboxing2.java @@ -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)")); - } } diff --git a/jadx-core/src/test/smali/invoke/TestCastInOverloadedInvoke2.smali b/jadx-core/src/test/smali/invoke/TestCastInOverloadedInvoke2.smali new file mode 100644 index 000000000..76c9393ea --- /dev/null +++ b/jadx-core/src/test/smali/invoke/TestCastInOverloadedInvoke2.smali @@ -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;->()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