From ac8785e5d550c2ec7c7d02dd2990f859a78c111c Mon Sep 17 00:00:00 2001 From: "JesusFreke@JesusFreke.com" Date: Sun, 24 Jan 2010 03:40:43 +0000 Subject: [PATCH] Implemented verification for filled-new-array/range git-svn-id: https://smali.googlecode.com/svn/trunk@576 55b6fa8a-2a1e-11de-a435-ffa8d773f76a --- .../dexlib/Code/Analysis/MethodAnalyzer.java | 113 +++++++++++++----- 1 file changed, 85 insertions(+), 28 deletions(-) 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 d4f32c78..c626359e 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 @@ -460,6 +460,8 @@ public class MethodAnalyzer { return handleNewArray(analyzedInstruction); case FILLED_NEW_ARRAY: return handleFilledNewArray(analyzedInstruction); + case FILLED_NEW_ARRAY_RANGE: + return handleFilledNewArrayRange(analyzedInstruction); } assert false; return false; @@ -948,41 +950,40 @@ public class MethodAnalyzer { return true; } - private boolean handleFilledNewArray(AnalyzedInstruction analyzedInstruction) { + private static interface RegisterIterator { + int getRegister(); + boolean moveNext(); + } + + private boolean handleFilledNewArrayCommon(AnalyzedInstruction analyzedInstruction, + RegisterIterator registerIterator) { + InstructionWithReference instruction = (InstructionWithReference)analyzedInstruction.instruction; + RegisterType arrayType; RegisterType arrayImmediateElementType; - { - InstructionWithReference instruction = (InstructionWithReference)analyzedInstruction.instruction; - Item item = instruction.getReferencedItem(); - assert item.getItemType() == ItemType.TYPE_TYPE_ID_ITEM; + Item item = instruction.getReferencedItem(); + assert item.getItemType() == ItemType.TYPE_TYPE_ID_ITEM; - ClassPath.ClassDef classDef = ClassPath.getClassDef((TypeIdItem)item); + ClassPath.ClassDef classDef = ClassPath.getClassDef((TypeIdItem)item); - if (classDef.getClassType().charAt(0) != '[') { - throw new ValidationException("Cannot use non-array type \"" + classDef.getClassType() + - "\" with new-array. Use new-instance instead."); - } - - ClassPath.ArrayClassDef arrayClassDef = (ClassPath.ArrayClassDef)classDef; - arrayType = RegisterType.getRegisterType(RegisterType.Category.Reference, classDef); - arrayImmediateElementType = RegisterType.getRegisterTypeForType( - arrayClassDef.getImmediateElementClass().getClassType()); - String baseElementType = arrayClassDef.getBaseElementClass().getClassType(); - if (baseElementType.charAt(0) == 'J' || baseElementType.charAt(0) == 'D') { - throw new ValidationException("Cannot use filled-new-array to create an array of wide values " + - "(long or double)"); - } + if (classDef.getClassType().charAt(0) != '[') { + throw new ValidationException("Cannot use non-array type \"" + classDef.getClassType() + + "\" with new-array. Use new-instance instead."); } - FiveRegisterInstruction instruction = (FiveRegisterInstruction)analyzedInstruction.instruction; - int registerCount = instruction.getRegCount(); + ClassPath.ArrayClassDef arrayClassDef = (ClassPath.ArrayClassDef)classDef; + arrayType = RegisterType.getRegisterType(RegisterType.Category.Reference, classDef); + arrayImmediateElementType = RegisterType.getRegisterTypeForType( + arrayClassDef.getImmediateElementClass().getClassType()); + String baseElementType = arrayClassDef.getBaseElementClass().getClassType(); + if (baseElementType.charAt(0) == 'J' || baseElementType.charAt(0) == 'D') { + throw new ValidationException("Cannot use filled-new-array to create an array of wide values " + + "(long or double)"); + } - byte[] registers = new byte[]{instruction.getRegisterD(), instruction.getRegisterE(), instruction.getRegisterF(), - instruction.getRegisterG(), instruction.getRegisterA()}; - - for (int i=0; i= registerCount) { + return false; + } + return true; + } + }); + } + + private boolean handleFilledNewArrayRange(AnalyzedInstruction analyzedInstruction) { + final RegisterRangeInstruction instruction = (RegisterRangeInstruction)analyzedInstruction.instruction; + + //instruction.getStartRegister() and instruction.getRegCount() both return an int value, but are actually + //unsigned 16 bit values, so we don't have to worry about overflowing an int when adding them together + if (instruction.getStartRegister() + instruction.getRegCount() >= 1<<16) { + throw new ValidationException(String.format("Invalid register range {v%d .. v%d}. The ending register " + + " is larger than the largest allowed register of v65535.", + instruction.getStartRegister(), + instruction.getStartRegister() + instruction.getRegCount() - 1)); + } + + return handleFilledNewArrayCommon(analyzedInstruction, + new RegisterIterator() { + private int currentRegister = 0; + private final int startRegister = instruction.getStartRegister(); + private final int registerCount = instruction.getRegCount(); + + public int getRegister() { + return startRegister + currentRegister; + } + + public boolean moveNext() { + currentRegister++; + if (currentRegister >= registerCount) { + return false; + } + return true; + } + }); + } + private static void checkRegister(RegisterType registerType, EnumSet validCategories) { if (!validCategories.contains(registerType.category)) { //TODO: add expected categories to error message