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