From c849236be2031b02d66eac4149617fd8a83572b4 Mon Sep 17 00:00:00 2001 From: "JesusFreke@JesusFreke.com" Date: Mon, 25 Jan 2010 01:42:45 +0000 Subject: [PATCH] Implemented verification for aput/aput-boolean/aput-byte/aput-char/aput-short git-svn-id: https://smali.googlecode.com/svn/trunk@590 55b6fa8a-2a1e-11de-a435-ffa8d773f76a --- .../dexlib/Code/Analysis/MethodAnalyzer.java | 72 +++++++++++++++++++ 1 file changed, 72 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 68ce5b2f..1139d870 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 @@ -514,6 +514,16 @@ public class MethodAnalyzer { return handleAgetWide(analyzedInstruction); case AGET_OBJECT: return handleAgetObject(analyzedInstruction); + case APUT: + return handle32BitPrimitiveAput(analyzedInstruction, RegisterType.Category.Integer); + case APUT_BOOLEAN: + return handle32BitPrimitiveAput(analyzedInstruction, RegisterType.Category.Boolean); + case APUT_BYTE: + return handle32BitPrimitiveAput(analyzedInstruction, RegisterType.Category.Byte); + case APUT_CHAR: + return handle32BitPrimitiveAput(analyzedInstruction, RegisterType.Category.Char); + case APUT_SHORT: + return handle32BitPrimitiveAput(analyzedInstruction, RegisterType.Category.Short); } assert false; @@ -1519,6 +1529,68 @@ public class MethodAnalyzer { return true; } + private boolean handle32BitPrimitiveAput(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 sourceRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA()); + assert sourceRegisterType != null; + if (sourceRegisterType.category == RegisterType.Category.Unknown) { + return false; + } + RegisterType instructionRegisterType = RegisterType.getRegisterType(instructionCategory, null); + if (!sourceRegisterType.canBeAssignedTo(instructionRegisterType)) { + throw new ValidationException(String.format("Cannot use %s with source register type %s.", + analyzedInstruction.instruction.opcode.name, sourceRegisterType.toString())); + } + + + 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())); + } + } + + return true; + } + private static boolean checkArrayFieldAssignment(RegisterType.Category arrayFieldCategory, RegisterType.Category instructionCategory) { if (arrayFieldCategory == instructionCategory) {