From b2397452907c28b0743bbbcdf9fa6b2a8208aeab Mon Sep 17 00:00:00 2001 From: "JesusFreke@JesusFreke.com" Date: Mon, 25 Jan 2010 00:20:56 +0000 Subject: [PATCH] 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 --- .../dexlib/Code/Analysis/MethodAnalyzer.java | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/MethodAnalyzer.java b/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/MethodAnalyzer.java index fbdc16cd..bc0f24ec 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/MethodAnalyzer.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/MethodAnalyzer.java @@ -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