From d60698206e70782c5df036b62a1f9e7410aad4e7 Mon Sep 17 00:00:00 2001 From: Skylot Date: Sun, 29 Sep 2013 19:36:56 +0400 Subject: [PATCH] core: fix type in fill-array instruction --- .../main/java/jadx/core/codegen/InsnGen.java | 22 ++++++++++------- .../core/dex/instructions/FillArrayNode.java | 21 ++++++++++++---- .../core/dex/instructions/args/ArgType.java | 24 ++++++++++++++----- .../jadx/core/dex/visitors/ModVisitor.java | 2 ++ .../java/jadx/core/utils/ErrorsCounter.java | 2 ++ .../jadx/tests/functional/TypeMergeTest.java | 9 +++++++ .../main/java/jadx/samples/TestArrays.java | 18 +++++++++++++- 7 files changed, 79 insertions(+), 19 deletions(-) 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 b8a696467..a96395a63 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java @@ -30,6 +30,8 @@ import jadx.core.dex.nodes.FieldNode; import jadx.core.dex.nodes.InsnNode; import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.nodes.RootNode; +import jadx.core.utils.ErrorsCounter; +import jadx.core.utils.InsnUtils; import jadx.core.utils.StringUtils; import jadx.core.utils.exceptions.CodegenException; @@ -450,15 +452,19 @@ public class InsnGen { } private void fillArray(FillArrayNode insn, CodeWriter code) throws CodegenException { - ArgType elType = insn.getResult().getType().getArrayElement(); - if (elType.getPrimitiveType() == null) { - elType = elType.selectFirst(); + ArgType insnArrayType = insn.getResult().getType(); + ArgType insnElementType = insnArrayType.getArrayElement(); + ArgType elType = insn.getElementType(); + if (!elType.equals(insnElementType) && !insnArrayType.equals(ArgType.OBJECT)) { + ErrorsCounter.methodError(mth, + "Incorrect type for fill-array insn " + InsnUtils.formatOffset(insn.getOffset())); } StringBuilder str = new StringBuilder(); + Object data = insn.getData(); switch (elType.getPrimitiveType()) { case BOOLEAN: case BYTE: - byte[] array = (byte[]) insn.getData(); + byte[] array = (byte[]) data; for (byte b : array) { str.append(TypeGen.literalToString(b, elType)); str.append(", "); @@ -466,7 +472,7 @@ public class InsnGen { break; case SHORT: case CHAR: - short[] sarray = (short[]) insn.getData(); + short[] sarray = (short[]) data; for (short b : sarray) { str.append(TypeGen.literalToString(b, elType)); str.append(", "); @@ -474,7 +480,7 @@ public class InsnGen { break; case INT: case FLOAT: - int[] iarray = (int[]) insn.getData(); + int[] iarray = (int[]) data; for (int b : iarray) { str.append(TypeGen.literalToString(b, elType)); str.append(", "); @@ -482,7 +488,7 @@ public class InsnGen { break; case LONG: case DOUBLE: - long[] larray = (long[]) insn.getData(); + long[] larray = (long[]) data; for (long b : larray) { str.append(TypeGen.literalToString(b, elType)); str.append(", "); @@ -494,7 +500,7 @@ public class InsnGen { } int len = str.length(); str.delete(len - 2, len); - code.add("new ").add(useType(elType)).add("[] { ").add(str.toString()).add(" }"); + code.add("new ").add(useType(elType)).add("[]{").add(str.toString()).add('}'); } private void makeConstructor(ConstructorInsn insn, CodeWriter code, EnumSet state) diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/FillArrayNode.java b/jadx-core/src/main/java/jadx/core/dex/instructions/FillArrayNode.java index 4b104efae..9a8e1be77 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/FillArrayNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/FillArrayNode.java @@ -4,18 +4,17 @@ import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.instructions.args.InsnArg; import jadx.core.dex.instructions.args.PrimitiveType; import jadx.core.dex.nodes.InsnNode; +import jadx.core.utils.exceptions.JadxRuntimeException; import com.android.dx.io.instructions.FillArrayDataPayloadDecodedInstruction; public class FillArrayNode extends InsnNode { private final Object data; + private ArgType elemType; public FillArrayNode(int resReg, FillArrayDataPayloadDecodedInstruction payload) { super(InsnType.FILL_ARRAY, 0); - - this.data = payload.getData(); - ArgType elType; switch (payload.getElementWidthUnit()) { case 1: @@ -32,12 +31,26 @@ public class FillArrayNode extends InsnNode { break; default: - throw new AssertionError(); + throw new JadxRuntimeException("Unknown array element width: " + payload.getElementWidthUnit()); } setResult(InsnArg.reg(resReg, ArgType.array(elType))); + + this.data = payload.getData(); + this.elemType = elType; } public Object getData() { return data; } + + public ArgType getElementType() { + return elemType; + } + + public void mergeElementType(ArgType foundElemType) { + ArgType r = ArgType.merge(elemType, foundElemType); + if (r != null) { + elemType = r; + } + } } diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/args/ArgType.java b/jadx-core/src/main/java/jadx/core/dex/instructions/args/ArgType.java index a44c99215..4832dd045 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/args/ArgType.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/args/ArgType.java @@ -339,7 +339,7 @@ public abstract class ArgType { } public static ArgType merge(ArgType a, ArgType b) { - if (a == b) + if (a.equals(b)) return a; if (b == null || a == null) @@ -352,9 +352,9 @@ public abstract class ArgType { } private static ArgType mergeInternal(ArgType a, ArgType b) { - if (a == UNKNOWN) + if (a == UNKNOWN) { return b; - + } if (!a.isTypeKnown()) { if (b.isTypeKnown()) { if (a.contains(b.getPrimitiveType())) @@ -399,9 +399,21 @@ public abstract class ArgType { return (obj == null ? null : object(obj)); } } - if (a.isArray() && b.isArray()) { - ArgType res = merge(a.getArrayElement(), b.getArrayElement()); - return (res == null ? null : ArgType.array(res)); + if (a.isArray()) { + if (b.isArray()) { + ArgType ea = a.getArrayElement(); + ArgType eb = b.getArrayElement(); + if (ea.isPrimitive() && eb.isPrimitive()) { + return OBJECT; + } else { + ArgType res = merge(ea, eb); + return (res == null ? null : ArgType.array(res)); + } + } else if (b.equals(OBJECT)) { + return OBJECT; + } else { + return null; + } } if (a.isPrimitive() && b.isPrimitive() && a.getRegCount() == b.getRegCount()) { return primitive(PrimitiveType.getSmaller(a.getPrimitiveType(), b.getPrimitiveType())); diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java index 8abc7d8db..546fbda22 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java @@ -5,6 +5,7 @@ import jadx.core.dex.attributes.AttributeType; import jadx.core.dex.info.MethodInfo; import jadx.core.dex.instructions.ConstClassNode; import jadx.core.dex.instructions.ConstStringNode; +import jadx.core.dex.instructions.FillArrayNode; import jadx.core.dex.instructions.IndexInsnNode; import jadx.core.dex.instructions.InsnType; import jadx.core.dex.instructions.InvokeNode; @@ -164,6 +165,7 @@ public class ModVisitor extends AbstractVisitor { InsnNode ni = block.getInstructions().get(next); if (ni.getType() == InsnType.FILL_ARRAY) { ni.getResult().merge(insn.getResult()); + ((FillArrayNode) ni).mergeElementType(insn.getResult().getType().getArrayElement()); remover.add(insn); } } diff --git a/jadx-core/src/main/java/jadx/core/utils/ErrorsCounter.java b/jadx-core/src/main/java/jadx/core/utils/ErrorsCounter.java index bc94ad3f5..3f1a2988e 100644 --- a/jadx-core/src/main/java/jadx/core/utils/ErrorsCounter.java +++ b/jadx-core/src/main/java/jadx/core/utils/ErrorsCounter.java @@ -1,5 +1,6 @@ package jadx.core.utils; +import jadx.core.dex.attributes.AttributeFlag; import jadx.core.dex.attributes.IAttributeNode; import jadx.core.dex.attributes.JadxErrorAttr; import jadx.core.dex.nodes.ClassNode; @@ -40,6 +41,7 @@ public class ErrorsCounter { } node.getAttributes().add(new JadxErrorAttr(e)); } else { + node.getAttributes().add(AttributeFlag.INCONSISTENT_CODE); LOG.error(msg); } } diff --git a/jadx-core/src/test/java/jadx/tests/functional/TypeMergeTest.java b/jadx-core/src/test/java/jadx/tests/functional/TypeMergeTest.java index 83b30a454..297fa38a6 100644 --- a/jadx-core/src/test/java/jadx/tests/functional/TypeMergeTest.java +++ b/jadx-core/src/test/java/jadx/tests/functional/TypeMergeTest.java @@ -11,11 +11,13 @@ import org.junit.Before; import org.junit.Test; import static jadx.core.dex.instructions.args.ArgType.BOOLEAN; +import static jadx.core.dex.instructions.args.ArgType.BYTE; import static jadx.core.dex.instructions.args.ArgType.CHAR; import static jadx.core.dex.instructions.args.ArgType.INT; import static jadx.core.dex.instructions.args.ArgType.LONG; import static jadx.core.dex.instructions.args.ArgType.NARROW; import static jadx.core.dex.instructions.args.ArgType.OBJECT; +import static jadx.core.dex.instructions.args.ArgType.STRING; import static jadx.core.dex.instructions.args.ArgType.UNKNOWN; import static jadx.core.dex.instructions.args.ArgType.UNKNOWN_OBJECT; import static jadx.core.dex.instructions.args.ArgType.genericType; @@ -57,6 +59,13 @@ public class TypeMergeTest { unknown(PrimitiveType.OBJECT, PrimitiveType.ARRAY), unknown(PrimitiveType.OBJECT)); + check(ArgType.array(INT), ArgType.array(BYTE), ArgType.OBJECT); + first(ArgType.array(INT), ArgType.array(INT)); + first(ArgType.array(STRING), ArgType.array(STRING)); + + first(OBJECT, ArgType.array(INT)); + first(OBJECT, ArgType.array(STRING)); + ArgType objExc = object("java.lang.Exception"); ArgType objThr = object("java.lang.Throwable"); ArgType objIO = object("java.io.IOException"); diff --git a/jadx-samples/src/main/java/jadx/samples/TestArrays.java b/jadx-samples/src/main/java/jadx/samples/TestArrays.java index 2d4e55b99..fbe599b90 100644 --- a/jadx-samples/src/main/java/jadx/samples/TestArrays.java +++ b/jadx-samples/src/main/java/jadx/samples/TestArrays.java @@ -4,7 +4,7 @@ public class TestArrays extends AbstractTest { public int test1(int i) { // fill-array-data - int[] a = new int[] { 1, 2, 3, 5 }; + int[] a = new int[]{1, 2, 3, 5}; return a[i]; } @@ -20,11 +20,27 @@ public class TestArrays extends AbstractTest { return a.length; } + private static Object test4(int type) { + if (type == 1) { + return new int[]{1, 2}; + } else if (type == 2) { + return new float[]{1, 2}; + } else if (type == 3) { + return new short[]{1, 2}; + } else if (type == 4) { + return new byte[]{1, 2}; + } else { + return null; + } + } + @Override public boolean testRun() throws Exception { assertEquals(test1(2), 3); assertEquals(test2(2), 2); assertEquals(test3(2), 2); + + assertTrue(test4(4) instanceof byte[]); return true; }