• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
dvmVerificationStartup(void)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  */
dvmVerificationShutdown(void)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  */
dvmVerifyAllClasses(DexFile * pDexFile)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  */
dvmVerifyClass(ClassObject * clazz,int verifyFlags)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  * Perform verification on a single method.
155  *
156  * We do this in three passes:
157  *  (1) Walk through all code units, determining instruction lengths.
158  *  (2) Do static checks, including branch target and operand validation.
159  *  (3) Do structural checks, including data-flow analysis.
160  *
161  * Some checks may be bypassed depending on the verification mode.  We can't
162  * turn this stuff off completely if we want to do "exact" GC.
163  *
164  * - operands of getfield, putfield, getstatic, putstatic must be valid
165  * - operands of method invocation instructions must be valid
166  *
167  * - code array must not be empty
168  * - (N/A) code_length must be less than 65536
169  * - opcode of first instruction begins at index 0
170  * - only documented instructions may appear
171  * - each instruction follows the last
172  * - (below) last byte of last instruction is at (code_length-1)
173  */
verifyMethod(Method * meth,int verifyFlags)174 static bool verifyMethod(Method* meth, int verifyFlags)
175 {
176     bool result = false;
177     UninitInstanceMap* uninitMap = NULL;
178     InsnFlags* insnFlags = NULL;
179     int i, newInstanceCount;
180 
181     /*
182      * If there aren't any instructions, make sure that's expected, then
183      * exit successfully. Note: meth->insns gets set to a native function
184      * pointer on first call.
185      */
186     if (dvmGetMethodInsnsSize(meth) == 0) {
187         if (!dvmIsNativeMethod(meth) && !dvmIsAbstractMethod(meth)) {
188             LOG_VFY_METH(meth,
189                 "VFY: zero-length code in concrete non-native method\n");
190             goto bail;
191         }
192 
193         goto success;
194     }
195 
196     /*
197      * Sanity-check the register counts.  ins + locals = registers, so make
198      * sure that ins <= registers.
199      */
200     if (meth->insSize > meth->registersSize) {
201         LOG_VFY_METH(meth, "VFY: bad register counts (ins=%d regs=%d)\n",
202             meth->insSize, meth->registersSize);
203         goto bail;
204     }
205 
206     /*
207      * Allocate and populate an array to hold instruction data.
208      *
209      * TODO: Consider keeping a reusable pre-allocated array sitting
210      * around for smaller methods.
211      */
212     insnFlags = (InsnFlags*)
213         calloc(dvmGetMethodInsnsSize(meth), sizeof(InsnFlags));
214     if (insnFlags == NULL)
215         goto bail;
216 
217     /*
218      * Compute the width of each instruction and store the result in insnFlags.
219      * Count up the #of occurrences of new-instance instructions while we're
220      * at it.
221      */
222     if (!dvmComputeCodeWidths(meth, insnFlags, &newInstanceCount))
223         goto bail;
224 
225     /*
226      * Allocate a map to hold the classes of uninitialized instances.
227      */
228     uninitMap = dvmCreateUninitInstanceMap(meth, insnFlags, newInstanceCount);
229     if (uninitMap == NULL)
230         goto bail;
231 
232     /*
233      * Set the "in try" flags for all instructions guarded by a "try" block.
234      */
235     if (!dvmSetTryFlags(meth, insnFlags))
236         goto bail;
237 
238     /*
239      * Perform static instruction verification.
240      */
241     if (!verifyInstructions(meth, insnFlags, verifyFlags))
242         goto bail;
243 
244     /*
245      * Do code-flow analysis.  Do this after verifying the branch targets
246      * so we don't need to worry about it here.
247      *
248      * If there are no registers, we don't need to do much in the way of
249      * analysis, but we still need to verify that nothing actually tries
250      * to use a register.
251      */
252     if (!dvmVerifyCodeFlow(meth, insnFlags, uninitMap)) {
253         //LOGD("+++ %s failed code flow\n", meth->name);
254         goto bail;
255     }
256 
257 success:
258     result = true;
259 
260 bail:
261     dvmFreeUninitInstanceMap(uninitMap);
262     free(insnFlags);
263     return result;
264 }
265 
266 
267 /*
268  * Verify an array data table.  "curOffset" is the offset of the fill-array-data
269  * instruction.
270  */
checkArrayData(const Method * meth,int curOffset)271 static bool checkArrayData(const Method* meth, int curOffset)
272 {
273     const int insnCount = dvmGetMethodInsnsSize(meth);
274     const u2* insns = meth->insns + curOffset;
275     const u2* arrayData;
276     int valueCount, valueWidth, tableSize;
277     int offsetToArrayData;
278 
279     assert(curOffset >= 0 && curOffset < insnCount);
280 
281     /* make sure the start of the array data table is in range */
282     offsetToArrayData = insns[1] | (((s4)insns[2]) << 16);
283     if (curOffset + offsetToArrayData < 0 ||
284         curOffset + offsetToArrayData + 2 >= insnCount)
285     {
286         LOG_VFY_METH(meth,
287             "VFY: invalid array data start: at %d, data offset %d, count %d\n",
288             curOffset, offsetToArrayData, insnCount);
289         return false;
290     }
291 
292     /* offset to array data table is a relative branch-style offset */
293     arrayData = insns + offsetToArrayData;
294 
295     /* make sure the table is 32-bit aligned */
296     if ((((u4) arrayData) & 0x03) != 0) {
297         LOG_VFY_METH(meth,
298             "VFY: unaligned array data table: at %d, data offset %d\n",
299             curOffset, offsetToArrayData);
300         return false;
301     }
302 
303     valueWidth = arrayData[1];
304     valueCount = *(u4*)(&arrayData[2]);
305 
306     tableSize = 4 + (valueWidth * valueCount + 1) / 2;
307 
308     /* make sure the end of the switch is in range */
309     if (curOffset + offsetToArrayData + tableSize > insnCount) {
310         LOG_VFY_METH(meth,
311             "VFY: invalid array data end: at %d, data offset %d, end %d, "
312             "count %d\n",
313             curOffset, offsetToArrayData,
314             curOffset + offsetToArrayData + tableSize,
315             insnCount);
316         return false;
317     }
318 
319     return true;
320 }
321 
322 
323 /*
324  * Decode the current instruction.
325  */
decodeInstruction(const Method * meth,int insnIdx,DecodedInstruction * pDecInsn)326 static void decodeInstruction(const Method* meth, int insnIdx,
327     DecodedInstruction* pDecInsn)
328 {
329     dexDecodeInstruction(gDvm.instrFormat, meth->insns + insnIdx, pDecInsn);
330 }
331 
332 
333 /*
334  * Perform static checks on a "new-instance" instruction.  Specifically,
335  * make sure the class reference isn't for an array class.
336  *
337  * We don't need the actual class, just a pointer to the class name.
338  */
checkNewInstance(const Method * meth,int insnIdx)339 static bool checkNewInstance(const Method* meth, int insnIdx)
340 {
341     DvmDex* pDvmDex = meth->clazz->pDvmDex;
342     DecodedInstruction decInsn;
343     const char* classDescriptor;
344     u4 idx;
345 
346     decodeInstruction(meth, insnIdx, &decInsn);
347     idx = decInsn.vB;       // 2nd item
348     if (idx >= pDvmDex->pHeader->typeIdsSize) {
349         LOG_VFY_METH(meth, "VFY: bad type index %d (max %d)\n",
350             idx, pDvmDex->pHeader->typeIdsSize);
351         return false;
352     }
353 
354     classDescriptor = dexStringByTypeIdx(pDvmDex->pDexFile, idx);
355     if (classDescriptor[0] != 'L') {
356         LOG_VFY_METH(meth, "VFY: can't call new-instance on type '%s'\n",
357             classDescriptor);
358         return false;
359     }
360 
361     return true;
362 }
363 
364 /*
365  * Perform static checks on a "new-array" instruction.  Specifically, make
366  * sure they aren't creating an array of arrays that causes the number of
367  * dimensions to exceed 255.
368  */
checkNewArray(const Method * meth,int insnIdx)369 static bool checkNewArray(const Method* meth, int insnIdx)
370 {
371     DvmDex* pDvmDex = meth->clazz->pDvmDex;
372     DecodedInstruction decInsn;
373     const char* classDescriptor;
374     u4 idx;
375 
376     decodeInstruction(meth, insnIdx, &decInsn);
377     idx = decInsn.vC;       // 3rd item
378     if (idx >= pDvmDex->pHeader->typeIdsSize) {
379         LOG_VFY_METH(meth, "VFY: bad type index %d (max %d)\n",
380             idx, pDvmDex->pHeader->typeIdsSize);
381         return false;
382     }
383 
384     classDescriptor = dexStringByTypeIdx(pDvmDex->pDexFile, idx);
385 
386     int bracketCount = 0;
387     const char* cp = classDescriptor;
388     while (*cp++ == '[')
389         bracketCount++;
390 
391     if (bracketCount == 0) {
392         /* The given class must be an array type. */
393         LOG_VFY_METH(meth, "VFY: can't new-array class '%s' (not an array)\n",
394             classDescriptor);
395         return false;
396     } else if (bracketCount > 255) {
397         /* It is illegal to create an array of more than 255 dimensions. */
398         LOG_VFY_METH(meth, "VFY: can't new-array class '%s' (exceeds limit)\n",
399             classDescriptor);
400         return false;
401     }
402 
403     return true;
404 }
405 
406 /*
407  * Perform static checks on an instruction that takes a class constant.
408  * Ensure that the class index is in the valid range.
409  */
checkTypeIndex(const Method * meth,int insnIdx,bool useB)410 static bool checkTypeIndex(const Method* meth, int insnIdx, bool useB)
411 {
412     DvmDex* pDvmDex = meth->clazz->pDvmDex;
413     DecodedInstruction decInsn;
414     u4 idx;
415 
416     decodeInstruction(meth, insnIdx, &decInsn);
417     if (useB)
418         idx = decInsn.vB;
419     else
420         idx = decInsn.vC;
421     if (idx >= pDvmDex->pHeader->typeIdsSize) {
422         LOG_VFY_METH(meth, "VFY: bad type index %d (max %d)\n",
423             idx, pDvmDex->pHeader->typeIdsSize);
424         return false;
425     }
426 
427     return true;
428 }
429 
430 /*
431  * Perform static checks on a field get or set instruction.  All we do
432  * here is ensure that the field index is in the valid range.
433  */
checkFieldIndex(const Method * meth,int insnIdx,bool useB)434 static bool checkFieldIndex(const Method* meth, int insnIdx, bool useB)
435 {
436     DvmDex* pDvmDex = meth->clazz->pDvmDex;
437     DecodedInstruction decInsn;
438     u4 idx;
439 
440     decodeInstruction(meth, insnIdx, &decInsn);
441     if (useB)
442         idx = decInsn.vB;
443     else
444         idx = decInsn.vC;
445     if (idx >= pDvmDex->pHeader->fieldIdsSize) {
446         LOG_VFY_METH(meth,
447             "VFY: bad field index %d (max %d) at offset 0x%04x\n",
448             idx, pDvmDex->pHeader->fieldIdsSize, insnIdx);
449         return false;
450     }
451 
452     return true;
453 }
454 
455 /*
456  * Perform static checks on a method invocation instruction.  All we do
457  * here is ensure that the method index is in the valid range.
458  */
checkMethodIndex(const Method * meth,int insnIdx)459 static bool checkMethodIndex(const Method* meth, int insnIdx)
460 {
461     DvmDex* pDvmDex = meth->clazz->pDvmDex;
462     DecodedInstruction decInsn;
463 
464     decodeInstruction(meth, insnIdx, &decInsn);
465     if (decInsn.vB >= pDvmDex->pHeader->methodIdsSize) {
466         LOG_VFY_METH(meth, "VFY: bad method index %d (max %d)\n",
467             decInsn.vB, pDvmDex->pHeader->methodIdsSize);
468         return false;
469     }
470 
471     return true;
472 }
473 
474 /*
475  * Perform static checks on a string constant instruction.  All we do
476  * here is ensure that the string index is in the valid range.
477  */
checkStringIndex(const Method * meth,int insnIdx)478 static bool checkStringIndex(const Method* meth, int insnIdx)
479 {
480     DvmDex* pDvmDex = meth->clazz->pDvmDex;
481     DecodedInstruction decInsn;
482 
483     decodeInstruction(meth, insnIdx, &decInsn);
484     if (decInsn.vB >= pDvmDex->pHeader->stringIdsSize) {
485         LOG_VFY_METH(meth, "VFY: bad string index %d (max %d)\n",
486             decInsn.vB, pDvmDex->pHeader->stringIdsSize);
487         return false;
488     }
489 
490     return true;
491 }
492 
493 /*
494  * Perform static verification on instructions.
495  *
496  * As a side effect, this sets the "branch target" flags in InsnFlags.
497  *
498  * "(CF)" items are handled during code-flow analysis.
499  *
500  * v3 4.10.1
501  * - target of each jump and branch instruction must be valid
502  * - targets of switch statements must be valid
503  * - (CF) operands referencing constant pool entries must be valid
504  * - (CF) operands of getfield, putfield, getstatic, putstatic must be valid
505  * - (new) verify operands of "quick" field ops
506  * - (CF) operands of method invocation instructions must be valid
507  * - (new) verify operands of "quick" method invoke ops
508  * - (CF) only invoke-direct can call a method starting with '<'
509  * - (CF) <clinit> must never be called explicitly
510  * - (CF) operands of instanceof, checkcast, new (and variants) must be valid
511  * - new-array[-type] limited to 255 dimensions
512  * - can't use "new" on an array class
513  * - (?) limit dimensions in multi-array creation
514  * - (CF) local variable load/store register values must be in valid range
515  *
516  * v3 4.11.1.2
517  * - branches must be within the bounds of the code array
518  * - targets of all control-flow instructions are the start of an instruction
519  * - (CF) register accesses fall within range of allocated registers
520  * - (N/A) access to constant pool must be of appropriate type
521  * - (CF) code does not end in the middle of an instruction
522  * - (CF) execution cannot fall off the end of the code
523  * - (earlier) for each exception handler, the "try" area must begin and
524  *   end at the start of an instruction (end can be at the end of the code)
525  * - (earlier) for each exception handler, the handler must start at a valid
526  *   instruction
527  *
528  * TODO: move some of the "CF" items in here for better performance (the
529  * code-flow analysis sometimes has to process the same instruction several
530  * times).
531  */
verifyInstructions(const Method * meth,InsnFlags * insnFlags,int verifyFlags)532 static bool verifyInstructions(const Method* meth, InsnFlags* insnFlags,
533     int verifyFlags)
534 {
535     const int insnCount = dvmGetMethodInsnsSize(meth);
536     const u2* insns = meth->insns;
537     int i;
538 
539     /* the start of the method is a "branch target" */
540     dvmInsnSetBranchTarget(insnFlags, 0, true);
541 
542     for (i = 0; i < insnCount; /**/) {
543         /*
544          * These types of instructions can be GC points.  To support precise
545          * GC, all such instructions must export the PC in the interpreter,
546          * or the GC won't be able to identify the current PC for the thread.
547          */
548         static const int gcMask = kInstrCanBranch | kInstrCanSwitch |
549             kInstrCanThrow | kInstrCanReturn;
550 
551         int width = dvmInsnGetWidth(insnFlags, i);
552         OpCode opcode = *insns & 0xff;
553         InstructionFlags opFlags = dexGetInstrFlags(gDvm.instrFlags, opcode);
554         int offset, absOffset;
555 
556         if ((opFlags & gcMask) != 0) {
557             /*
558              * This instruction is probably a GC point.  Branch instructions
559              * only qualify if they go backward, so we need to check the
560              * offset.
561              */
562             int offset = -1;
563             bool unused;
564             if (dvmGetBranchTarget(meth, insnFlags, i, &offset, &unused)) {
565                 if (offset < 0) {
566                     dvmInsnSetGcPoint(insnFlags, i, true);
567                 }
568             } else {
569                 /* not a branch target */
570                 dvmInsnSetGcPoint(insnFlags, i, true);
571             }
572         }
573 
574         switch (opcode) {
575         case OP_NOP:
576             /* plain no-op or switch table data; nothing to do here */
577             break;
578 
579         case OP_CONST_STRING:
580         case OP_CONST_STRING_JUMBO:
581             if (!checkStringIndex(meth, i))
582                 return false;
583             break;
584 
585         case OP_CONST_CLASS:
586         case OP_CHECK_CAST:
587             if (!checkTypeIndex(meth, i, true))
588                 return false;
589             break;
590         case OP_INSTANCE_OF:
591             if (!checkTypeIndex(meth, i, false))
592                 return false;
593             break;
594 
595         case OP_PACKED_SWITCH:
596         case OP_SPARSE_SWITCH:
597             /* verify the associated table */
598             if (!dvmCheckSwitchTargets(meth, insnFlags, i))
599                 return false;
600             break;
601 
602         case OP_FILL_ARRAY_DATA:
603             /* verify the associated table */
604             if (!checkArrayData(meth, i))
605                 return false;
606             break;
607 
608         case OP_GOTO:
609         case OP_GOTO_16:
610         case OP_IF_EQ:
611         case OP_IF_NE:
612         case OP_IF_LT:
613         case OP_IF_GE:
614         case OP_IF_GT:
615         case OP_IF_LE:
616         case OP_IF_EQZ:
617         case OP_IF_NEZ:
618         case OP_IF_LTZ:
619         case OP_IF_GEZ:
620         case OP_IF_GTZ:
621         case OP_IF_LEZ:
622             /* check the destination */
623             if (!dvmCheckBranchTarget(meth, insnFlags, i, false))
624                 return false;
625             break;
626         case OP_GOTO_32:
627             /* check the destination; self-branch is okay */
628             if (!dvmCheckBranchTarget(meth, insnFlags, i, true))
629                 return false;
630             break;
631 
632         case OP_NEW_INSTANCE:
633             if (!checkNewInstance(meth, i))
634                 return false;
635             break;
636 
637         case OP_NEW_ARRAY:
638             if (!checkNewArray(meth, i))
639                 return false;
640             break;
641 
642         case OP_FILLED_NEW_ARRAY:
643             if (!checkTypeIndex(meth, i, true))
644                 return false;
645             break;
646         case OP_FILLED_NEW_ARRAY_RANGE:
647             if (!checkTypeIndex(meth, i, true))
648                 return false;
649             break;
650 
651         case OP_IGET:
652         case OP_IGET_WIDE:
653         case OP_IGET_OBJECT:
654         case OP_IGET_BOOLEAN:
655         case OP_IGET_BYTE:
656         case OP_IGET_CHAR:
657         case OP_IGET_SHORT:
658         case OP_IPUT:
659         case OP_IPUT_WIDE:
660         case OP_IPUT_OBJECT:
661         case OP_IPUT_BOOLEAN:
662         case OP_IPUT_BYTE:
663         case OP_IPUT_CHAR:
664         case OP_IPUT_SHORT:
665             /* check the field index */
666             if (!checkFieldIndex(meth, i, false))
667                 return false;
668             break;
669         case OP_SGET:
670         case OP_SGET_WIDE:
671         case OP_SGET_OBJECT:
672         case OP_SGET_BOOLEAN:
673         case OP_SGET_BYTE:
674         case OP_SGET_CHAR:
675         case OP_SGET_SHORT:
676         case OP_SPUT:
677         case OP_SPUT_WIDE:
678         case OP_SPUT_OBJECT:
679         case OP_SPUT_BOOLEAN:
680         case OP_SPUT_BYTE:
681         case OP_SPUT_CHAR:
682         case OP_SPUT_SHORT:
683             /* check the field index */
684             if (!checkFieldIndex(meth, i, true))
685                 return false;
686             break;
687 
688         case OP_INVOKE_VIRTUAL:
689         case OP_INVOKE_SUPER:
690         case OP_INVOKE_DIRECT:
691         case OP_INVOKE_STATIC:
692         case OP_INVOKE_INTERFACE:
693         case OP_INVOKE_VIRTUAL_RANGE:
694         case OP_INVOKE_SUPER_RANGE:
695         case OP_INVOKE_DIRECT_RANGE:
696         case OP_INVOKE_STATIC_RANGE:
697         case OP_INVOKE_INTERFACE_RANGE:
698             /* check the method index */
699             if (!checkMethodIndex(meth, i))
700                 return false;
701             break;
702 
703         case OP_EXECUTE_INLINE:
704         case OP_INVOKE_DIRECT_EMPTY:
705         case OP_IGET_QUICK:
706         case OP_IGET_WIDE_QUICK:
707         case OP_IGET_OBJECT_QUICK:
708         case OP_IPUT_QUICK:
709         case OP_IPUT_WIDE_QUICK:
710         case OP_IPUT_OBJECT_QUICK:
711         case OP_INVOKE_VIRTUAL_QUICK:
712         case OP_INVOKE_VIRTUAL_QUICK_RANGE:
713         case OP_INVOKE_SUPER_QUICK:
714         case OP_INVOKE_SUPER_QUICK_RANGE:
715             if ((verifyFlags & VERIFY_ALLOW_OPT_INSTRS) == 0) {
716                 LOG_VFY("VFY: not expecting optimized instructions\n");
717                 return false;
718             }
719             break;
720 
721         default:
722             /* nothing to do */
723             break;
724         }
725 
726         assert(width > 0);
727         i += width;
728         insns += width;
729     }
730 
731     /* make sure the last instruction ends at the end of the insn area */
732     if (i != insnCount) {
733         LOG_VFY_METH(meth,
734             "VFY: code did not end when expected (end at %d, count %d)\n",
735             i, insnCount);
736         return false;
737     }
738 
739     return true;
740 }
741 
742