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