blob: ab1e50b4f76f70a15481805fca9c6e60d9db4c8f [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 */
16/*
17 * Dalvik classfile verification. This file contains the verifier entry
18 * points and the static constraint checks.
19 */
20#include "Dalvik.h"
21#include "analysis/CodeVerify.h"
22#include "libdex/DexCatch.h"
23#include "libdex/InstrUtils.h"
24
25//#define static
26
27/* verification failure reporting */
28#define LOG_VFY(...) dvmLogVerifyFailure(NULL, __VA_ARGS__);
29#define LOG_VFY_METH(_meth, ...) dvmLogVerifyFailure(_meth, __VA_ARGS__);
30
31
32/* fwd */
33static bool computeCodeWidths(const Method* meth, InsnFlags* insnFlags,\
34 int* pNewInstanceCount);
35static bool setTryFlags(const Method* meth, InsnFlags* insnFlags);
36static bool verifyMethod(Method* meth, int verifyFlags);
37static bool verifyInstructions(const Method* meth, InsnFlags* insnFlags,
38 int verifyFlags);
39static bool checkNewInstance(const Method* meth, int insnIdx);
40static bool checkNewArray(const Method* meth, int insnIdx);
41
42
43/*
44 * Initialize some things we need for verification.
45 */
46bool dvmVerificationStartup(void)
47{
48 gDvm.instrWidth = dexCreateInstrWidthTable();
49 gDvm.instrFormat = dexCreateInstrFormatTable();
50 gDvm.instrFlags = dexCreateInstrFlagsTable();
51 return (gDvm.instrWidth != NULL && gDvm.instrFormat!= NULL);
52}
53
54/*
55 * Initialize some things we need for verification.
56 */
57void dvmVerificationShutdown(void)
58{
59 free(gDvm.instrWidth);
60 free(gDvm.instrFormat);
61 free(gDvm.instrFlags);
62}
63
64/*
65 * Induce verification on all classes loaded from this DEX file as part
66 * of pre-verification and optimization. This is never called from a
67 * normally running VM.
68 *
69 * Returns "true" when all classes have been processed.
70 */
71bool dvmVerifyAllClasses(DexFile* pDexFile)
72{
73 u4 count = pDexFile->pHeader->classDefsSize;
74 u4 idx;
75
76 assert(gDvm.optimizing);
77
78 if (gDvm.classVerifyMode == VERIFY_MODE_NONE) {
79 LOGV("+++ verification is disabled, skipping all classes\n");
80 return true;
81 }
82 if (gDvm.classVerifyMode == VERIFY_MODE_REMOTE &&
83 gDvm.optimizingBootstrapClass)
84 {
85 LOGV("+++ verification disabled for bootstrap classes\n");
86 return true;
87 }
88
89 for (idx = 0; idx < count; idx++) {
90 const DexClassDef* pClassDef;
91 const char* classDescriptor;
92 ClassObject* clazz;
93
94 pClassDef = dexGetClassDef(pDexFile, idx);
95 classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
96
97 /* all classes are loaded into the bootstrap class loader */
98 clazz = dvmLookupClass(classDescriptor, NULL, false);
99 if (clazz != NULL) {
100 if (clazz->pDvmDex->pDexFile != pDexFile) {
101 LOGD("DexOpt: not verifying '%s': multiple definitions\n",
102 classDescriptor);
103 } else {
104 if (dvmVerifyClass(clazz, VERIFY_DEFAULT)) {
105 assert((clazz->accessFlags & JAVA_FLAGS_MASK) ==
106 pClassDef->accessFlags);
107 ((DexClassDef*)pClassDef)->accessFlags |=
108 CLASS_ISPREVERIFIED;
109 }
110 /* keep going even if one fails */
111 }
112 } else {
113 LOGV("DexOpt: +++ not verifying '%s'\n", classDescriptor);
114 }
115 }
116
117 return true;
118}
119
120/*
121 * Verify a class.
122 *
123 * By the time we get here, the value of gDvm.classVerifyMode should already
124 * have been factored in. If you want to call into the verifier even
125 * though verification is disabled, that's your business.
126 *
127 * Returns "true" on success.
128 */
129bool dvmVerifyClass(ClassObject* clazz, int verifyFlags)
130{
131 int i;
132
133 if (dvmIsClassVerified(clazz)) {
134 LOGD("Ignoring duplicate verify attempt on %s\n", clazz->descriptor);
135 return true;
136 }
137
138 //LOGI("Verify1 '%s'\n", clazz->descriptor);
139
140 // TODO - verify class structure in DEX?
141
142 for (i = 0; i < clazz->directMethodCount; i++) {
143 if (!verifyMethod(&clazz->directMethods[i], verifyFlags)) {
144 LOG_VFY("Verifier rejected class %s\n", clazz->descriptor);
145 return false;
146 }
147 }
148 for (i = 0; i < clazz->virtualMethodCount; i++) {
149 if (!verifyMethod(&clazz->virtualMethods[i], verifyFlags)) {
150 LOG_VFY("Verifier rejected class %s\n", clazz->descriptor);
151 return false;
152 }
153 }
154
155 return true;
156}
157
158/*
159 * Perform verification on a single method.
160 *
161 * We do this in three passes:
162 * (1) Walk through all code units, determining instruction lengths.
163 * (2) Do static checks, including branch target and operand validation.
164 * (3) Do structural checks, including data-flow analysis.
165 *
166 * Some checks may be bypassed depending on the verification mode. We can't
167 * turn this stuff off completely if we want to do "exact" GC.
168 *
169 * - operands of getfield, putfield, getstatic, putstatic must be valid
170 * - operands of method invocation instructions must be valid
171 *
172 * - code array must not be empty
173 * - (N/A) code_length must be less than 65536
174 * - opcode of first instruction begins at index 0
175 * - only documented instructions may appear
176 * - each instruction follows the last
177 * - (below) last byte of last instruction is at (code_length-1)
178 */
179static bool verifyMethod(Method* meth, int verifyFlags)
180{
181 bool result = false;
182 UninitInstanceMap* uninitMap = NULL;
183 InsnFlags* insnFlags = NULL;
184 int i, newInstanceCount;
185
186 /*
187 * If there aren't any instructions, make sure that's expected, then
188 * exit successfully. Note: meth->insns gets set to a native function
189 * pointer on first call.
190 */
191 if (dvmGetMethodInsnsSize(meth) == 0) {
192 if (!dvmIsNativeMethod(meth) && !dvmIsAbstractMethod(meth)) {
193 LOG_VFY_METH(meth,
194 "VFY: zero-length code in concrete non-native method\n");
195 goto bail;
196 }
197
198 goto success;
199 }
200
201 /*
202 * Allocate and populate an array to hold instruction data.
203 *
204 * TODO: Consider keeping a reusable pre-allocated array sitting
205 * around for smaller methods.
206 */
207 insnFlags = (InsnFlags*)
208 calloc(dvmGetMethodInsnsSize(meth), sizeof(InsnFlags));
209 if (insnFlags == NULL)
210 goto bail;
211
212 /*
213 * Compute the width of each instruction and store the result in insnFlags.
214 * Count up the #of occurrences of new-instance instructions while we're
215 * at it.
216 */
217 if (!computeCodeWidths(meth, insnFlags, &newInstanceCount))
218 goto bail;
219
220 /*
221 * Allocate a map to hold the classes of uninitialized instances.
222 */
223 uninitMap = dvmCreateUninitInstanceMap(meth, insnFlags, newInstanceCount);
224 if (uninitMap == NULL)
225 goto bail;
226
227 /*
228 * Set the "in try" flags for all instructions guarded by a "try" block.
229 */
230 if (!setTryFlags(meth, insnFlags))
231 goto bail;
232
233 /*
234 * Perform static instruction verification.
235 */
236 if (!verifyInstructions(meth, insnFlags, verifyFlags))
237 goto bail;
238
239 /*
240 * Do code-flow analysis. Do this after verifying the branch targets
241 * so we don't need to worry about it here.
242 *
243 * If there are no registers, we don't need to do much in the way of
244 * analysis, but we still need to verify that nothing actually tries
245 * to use a register.
246 */
247 if (!dvmVerifyCodeFlow(meth, insnFlags, uninitMap)) {
248 //LOGD("+++ %s failed code flow\n", meth->name);
249 goto bail;
250 }
251
252success:
253 result = true;
254
255bail:
256 dvmFreeUninitInstanceMap(uninitMap);
257 free(insnFlags);
258 return result;
259}
260
261
262/*
263 * Compute the width of the instruction at each address in the instruction
264 * stream. Addresses that are in the middle of an instruction, or that
265 * are part of switch table data, are not set (so the caller should probably
266 * initialize "insnFlags" to zero).
267 *
268 * Logs an error and returns "false" on failure.
269 */
270static bool computeCodeWidths(const Method* meth, InsnFlags* insnFlags,
271 int* pNewInstanceCount)
272{
273 const int insnCount = dvmGetMethodInsnsSize(meth);
274 const u2* insns = meth->insns;
275 bool result = false;
276 int i;
277
278 *pNewInstanceCount = 0;
279
280 for (i = 0; i < insnCount; /**/) {
281 int width;
282
283 /*
284 * Switch tables are identified with "extended NOP" opcodes. They
285 * contain no executable code, so we can just skip past them.
286 */
287 if (*insns == kPackedSwitchSignature) {
288 width = 4 + insns[1] * 2;
289 } else if (*insns == kSparseSwitchSignature) {
290 width = 2 + insns[1] * 4;
291 /*
292 * Array data table is identified with similar extended NOP opcode.
293 */
294 } else if (*insns == kArrayDataSignature) {
295 u4 size = insns[2] | (((u4)insns[3]) << 16);
296 width = 4 + (insns[1] * size + 1) / 2;
297 } else {
298 int instr = *insns & 0xff;
299 width = dexGetInstrWidthAbs(gDvm.instrWidth, instr);
300 if (width == 0) {
301 LOG_VFY_METH(meth,
302 "VFY: invalid post-opt instruction (0x%x)\n", instr);
303 goto bail;
304 }
305 if (width < 0 || width > 5) {
306 LOGE("VFY: bizarre width value %d\n", width);
307 dvmAbort();
308 }
309
310 if (instr == OP_NEW_INSTANCE)
311 (*pNewInstanceCount)++;
312 }
313
314 if (width > 65535) {
315 LOG_VFY_METH(meth, "VFY: insane width %d\n", width);
316 goto bail;
317 }
318
319 insnFlags[i] |= width;
320 i += width;
321 insns += width;
322 }
323 if (i != (int) dvmGetMethodInsnsSize(meth)) {
324 LOG_VFY_METH(meth, "VFY: code did not end where expected (%d vs. %d)\n",
325 i, dvmGetMethodInsnsSize(meth));
326 goto bail;
327 }
328
329 result = true;
330
331bail:
332 return result;
333}
334
335/*
336 * Set the "in try" flags for all instructions protected by "try" statements.
337 * Also sets the "branch target" flags for exception handlers.
338 *
339 * Call this after widths have been set in "insnFlags".
340 *
341 * Returns "false" if something in the exception table looks fishy, but
342 * we're expecting the exception table to be somewhat sane.
343 */
344static bool setTryFlags(const Method* meth, InsnFlags* insnFlags)
345{
346 u4 insnsSize = dvmGetMethodInsnsSize(meth);
347 DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
348 const DexCode* pCode = dvmGetMethodCode(meth);
349 u4 triesSize = pCode->triesSize;
350 const DexTry* pTries;
351 u4 handlersSize;
352 u4 offset;
353 u4 i;
354
355 if (triesSize == 0) {
356 return true;
357 }
358
359 pTries = dexGetTries(pCode);
360 handlersSize = dexGetHandlersSize(pCode);
361
362 for (i = 0; i < triesSize; i++) {
363 const DexTry* pTry = &pTries[i];
364 u4 start = pTry->startAddr;
365 u4 end = start + pTry->insnCount;
366 u4 addr;
367
368 if ((start >= end) || (start >= insnsSize) || (end > insnsSize)) {
369 LOG_VFY_METH(meth,
370 "VFY: bad exception entry: startAddr=%d endAddr=%d (size=%d)\n",
371 start, end, insnsSize);
372 return false;
373 }
374
375 if (dvmInsnGetWidth(insnFlags, start) == 0) {
376 LOG_VFY_METH(meth,
377 "VFY: 'try' block starts inside an instruction (%d)\n",
378 start);
379 return false;
380 }
381
382 for (addr = start; addr < end;
383 addr += dvmInsnGetWidth(insnFlags, addr))
384 {
385 assert(dvmInsnGetWidth(insnFlags, addr) != 0);
386 dvmInsnSetInTry(insnFlags, addr, true);
387 }
388 }
389
390 /* Iterate over each of the handlers to verify target addresses. */
391 offset = dexGetFirstHandlerOffset(pCode);
392 for (i = 0; i < handlersSize; i++) {
393 DexCatchIterator iterator;
394 dexCatchIteratorInit(&iterator, pCode, offset);
395
396 for (;;) {
397 DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
398 u4 addr;
399
400 if (handler == NULL) {
401 break;
402 }
403
404 addr = handler->address;
405 if (dvmInsnGetWidth(insnFlags, addr) == 0) {
406 LOG_VFY_METH(meth,
407 "VFY: exception handler starts at bad address (%d)\n",
408 addr);
409 return false;
410 }
411
412 dvmInsnSetBranchTarget(insnFlags, addr, true);
413 }
414
415 offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
416 }
417
418 return true;
419}
420
421/*
422 * Verify a switch table. "curOffset" is the offset of the switch
423 * instruction.
424 */
425static bool checkSwitchTargets(const Method* meth, InsnFlags* insnFlags,
426 int curOffset)
427{
428 const int insnCount = dvmGetMethodInsnsSize(meth);
429 const u2* insns = meth->insns + curOffset;
430 const u2* switchInsns;
431 int switchCount, tableSize;
432 int offsetToSwitch, offsetToKeys, offsetToTargets, targ;
433 int offset, absOffset;
434
435 assert(curOffset >= 0 && curOffset < insnCount);
436
437 /* make sure the start of the switch is in range */
438 offsetToSwitch = (s2) insns[1];
439 if (curOffset + offsetToSwitch < 0 ||
440 curOffset + offsetToSwitch + 2 >= insnCount)
441 {
442 LOG_VFY_METH(meth,
443 "VFY: invalid switch start: at %d, switch offset %d, count %d\n",
444 curOffset, offsetToSwitch, insnCount);
445 return false;
446 }
447
448 /* offset to switch table is a relative branch-style offset */
449 switchInsns = insns + offsetToSwitch;
450
451 /* make sure the table is 32-bit aligned */
452 if ((((u4) switchInsns) & 0x03) != 0) {
453 LOG_VFY_METH(meth,
454 "VFY: unaligned switch table: at %d, switch offset %d\n",
455 curOffset, offsetToSwitch);
456 return false;
457 }
458
459 switchCount = switchInsns[1];
460
461 if ((*insns & 0xff) == OP_PACKED_SWITCH) {
462 /* 0=sig, 1=count, 2/3=firstKey */
463 offsetToTargets = 4;
464 offsetToKeys = -1;
465 } else {
466 /* 0=sig, 1=count, 2..count*2 = keys */
467 offsetToKeys = 2;
468 offsetToTargets = 2 + 2*switchCount;
469 }
470 tableSize = offsetToTargets + switchCount*2;
471
472 /* make sure the end of the switch is in range */
473 if (curOffset + offsetToSwitch + tableSize > insnCount) {
474 LOG_VFY_METH(meth,
475 "VFY: invalid switch end: at %d, switch offset %d, end %d, count %d\n",
476 curOffset, offsetToSwitch, curOffset + offsetToSwitch + tableSize,
477 insnCount);
478 return false;
479 }
480
481 /* for a sparse switch, verify the keys are in ascending order */
482 if (offsetToKeys > 0 && switchCount > 1) {
483 s4 lastKey;
484
485 lastKey = switchInsns[offsetToKeys] |
486 (switchInsns[offsetToKeys+1] << 16);
487 for (targ = 1; targ < switchCount; targ++) {
488 s4 key = (s4) switchInsns[offsetToKeys + targ*2] |
489 (s4) (switchInsns[offsetToKeys + targ*2 +1] << 16);
490 if (key <= lastKey) {
491 LOG_VFY_METH(meth,
492 "VFY: invalid packed switch: last key=%d, this=%d\n",
493 lastKey, key);
494 return false;
495 }
496
497 lastKey = key;
498 }
499 }
500
501 /* verify each switch target */
502 for (targ = 0; targ < switchCount; targ++) {
503 offset = (s4) switchInsns[offsetToTargets + targ*2] |
504 (s4) (switchInsns[offsetToTargets + targ*2 +1] << 16);
505 absOffset = curOffset + offset;
506
507 if (absOffset < 0 || absOffset >= insnCount ||
508 !dvmInsnIsOpcode(insnFlags, absOffset))
509 {
510 LOG_VFY_METH(meth,
511 "VFY: invalid switch target %d (-> 0x%x) at 0x%x[%d]\n",
512 offset, absOffset, curOffset, targ);
513 return false;
514 }
515 dvmInsnSetBranchTarget(insnFlags, absOffset, true);
516 }
517
518 return true;
519}
520
521/*
522 * Verify an array data table. "curOffset" is the offset of the fill-array-data
523 * instruction.
524 */
525static bool checkArrayData(const Method* meth, int curOffset)
526{
527 const int insnCount = dvmGetMethodInsnsSize(meth);
528 const u2* insns = meth->insns + curOffset;
529 const u2* arrayData;
530 int valueCount, valueWidth, tableSize;
531 int offsetToArrayData;
532
533 assert(curOffset >= 0 && curOffset < insnCount);
534
535 /* make sure the start of the array data table is in range */
536 offsetToArrayData = insns[1] | (((s4)insns[2]) << 16);
537 if (curOffset + offsetToArrayData < 0 ||
538 curOffset + offsetToArrayData + 2 >= insnCount)
539 {
540 LOG_VFY_METH(meth,
541 "VFY: invalid array data start: at %d, data offset %d, count %d\n",
542 curOffset, offsetToArrayData, insnCount);
543 return false;
544 }
545
546 /* offset to array data table is a relative branch-style offset */
547 arrayData = insns + offsetToArrayData;
548
549 /* make sure the table is 32-bit aligned */
550 if ((((u4) arrayData) & 0x03) != 0) {
551 LOG_VFY_METH(meth,
552 "VFY: unaligned array data table: at %d, data offset %d\n",
553 curOffset, offsetToArrayData);
554 return false;
555 }
556
557 valueWidth = arrayData[1];
558 valueCount = *(u4*)(&arrayData[2]);
559
560 tableSize = 4 + (valueWidth * valueCount + 1) / 2;
561
562 /* make sure the end of the switch is in range */
563 if (curOffset + offsetToArrayData + tableSize > insnCount) {
564 LOG_VFY_METH(meth,
565 "VFY: invalid array data end: at %d, data offset %d, end %d, "
566 "count %d\n",
567 curOffset, offsetToArrayData,
568 curOffset + offsetToArrayData + tableSize,
569 insnCount);
570 return false;
571 }
572
573 return true;
574}
575
576/*
577 * Verify that the target of a branch instruction is valid.
578 *
579 * We don't expect code to jump directly into an exception handler, but
580 * it's valid to do so as long as the target isn't a "move-exception"
581 * instruction. We verify that in a later stage.
582 *
583 * The VM spec doesn't forbid an instruction from branching to itself,
584 * but the Dalvik spec declares that only certain instructions can do so.
585 */
586static bool checkBranchTarget(const Method* meth, InsnFlags* insnFlags,
587 int curOffset, bool selfOkay)
588{
589 const int insnCount = dvmGetMethodInsnsSize(meth);
590 const u2* insns = meth->insns + curOffset;
591 int offset, absOffset;
592 bool isConditional;
593
594 if (!dvmGetBranchTarget(meth, insnFlags, curOffset, &offset,
595 &isConditional))
596 return false;
597
598 if (!selfOkay && offset == 0) {
599 LOG_VFY_METH(meth, "VFY: branch offset of zero not allowed at 0x%x\n",
600 curOffset);
601 return false;
602 }
603
604 /*
605 * Check for 32-bit overflow. This isn't strictly necessary if we can
606 * depend on the VM to have identical "wrap-around" behavior, but
607 * it's unwise to depend on that.
608 */
609 if (((s8) curOffset + (s8) offset) != (s8)(curOffset + offset)) {
610 LOG_VFY_METH(meth, "VFY: branch target overflow 0x%x +%d\n",
611 curOffset, offset);
612 return false;
613 }
614 absOffset = curOffset + offset;
615 if (absOffset < 0 || absOffset >= insnCount ||
616 !dvmInsnIsOpcode(insnFlags, absOffset))
617 {
618 LOG_VFY_METH(meth,
619 "VFY: invalid branch target %d (-> 0x%x) at 0x%x\n",
620 offset, absOffset, curOffset);
621 return false;
622 }
623 dvmInsnSetBranchTarget(insnFlags, absOffset, true);
624
625 return true;
626}
627
628/*
629 * Perform static verification on instructions.
630 *
631 * As a side effect, this sets the "branch target" flags in InsnFlags.
632 *
633 * "(CF)" items are handled during code-flow analysis.
634 *
635 * v3 4.10.1
636 * - target of each jump and branch instruction must be valid
637 * - targets of switch statements must be valid
638 * - (CF) operands referencing constant pool entries must be valid
639 * - (CF) operands of getfield, putfield, getstatic, putstatic must be valid
640 * - (new) verify operands of "quick" field ops
641 * - (CF) operands of method invocation instructions must be valid
642 * - (new) verify operands of "quick" method invoke ops
643 * - (CF) only invoke-direct can call a method starting with '<'
644 * - (CF) <clinit> must never be called explicitly
645 * - (CF) operands of instanceof, checkcast, new (and variants) must be valid
646 * - new-array[-type] limited to 255 dimensions
647 * - can't use "new" on an array class
648 * - (?) limit dimensions in multi-array creation
649 * - (CF) local variable load/store register values must be in valid range
650 *
651 * v3 4.11.1.2
652 * - branches must be within the bounds of the code array
653 * - targets of all control-flow instructions are the start of an instruction
654 * - (CF) register accesses fall within range of allocated registers
655 * - (N/A) access to constant pool must be of appropriate type
656 * - (CF) code does not end in the middle of an instruction
657 * - (CF) execution cannot fall off the end of the code
658 * - (earlier) for each exception handler, the "try" area must begin and
659 * end at the start of an instruction (end can be at the end of the code)
660 * - (earlier) for each exception handler, the handler must start at a valid
661 * instruction
662 */
663static bool verifyInstructions(const Method* meth, InsnFlags* insnFlags,
664 int verifyFlags)
665{
666 const int insnCount = dvmGetMethodInsnsSize(meth);
667 const u2* insns = meth->insns;
668 int i, width, offset, absOffset;
669
670 /* the start of the method is a "branch target" */
671 dvmInsnSetBranchTarget(insnFlags, 0, true);
672
673 for (i = 0; i < insnCount; /**/) {
674 width = dvmInsnGetWidth(insnFlags, i);
675
676 switch (*insns & 0xff) {
677 case OP_NOP:
678 /* plain no-op or switch table data; nothing to do here */
679 break;
680
681 case OP_PACKED_SWITCH:
682 case OP_SPARSE_SWITCH:
683 /* verify the associated table */
684 if (!checkSwitchTargets(meth, insnFlags, i))
685 return false;
686 break;
687
688 case OP_FILL_ARRAY_DATA:
689 /* verify the associated table */
690 if (!checkArrayData(meth, i))
691 return false;
692 break;
693
694 case OP_GOTO:
695 case OP_GOTO_16:
696 case OP_IF_EQ:
697 case OP_IF_NE:
698 case OP_IF_LT:
699 case OP_IF_GE:
700 case OP_IF_GT:
701 case OP_IF_LE:
702 case OP_IF_EQZ:
703 case OP_IF_NEZ:
704 case OP_IF_LTZ:
705 case OP_IF_GEZ:
706 case OP_IF_GTZ:
707 case OP_IF_LEZ:
708 /* check the destination */
709 if (!checkBranchTarget(meth, insnFlags, i, false))
710 return false;
711 break;
712 case OP_GOTO_32:
713 /* check the destination; self-branch is okay */
714 if (!checkBranchTarget(meth, insnFlags, i, true))
715 return false;
716 break;
717
718 case OP_NEW_INSTANCE:
719 if (!checkNewInstance(meth, i))
720 return false;
721 break;
722
723 case OP_NEW_ARRAY:
724 if (!checkNewArray(meth, i))
725 return false;
726 break;
727
728 case OP_EXECUTE_INLINE:
729 case OP_INVOKE_DIRECT_EMPTY:
730 case OP_IGET_QUICK:
731 case OP_IGET_WIDE_QUICK:
732 case OP_IGET_OBJECT_QUICK:
733 case OP_IPUT_QUICK:
734 case OP_IPUT_WIDE_QUICK:
735 case OP_IPUT_OBJECT_QUICK:
736 case OP_INVOKE_VIRTUAL_QUICK:
737 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
738 case OP_INVOKE_SUPER_QUICK:
739 case OP_INVOKE_SUPER_QUICK_RANGE:
740 if ((verifyFlags & VERIFY_ALLOW_OPT_INSTRS) == 0) {
741 LOG_VFY("VFY: not expecting optimized instructions\n");
742 return false;
743 }
744 break;
745
746 default:
747 /* nothing to do */
748 break;
749 }
750
751 assert(width > 0);
752 i += width;
753 insns += width;
754 }
755
756 /* make sure the last instruction ends at the end of the insn area */
757 if (i != insnCount) {
758 LOG_VFY_METH(meth,
759 "VFY: code did not end when expected (end at %d, count %d)\n",
760 i, insnCount);
761 return false;
762 }
763
764 return true;
765}
766
767/*
768 * Perform static checks on a "new-instance" instruction. Specifically,
769 * make sure the class reference isn't for an array class.
770 *
771 * We don't need the actual class, just a pointer to the class name.
772 */
773static bool checkNewInstance(const Method* meth, int insnIdx)
774{
775 DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
776 DecodedInstruction decInsn;
777 const char* classDescriptor;
778
779 dexDecodeInstruction(gDvm.instrFormat, meth->insns + insnIdx, &decInsn);
780 classDescriptor = dexStringByTypeIdx(pDexFile, decInsn.vB); // 2nd item
781
782 if (classDescriptor[0] != 'L') {
783 LOG_VFY_METH(meth, "VFY: can't call new-instance on type '%s'\n",
784 classDescriptor);
785 return false;
786 }
787
788 return true;
789}
790
791/*
792 * Perform static checks on a "new-array" instruction. Specifically, make
793 * sure they aren't creating an array of arrays that causes the number of
794 * dimensions to exceed 255.
795 */
796static bool checkNewArray(const Method* meth, int insnIdx)
797{
798 DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
799 DecodedInstruction decInsn;
800 const char* classDescriptor;
801
802 dexDecodeInstruction(gDvm.instrFormat, meth->insns + insnIdx, &decInsn);
803 classDescriptor = dexStringByTypeIdx(pDexFile, decInsn.vC); // 3rd item
804
805 int bracketCount = 0;
806 const char* cp = classDescriptor;
807 while (*cp++ == '[')
808 bracketCount++;
809
810 if (bracketCount == 0) {
811 /* The given class must be an array type. */
812 LOG_VFY_METH(meth, "VFY: can't new-array class '%s' (not an array)\n",
813 classDescriptor);
814 return false;
815 } else if (bracketCount > 255) {
816 /* It is illegal to create an array of more than 255 dimensions. */
817 LOG_VFY_METH(meth, "VFY: can't new-array class '%s' (exceeds limit)\n",
818 classDescriptor);
819 return false;
820 }
821
822 return true;
823}