From be9dae57b9257536b0eb206ccc8ff52e9343e9f8 Mon Sep 17 00:00:00 2001 From: Skylot Date: Tue, 30 Jul 2019 22:46:28 +0300 Subject: [PATCH] fix: add explicit cast for byte literal in method invoke (#719) --- .../dex/instructions/CallMthInterface.java | 5 +++++ .../core/dex/instructions/InvokeNode.java | 7 ++++++- .../instructions/mods/ConstructorInsn.java | 5 +++++ .../java/jadx/core/dex/nodes/InsnNode.java | 2 +- .../core/dex/visitors/ConstInlineVisitor.java | 21 +++++++++++++++++++ .../integration/enums/TestInnerEnums.java | 8 +++---- 6 files changed, 42 insertions(+), 6 deletions(-) diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/CallMthInterface.java b/jadx-core/src/main/java/jadx/core/dex/instructions/CallMthInterface.java index f5649c305..9a4754474 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/CallMthInterface.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/CallMthInterface.java @@ -8,4 +8,9 @@ public interface CallMthInterface { MethodInfo getCallMth(); RegisterArg getInstanceArg(); + + /** + * Return offset to match method args from {@link #getCallMth()} + */ + int getFirstArgOffset(); } diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/InvokeNode.java b/jadx-core/src/main/java/jadx/core/dex/instructions/InvokeNode.java index ad3995037..c44f715df 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/InvokeNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/InvokeNode.java @@ -18,7 +18,7 @@ public class InvokeNode extends InsnNode implements CallMthInterface { private final MethodInfo mth; public InvokeNode(MethodInfo mth, DecodedInstruction insn, InvokeType type, boolean isRange, int resReg) { - super(InsnType.INVOKE, mth.getArgsCount() + (type != InvokeType.STATIC ? 1 : 0)); + super(InsnType.INVOKE, mth.getArgsCount() + (type == InvokeType.STATIC ? 0 : 1)); this.mth = mth; this.type = type; @@ -66,6 +66,11 @@ public class InvokeNode extends InsnNode implements CallMthInterface { return null; } + @Override + public int getFirstArgOffset() { + return type == InvokeType.STATIC ? 0 : 1; + } + @Override public InsnNode copy() { return copyCommonParams(new InvokeNode(mth, type, getArgsCount())); diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/mods/ConstructorInsn.java b/jadx-core/src/main/java/jadx/core/dex/instructions/mods/ConstructorInsn.java index ba3c0f205..58aecdd18 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/mods/ConstructorInsn.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/mods/ConstructorInsn.java @@ -92,6 +92,11 @@ public class ConstructorInsn extends InsnNode implements CallMthInterface { return callType == CallType.SELF; } + @Override + public int getFirstArgOffset() { + return 0; + } + @Override public boolean isSame(InsnNode obj) { if (this == obj) { diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java index 15d56a053..a83d750fa 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java @@ -143,7 +143,7 @@ public class InsnNode extends LineAttrNode { return arg; } - protected int getArgIndex(InsnArg arg) { + public int getArgIndex(InsnArg arg) { int count = getArgsCount(); for (int i = 0; i < count; i++) { if (arg == arguments.get(i)) { diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/ConstInlineVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/ConstInlineVisitor.java index 366b489e8..af935820f 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/ConstInlineVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/ConstInlineVisitor.java @@ -4,6 +4,8 @@ import java.util.ArrayList; import java.util.List; import jadx.core.dex.attributes.AFlag; +import jadx.core.dex.info.MethodInfo; +import jadx.core.dex.instructions.CallMthInterface; import jadx.core.dex.instructions.ConstStringNode; import jadx.core.dex.instructions.IndexInsnNode; import jadx.core.dex.instructions.InsnType; @@ -203,6 +205,10 @@ public class ConstInlineVisitor extends AbstractVisitor { } if (fieldNode != null) { litArg.wrapInstruction(mth, new IndexInsnNode(InsnType.SGET, fieldNode.getFieldInfo(), 0)); + } else { + if (needExplicitCast(useInsn, litArg)) { + litArg.add(AFlag.EXPLICIT_PRIMITIVE_TYPE); + } } } else { if (!useInsn.replaceArg(arg, constArg.duplicate())) { @@ -214,4 +220,19 @@ public class ConstInlineVisitor extends AbstractVisitor { } return true; } + + private static boolean needExplicitCast(InsnNode insn, LiteralArg arg) { + if (insn instanceof CallMthInterface) { + CallMthInterface callInsn = (CallMthInterface) insn; + MethodInfo callMth = callInsn.getCallMth(); + int offset = callInsn.getFirstArgOffset(); + int argIndex = insn.getArgIndex(arg); + ArgType argType = callMth.getArgumentsTypes().get(argIndex - offset); + if (argType.isPrimitive()) { + arg.setType(argType); + return argType.equals(ArgType.BYTE); + } + } + return false; + } } diff --git a/jadx-core/src/test/java/jadx/tests/integration/enums/TestInnerEnums.java b/jadx-core/src/test/java/jadx/tests/integration/enums/TestInnerEnums.java index 025ff5bf1..3b59766f7 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/enums/TestInnerEnums.java +++ b/jadx-core/src/test/java/jadx/tests/integration/enums/TestInnerEnums.java @@ -14,9 +14,9 @@ public class TestInnerEnums extends IntegrationTest { public static class TestCls { public enum Numbers { - ONE(1, NumString.ONE), TWO(2, NumString.TWO); + ONE((byte) 1, NumString.ONE), TWO((byte) 2, NumString.TWO); - private final int num; + private final byte num; private final NumString str; public enum NumString { @@ -33,7 +33,7 @@ public class TestInnerEnums extends IntegrationTest { } } - Numbers(int n, NumString str) { + Numbers(byte n, NumString str) { this.num = n; this.str = str; } @@ -63,7 +63,7 @@ public class TestInnerEnums extends IntegrationTest { ClassNode cls = getClassNode(TestCls.class); String code = cls.getCode().toString(); - assertThat(code, containsOne("ONE(1, NumString.ONE)")); + assertThat(code, containsOne("ONE((byte) 1, NumString.ONE)")); assertThat(code, containsOne("ONE(\"one\")")); } }