Implemented verification for aget/aget-boolean/aget-byte/aget-char/aget-short

git-svn-id: https://smali.googlecode.com/svn/trunk@587 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
JesusFreke@JesusFreke.com
2010-01-25 00:20:56 +00:00
parent 16a709ba04
commit b239745290

View File

@ -500,7 +500,18 @@ public class MethodAnalyzer {
case IF_GTZ:
case IF_LEZ:
return handleIfz(analyzedInstruction);
case AGET:
return handle32BitPrimitiveAget(analyzedInstruction, RegisterType.Category.Integer);
case AGET_BOOLEAN:
return handle32BitPrimitiveAget(analyzedInstruction, RegisterType.Category.Boolean);
case AGET_BYTE:
return handle32BitPrimitiveAget(analyzedInstruction, RegisterType.Category.Byte);
case AGET_CHAR:
return handle32BitPrimitiveAget(analyzedInstruction, RegisterType.Category.Char);
case AGET_SHORT:
return handle32BitPrimitiveAget(analyzedInstruction, RegisterType.Category.Short);
}
assert false;
return false;
}
@ -1349,6 +1360,73 @@ public class MethodAnalyzer {
return true;
}
private boolean handle32BitPrimitiveAget(AnalyzedInstruction analyzedInstruction,
RegisterType.Category instructionCategory) {
ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction;
RegisterType indexRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterC());
assert indexRegisterType != null;
if (indexRegisterType.category == RegisterType.Category.Unknown) {
return false;
}
checkRegister(indexRegisterType, Primitive32BitCategories);
RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
assert arrayRegisterType != null;
if (indexRegisterType.category == RegisterType.Category.Unknown) {
return false;
}
if (arrayRegisterType.category != RegisterType.Category.Null) {
if (arrayRegisterType.category != RegisterType.Category.Reference) {
throw new ValidationException(String.format("Cannot use %s with non-array type %s",
analyzedInstruction.instruction.opcode.name, arrayRegisterType.category.toString()));
}
assert arrayRegisterType.type != null;
if (arrayRegisterType.type.getClassType().charAt(0) != '[') {
throw new ValidationException(String.format("Cannot use %s with non-array type %s",
analyzedInstruction.instruction.opcode.name, arrayRegisterType.type.getClassType()));
}
assert arrayRegisterType.type instanceof ClassPath.ArrayClassDef;
ClassPath.ArrayClassDef arrayClassDef = (ClassPath.ArrayClassDef)arrayRegisterType.type;
if (arrayClassDef.getArrayDimensions() != 1) {
throw new ValidationException(String.format("Cannot use %s with multi-dimensional array type %s",
analyzedInstruction.instruction.opcode.name, arrayRegisterType.type.getClassType()));
}
RegisterType arrayBaseType =
RegisterType.getRegisterTypeForType(arrayClassDef.getBaseElementClass().getClassType());
if (checkArrayFieldAssignment(arrayBaseType.category, instructionCategory)) {
throw new ValidationException(String.format("Cannot use %s with array type %s. Incorrect array type " +
"for the instruction.", analyzedInstruction.instruction.opcode.name,
arrayRegisterType.type.getClassType()));
}
}
setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
RegisterType.getRegisterType(instructionCategory, null));
return true;
}
private static boolean checkArrayFieldAssignment(RegisterType.Category arrayFieldCategory,
RegisterType.Category instructionCategory) {
if (arrayFieldCategory == instructionCategory) {
return true;
}
if ((arrayFieldCategory == RegisterType.Category.Integer &&
instructionCategory == RegisterType.Category.Float) ||
(arrayFieldCategory == RegisterType.Category.Float &&
instructionCategory == RegisterType.Category.Integer)) {
return true;
}
return false;
}
private static void checkRegister(RegisterType registerType, EnumSet validCategories) {
if (!validCategories.contains(registerType.category)) {
//TODO: add expected categories to error message