fix: correct type and data merge for filled-array instruction

This commit is contained in:
Skylot
2020-08-23 15:11:27 +01:00
parent 605a67932f
commit 89b4ae6a6f
5 changed files with 94 additions and 7 deletions
@@ -569,8 +569,16 @@ public class InsnGen {
private void fillArray(CodeWriter code, FillArrayInsn arrayNode) throws CodegenException {
code.add("// fill-array-data instruction");
code.startLine();
List<LiteralArg> args = arrayNode.getLiteralArgs(arrayNode.getElementType());
InsnArg arrArg = arrayNode.getArg(0);
ArgType arrayType = arrArg.getType();
ArgType elemType;
if (arrayType.isTypeKnown() && arrayType.isArray()) {
elemType = arrayType.getArrayElement();
} else {
ArgType elementType = arrayNode.getElementType(); // unknown type
elemType = elementType.selectFirst();
}
List<LiteralArg> args = arrayNode.getLiteralArgs(elemType);
int len = args.size();
for (int i = 0; i < len; i++) {
if (i != 0) {
@@ -14,7 +14,7 @@ import jadx.core.utils.exceptions.JadxRuntimeException;
public final class FillArrayData extends InsnNode {
private static final ArgType ONE_BYTE_TYPE = ArgType.unknown(PrimitiveType.BOOLEAN, PrimitiveType.BYTE);
private static final ArgType ONE_BYTE_TYPE = ArgType.unknown(PrimitiveType.BYTE, PrimitiveType.BOOLEAN);
private static final ArgType TWO_BYTES_TYPE = ArgType.unknown(PrimitiveType.SHORT, PrimitiveType.CHAR);
private static final ArgType FOUR_BYTES_TYPE = ArgType.unknown(PrimitiveType.INT, PrimitiveType.FLOAT);
private static final ArgType EIGHT_BYTES_TYPE = ArgType.unknown(PrimitiveType.LONG, PrimitiveType.DOUBLE);
@@ -0,0 +1,53 @@
package jadx.core.utils;
import org.jetbrains.annotations.Nullable;
import jadx.api.plugins.input.data.annotations.EncodedValue;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.instructions.args.InsnArg;
import jadx.core.dex.instructions.args.LiteralArg;
import jadx.core.dex.nodes.RootNode;
public class EncodedValueUtils {
/**
* Return constant literal from {@code jadx.api.plugins.input.data.annotations.EncodedValue}
*
* @return LiteralArg, String, ArgType or null
*/
@Nullable
public static Object convertToConstValue(RootNode root, EncodedValue encodedValue) {
if (encodedValue == null) {
return null;
}
Object value = encodedValue.getValue();
switch (encodedValue.getType()) {
case ENCODED_NULL:
return InsnArg.lit(0, ArgType.OBJECT);
case ENCODED_BOOLEAN:
return Boolean.TRUE.equals(value) ? LiteralArg.TRUE : LiteralArg.FALSE;
case ENCODED_BYTE:
return InsnArg.lit((Byte) value, ArgType.BYTE);
case ENCODED_SHORT:
return InsnArg.lit((Short) value, ArgType.SHORT);
case ENCODED_CHAR:
return InsnArg.lit((Character) value, ArgType.CHAR);
case ENCODED_INT:
return InsnArg.lit((Integer) value, ArgType.INT);
case ENCODED_LONG:
return InsnArg.lit((Long) value, ArgType.LONG);
case ENCODED_FLOAT:
return InsnArg.lit(Float.floatToIntBits((Float) value), ArgType.FLOAT);
case ENCODED_DOUBLE:
return InsnArg.lit(Double.doubleToLongBits((Double) value), ArgType.DOUBLE);
case ENCODED_STRING:
return (String) value;
case ENCODED_TYPE:
return ArgType.parse((String) value);
default:
return null;
}
}
}
@@ -101,11 +101,8 @@ public class InsnUtils {
return null;
}
FieldInitAttr attr = fieldNode.get(AType.FIELD_INIT);
if (attr != null) {
if (attr.getValueType() == FieldInitAttr.InitType.CONST) {
return attr.getEncodedValue().getValue();
}
return attr.getInsn();
if (attr != null && attr.getValueType() == FieldInitAttr.InitType.CONST) {
return EncodedValueUtils.convertToConstValue(root, attr.getEncodedValue());
}
return null;
@@ -0,0 +1,29 @@
package jadx.tests.integration.arrays;
import org.junit.jupiter.api.Test;
import jadx.tests.api.IntegrationTest;
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
public class TestArrayFill4 extends IntegrationTest {
public static class TestCls {
// replaced constant break filled array creation
private static final int ARRAY_SIZE = 4;
public long[] test() {
return new long[] { 0, 1, Long.MAX_VALUE, Long.MIN_VALUE + 1 };
}
}
@Test
public void test() {
noDebugInfo();
assertThat(getClassNode(TestCls.class))
.code()
.doesNotContain("new long[ARRAY_SIZE];")
.containsOne("return new long[]{0, 1, ");
}
}