Home | History | Annotate | Download | only in analysis
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 /*
     18  * Dalvik classfile verification.  This file contains the verifier entry
     19  * points and the static constraint checks.
     20  */
     21 #include "Dalvik.h"
     22 #include "analysis/CodeVerify.h"
     23 
     24 
     25 /* fwd */
     26 static bool verifyMethod(Method* meth, int verifyFlags);
     27 static bool verifyInstructions(const Method* meth, InsnFlags* insnFlags,
     28     int verifyFlags);
     29 
     30 
     31 /*
     32  * Initialize some things we need for verification.
     33  */
     34 bool dvmVerificationStartup(void)
     35 {
     36     gDvm.instrWidth = dexCreateInstrWidthTable();
     37     gDvm.instrFormat = dexCreateInstrFormatTable();
     38     gDvm.instrFlags = dexCreateInstrFlagsTable();
     39     if (gDvm.instrWidth == NULL || gDvm.instrFormat == NULL ||
     40         gDvm.instrFlags == NULL)
     41     {
     42         LOGE("Unable to create instruction tables\n");
     43         return false;
     44     }
     45 
     46     return true;
     47 }
     48 
     49 /*
     50  * Free up some things we needed for verification.
     51  */
     52 void dvmVerificationShutdown(void)
     53 {
     54     free(gDvm.instrWidth);
     55     free(gDvm.instrFormat);
     56     free(gDvm.instrFlags);
     57 }
     58 
     59 /*
     60  * Induce verification on all classes loaded from this DEX file as part
     61  * of pre-verification and optimization.  This is never called from a
     62  * normally running VM.
     63  *
     64  * Returns "true" when all classes have been processed.
     65  */
     66 bool dvmVerifyAllClasses(DexFile* pDexFile)
     67 {
     68     u4 count = pDexFile->pHeader->classDefsSize;
     69     u4 idx;
     70 
     71     assert(gDvm.optimizing);
     72 
     73     if (gDvm.classVerifyMode == VERIFY_MODE_NONE) {
     74         LOGV("+++ verification is disabled, skipping all classes\n");
     75         return true;
     76     }
     77     if (gDvm.classVerifyMode == VERIFY_MODE_REMOTE &&
     78         gDvm.optimizingBootstrapClass)
     79     {
     80         LOGV("+++ verification disabled for bootstrap classes\n");
     81         return true;
     82     }
     83 
     84     for (idx = 0; idx < count; idx++) {
     85         const DexClassDef* pClassDef;
     86         const char* classDescriptor;
     87         ClassObject* clazz;
     88 
     89         pClassDef = dexGetClassDef(pDexFile, idx);
     90         classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
     91 
     92         /* all classes are loaded into the bootstrap class loader */
     93         clazz = dvmLookupClass(classDescriptor, NULL, false);
     94         if (clazz != NULL) {
     95             if (clazz->pDvmDex->pDexFile != pDexFile) {
     96                 LOGD("DexOpt: not verifying '%s': multiple definitions\n",
     97                     classDescriptor);
     98             } else {
     99                 if (dvmVerifyClass(clazz, VERIFY_DEFAULT)) {
    100                     assert((clazz->accessFlags & JAVA_FLAGS_MASK) ==
    101                         pClassDef->accessFlags);
    102                     ((DexClassDef*)pClassDef)->accessFlags |=
    103                         CLASS_ISPREVERIFIED;
    104                 }
    105                 /* keep going even if one fails */
    106             }
    107         } else {
    108             LOGV("DexOpt: +++  not verifying '%s'\n", classDescriptor);
    109         }
    110     }
    111 
    112     return true;
    113 }
    114 
    115 /*
    116  * Verify a class.
    117  *
    118  * By the time we get here, the value of gDvm.classVerifyMode should already
    119  * have been factored in.  If you want to call into the verifier even
    120  * though verification is disabled, that's your business.
    121  *
    122  * Returns "true" on success.
    123  */
    124 bool dvmVerifyClass(ClassObject* clazz, int verifyFlags)
    125 {
    126     int i;
    127 
    128     if (dvmIsClassVerified(clazz)) {
    129         LOGD("Ignoring duplicate verify attempt on %s\n", clazz->descriptor);
    130         return true;
    131     }
    132 
    133     //LOGI("Verify1 '%s'\n", clazz->descriptor);
    134 
    135     // TODO - verify class structure in DEX?
    136 
    137     for (i = 0; i < clazz->directMethodCount; i++) {
    138         if (!verifyMethod(&clazz->directMethods[i], verifyFlags)) {
    139             LOG_VFY("Verifier rejected class %s\n", clazz->descriptor);
    140             return false;
    141         }
    142     }
    143     for (i = 0; i < clazz->virtualMethodCount; i++) {
    144         if (!verifyMethod(&clazz->virtualMethods[i], verifyFlags)) {
    145             LOG_VFY("Verifier rejected class %s\n", clazz->descriptor);
    146             return false;
    147         }
    148     }
    149 
    150     return true;
    151 }
    152 
    153 
    154 /*
    155  * Perform verification on a single method.
    156  *
    157  * We do this in three passes:
    158  *  (1) Walk through all code units, determining instruction lengths.
    159  *  (2) Do static checks, including branch target and operand validation.
    160  *  (3) Do structural checks, including data-flow analysis.
    161  *
    162  * Some checks may be bypassed depending on the verification mode.  We can't
    163  * turn this stuff off completely if we want to do "exact" GC.
    164  *
    165  * - operands of getfield, putfield, getstatic, putstatic must be valid
    166  * - operands of method invocation instructions must be valid
    167  *
    168  * - code array must not be empty
    169  * - (N/A) code_length must be less than 65536
    170  * - opcode of first instruction begins at index 0
    171  * - only documented instructions may appear
    172  * - each instruction follows the last
    173  * - (below) last byte of last instruction is at (code_length-1)
    174  */
    175 static bool verifyMethod(Method* meth, int verifyFlags)
    176 {
    177     bool result = false;
    178     UninitInstanceMap* uninitMap = NULL;
    179     InsnFlags* insnFlags = NULL;
    180     int i, newInstanceCount;
    181 
    182     /*
    183      * If there aren't any instructions, make sure that's expected, then
    184      * exit successfully. Note: meth->insns gets set to a native function
    185      * pointer on first call.
    186      */
    187     if (dvmGetMethodInsnsSize(meth) == 0) {
    188         if (!dvmIsNativeMethod(meth) && !dvmIsAbstractMethod(meth)) {
    189             LOG_VFY_METH(meth,
    190                 "VFY: zero-length code in concrete non-native method\n");
    191             goto bail;
    192         }
    193 
    194         goto success;
    195     }
    196 
    197     /*
    198      * Sanity-check the register counts.  ins + locals = registers, so make
    199      * sure that ins <= registers.
    200      */
    201     if (meth->insSize > meth->registersSize) {
    202         LOG_VFY_METH(meth, "VFY: bad register counts (ins=%d regs=%d)\n",
    203             meth->insSize, meth->registersSize);
    204         goto bail;
    205     }
    206 
    207     /*
    208      * Allocate and populate an array to hold instruction data.
    209      *
    210      * TODO: Consider keeping a reusable pre-allocated array sitting
    211      * around for smaller methods.
    212      */
    213     insnFlags = (InsnFlags*)
    214         calloc(dvmGetMethodInsnsSize(meth), sizeof(InsnFlags));
    215     if (insnFlags == NULL)
    216         goto bail;
    217 
    218     /*
    219      * Compute the width of each instruction and store the result in insnFlags.
    220      * Count up the #of occurrences of new-instance instructions while we're
    221      * at it.
    222      */
    223     if (!dvmComputeCodeWidths(meth, insnFlags, &newInstanceCount))
    224         goto bail;
    225 
    226     /*
    227      * Allocate a map to hold the classes of uninitialized instances.
    228      */
    229     uninitMap = dvmCreateUninitInstanceMap(meth, insnFlags, newInstanceCount);
    230     if (uninitMap == NULL)
    231         goto bail;
    232 
    233     /*
    234      * Set the "in try" flags for all instructions guarded by a "try" block.
    235      */
    236     if (!dvmSetTryFlags(meth, insnFlags))
    237         goto bail;
    238 
    239     /*
    240      * Perform static instruction verification.
    241      */
    242     if (!verifyInstructions(meth, insnFlags, verifyFlags))
    243         goto bail;
    244 
    245     /*
    246      * Do code-flow analysis.  Do this after verifying the branch targets
    247      * so we don't need to worry about it here.
    248      *
    249      * If there are no registers, we don't need to do much in the way of
    250      * analysis, but we still need to verify that nothing actually tries
    251      * to use a register.
    252      */
    253     if (!dvmVerifyCodeFlow(meth, insnFlags, uninitMap)) {
    254         //LOGD("+++ %s failed code flow\n", meth->name);
    255         goto bail;
    256     }
    257 
    258 success:
    259     result = true;
    260 
    261 bail:
    262     dvmFreeUninitInstanceMap(uninitMap);
    263     free(insnFlags);
    264     return result;
    265 }
    266 
    267 
    268 /*
    269  * Verify an array data table.  "curOffset" is the offset of the fill-array-data
    270  * instruction.
    271  */
    272 static bool checkArrayData(const Method* meth, int curOffset)
    273 {
    274     const int insnCount = dvmGetMethodInsnsSize(meth);
    275     const u2* insns = meth->insns + curOffset;
    276     const u2* arrayData;
    277     int valueCount, valueWidth, tableSize;
    278     int offsetToArrayData;
    279 
    280     assert(curOffset >= 0 && curOffset < insnCount);
    281 
    282     /* make sure the start of the array data table is in range */
    283     offsetToArrayData = insns[1] | (((s4)insns[2]) << 16);
    284     if (curOffset + offsetToArrayData < 0 ||
    285         curOffset + offsetToArrayData + 2 >= insnCount)
    286     {
    287         LOG_VFY_METH(meth,
    288             "VFY: invalid array data start: at %d, data offset %d, count %d\n",
    289             curOffset, offsetToArrayData, insnCount);
    290         return false;
    291     }
    292 
    293     /* offset to array data table is a relative branch-style offset */
    294     arrayData = insns + offsetToArrayData;
    295 
    296     /* make sure the table is 32-bit aligned */
    297     if ((((u4) arrayData) & 0x03) != 0) {
    298         LOG_VFY_METH(meth,
    299             "VFY: unaligned array data table: at %d, data offset %d\n",
    300             curOffset, offsetToArrayData);
    301         return false;
    302     }
    303 
    304     valueWidth = arrayData[1];
    305     valueCount = *(u4*)(&arrayData[2]);
    306 
    307     tableSize = 4 + (valueWidth * valueCount + 1) / 2;
    308 
    309     /* make sure the end of the switch is in range */
    310     if (curOffset + offsetToArrayData + tableSize > insnCount) {
    311         LOG_VFY_METH(meth,
    312             "VFY: invalid array data end: at %d, data offset %d, end %d, "
    313             "count %d\n",
    314             curOffset, offsetToArrayData,
    315             curOffset + offsetToArrayData + tableSize,
    316             insnCount);
    317         return false;
    318     }
    319 
    320     return true;
    321 }
    322 
    323 
    324 /*
    325  * Decode the current instruction.
    326  */
    327 static void decodeInstruction(const Method* meth, int insnIdx,
    328     DecodedInstruction* pDecInsn)
    329 {
    330     dexDecodeInstruction(gDvm.instrFormat, meth->insns + insnIdx, pDecInsn);
    331 }
    332 
    333 
    334 /*
    335  * Perform static checks on a "new-instance" instruction.  Specifically,
    336  * make sure the class reference isn't for an array class.
    337  *
    338  * We don't need the actual class, just a pointer to the class name.
    339  */
    340 static bool checkNewInstance(const Method* meth, int insnIdx)
    341 {
    342     DvmDex* pDvmDex = meth->clazz->pDvmDex;
    343     DecodedInstruction decInsn;
    344     const char* classDescriptor;
    345     u4 idx;
    346 
    347     decodeInstruction(meth, insnIdx, &decInsn);
    348     idx = decInsn.vB;       // 2nd item
    349     if (idx >= pDvmDex->pHeader->typeIdsSize) {
    350         LOG_VFY_METH(meth, "VFY: bad type index %d (max %d)\n",
    351             idx, pDvmDex->pHeader->typeIdsSize);
    352         return false;
    353     }
    354 
    355     classDescriptor = dexStringByTypeIdx(pDvmDex->pDexFile, idx);
    356     if (classDescriptor[0] != 'L') {
    357         LOG_VFY_METH(meth, "VFY: can't call new-instance on type '%s'\n",
    358             classDescriptor);
    359         return false;
    360     }
    361 
    362     return true;
    363 }
    364 
    365 /*
    366  * Perform static checks on a "new-array" instruction.  Specifically, make
    367  * sure they aren't creating an array of arrays that causes the number of
    368  * dimensions to exceed 255.
    369  */
    370 static bool checkNewArray(const Method* meth, int insnIdx)
    371 {
    372     DvmDex* pDvmDex = meth->clazz->pDvmDex;
    373     DecodedInstruction decInsn;
    374     const char* classDescriptor;
    375     u4 idx;
    376 
    377     decodeInstruction(meth, insnIdx, &decInsn);
    378     idx = decInsn.vC;       // 3rd item
    379     if (idx >= pDvmDex->pHeader->typeIdsSize) {
    380         LOG_VFY_METH(meth, "VFY: bad type index %d (max %d)\n",
    381             idx, pDvmDex->pHeader->typeIdsSize);
    382         return false;
    383     }
    384 
    385     classDescriptor = dexStringByTypeIdx(pDvmDex->pDexFile, idx);
    386 
    387     int bracketCount = 0;
    388     const char* cp = classDescriptor;
    389     while (*cp++ == '[')
    390         bracketCount++;
    391 
    392     if (bracketCount == 0) {
    393         /* The given class must be an array type. */
    394         LOG_VFY_METH(meth, "VFY: can't new-array class '%s' (not an array)\n",
    395             classDescriptor);
    396         return false;
    397     } else if (bracketCount > 255) {
    398         /* It is illegal to create an array of more than 255 dimensions. */
    399         LOG_VFY_METH(meth, "VFY: can't new-array class '%s' (exceeds limit)\n",
    400             classDescriptor);
    401         return false;
    402     }
    403 
    404     return true;
    405 }
    406 
    407 /*
    408  * Perform static checks on an instruction that takes a class constant.
    409  * Ensure that the class index is in the valid range.
    410  */
    411 static bool checkTypeIndex(const Method* meth, int insnIdx, bool useB)
    412 {
    413     DvmDex* pDvmDex = meth->clazz->pDvmDex;
    414     DecodedInstruction decInsn;
    415     u4 idx;
    416 
    417     decodeInstruction(meth, insnIdx, &decInsn);
    418     if (useB)
    419         idx = decInsn.vB;
    420     else
    421         idx = decInsn.vC;
    422     if (idx >= pDvmDex->pHeader->typeIdsSize) {
    423         LOG_VFY_METH(meth, "VFY: bad type index %d (max %d)\n",
    424             idx, pDvmDex->pHeader->typeIdsSize);
    425         return false;
    426     }
    427 
    428     return true;
    429 }
    430 
    431 /*
    432  * Perform static checks on a field get or set instruction.  All we do
    433  * here is ensure that the field index is in the valid range.
    434  */
    435 static bool checkFieldIndex(const Method* meth, int insnIdx, bool useB)
    436 {
    437     DvmDex* pDvmDex = meth->clazz->pDvmDex;
    438     DecodedInstruction decInsn;
    439     u4 idx;
    440 
    441     decodeInstruction(meth, insnIdx, &decInsn);
    442     if (useB)
    443         idx = decInsn.vB;
    444     else
    445         idx = decInsn.vC;
    446     if (idx >= pDvmDex->pHeader->fieldIdsSize) {
    447         LOG_VFY_METH(meth,
    448             "VFY: bad field index %d (max %d) at offset 0x%04x\n",
    449             idx, pDvmDex->pHeader->fieldIdsSize, insnIdx);
    450         return false;
    451     }
    452 
    453     return true;
    454 }
    455 
    456 /*
    457  * Perform static checks on a method invocation instruction.  All we do
    458  * here is ensure that the method index is in the valid range.
    459  */
    460 static bool checkMethodIndex(const Method* meth, int insnIdx)
    461 {
    462     DvmDex* pDvmDex = meth->clazz->pDvmDex;
    463     DecodedInstruction decInsn;
    464 
    465     decodeInstruction(meth, insnIdx, &decInsn);
    466     if (decInsn.vB >= pDvmDex->pHeader->methodIdsSize) {
    467         LOG_VFY_METH(meth, "VFY: bad method index %d (max %d)\n",
    468             decInsn.vB, pDvmDex->pHeader->methodIdsSize);
    469         return false;
    470     }
    471 
    472     return true;
    473 }
    474 
    475 /*
    476  * Perform static checks on a string constant instruction.  All we do
    477  * here is ensure that the string index is in the valid range.
    478  */
    479 static bool checkStringIndex(const Method* meth, int insnIdx)
    480 {
    481     DvmDex* pDvmDex = meth->clazz->pDvmDex;
    482     DecodedInstruction decInsn;
    483 
    484     decodeInstruction(meth, insnIdx, &decInsn);
    485     if (decInsn.vB >= pDvmDex->pHeader->stringIdsSize) {
    486         LOG_VFY_METH(meth, "VFY: bad string index %d (max %d)\n",
    487             decInsn.vB, pDvmDex->pHeader->stringIdsSize);
    488         return false;
    489     }
    490 
    491     return true;
    492 }
    493 
    494 /*
    495  * Perform static verification on instructions.
    496  *
    497  * As a side effect, this sets the "branch target" flags in InsnFlags.
    498  *
    499  * "(CF)" items are handled during code-flow analysis.
    500  *
    501  * v3 4.10.1
    502  * - target of each jump and branch instruction must be valid
    503  * - targets of switch statements must be valid
    504  * - (CF) operands referencing constant pool entries must be valid
    505  * - (CF) operands of getfield, putfield, getstatic, putstatic must be valid
    506  * - (new) verify operands of "quick" field ops
    507  * - (CF) operands of method invocation instructions must be valid
    508  * - (new) verify operands of "quick" method invoke ops
    509  * - (CF) only invoke-direct can call a method starting with '<'
    510  * - (CF) <clinit> must never be called explicitly
    511  * - (CF) operands of instanceof, checkcast, new (and variants) must be valid
    512  * - new-array[-type] limited to 255 dimensions
    513  * - can't use "new" on an array class
    514  * - (?) limit dimensions in multi-array creation
    515  * - (CF) local variable load/store register values must be in valid range
    516  *
    517  * v3 4.11.1.2
    518  * - branches must be within the bounds of the code array
    519  * - targets of all control-flow instructions are the start of an instruction
    520  * - (CF) register accesses fall within range of allocated registers
    521  * - (N/A) access to constant pool must be of appropriate type
    522  * - (CF) code does not end in the middle of an instruction
    523  * - (CF) execution cannot fall off the end of the code
    524  * - (earlier) for each exception handler, the "try" area must begin and
    525  *   end at the start of an instruction (end can be at the end of the code)
    526  * - (earlier) for each exception handler, the handler must start at a valid
    527  *   instruction
    528  *
    529  * TODO: move some of the "CF" items in here for better performance (the
    530  * code-flow analysis sometimes has to process the same instruction several
    531  * times).
    532  */
    533 static bool verifyInstructions(const Method* meth, InsnFlags* insnFlags,
    534     int verifyFlags)
    535 {
    536     const int insnCount = dvmGetMethodInsnsSize(meth);
    537     const u2* insns = meth->insns;
    538     int i;
    539 
    540     /* the start of the method is a "branch target" */
    541     dvmInsnSetBranchTarget(insnFlags, 0, true);
    542 
    543     for (i = 0; i < insnCount; /**/) {
    544         /*
    545          * These types of instructions can be GC points.  To support precise
    546          * GC, all such instructions must export the PC in the interpreter,
    547          * or the GC won't be able to identify the current PC for the thread.
    548          */
    549         static const int gcMask = kInstrCanBranch | kInstrCanSwitch |
    550             kInstrCanThrow | kInstrCanReturn;
    551 
    552         int width = dvmInsnGetWidth(insnFlags, i);
    553         OpCode opcode = *insns & 0xff;
    554         InstructionFlags opFlags = dexGetInstrFlags(gDvm.instrFlags, opcode);
    555         int offset, absOffset;
    556 
    557         if ((opFlags & gcMask) != 0) {
    558             /*
    559              * This instruction is probably a GC point.  Branch instructions
    560              * only qualify if they go backward, so we need to check the
    561              * offset.
    562              */
    563             int offset = -1;
    564             bool unused;
    565             if (dvmGetBranchTarget(meth, insnFlags, i, &offset, &unused)) {
    566                 if (offset < 0) {
    567                     dvmInsnSetGcPoint(insnFlags, i, true);
    568                 }
    569             } else {
    570                 /* not a branch target */
    571                 dvmInsnSetGcPoint(insnFlags, i, true);
    572             }
    573         }
    574 
    575         switch (opcode) {
    576         case OP_NOP:
    577             /* plain no-op or switch table data; nothing to do here */
    578             break;
    579 
    580         case OP_CONST_STRING:
    581         case OP_CONST_STRING_JUMBO:
    582             if (!checkStringIndex(meth, i))
    583                 return false;
    584             break;
    585 
    586         case OP_CONST_CLASS:
    587         case OP_CHECK_CAST:
    588             if (!checkTypeIndex(meth, i, true))
    589                 return false;
    590             break;
    591         case OP_INSTANCE_OF:
    592             if (!checkTypeIndex(meth, i, false))
    593                 return false;
    594             break;
    595 
    596         case OP_PACKED_SWITCH:
    597         case OP_SPARSE_SWITCH:
    598             /* verify the associated table */
    599             if (!dvmCheckSwitchTargets(meth, insnFlags, i))
    600                 return false;
    601             break;
    602 
    603         case OP_FILL_ARRAY_DATA:
    604             /* verify the associated table */
    605             if (!checkArrayData(meth, i))
    606                 return false;
    607             break;
    608 
    609         case OP_GOTO:
    610         case OP_GOTO_16:
    611         case OP_IF_EQ:
    612         case OP_IF_NE:
    613         case OP_IF_LT:
    614         case OP_IF_GE:
    615         case OP_IF_GT:
    616         case OP_IF_LE:
    617         case OP_IF_EQZ:
    618         case OP_IF_NEZ:
    619         case OP_IF_LTZ:
    620         case OP_IF_GEZ:
    621         case OP_IF_GTZ:
    622         case OP_IF_LEZ:
    623             /* check the destination */
    624             if (!dvmCheckBranchTarget(meth, insnFlags, i, false))
    625                 return false;
    626             break;
    627         case OP_GOTO_32:
    628             /* check the destination; self-branch is okay */
    629             if (!dvmCheckBranchTarget(meth, insnFlags, i, true))
    630                 return false;
    631             break;
    632 
    633         case OP_NEW_INSTANCE:
    634             if (!checkNewInstance(meth, i))
    635                 return false;
    636             break;
    637 
    638         case OP_NEW_ARRAY:
    639             if (!checkNewArray(meth, i))
    640                 return false;
    641             break;
    642 
    643         case OP_FILLED_NEW_ARRAY:
    644             if (!checkTypeIndex(meth, i, true))
    645                 return false;
    646             break;
    647         case OP_FILLED_NEW_ARRAY_RANGE:
    648             if (!checkTypeIndex(meth, i, true))
    649                 return false;
    650             break;
    651 
    652         case OP_IGET:
    653         case OP_IGET_WIDE:
    654         case OP_IGET_OBJECT:
    655         case OP_IGET_BOOLEAN:
    656         case OP_IGET_BYTE:
    657         case OP_IGET_CHAR:
    658         case OP_IGET_SHORT:
    659         case OP_IPUT:
    660         case OP_IPUT_WIDE:
    661         case OP_IPUT_OBJECT:
    662         case OP_IPUT_BOOLEAN:
    663         case OP_IPUT_BYTE:
    664         case OP_IPUT_CHAR:
    665         case OP_IPUT_SHORT:
    666             /* check the field index */
    667             if (!checkFieldIndex(meth, i, false))
    668                 return false;
    669             break;
    670         case OP_SGET:
    671         case OP_SGET_WIDE:
    672         case OP_SGET_OBJECT:
    673         case OP_SGET_BOOLEAN:
    674         case OP_SGET_BYTE:
    675         case OP_SGET_CHAR:
    676         case OP_SGET_SHORT:
    677         case OP_SPUT:
    678         case OP_SPUT_WIDE:
    679         case OP_SPUT_OBJECT:
    680         case OP_SPUT_BOOLEAN:
    681         case OP_SPUT_BYTE:
    682         case OP_SPUT_CHAR:
    683         case OP_SPUT_SHORT:
    684             /* check the field index */
    685             if (!checkFieldIndex(meth, i, true))
    686                 return false;
    687             break;
    688 
    689         case OP_INVOKE_VIRTUAL:
    690         case OP_INVOKE_SUPER:
    691         case OP_INVOKE_DIRECT:
    692         case OP_INVOKE_STATIC:
    693         case OP_INVOKE_INTERFACE:
    694         case OP_INVOKE_VIRTUAL_RANGE:
    695         case OP_INVOKE_SUPER_RANGE:
    696         case OP_INVOKE_DIRECT_RANGE:
    697         case OP_INVOKE_STATIC_RANGE:
    698         case OP_INVOKE_INTERFACE_RANGE:
    699             /* check the method index */
    700             if (!checkMethodIndex(meth, i))
    701                 return false;
    702             break;
    703 
    704         case OP_EXECUTE_INLINE:
    705         case OP_INVOKE_DIRECT_EMPTY:
    706         case OP_IGET_QUICK:
    707         case OP_IGET_WIDE_QUICK:
    708         case OP_IGET_OBJECT_QUICK:
    709         case OP_IPUT_QUICK:
    710         case OP_IPUT_WIDE_QUICK:
    711         case OP_IPUT_OBJECT_QUICK:
    712         case OP_INVOKE_VIRTUAL_QUICK:
    713         case OP_INVOKE_VIRTUAL_QUICK_RANGE:
    714         case OP_INVOKE_SUPER_QUICK:
    715         case OP_INVOKE_SUPER_QUICK_RANGE:
    716             if ((verifyFlags & VERIFY_ALLOW_OPT_INSTRS) == 0) {
    717                 LOG_VFY("VFY: not expecting optimized instructions\n");
    718                 return false;
    719             }
    720             break;
    721 
    722         default:
    723             /* nothing to do */
    724             break;
    725         }
    726 
    727         assert(width > 0);
    728         i += width;
    729         insns += width;
    730     }
    731 
    732     /* make sure the last instruction ends at the end of the insn area */
    733     if (i != insnCount) {
    734         LOG_VFY_METH(meth,
    735             "VFY: code did not end when expected (end at %d, count %d)\n",
    736             i, insnCount);
    737         return false;
    738     }
    739 
    740     return true;
    741 }
    742 
    743