Commit d6069820 authored by Skylot's avatar Skylot

core: fix type in fill-array instruction

parent c59b65e7
...@@ -30,6 +30,8 @@ import jadx.core.dex.nodes.FieldNode; ...@@ -30,6 +30,8 @@ import jadx.core.dex.nodes.FieldNode;
import jadx.core.dex.nodes.InsnNode; import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.nodes.RootNode; 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.StringUtils;
import jadx.core.utils.exceptions.CodegenException; import jadx.core.utils.exceptions.CodegenException;
...@@ -450,15 +452,19 @@ public class InsnGen { ...@@ -450,15 +452,19 @@ public class InsnGen {
} }
private void fillArray(FillArrayNode insn, CodeWriter code) throws CodegenException { private void fillArray(FillArrayNode insn, CodeWriter code) throws CodegenException {
ArgType elType = insn.getResult().getType().getArrayElement(); ArgType insnArrayType = insn.getResult().getType();
if (elType.getPrimitiveType() == null) { ArgType insnElementType = insnArrayType.getArrayElement();
elType = elType.selectFirst(); 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(); StringBuilder str = new StringBuilder();
Object data = insn.getData();
switch (elType.getPrimitiveType()) { switch (elType.getPrimitiveType()) {
case BOOLEAN: case BOOLEAN:
case BYTE: case BYTE:
byte[] array = (byte[]) insn.getData(); byte[] array = (byte[]) data;
for (byte b : array) { for (byte b : array) {
str.append(TypeGen.literalToString(b, elType)); str.append(TypeGen.literalToString(b, elType));
str.append(", "); str.append(", ");
...@@ -466,7 +472,7 @@ public class InsnGen { ...@@ -466,7 +472,7 @@ public class InsnGen {
break; break;
case SHORT: case SHORT:
case CHAR: case CHAR:
short[] sarray = (short[]) insn.getData(); short[] sarray = (short[]) data;
for (short b : sarray) { for (short b : sarray) {
str.append(TypeGen.literalToString(b, elType)); str.append(TypeGen.literalToString(b, elType));
str.append(", "); str.append(", ");
...@@ -474,7 +480,7 @@ public class InsnGen { ...@@ -474,7 +480,7 @@ public class InsnGen {
break; break;
case INT: case INT:
case FLOAT: case FLOAT:
int[] iarray = (int[]) insn.getData(); int[] iarray = (int[]) data;
for (int b : iarray) { for (int b : iarray) {
str.append(TypeGen.literalToString(b, elType)); str.append(TypeGen.literalToString(b, elType));
str.append(", "); str.append(", ");
...@@ -482,7 +488,7 @@ public class InsnGen { ...@@ -482,7 +488,7 @@ public class InsnGen {
break; break;
case LONG: case LONG:
case DOUBLE: case DOUBLE:
long[] larray = (long[]) insn.getData(); long[] larray = (long[]) data;
for (long b : larray) { for (long b : larray) {
str.append(TypeGen.literalToString(b, elType)); str.append(TypeGen.literalToString(b, elType));
str.append(", "); str.append(", ");
...@@ -494,7 +500,7 @@ public class InsnGen { ...@@ -494,7 +500,7 @@ public class InsnGen {
} }
int len = str.length(); int len = str.length();
str.delete(len - 2, len); 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<IGState> state) private void makeConstructor(ConstructorInsn insn, CodeWriter code, EnumSet<IGState> state)
......
...@@ -4,18 +4,17 @@ import jadx.core.dex.instructions.args.ArgType; ...@@ -4,18 +4,17 @@ import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.instructions.args.InsnArg; import jadx.core.dex.instructions.args.InsnArg;
import jadx.core.dex.instructions.args.PrimitiveType; import jadx.core.dex.instructions.args.PrimitiveType;
import jadx.core.dex.nodes.InsnNode; import jadx.core.dex.nodes.InsnNode;
import jadx.core.utils.exceptions.JadxRuntimeException;
import com.android.dx.io.instructions.FillArrayDataPayloadDecodedInstruction; import com.android.dx.io.instructions.FillArrayDataPayloadDecodedInstruction;
public class FillArrayNode extends InsnNode { public class FillArrayNode extends InsnNode {
private final Object data; private final Object data;
private ArgType elemType;
public FillArrayNode(int resReg, FillArrayDataPayloadDecodedInstruction payload) { public FillArrayNode(int resReg, FillArrayDataPayloadDecodedInstruction payload) {
super(InsnType.FILL_ARRAY, 0); super(InsnType.FILL_ARRAY, 0);
this.data = payload.getData();
ArgType elType; ArgType elType;
switch (payload.getElementWidthUnit()) { switch (payload.getElementWidthUnit()) {
case 1: case 1:
...@@ -32,12 +31,26 @@ public class FillArrayNode extends InsnNode { ...@@ -32,12 +31,26 @@ public class FillArrayNode extends InsnNode {
break; break;
default: default:
throw new AssertionError(); throw new JadxRuntimeException("Unknown array element width: " + payload.getElementWidthUnit());
} }
setResult(InsnArg.reg(resReg, ArgType.array(elType))); setResult(InsnArg.reg(resReg, ArgType.array(elType)));
this.data = payload.getData();
this.elemType = elType;
} }
public Object getData() { public Object getData() {
return data; return data;
} }
public ArgType getElementType() {
return elemType;
}
public void mergeElementType(ArgType foundElemType) {
ArgType r = ArgType.merge(elemType, foundElemType);
if (r != null) {
elemType = r;
}
}
} }
...@@ -339,7 +339,7 @@ public abstract class ArgType { ...@@ -339,7 +339,7 @@ public abstract class ArgType {
} }
public static ArgType merge(ArgType a, ArgType b) { public static ArgType merge(ArgType a, ArgType b) {
if (a == b) if (a.equals(b))
return a; return a;
if (b == null || a == null) if (b == null || a == null)
...@@ -352,9 +352,9 @@ public abstract class ArgType { ...@@ -352,9 +352,9 @@ public abstract class ArgType {
} }
private static ArgType mergeInternal(ArgType a, ArgType b) { private static ArgType mergeInternal(ArgType a, ArgType b) {
if (a == UNKNOWN) if (a == UNKNOWN) {
return b; return b;
}
if (!a.isTypeKnown()) { if (!a.isTypeKnown()) {
if (b.isTypeKnown()) { if (b.isTypeKnown()) {
if (a.contains(b.getPrimitiveType())) if (a.contains(b.getPrimitiveType()))
...@@ -399,10 +399,22 @@ public abstract class ArgType { ...@@ -399,10 +399,22 @@ public abstract class ArgType {
return (obj == null ? null : object(obj)); return (obj == null ? null : object(obj));
} }
} }
if (a.isArray() && b.isArray()) { if (a.isArray()) {
ArgType res = merge(a.getArrayElement(), b.getArrayElement()); 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)); 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()) { if (a.isPrimitive() && b.isPrimitive() && a.getRegCount() == b.getRegCount()) {
return primitive(PrimitiveType.getSmaller(a.getPrimitiveType(), b.getPrimitiveType())); return primitive(PrimitiveType.getSmaller(a.getPrimitiveType(), b.getPrimitiveType()));
} }
......
...@@ -5,6 +5,7 @@ import jadx.core.dex.attributes.AttributeType; ...@@ -5,6 +5,7 @@ import jadx.core.dex.attributes.AttributeType;
import jadx.core.dex.info.MethodInfo; import jadx.core.dex.info.MethodInfo;
import jadx.core.dex.instructions.ConstClassNode; import jadx.core.dex.instructions.ConstClassNode;
import jadx.core.dex.instructions.ConstStringNode; import jadx.core.dex.instructions.ConstStringNode;
import jadx.core.dex.instructions.FillArrayNode;
import jadx.core.dex.instructions.IndexInsnNode; import jadx.core.dex.instructions.IndexInsnNode;
import jadx.core.dex.instructions.InsnType; import jadx.core.dex.instructions.InsnType;
import jadx.core.dex.instructions.InvokeNode; import jadx.core.dex.instructions.InvokeNode;
...@@ -164,6 +165,7 @@ public class ModVisitor extends AbstractVisitor { ...@@ -164,6 +165,7 @@ public class ModVisitor extends AbstractVisitor {
InsnNode ni = block.getInstructions().get(next); InsnNode ni = block.getInstructions().get(next);
if (ni.getType() == InsnType.FILL_ARRAY) { if (ni.getType() == InsnType.FILL_ARRAY) {
ni.getResult().merge(insn.getResult()); ni.getResult().merge(insn.getResult());
((FillArrayNode) ni).mergeElementType(insn.getResult().getType().getArrayElement());
remover.add(insn); remover.add(insn);
} }
} }
......
package jadx.core.utils; package jadx.core.utils;
import jadx.core.dex.attributes.AttributeFlag;
import jadx.core.dex.attributes.IAttributeNode; import jadx.core.dex.attributes.IAttributeNode;
import jadx.core.dex.attributes.JadxErrorAttr; import jadx.core.dex.attributes.JadxErrorAttr;
import jadx.core.dex.nodes.ClassNode; import jadx.core.dex.nodes.ClassNode;
...@@ -40,6 +41,7 @@ public class ErrorsCounter { ...@@ -40,6 +41,7 @@ public class ErrorsCounter {
} }
node.getAttributes().add(new JadxErrorAttr(e)); node.getAttributes().add(new JadxErrorAttr(e));
} else { } else {
node.getAttributes().add(AttributeFlag.INCONSISTENT_CODE);
LOG.error(msg); LOG.error(msg);
} }
} }
......
...@@ -11,11 +11,13 @@ import org.junit.Before; ...@@ -11,11 +11,13 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import static jadx.core.dex.instructions.args.ArgType.BOOLEAN; 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.CHAR;
import static jadx.core.dex.instructions.args.ArgType.INT; 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.LONG;
import static jadx.core.dex.instructions.args.ArgType.NARROW; 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.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;
import static jadx.core.dex.instructions.args.ArgType.UNKNOWN_OBJECT; import static jadx.core.dex.instructions.args.ArgType.UNKNOWN_OBJECT;
import static jadx.core.dex.instructions.args.ArgType.genericType; import static jadx.core.dex.instructions.args.ArgType.genericType;
...@@ -57,6 +59,13 @@ public class TypeMergeTest { ...@@ -57,6 +59,13 @@ public class TypeMergeTest {
unknown(PrimitiveType.OBJECT, PrimitiveType.ARRAY), unknown(PrimitiveType.OBJECT, PrimitiveType.ARRAY),
unknown(PrimitiveType.OBJECT)); 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 objExc = object("java.lang.Exception");
ArgType objThr = object("java.lang.Throwable"); ArgType objThr = object("java.lang.Throwable");
ArgType objIO = object("java.io.IOException"); ArgType objIO = object("java.io.IOException");
......
...@@ -4,7 +4,7 @@ public class TestArrays extends AbstractTest { ...@@ -4,7 +4,7 @@ public class TestArrays extends AbstractTest {
public int test1(int i) { public int test1(int i) {
// fill-array-data // fill-array-data
int[] a = new int[] { 1, 2, 3, 5 }; int[] a = new int[]{1, 2, 3, 5};
return a[i]; return a[i];
} }
...@@ -20,11 +20,27 @@ public class TestArrays extends AbstractTest { ...@@ -20,11 +20,27 @@ public class TestArrays extends AbstractTest {
return a.length; 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 @Override
public boolean testRun() throws Exception { public boolean testRun() throws Exception {
assertEquals(test1(2), 3); assertEquals(test1(2), 3);
assertEquals(test2(2), 2); assertEquals(test2(2), 2);
assertEquals(test3(2), 2); assertEquals(test3(2), 2);
assertTrue(test4(4) instanceof byte[]);
return true; return true;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment