blob: 97d98d77ec61b597f7bae5c188289eccfdd74c64 [file] [log] [blame]
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001/*
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 bytecode structural verifier. The only public entry point
19 * (except for a few shared utility functions) is dvmVerifyCodeFlow().
20 *
21 * TODO: might benefit from a signature-->class lookup cache. Could avoid
22 * some string-peeling and wouldn't need to compute hashes.
23 *
24 * TODO: we do too much stuff in here that could be done in the static
25 * verification pass. It's convenient, because we have all of the
26 * necessary information, but it's more efficient to do it over in
27 * DexVerify.c because in here we may have to process instructions
28 * multiple times.
29 */
30#include "Dalvik.h"
31#include "analysis/CodeVerify.h"
32#include "analysis/RegisterMap.h"
33#include "libdex/DexCatch.h"
34#include "libdex/InstrUtils.h"
35
36#include <stddef.h>
37
38
39/*
40 * We don't need to store the register data for many instructions, because
41 * we either only need it at branch points (for verification) or GC points
42 * and branches (for verification + type-precise register analysis).
43 */
44typedef enum RegisterTrackingMode {
45 kTrackRegsBranches,
46 kTrackRegsGcPoints,
47 kTrackRegsAll
48} RegisterTrackingMode;
49
50/*
51 * Set this to enable dead code scanning. This is not required, but it's
52 * very useful when testing changes to the verifier (to make sure we're not
53 * skipping over stuff) and for checking the optimized output from "dx".
54 * The only reason not to do it is that it slightly increases the time
55 * required to perform verification.
56 */
57#define DEAD_CODE_SCAN true
58
59static bool gDebugVerbose = false; // TODO: remove this
60
61#if 0
62int gDvm__totalInstr = 0;
63int gDvm__gcInstr = 0;
64int gDvm__gcData = 0;
65int gDvm__gcSimpleData = 0;
66#endif
67
68/*
69 * Selectively enable verbose debug logging -- use this to activate
70 * dumpRegTypes() calls for all instructions in the specified method.
71 */
72static inline bool doVerboseLogging(const Method* meth) {
73 return false; /* COMMENT OUT to enable verbose debugging */
74
The Android Open Source Project99409882009-03-18 22:20:24 -070075 const char* cd = "Landroid/net/http/Request;";
76 const char* mn = "readResponse";
77 const char* sg = "(Landroid/net/http/AndroidHttpClientConnection;)V";
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080078 return (strcmp(meth->clazz->descriptor, cd) == 0 &&
79 dvmCompareNameDescriptorAndMethod(mn, sg, meth) == 0);
80}
81
82#define SHOW_REG_DETAILS (0 /*| DRT_SHOW_REF_TYPES | DRT_SHOW_LOCALS*/)
83
84/*
85 * We need an extra "pseudo register" to hold the return type briefly. It
86 * can be category 1 or 2, so we need two slots.
87 */
88#define kExtraRegs 2
89#define RESULT_REGISTER(_insnRegCount) (_insnRegCount)
90
91/*
92 * Big fat collection of registers.
93 */
94typedef struct RegisterTable {
95 /*
96 * Array of RegType arrays, one per address in the method. We only
97 * set the pointers for certain addresses, based on what we're trying
98 * to accomplish.
99 */
100 RegType** addrRegs;
101
102 /*
103 * Number of registers we track for each instruction. This is equal
104 * to the method's declared "registersSize" plus kExtraRegs.
105 */
106 int insnRegCountPlus;
107
108 /*
109 * A single large alloc, with all of the storage needed for addrRegs.
110 */
111 RegType* regAlloc;
112} RegisterTable;
113
114
115/* fwd */
116static void checkMergeTab(void);
117static bool isInitMethod(const Method* meth);
118static RegType getInvocationThis(const RegType* insnRegs,\
Andy McFadden62a75162009-04-17 17:23:37 -0700119 const int insnRegCount, const DecodedInstruction* pDecInsn,
120 VerifyError* pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800121static void verifyRegisterType(const RegType* insnRegs, const int insnRegCount,\
Andy McFadden62a75162009-04-17 17:23:37 -0700122 u4 vsrc, RegType checkType, VerifyError* pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800123static bool doCodeVerification(const Method* meth, InsnFlags* insnFlags,\
124 RegisterTable* regTable, UninitInstanceMap* uninitMap);
125static bool verifyInstruction(const Method* meth, InsnFlags* insnFlags,\
126 RegisterTable* regTable, RegType* workRegs, int insnIdx,
127 UninitInstanceMap* uninitMap, int* pStartGuess);
128static ClassObject* findCommonSuperclass(ClassObject* c1, ClassObject* c2);
129static void dumpRegTypes(const Method* meth, const InsnFlags* insnFlags,\
130 const RegType* addrRegs, int addr, const char* addrName,
131 const UninitInstanceMap* uninitMap, int displayFlags);
132
133/* bit values for dumpRegTypes() "displayFlags" */
134enum {
135 DRT_SIMPLE = 0,
136 DRT_SHOW_REF_TYPES = 0x01,
137 DRT_SHOW_LOCALS = 0x02,
138};
139
140
141/*
142 * ===========================================================================
143 * RegType and UninitInstanceMap utility functions
144 * ===========================================================================
145 */
146
147#define __ kRegTypeUnknown
148#define _U kRegTypeUninit
149#define _X kRegTypeConflict
150#define _F kRegTypeFloat
151#define _0 kRegTypeZero
152#define _1 kRegTypeOne
153#define _Z kRegTypeBoolean
154#define _b kRegTypePosByte
155#define _B kRegTypeByte
156#define _s kRegTypePosShort
157#define _S kRegTypeShort
158#define _C kRegTypeChar
159#define _I kRegTypeInteger
160#define _J kRegTypeLongLo
161#define _j kRegTypeLongHi
162#define _D kRegTypeDoubleLo
163#define _d kRegTypeDoubleHi
164
165/*
166 * Merge result table for primitive values. The table is symmetric along
167 * the diagonal.
168 *
169 * Note that 32-bit int/float do not merge into 64-bit long/double. This
170 * is a register merge, not a widening conversion. Only the "implicit"
171 * widening within a category, e.g. byte to short, is allowed.
172 *
173 * Because Dalvik does not draw a distinction between int and float, we
174 * have to allow free exchange between 32-bit int/float and 64-bit
175 * long/double.
176 *
177 * Note that Uninit+Uninit=Uninit. This holds true because we only
178 * use this when the RegType value is exactly equal to kRegTypeUninit, which
179 * can only happen for the zeroeth entry in the table.
180 *
181 * "Unknown" never merges with anything known. The only time a register
182 * transitions from "unknown" to "known" is when we're executing code
183 * for the first time, and we handle that with a simple copy.
184 */
185const char gDvmMergeTab[kRegTypeMAX][kRegTypeMAX] =
186{
187 /* chk: _ U X F 0 1 Z b B s S C I J j D d */
188 { /*_*/ __,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X },
189 { /*U*/ _X,_U,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X },
190 { /*X*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X },
191 { /*F*/ _X,_X,_X,_F,_F,_F,_F,_F,_F,_F,_F,_F,_F,_X,_X,_X,_X },
192 { /*0*/ _X,_X,_X,_F,_0,_Z,_Z,_b,_B,_s,_S,_C,_I,_X,_X,_X,_X },
193 { /*1*/ _X,_X,_X,_F,_Z,_1,_Z,_b,_B,_s,_S,_C,_I,_X,_X,_X,_X },
194 { /*Z*/ _X,_X,_X,_F,_Z,_Z,_Z,_b,_B,_s,_S,_C,_I,_X,_X,_X,_X },
195 { /*b*/ _X,_X,_X,_F,_b,_b,_b,_b,_B,_s,_S,_C,_I,_X,_X,_X,_X },
196 { /*B*/ _X,_X,_X,_F,_B,_B,_B,_B,_B,_S,_S,_I,_I,_X,_X,_X,_X },
197 { /*s*/ _X,_X,_X,_F,_s,_s,_s,_s,_S,_s,_S,_C,_I,_X,_X,_X,_X },
198 { /*S*/ _X,_X,_X,_F,_S,_S,_S,_S,_S,_S,_S,_I,_I,_X,_X,_X,_X },
199 { /*C*/ _X,_X,_X,_F,_C,_C,_C,_C,_I,_C,_I,_C,_I,_X,_X,_X,_X },
200 { /*I*/ _X,_X,_X,_F,_I,_I,_I,_I,_I,_I,_I,_I,_I,_X,_X,_X,_X },
201 { /*J*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_J,_X,_J,_X },
202 { /*j*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_j,_X,_j },
203 { /*D*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_J,_X,_D,_X },
204 { /*d*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_j,_X,_d },
205};
206
207#undef __
208#undef _U
209#undef _X
210#undef _F
211#undef _0
212#undef _1
213#undef _Z
214#undef _b
215#undef _B
216#undef _s
217#undef _S
218#undef _C
219#undef _I
220#undef _J
221#undef _j
222#undef _D
223#undef _d
224
225#ifndef NDEBUG
226/*
227 * Verify symmetry in the conversion table.
228 */
229static void checkMergeTab(void)
230{
231 int i, j;
232
233 for (i = 0; i < kRegTypeMAX; i++) {
234 for (j = i; j < kRegTypeMAX; j++) {
235 if (gDvmMergeTab[i][j] != gDvmMergeTab[j][i]) {
236 LOGE("Symmetry violation: %d,%d vs %d,%d\n", i, j, j, i);
237 dvmAbort();
238 }
239 }
240 }
241}
242#endif
243
244/*
245 * Determine whether we can convert "srcType" to "checkType", where
246 * "checkType" is one of the category-1 non-reference types.
247 *
248 * 32-bit int and float are interchangeable.
249 */
250static bool canConvertTo1nr(RegType srcType, RegType checkType)
251{
252 static const char convTab
253 [kRegType1nrEND-kRegType1nrSTART+1][kRegType1nrEND-kRegType1nrSTART+1] =
254 {
255 /* chk: F 0 1 Z b B s S C I */
256 { /*F*/ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
257 { /*0*/ 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
258 { /*1*/ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 },
259 { /*Z*/ 1, 0, 0, 1, 1, 1, 1, 1, 1, 1 },
260 { /*b*/ 1, 0, 0, 0, 1, 1, 1, 1, 1, 1 },
261 { /*B*/ 1, 0, 0, 0, 0, 1, 0, 1, 0, 1 },
262 { /*s*/ 1, 0, 0, 0, 0, 0, 1, 1, 1, 1 },
263 { /*S*/ 1, 0, 0, 0, 0, 0, 0, 1, 0, 1 },
264 { /*C*/ 1, 0, 0, 0, 0, 0, 0, 0, 1, 1 },
265 { /*I*/ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
266 };
267
268 assert(checkType >= kRegType1nrSTART && checkType <= kRegType1nrEND);
269#if 0
270 if (checkType < kRegType1nrSTART || checkType > kRegType1nrEND) {
271 LOG_VFY("Unexpected checkType %d (srcType=%d)\n", checkType, srcType);
272 assert(false);
273 return false;
274 }
275#endif
276
277 //printf("convTab[%d][%d] = %d\n", srcType, checkType,
278 // convTab[srcType-kRegType1nrSTART][checkType-kRegType1nrSTART]);
279 if (srcType >= kRegType1nrSTART && srcType <= kRegType1nrEND)
280 return (bool) convTab[srcType-kRegType1nrSTART][checkType-kRegType1nrSTART];
281
282 return false;
283}
284
285/*
286 * Determine whether the types are compatible. In Dalvik, 64-bit doubles
287 * and longs are interchangeable.
288 */
289static bool canConvertTo2(RegType srcType, RegType checkType)
290{
291 return ((srcType == kRegTypeLongLo || srcType == kRegTypeDoubleLo) &&
292 (checkType == kRegTypeLongLo || checkType == kRegTypeDoubleLo));
293}
294
295/*
296 * Determine whether or not "instrType" and "targetType" are compatible,
297 * for purposes of getting or setting a value in a field or array. The
298 * idea is that an instruction with a category 1nr type (say, aget-short
299 * or iput-boolean) is accessing a static field, instance field, or array
300 * entry, and we want to make sure sure that the operation is legal.
301 *
302 * At a minimum, source and destination must have the same width. We
303 * further refine this to assert that "short" and "char" are not
304 * compatible, because the sign-extension is different on the "get"
305 * operations. As usual, "float" and "int" are interoperable.
306 *
307 * We're not considering the actual contents of the register, so we'll
308 * never get "pseudo-types" like kRegTypeZero or kRegTypePosShort. We
309 * could get kRegTypeUnknown in "targetType" if a field or array class
310 * lookup failed. Category 2 types and references are checked elsewhere.
311 */
312static bool checkFieldArrayStore1nr(RegType instrType, RegType targetType)
313{
314 if (instrType == targetType)
315 return true; /* quick positive; most common case */
316
317 if ((instrType == kRegTypeInteger && targetType == kRegTypeFloat) ||
318 (instrType == kRegTypeFloat && targetType == kRegTypeInteger))
319 {
320 return true;
321 }
322
323 return false;
324}
325
326/*
327 * Convert a VM PrimitiveType enum value to the equivalent RegType value.
328 */
329static RegType primitiveTypeToRegType(PrimitiveType primType)
330{
The Android Open Source Project99409882009-03-18 22:20:24 -0700331 static const struct {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800332 RegType regType; /* type equivalent */
333 PrimitiveType primType; /* verification */
334 } convTab[] = {
335 /* must match order of enum in Object.h */
336 { kRegTypeBoolean, PRIM_BOOLEAN },
337 { kRegTypeChar, PRIM_CHAR },
338 { kRegTypeFloat, PRIM_FLOAT },
339 { kRegTypeDoubleLo, PRIM_DOUBLE },
340 { kRegTypeByte, PRIM_BYTE },
341 { kRegTypeShort, PRIM_SHORT },
342 { kRegTypeInteger, PRIM_INT },
343 { kRegTypeLongLo, PRIM_LONG },
344 // PRIM_VOID
345 };
346
347 if (primType < 0 || primType > (int) (sizeof(convTab) / sizeof(convTab[0])))
348 {
349 assert(false);
350 return kRegTypeUnknown;
351 }
352
353 assert(convTab[primType].primType == primType);
354 return convTab[primType].regType;
355}
356
357/*
358 * Create a new uninitialized instance map.
359 *
360 * The map is allocated and populated with address entries. The addresses
361 * appear in ascending order to allow binary searching.
362 *
363 * Very few methods have 10 or more new-instance instructions; the
364 * majority have 0 or 1. Occasionally a static initializer will have 200+.
365 */
366UninitInstanceMap* dvmCreateUninitInstanceMap(const Method* meth,
367 const InsnFlags* insnFlags, int newInstanceCount)
368{
369 const int insnsSize = dvmGetMethodInsnsSize(meth);
370 const u2* insns = meth->insns;
371 UninitInstanceMap* uninitMap;
372 bool isInit = false;
373 int idx, addr;
374
375 if (isInitMethod(meth)) {
376 newInstanceCount++;
377 isInit = true;
378 }
379
380 /*
381 * Allocate the header and map as a single unit.
382 *
383 * TODO: consider having a static instance so we can avoid allocations.
384 * I don't think the verifier is guaranteed to be single-threaded when
385 * running in the VM (rather than dexopt), so that must be taken into
386 * account.
387 */
388 int size = offsetof(UninitInstanceMap, map) +
389 newInstanceCount * sizeof(uninitMap->map[0]);
390 uninitMap = calloc(1, size);
391 if (uninitMap == NULL)
392 return NULL;
393 uninitMap->numEntries = newInstanceCount;
394
395 idx = 0;
396 if (isInit) {
397 uninitMap->map[idx++].addr = kUninitThisArgAddr;
398 }
399
400 /*
401 * Run through and find the new-instance instructions.
402 */
403 for (addr = 0; addr < insnsSize; /**/) {
404 int width = dvmInsnGetWidth(insnFlags, addr);
405
406 if ((*insns & 0xff) == OP_NEW_INSTANCE)
407 uninitMap->map[idx++].addr = addr;
408
409 addr += width;
410 insns += width;
411 }
412
413 assert(idx == newInstanceCount);
414 return uninitMap;
415}
416
417/*
418 * Free the map.
419 */
420void dvmFreeUninitInstanceMap(UninitInstanceMap* uninitMap)
421{
422 free(uninitMap);
423}
424
425/*
426 * Set the class object associated with the instruction at "addr".
427 *
428 * Returns the map slot index, or -1 if the address isn't listed in the map
429 * (shouldn't happen) or if a class is already associated with the address
430 * (bad bytecode).
431 *
432 * Entries, once set, do not change -- a given address can only allocate
433 * one type of object.
434 */
435int dvmSetUninitInstance(UninitInstanceMap* uninitMap, int addr,
436 ClassObject* clazz)
437{
438 int idx;
439
440 assert(clazz != NULL);
441
442 /* TODO: binary search when numEntries > 8 */
443 for (idx = uninitMap->numEntries - 1; idx >= 0; idx--) {
444 if (uninitMap->map[idx].addr == addr) {
445 if (uninitMap->map[idx].clazz != NULL &&
446 uninitMap->map[idx].clazz != clazz)
447 {
448 LOG_VFY("VFY: addr %d already set to %p, not setting to %p\n",
449 addr, uninitMap->map[idx].clazz, clazz);
450 return -1; // already set to something else??
451 }
452 uninitMap->map[idx].clazz = clazz;
453 return idx;
454 }
455 }
456
457 LOG_VFY("VFY: addr %d not found in uninit map\n", addr);
458 assert(false); // shouldn't happen
459 return -1;
460}
461
462/*
463 * Get the class object at the specified index.
464 */
465ClassObject* dvmGetUninitInstance(const UninitInstanceMap* uninitMap, int idx)
466{
467 assert(idx >= 0 && idx < uninitMap->numEntries);
468 return uninitMap->map[idx].clazz;
469}
470
471/* determine if "type" is actually an object reference (init/uninit/zero) */
472static inline bool regTypeIsReference(RegType type) {
473 return (type > kRegTypeMAX || type == kRegTypeUninit ||
474 type == kRegTypeZero);
475}
476
477/* determine if "type" is an uninitialized object reference */
478static inline bool regTypeIsUninitReference(RegType type) {
479 return ((type & kRegTypeUninitMask) == kRegTypeUninit);
480}
481
482/* convert the initialized reference "type" to a ClassObject pointer */
483/* (does not expect uninit ref types or "zero") */
484static ClassObject* regTypeInitializedReferenceToClass(RegType type)
485{
486 assert(regTypeIsReference(type) && type != kRegTypeZero);
487 if ((type & 0x01) == 0) {
488 return (ClassObject*) type;
489 } else {
490 //LOG_VFY("VFY: attempted to use uninitialized reference\n");
491 return NULL;
492 }
493}
494
495/* extract the index into the uninitialized instance map table */
496static inline int regTypeToUninitIndex(RegType type) {
497 assert(regTypeIsUninitReference(type));
498 return (type & ~kRegTypeUninitMask) >> kRegTypeUninitShift;
499}
500
501/* convert the reference "type" to a ClassObject pointer */
502static ClassObject* regTypeReferenceToClass(RegType type,
503 const UninitInstanceMap* uninitMap)
504{
505 assert(regTypeIsReference(type) && type != kRegTypeZero);
506 if (regTypeIsUninitReference(type)) {
507 assert(uninitMap != NULL);
508 return dvmGetUninitInstance(uninitMap, regTypeToUninitIndex(type));
509 } else {
510 return (ClassObject*) type;
511 }
512}
513
514/* convert the ClassObject pointer to an (initialized) register type */
515static inline RegType regTypeFromClass(ClassObject* clazz) {
516 return (u4) clazz;
517}
518
519/* return the RegType for the uninitialized reference in slot "uidx" */
520static RegType regTypeFromUninitIndex(int uidx) {
521 return (u4) (kRegTypeUninit | (uidx << kRegTypeUninitShift));
522}
523
524
525/*
526 * ===========================================================================
527 * Signature operations
528 * ===========================================================================
529 */
530
531/*
532 * Is this method a constructor?
533 */
534static bool isInitMethod(const Method* meth)
535{
536 return (*meth->name == '<' && strcmp(meth->name+1, "init>") == 0);
537}
538
539/*
540 * Is this method a class initializer?
541 */
542static bool isClassInitMethod(const Method* meth)
543{
544 return (*meth->name == '<' && strcmp(meth->name+1, "clinit>") == 0);
545}
546
547/*
548 * Look up a class reference given as a simple string descriptor.
Andy McFadden62a75162009-04-17 17:23:37 -0700549 *
550 * If we can't find it, return a generic substitute when possible.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800551 */
552static ClassObject* lookupClassByDescriptor(const Method* meth,
Andy McFadden62a75162009-04-17 17:23:37 -0700553 const char* pDescriptor, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800554{
555 /*
556 * The javac compiler occasionally puts references to nonexistent
557 * classes in signatures. For example, if you have a non-static
558 * inner class with no constructor, the compiler provides
559 * a private <init> for you. Constructing the class
560 * requires <init>(parent), but the outer class can't call
561 * that because the method is private. So the compiler
562 * generates a package-scope <init>(parent,bogus) method that
563 * just calls the regular <init> (the "bogus" part being necessary
564 * to distinguish the signature of the synthetic method).
565 * Treating the bogus class as an instance of java.lang.Object
566 * allows the verifier to process the class successfully.
567 */
568
569 //LOGI("Looking up '%s'\n", typeStr);
570 ClassObject* clazz;
571 clazz = dvmFindClassNoInit(pDescriptor, meth->clazz->classLoader);
572 if (clazz == NULL) {
573 dvmClearOptException(dvmThreadSelf());
574 if (strchr(pDescriptor, '$') != NULL) {
575 LOGV("VFY: unable to find class referenced in signature (%s)\n",
576 pDescriptor);
577 } else {
578 LOG_VFY("VFY: unable to find class referenced in signature (%s)\n",
579 pDescriptor);
580 }
581
582 if (pDescriptor[0] == '[') {
583 /* We are looking at an array descriptor. */
584
585 /*
586 * There should never be a problem loading primitive arrays.
587 */
588 if (pDescriptor[1] != 'L' && pDescriptor[1] != '[') {
589 LOG_VFY("VFY: invalid char in signature in '%s'\n",
590 pDescriptor);
Andy McFadden62a75162009-04-17 17:23:37 -0700591 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800592 }
593
594 /*
595 * Try to continue with base array type. This will let
596 * us pass basic stuff (e.g. get array len) that wouldn't
597 * fly with an Object. This is NOT correct if the
598 * missing type is a primitive array, but we should never
599 * have a problem loading those. (I'm not convinced this
600 * is correct or even useful. Just use Object here?)
601 */
602 clazz = dvmFindClassNoInit("[Ljava/lang/Object;",
603 meth->clazz->classLoader);
604 } else if (pDescriptor[0] == 'L') {
605 /*
606 * We are looking at a non-array reference descriptor;
607 * try to continue with base reference type.
608 */
609 clazz = gDvm.classJavaLangObject;
610 } else {
611 /* We are looking at a primitive type. */
612 LOG_VFY("VFY: invalid char in signature in '%s'\n", pDescriptor);
Andy McFadden62a75162009-04-17 17:23:37 -0700613 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800614 }
615
616 if (clazz == NULL) {
Andy McFadden62a75162009-04-17 17:23:37 -0700617 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800618 }
619 }
620
621 if (dvmIsPrimitiveClass(clazz)) {
622 LOG_VFY("VFY: invalid use of primitive type '%s'\n", pDescriptor);
Andy McFadden62a75162009-04-17 17:23:37 -0700623 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800624 clazz = NULL;
625 }
626
627 return clazz;
628}
629
630/*
631 * Look up a class reference in a signature. Could be an arg or the
632 * return value.
633 *
634 * Advances "*pSig" to the last character in the signature (that is, to
635 * the ';').
636 *
637 * NOTE: this is also expected to verify the signature.
638 */
639static ClassObject* lookupSignatureClass(const Method* meth, const char** pSig,
Andy McFadden62a75162009-04-17 17:23:37 -0700640 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800641{
642 const char* sig = *pSig;
643 const char* endp = sig;
644
645 assert(sig != NULL && *sig == 'L');
646
647 while (*++endp != ';' && *endp != '\0')
648 ;
649 if (*endp != ';') {
650 LOG_VFY("VFY: bad signature component '%s' (missing ';')\n", sig);
Andy McFadden62a75162009-04-17 17:23:37 -0700651 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800652 return NULL;
653 }
654
655 endp++; /* Advance past the ';'. */
656 int typeLen = endp - sig;
657 char typeStr[typeLen+1]; /* +1 for the '\0' */
658 memcpy(typeStr, sig, typeLen);
659 typeStr[typeLen] = '\0';
660
661 *pSig = endp - 1; /* - 1 so that *pSig points at, not past, the ';' */
662
Andy McFadden62a75162009-04-17 17:23:37 -0700663 return lookupClassByDescriptor(meth, typeStr, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800664}
665
666/*
667 * Look up an array class reference in a signature. Could be an arg or the
668 * return value.
669 *
670 * Advances "*pSig" to the last character in the signature.
671 *
672 * NOTE: this is also expected to verify the signature.
673 */
674static ClassObject* lookupSignatureArrayClass(const Method* meth,
Andy McFadden62a75162009-04-17 17:23:37 -0700675 const char** pSig, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800676{
677 const char* sig = *pSig;
678 const char* endp = sig;
679
680 assert(sig != NULL && *sig == '[');
681
682 /* find the end */
683 while (*++endp == '[' && *endp != '\0')
684 ;
685
686 if (*endp == 'L') {
687 while (*++endp != ';' && *endp != '\0')
688 ;
689 if (*endp != ';') {
690 LOG_VFY("VFY: bad signature component '%s' (missing ';')\n", sig);
Andy McFadden62a75162009-04-17 17:23:37 -0700691 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800692 return NULL;
693 }
694 }
695
696 int typeLen = endp - sig +1;
697 char typeStr[typeLen+1];
698 memcpy(typeStr, sig, typeLen);
699 typeStr[typeLen] = '\0';
700
701 *pSig = endp;
702
Andy McFadden62a75162009-04-17 17:23:37 -0700703 return lookupClassByDescriptor(meth, typeStr, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800704}
705
706/*
707 * Set the register types for the first instruction in the method based on
708 * the method signature.
709 *
710 * This has the side-effect of validating the signature.
711 *
712 * Returns "true" on success.
713 */
714static bool setTypesFromSignature(const Method* meth, RegType* regTypes,
715 UninitInstanceMap* uninitMap)
716{
717 DexParameterIterator iterator;
718 int actualArgs, expectedArgs, argStart;
Andy McFadden62a75162009-04-17 17:23:37 -0700719 VerifyError failure = VERIFY_ERROR_NONE;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800720
721 dexParameterIteratorInit(&iterator, &meth->prototype);
722 argStart = meth->registersSize - meth->insSize;
723 expectedArgs = meth->insSize; /* long/double count as two */
724 actualArgs = 0;
725
726 assert(argStart >= 0); /* should have been verified earlier */
727
728 /*
729 * Include the "this" pointer.
730 */
731 if (!dvmIsStaticMethod(meth)) {
732 /*
733 * If this is a constructor for a class other than java.lang.Object,
734 * mark the first ("this") argument as uninitialized. This restricts
735 * field access until the superclass constructor is called.
736 */
737 if (isInitMethod(meth) && meth->clazz != gDvm.classJavaLangObject) {
738 int uidx = dvmSetUninitInstance(uninitMap, kUninitThisArgAddr,
739 meth->clazz);
740 assert(uidx == 0);
741 regTypes[argStart + actualArgs] = regTypeFromUninitIndex(uidx);
742 } else {
743 regTypes[argStart + actualArgs] = regTypeFromClass(meth->clazz);
744 }
745 actualArgs++;
746 }
747
748 for (;;) {
749 const char* descriptor = dexParameterIteratorNextDescriptor(&iterator);
750
751 if (descriptor == NULL) {
752 break;
753 }
754
755 if (actualArgs >= expectedArgs) {
756 LOG_VFY("VFY: expected %d args, found more (%s)\n",
757 expectedArgs, descriptor);
758 goto bad_sig;
759 }
760
761 switch (*descriptor) {
762 case 'L':
763 case '[':
764 /*
765 * We assume that reference arguments are initialized. The
766 * only way it could be otherwise (assuming the caller was
767 * verified) is if the current method is <init>, but in that
768 * case it's effectively considered initialized the instant
769 * we reach here (in the sense that we can return without
770 * doing anything or call virtual methods).
771 */
772 {
773 ClassObject* clazz =
Andy McFadden62a75162009-04-17 17:23:37 -0700774 lookupClassByDescriptor(meth, descriptor, &failure);
775 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800776 goto bad_sig;
777 regTypes[argStart + actualArgs] = regTypeFromClass(clazz);
778 }
779 actualArgs++;
780 break;
781 case 'Z':
782 regTypes[argStart + actualArgs] = kRegTypeBoolean;
783 actualArgs++;
784 break;
785 case 'C':
786 regTypes[argStart + actualArgs] = kRegTypeChar;
787 actualArgs++;
788 break;
789 case 'B':
790 regTypes[argStart + actualArgs] = kRegTypeByte;
791 actualArgs++;
792 break;
793 case 'I':
794 regTypes[argStart + actualArgs] = kRegTypeInteger;
795 actualArgs++;
796 break;
797 case 'S':
798 regTypes[argStart + actualArgs] = kRegTypeShort;
799 actualArgs++;
800 break;
801 case 'F':
802 regTypes[argStart + actualArgs] = kRegTypeFloat;
803 actualArgs++;
804 break;
805 case 'D':
806 regTypes[argStart + actualArgs] = kRegTypeDoubleLo;
807 regTypes[argStart + actualArgs +1] = kRegTypeDoubleHi;
808 actualArgs += 2;
809 break;
810 case 'J':
811 regTypes[argStart + actualArgs] = kRegTypeLongLo;
812 regTypes[argStart + actualArgs +1] = kRegTypeLongHi;
813 actualArgs += 2;
814 break;
815 default:
816 LOG_VFY("VFY: unexpected signature type char '%c'\n", *descriptor);
817 goto bad_sig;
818 }
819 }
820
821 if (actualArgs != expectedArgs) {
822 LOG_VFY("VFY: expected %d args, found %d\n", expectedArgs, actualArgs);
823 goto bad_sig;
824 }
825
826 const char* descriptor = dexProtoGetReturnType(&meth->prototype);
827
828 /*
829 * Validate return type. We don't do the type lookup; just want to make
830 * sure that it has the right format. Only major difference from the
831 * method argument format is that 'V' is supported.
832 */
833 switch (*descriptor) {
834 case 'I':
835 case 'C':
836 case 'S':
837 case 'B':
838 case 'Z':
839 case 'V':
840 case 'F':
841 case 'D':
842 case 'J':
843 if (*(descriptor+1) != '\0')
844 goto bad_sig;
845 break;
846 case '[':
847 /* single/multi, object/primitive */
848 while (*++descriptor == '[')
849 ;
850 if (*descriptor == 'L') {
851 while (*++descriptor != ';' && *descriptor != '\0')
852 ;
853 if (*descriptor != ';')
854 goto bad_sig;
855 } else {
856 if (*(descriptor+1) != '\0')
857 goto bad_sig;
858 }
859 break;
860 case 'L':
861 /* could be more thorough here, but shouldn't be required */
862 while (*++descriptor != ';' && *descriptor != '\0')
863 ;
864 if (*descriptor != ';')
865 goto bad_sig;
866 break;
867 default:
868 goto bad_sig;
869 }
870
871 return true;
872
873//fail:
874// LOG_VFY_METH(meth, "VFY: bad sig\n");
875// return false;
876
877bad_sig:
878 {
879 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
880 LOG_VFY("VFY: bad signature '%s' for %s.%s\n",
881 desc, meth->clazz->descriptor, meth->name);
882 free(desc);
883 }
884 return false;
885}
886
887/*
888 * Return the register type for the method. We can't just use the
889 * already-computed DalvikJniReturnType, because if it's a reference type
890 * we need to do the class lookup.
891 *
892 * Returned references are assumed to be initialized.
893 *
894 * Returns kRegTypeUnknown for "void".
895 */
896static RegType getMethodReturnType(const Method* meth)
897{
898 RegType type;
899 const char* descriptor = dexProtoGetReturnType(&meth->prototype);
900
901 switch (*descriptor) {
902 case 'I':
903 type = kRegTypeInteger;
904 break;
905 case 'C':
906 type = kRegTypeChar;
907 break;
908 case 'S':
909 type = kRegTypeShort;
910 break;
911 case 'B':
912 type = kRegTypeByte;
913 break;
914 case 'Z':
915 type = kRegTypeBoolean;
916 break;
917 case 'V':
918 type = kRegTypeUnknown;
919 break;
920 case 'F':
921 type = kRegTypeFloat;
922 break;
923 case 'D':
924 type = kRegTypeDoubleLo;
925 break;
926 case 'J':
927 type = kRegTypeLongLo;
928 break;
929 case 'L':
930 case '[':
931 {
Andy McFadden62a75162009-04-17 17:23:37 -0700932 VerifyError failure = VERIFY_ERROR_NONE;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800933 ClassObject* clazz =
Andy McFadden62a75162009-04-17 17:23:37 -0700934 lookupClassByDescriptor(meth, descriptor, &failure);
935 assert(VERIFY_OK(failure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800936 type = regTypeFromClass(clazz);
937 }
938 break;
939 default:
940 /* we verified signature return type earlier, so this is impossible */
941 assert(false);
942 type = kRegTypeConflict;
943 break;
944 }
945
946 return type;
947}
948
949/*
950 * Convert a single-character signature value (i.e. a primitive type) to
951 * the corresponding RegType. This is intended for access to object fields
952 * holding primitive types.
953 *
954 * Returns kRegTypeUnknown for objects, arrays, and void.
955 */
956static RegType primSigCharToRegType(char sigChar)
957{
958 RegType type;
959
960 switch (sigChar) {
961 case 'I':
962 type = kRegTypeInteger;
963 break;
964 case 'C':
965 type = kRegTypeChar;
966 break;
967 case 'S':
968 type = kRegTypeShort;
969 break;
970 case 'B':
971 type = kRegTypeByte;
972 break;
973 case 'Z':
974 type = kRegTypeBoolean;
975 break;
976 case 'F':
977 type = kRegTypeFloat;
978 break;
979 case 'D':
980 type = kRegTypeDoubleLo;
981 break;
982 case 'J':
983 type = kRegTypeLongLo;
984 break;
985 case 'V':
986 case 'L':
987 case '[':
988 type = kRegTypeUnknown;
989 break;
990 default:
991 assert(false);
992 type = kRegTypeUnknown;
993 break;
994 }
995
996 return type;
997}
998
999/*
1000 * Verify the arguments to a method. We're executing in "method", making
1001 * a call to the method reference in vB.
1002 *
1003 * If this is a "direct" invoke, we allow calls to <init>. For calls to
1004 * <init>, the first argument may be an uninitialized reference. Otherwise,
1005 * calls to anything starting with '<' will be rejected, as will any
1006 * uninitialized reference arguments.
1007 *
1008 * For non-static method calls, this will verify that the method call is
1009 * appropriate for the "this" argument.
1010 *
1011 * The method reference is in vBBBB. The "isRange" parameter determines
1012 * whether we use 0-4 "args" values or a range of registers defined by
1013 * vAA and vCCCC.
1014 *
1015 * Widening conversions on integers and references are allowed, but
1016 * narrowing conversions are not.
1017 *
Andy McFadden62a75162009-04-17 17:23:37 -07001018 * Returns the resolved method on success, NULL on failure (with *pFailure
1019 * set appropriately).
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001020 */
1021static Method* verifyInvocationArgs(const Method* meth, const RegType* insnRegs,
1022 const int insnRegCount, const DecodedInstruction* pDecInsn,
1023 UninitInstanceMap* uninitMap, MethodType methodType, bool isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07001024 bool isSuper, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001025{
1026 Method* resMethod;
1027 char* sigOriginal = NULL;
1028
1029 /*
1030 * Resolve the method. This could be an abstract or concrete method
1031 * depending on what sort of call we're making.
1032 */
1033 if (methodType == METHOD_INTERFACE) {
1034 resMethod = dvmOptResolveInterfaceMethod(meth->clazz, pDecInsn->vB);
1035 } else {
Andy McFadden62a75162009-04-17 17:23:37 -07001036 resMethod = dvmOptResolveMethod(meth->clazz, pDecInsn->vB, methodType,
1037 pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001038 }
1039 if (resMethod == NULL) {
1040 /* failed; print a meaningful failure message */
1041 DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
1042 const DexMethodId* pMethodId;
1043 const char* methodName;
1044 char* methodDesc;
1045 const char* classDescriptor;
1046
1047 pMethodId = dexGetMethodId(pDexFile, pDecInsn->vB);
1048 methodName = dexStringById(pDexFile, pMethodId->nameIdx);
1049 methodDesc = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
1050 classDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
1051
1052 if (!gDvm.optimizing) {
1053 char* dotMissingClass = dvmDescriptorToDot(classDescriptor);
1054 char* dotMethClass = dvmDescriptorToDot(meth->clazz->descriptor);
1055 //char* curMethodDesc =
1056 // dexProtoCopyMethodDescriptor(&meth->prototype);
1057
1058 LOGE("Could not find method %s.%s, referenced from "
1059 "method %s.%s\n",
1060 dotMissingClass, methodName/*, methodDesc*/,
1061 dotMethClass, meth->name/*, curMethodDesc*/);
1062
1063 free(dotMissingClass);
1064 free(dotMethClass);
1065 //free(curMethodDesc);
1066 }
1067
1068 LOG_VFY("VFY: unable to resolve %s method %u: %s.%s %s\n",
1069 dvmMethodTypeStr(methodType), pDecInsn->vB,
1070 classDescriptor, methodName, methodDesc);
1071 free(methodDesc);
Andy McFadden62a75162009-04-17 17:23:37 -07001072 *pFailure = VERIFY_ERROR_NO_METHOD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001073 goto fail;
1074 }
1075
1076 /*
1077 * Only time you can explicitly call a method starting with '<' is when
1078 * making a "direct" invocation on "<init>". There are additional
1079 * restrictions but we don't enforce them here.
1080 */
1081 if (resMethod->name[0] == '<') {
1082 if (methodType != METHOD_DIRECT || !isInitMethod(resMethod)) {
1083 LOG_VFY("VFY: invalid call to %s.%s\n",
1084 resMethod->clazz->descriptor, resMethod->name);
1085 goto bad_sig;
1086 }
1087 }
1088
1089 /*
1090 * If we're using invoke-super(method), make sure that the executing
1091 * method's class' superclass has a vtable entry for the target method.
1092 */
1093 if (isSuper) {
1094 assert(methodType == METHOD_VIRTUAL);
1095 ClassObject* super = meth->clazz->super;
1096 if (super == NULL || resMethod->methodIndex > super->vtableCount) {
1097 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1098 LOG_VFY("VFY: invalid invoke-super from %s.%s to super %s.%s %s\n",
1099 meth->clazz->descriptor, meth->name,
1100 (super == NULL) ? "-" : super->descriptor,
1101 resMethod->name, desc);
1102 free(desc);
Andy McFadden62a75162009-04-17 17:23:37 -07001103 *pFailure = VERIFY_ERROR_NO_METHOD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001104 goto fail;
1105 }
1106 }
1107
1108 /*
1109 * We use vAA as our expected arg count, rather than resMethod->insSize,
1110 * because we need to match the call to the signature. Also, we might
1111 * might be calling through an abstract method definition (which doesn't
1112 * have register count values).
1113 */
1114 sigOriginal = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1115 const char* sig = sigOriginal;
1116 int expectedArgs = pDecInsn->vA;
1117 int actualArgs = 0;
1118
1119 if (!isRange && expectedArgs > 5) {
1120 LOG_VFY("VFY: invalid arg count in non-range invoke (%d)\n",
1121 pDecInsn->vA);
1122 goto fail;
1123 }
1124 if (expectedArgs > meth->outsSize) {
1125 LOG_VFY("VFY: invalid arg count (%d) exceeds outsSize (%d)\n",
1126 expectedArgs, meth->outsSize);
1127 goto fail;
1128 }
1129
1130 if (*sig++ != '(')
1131 goto bad_sig;
1132
1133 /*
1134 * Check the "this" argument, which must be an instance of the class
1135 * that declared the method. For an interface class, we don't do the
1136 * full interface merge, so we can't do a rigorous check here (which
1137 * is okay since we have to do it at runtime).
1138 */
1139 if (!dvmIsStaticMethod(resMethod)) {
1140 ClassObject* actualThisRef;
1141 RegType actualArgType;
1142
1143 actualArgType = getInvocationThis(insnRegs, insnRegCount, pDecInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07001144 pFailure);
1145 if (!VERIFY_OK(*pFailure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001146 goto fail;
1147
1148 if (regTypeIsUninitReference(actualArgType) && resMethod->name[0] != '<')
1149 {
1150 LOG_VFY("VFY: 'this' arg must be initialized\n");
1151 goto fail;
1152 }
1153 if (methodType != METHOD_INTERFACE && actualArgType != kRegTypeZero) {
1154 actualThisRef = regTypeReferenceToClass(actualArgType, uninitMap);
1155 if (!dvmInstanceof(actualThisRef, resMethod->clazz)) {
1156 LOG_VFY("VFY: 'this' arg '%s' not instance of '%s'\n",
1157 actualThisRef->descriptor,
1158 resMethod->clazz->descriptor);
1159 goto fail;
1160 }
1161 }
1162 actualArgs++;
1163 }
1164
1165 /*
1166 * Process the target method's signature. This signature may or may not
1167 * have been verified, so we can't assume it's properly formed.
1168 */
1169 while (*sig != '\0' && *sig != ')') {
1170 if (actualArgs >= expectedArgs) {
1171 LOG_VFY("VFY: expected %d args, found more (%c)\n",
1172 expectedArgs, *sig);
1173 goto bad_sig;
1174 }
1175
1176 u4 getReg;
1177 if (isRange)
1178 getReg = pDecInsn->vC + actualArgs;
1179 else
1180 getReg = pDecInsn->arg[actualArgs];
1181
1182 switch (*sig) {
1183 case 'L':
1184 {
Andy McFadden62a75162009-04-17 17:23:37 -07001185 ClassObject* clazz = lookupSignatureClass(meth, &sig, pFailure);
1186 if (!VERIFY_OK(*pFailure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001187 goto bad_sig;
1188 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001189 regTypeFromClass(clazz), pFailure);
1190 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001191 LOG_VFY("VFY: bad arg %d (into %s)\n",
1192 actualArgs, clazz->descriptor);
1193 goto bad_sig;
1194 }
1195 }
1196 actualArgs++;
1197 break;
1198 case '[':
1199 {
1200 ClassObject* clazz =
Andy McFadden62a75162009-04-17 17:23:37 -07001201 lookupSignatureArrayClass(meth, &sig, pFailure);
1202 if (!VERIFY_OK(*pFailure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001203 goto bad_sig;
1204 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001205 regTypeFromClass(clazz), pFailure);
1206 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001207 LOG_VFY("VFY: bad arg %d (into %s)\n",
1208 actualArgs, clazz->descriptor);
1209 goto bad_sig;
1210 }
1211 }
1212 actualArgs++;
1213 break;
1214 case 'Z':
1215 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001216 kRegTypeBoolean, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001217 actualArgs++;
1218 break;
1219 case 'C':
1220 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001221 kRegTypeChar, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001222 actualArgs++;
1223 break;
1224 case 'B':
1225 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001226 kRegTypeByte, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001227 actualArgs++;
1228 break;
1229 case 'I':
1230 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001231 kRegTypeInteger, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001232 actualArgs++;
1233 break;
1234 case 'S':
1235 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001236 kRegTypeShort, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001237 actualArgs++;
1238 break;
1239 case 'F':
1240 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001241 kRegTypeFloat, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001242 actualArgs++;
1243 break;
1244 case 'D':
1245 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001246 kRegTypeDoubleLo, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001247 actualArgs += 2;
1248 break;
1249 case 'J':
1250 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001251 kRegTypeLongLo, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001252 actualArgs += 2;
1253 break;
1254 default:
1255 LOG_VFY("VFY: invocation target: bad signature type char '%c'\n",
1256 *sig);
1257 goto bad_sig;
1258 }
1259
1260 sig++;
1261 }
1262 if (*sig != ')') {
1263 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1264 LOG_VFY("VFY: invocation target: bad signature '%s'\n", desc);
1265 free(desc);
1266 goto bad_sig;
1267 }
1268
1269 if (actualArgs != expectedArgs) {
1270 LOG_VFY("VFY: expected %d args, found %d\n", expectedArgs, actualArgs);
1271 goto bad_sig;
1272 }
1273
1274 free(sigOriginal);
1275 return resMethod;
1276
1277bad_sig:
1278 if (resMethod != NULL) {
1279 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1280 LOG_VFY("VFY: rejecting call to %s.%s %s\n",
Andy McFadden62a75162009-04-17 17:23:37 -07001281 resMethod->clazz->descriptor, resMethod->name, desc);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001282 free(desc);
1283 }
1284
1285fail:
1286 free(sigOriginal);
Andy McFadden62a75162009-04-17 17:23:37 -07001287 if (*pFailure == VERIFY_ERROR_NONE)
1288 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001289 return NULL;
1290}
1291
1292/*
1293 * Get the class object for the type of data stored in a field. This isn't
1294 * stored in the Field struct, so we have to recover it from the signature.
1295 *
1296 * This only works for reference types. Don't call this for primitive types.
1297 *
1298 * If we can't find the class, we return java.lang.Object, so that
1299 * verification can continue if a field is only accessed in trivial ways.
1300 */
1301static ClassObject* getFieldClass(const Method* meth, const Field* field)
1302{
1303 ClassObject* fieldClass;
1304 const char* signature = field->signature;
1305
1306 if ((*signature == 'L') || (*signature == '[')) {
1307 fieldClass = dvmFindClassNoInit(signature,
1308 meth->clazz->classLoader);
1309 } else {
1310 return NULL;
1311 }
1312
1313 if (fieldClass == NULL) {
1314 dvmClearOptException(dvmThreadSelf());
1315 LOGV("VFY: unable to find class '%s' for field %s.%s, trying Object\n",
1316 field->signature, meth->clazz->descriptor, field->name);
1317 fieldClass = gDvm.classJavaLangObject;
1318 } else {
1319 assert(!dvmIsPrimitiveClass(fieldClass));
1320 }
1321 return fieldClass;
1322}
1323
1324
1325/*
1326 * ===========================================================================
1327 * Register operations
1328 * ===========================================================================
1329 */
1330
1331/*
1332 * Get the type of register N, verifying that the register is valid.
1333 *
Andy McFadden62a75162009-04-17 17:23:37 -07001334 * Sets "*pFailure" appropriately if the register number is out of range.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001335 */
1336static inline RegType getRegisterType(const RegType* insnRegs,
Andy McFadden62a75162009-04-17 17:23:37 -07001337 const int insnRegCount, u4 vsrc, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001338{
1339 RegType type;
1340
1341 if (vsrc >= (u4) insnRegCount) {
Andy McFadden62a75162009-04-17 17:23:37 -07001342 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001343 return kRegTypeUnknown;
1344 } else {
1345 return insnRegs[vsrc];
1346 }
1347}
1348
1349/*
1350 * Get the value from a register, and cast it to a ClassObject. Sets
Andy McFadden62a75162009-04-17 17:23:37 -07001351 * "*pFailure" if something fails.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001352 *
1353 * This fails if the register holds an uninitialized class.
1354 *
1355 * If the register holds kRegTypeZero, this returns a NULL pointer.
1356 */
1357static ClassObject* getClassFromRegister(const RegType* insnRegs,
Andy McFadden62a75162009-04-17 17:23:37 -07001358 const int insnRegCount, u4 vsrc, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001359{
1360 ClassObject* clazz = NULL;
1361 RegType type;
1362
1363 /* get the element type of the array held in vsrc */
Andy McFadden62a75162009-04-17 17:23:37 -07001364 type = getRegisterType(insnRegs, insnRegCount, vsrc, pFailure);
1365 if (!VERIFY_OK(*pFailure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001366 goto bail;
1367
1368 /* if "always zero", we allow it to fail at runtime */
1369 if (type == kRegTypeZero)
1370 goto bail;
1371
1372 if (!regTypeIsReference(type)) {
1373 LOG_VFY("VFY: tried to get class from non-ref register v%d (type=%d)\n",
1374 vsrc, type);
Andy McFadden62a75162009-04-17 17:23:37 -07001375 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001376 goto bail;
1377 }
1378 if (regTypeIsUninitReference(type)) {
1379 LOG_VFY("VFY: register %u holds uninitialized reference\n", vsrc);
Andy McFadden62a75162009-04-17 17:23:37 -07001380 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001381 goto bail;
1382 }
1383
1384 clazz = regTypeInitializedReferenceToClass(type);
1385
1386bail:
1387 return clazz;
1388}
1389
1390/*
1391 * Get the "this" pointer from a non-static method invocation. This
1392 * returns the RegType so the caller can decide whether it needs the
1393 * reference to be initialized or not. (Can also return kRegTypeZero
1394 * if the reference can only be zero at this point.)
1395 *
1396 * The argument count is in vA, and the first argument is in vC, for both
1397 * "simple" and "range" versions. We just need to make sure vA is >= 1
1398 * and then return vC.
1399 */
1400static RegType getInvocationThis(const RegType* insnRegs,
Andy McFadden62a75162009-04-17 17:23:37 -07001401 const int insnRegCount, const DecodedInstruction* pDecInsn,
1402 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001403{
1404 RegType thisType = kRegTypeUnknown;
1405
1406 if (pDecInsn->vA < 1) {
1407 LOG_VFY("VFY: invoke lacks 'this'\n");
Andy McFadden62a75162009-04-17 17:23:37 -07001408 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001409 goto bail;
1410 }
1411
1412 /* get the element type of the array held in vsrc */
Andy McFadden62a75162009-04-17 17:23:37 -07001413 thisType = getRegisterType(insnRegs, insnRegCount, pDecInsn->vC, pFailure);
1414 if (!VERIFY_OK(*pFailure)) {
1415 LOG_VFY("VFY: failed to get 'this' from register %u\n", pDecInsn->vC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001416 goto bail;
1417 }
1418
1419 if (!regTypeIsReference(thisType)) {
1420 LOG_VFY("VFY: tried to get class from non-ref register v%d (type=%d)\n",
1421 pDecInsn->vC, thisType);
Andy McFadden62a75162009-04-17 17:23:37 -07001422 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001423 goto bail;
1424 }
1425
1426bail:
1427 return thisType;
1428}
1429
1430/*
1431 * Set the type of register N, verifying that the register is valid. If
1432 * "newType" is the "Lo" part of a 64-bit value, register N+1 will be
1433 * set to "newType+1".
1434 *
Andy McFadden62a75162009-04-17 17:23:37 -07001435 * Sets "*pFailure" if the register number is out of range.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001436 */
1437static void setRegisterType(RegType* insnRegs, const int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001438 u4 vdst, RegType newType, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001439{
1440 //LOGD("set-reg v%u = %d\n", vdst, newType);
1441 switch (newType) {
1442 case kRegTypeUnknown:
1443 case kRegTypeBoolean:
1444 case kRegTypeOne:
1445 case kRegTypeByte:
1446 case kRegTypePosByte:
1447 case kRegTypeShort:
1448 case kRegTypePosShort:
1449 case kRegTypeChar:
1450 case kRegTypeInteger:
1451 case kRegTypeFloat:
1452 case kRegTypeZero:
1453 if (vdst >= (u4) insnRegCount) {
Andy McFadden62a75162009-04-17 17:23:37 -07001454 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001455 } else {
1456 insnRegs[vdst] = newType;
1457 }
1458 break;
1459 case kRegTypeLongLo:
1460 case kRegTypeDoubleLo:
1461 if (vdst+1 >= (u4) insnRegCount) {
Andy McFadden62a75162009-04-17 17:23:37 -07001462 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001463 } else {
1464 insnRegs[vdst] = newType;
1465 insnRegs[vdst+1] = newType+1;
1466 }
1467 break;
1468 case kRegTypeLongHi:
1469 case kRegTypeDoubleHi:
1470 /* should never set these explicitly */
Andy McFadden62a75162009-04-17 17:23:37 -07001471 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001472 break;
1473
1474 case kRegTypeUninit:
1475 default:
1476 if (regTypeIsReference(newType)) {
1477 if (vdst >= (u4) insnRegCount) {
Andy McFadden62a75162009-04-17 17:23:37 -07001478 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001479 break;
1480 }
1481 insnRegs[vdst] = newType;
1482
1483 /*
1484 * In most circumstances we won't see a reference to a primitive
1485 * class here (e.g. "D"), since that would mean the object in the
1486 * register is actually a primitive type. It can happen as the
1487 * result of an assumed-successful check-cast instruction in
1488 * which the second argument refers to a primitive class. (In
1489 * practice, such an instruction will always throw an exception.)
1490 *
1491 * This is not an issue for instructions like const-class, where
1492 * the object in the register is a java.lang.Class instance.
1493 */
1494 break;
1495 }
1496 /* bad - fall through */
1497
1498 case kRegTypeConflict: // should only be set during a merge
1499 LOG_VFY("Unexpected set type %d\n", newType);
1500 assert(false);
Andy McFadden62a75162009-04-17 17:23:37 -07001501 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001502 break;
1503 }
1504}
1505
1506/*
1507 * Verify that the contents of the specified register have the specified
1508 * type (or can be converted to it through an implicit widening conversion).
1509 *
1510 * In theory we could use this to modify the type of the source register,
1511 * e.g. a generic 32-bit constant, once used as a float, would thereafter
1512 * remain a float. There is no compelling reason to require this though.
1513 *
1514 * If "vsrc" is a reference, both it and the "vsrc" register must be
1515 * initialized ("vsrc" may be Zero). This will verify that the value in
1516 * the register is an instance of checkType, or if checkType is an
1517 * interface, verify that the register implements checkType.
1518 */
1519static void verifyRegisterType(const RegType* insnRegs, const int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001520 u4 vsrc, RegType checkType, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001521{
1522 if (vsrc >= (u4) insnRegCount) {
Andy McFadden62a75162009-04-17 17:23:37 -07001523 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001524 return;
1525 }
1526
1527 RegType srcType = insnRegs[vsrc];
1528
1529 //LOGD("check-reg v%u = %d\n", vsrc, checkType);
1530 switch (checkType) {
1531 case kRegTypeFloat:
1532 case kRegTypeBoolean:
1533 case kRegTypePosByte:
1534 case kRegTypeByte:
1535 case kRegTypePosShort:
1536 case kRegTypeShort:
1537 case kRegTypeChar:
1538 case kRegTypeInteger:
1539 if (!canConvertTo1nr(srcType, checkType)) {
1540 LOG_VFY("VFY: register1 v%u type %d, wanted %d\n",
1541 vsrc, srcType, checkType);
Andy McFadden62a75162009-04-17 17:23:37 -07001542 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001543 }
1544 break;
1545 case kRegTypeLongLo:
1546 case kRegTypeDoubleLo:
1547 if (vsrc+1 >= (u4) insnRegCount) {
1548 LOG_VFY("VFY: register2 v%u out of range (%d)\n",
1549 vsrc, insnRegCount);
Andy McFadden62a75162009-04-17 17:23:37 -07001550 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001551 } else if (insnRegs[vsrc+1] != srcType+1) {
1552 LOG_VFY("VFY: register2 v%u-%u values %d,%d\n",
1553 vsrc, vsrc+1, insnRegs[vsrc], insnRegs[vsrc+1]);
Andy McFadden62a75162009-04-17 17:23:37 -07001554 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001555 } else if (!canConvertTo2(srcType, checkType)) {
1556 LOG_VFY("VFY: register2 v%u type %d, wanted %d\n",
1557 vsrc, srcType, checkType);
Andy McFadden62a75162009-04-17 17:23:37 -07001558 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001559 }
1560 break;
1561
1562 case kRegTypeLongHi:
1563 case kRegTypeDoubleHi:
1564 case kRegTypeZero:
1565 case kRegTypeOne:
1566 case kRegTypeUnknown:
1567 case kRegTypeConflict:
1568 /* should never be checking for these explicitly */
1569 assert(false);
Andy McFadden62a75162009-04-17 17:23:37 -07001570 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001571 return;
1572 case kRegTypeUninit:
1573 default:
1574 /* make sure checkType is initialized reference */
1575 if (!regTypeIsReference(checkType)) {
1576 LOG_VFY("VFY: unexpected check type %d\n", checkType);
1577 assert(false);
Andy McFadden62a75162009-04-17 17:23:37 -07001578 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001579 break;
1580 }
1581 if (regTypeIsUninitReference(checkType)) {
1582 LOG_VFY("VFY: uninitialized ref not expected as reg check\n");
Andy McFadden62a75162009-04-17 17:23:37 -07001583 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001584 break;
1585 }
1586 /* make sure srcType is initialized reference or always-NULL */
1587 if (!regTypeIsReference(srcType)) {
1588 LOG_VFY("VFY: register1 v%u type %d, wanted ref\n", vsrc, srcType);
Andy McFadden62a75162009-04-17 17:23:37 -07001589 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001590 break;
1591 }
1592 if (regTypeIsUninitReference(srcType)) {
1593 LOG_VFY("VFY: register1 v%u holds uninitialized ref\n", vsrc);
Andy McFadden62a75162009-04-17 17:23:37 -07001594 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001595 break;
1596 }
1597 /* if the register isn't Zero, make sure it's an instance of check */
1598 if (srcType != kRegTypeZero) {
1599 ClassObject* srcClass = regTypeInitializedReferenceToClass(srcType);
1600 ClassObject* checkClass = regTypeInitializedReferenceToClass(checkType);
1601 assert(srcClass != NULL);
1602 assert(checkClass != NULL);
1603
1604 if (dvmIsInterfaceClass(checkClass)) {
1605 /*
1606 * All objects implement all interfaces as far as the
1607 * verifier is concerned. The runtime has to sort it out.
1608 * See comments above findCommonSuperclass.
1609 */
1610 /*
1611 if (srcClass != checkClass &&
1612 !dvmImplements(srcClass, checkClass))
1613 {
1614 LOG_VFY("VFY: %s does not implement %s\n",
1615 srcClass->descriptor, checkClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07001616 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001617 }
1618 */
1619 } else {
1620 if (!dvmInstanceof(srcClass, checkClass)) {
1621 LOG_VFY("VFY: %s is not instance of %s\n",
1622 srcClass->descriptor, checkClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07001623 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001624 }
1625 }
1626 }
1627 break;
1628 }
1629}
1630
1631/*
1632 * Set the type of the "result" register. Mostly this exists to expand
1633 * "insnRegCount" to encompass the result register.
1634 */
1635static void setResultRegisterType(RegType* insnRegs, const int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001636 RegType newType, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001637{
1638 setRegisterType(insnRegs, insnRegCount + kExtraRegs,
Andy McFadden62a75162009-04-17 17:23:37 -07001639 RESULT_REGISTER(insnRegCount), newType, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001640}
1641
1642
1643/*
1644 * Update all registers holding "uninitType" to instead hold the
1645 * corresponding initialized reference type. This is called when an
1646 * appropriate <init> method is invoked -- all copies of the reference
1647 * must be marked as initialized.
1648 */
1649static void markRefsAsInitialized(RegType* insnRegs, int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001650 UninitInstanceMap* uninitMap, RegType uninitType, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001651{
1652 ClassObject* clazz;
1653 RegType initType;
1654 int i, changed;
1655
1656 clazz = dvmGetUninitInstance(uninitMap, regTypeToUninitIndex(uninitType));
1657 if (clazz == NULL) {
1658 LOGE("VFY: unable to find type=0x%x (idx=%d)\n",
1659 uninitType, regTypeToUninitIndex(uninitType));
Andy McFadden62a75162009-04-17 17:23:37 -07001660 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001661 return;
1662 }
1663 initType = regTypeFromClass(clazz);
1664
1665 changed = 0;
1666 for (i = 0; i < insnRegCount; i++) {
1667 if (insnRegs[i] == uninitType) {
1668 insnRegs[i] = initType;
1669 changed++;
1670 }
1671 }
1672 //LOGD("VFY: marked %d registers as initialized\n", changed);
1673 assert(changed > 0);
1674
1675 return;
1676}
1677
1678/*
1679 * We're creating a new instance of class C at address A. Any registers
1680 * holding instances previously created at address A must be initialized
1681 * by now. If not, we mark them as "conflict" to prevent them from being
1682 * used (otherwise, markRefsAsInitialized would mark the old ones and the
1683 * new ones at the same time).
1684 */
1685static void markUninitRefsAsInvalid(RegType* insnRegs, int insnRegCount,
1686 UninitInstanceMap* uninitMap, RegType uninitType)
1687{
1688 int i, changed;
1689
1690 changed = 0;
1691 for (i = 0; i < insnRegCount; i++) {
1692 if (insnRegs[i] == uninitType) {
1693 insnRegs[i] = kRegTypeConflict;
1694 changed++;
1695 }
1696 }
1697
1698 //if (changed)
1699 // LOGD("VFY: marked %d uninitialized registers as invalid\n", changed);
1700}
1701
1702/*
1703 * Find the start of the register set for the specified instruction in
1704 * the current method.
1705 */
1706static inline RegType* getRegisterLine(const RegisterTable* regTable,
1707 int insnIdx)
1708{
1709 return regTable->addrRegs[insnIdx];
1710}
1711
1712/*
1713 * Copy a bunch of registers.
1714 */
1715static inline void copyRegisters(RegType* dst, const RegType* src,
1716 int numRegs)
1717{
1718 memcpy(dst, src, numRegs * sizeof(RegType));
1719}
1720
1721/*
1722 * Compare a bunch of registers.
1723 *
1724 * Returns 0 if they match. Using this for a sort is unwise, since the
1725 * value can change based on machine endianness.
1726 */
1727static inline int compareRegisters(const RegType* src1, const RegType* src2,
1728 int numRegs)
1729{
1730 return memcmp(src1, src2, numRegs * sizeof(RegType));
1731}
1732
1733/*
1734 * Register type categories, for type checking.
1735 *
1736 * The spec says category 1 includes boolean, byte, char, short, int, float,
1737 * reference, and returnAddress. Category 2 includes long and double.
1738 *
1739 * We treat object references separately, so we have "category1nr". We
1740 * don't support jsr/ret, so there is no "returnAddress" type.
1741 */
1742typedef enum TypeCategory {
1743 kTypeCategoryUnknown = 0,
1744 kTypeCategory1nr, // byte, char, int, float, boolean
1745 kTypeCategory2, // long, double
1746 kTypeCategoryRef, // object reference
1747} TypeCategory;
1748
1749/*
1750 * See if "type" matches "cat". All we're really looking for here is that
1751 * we're not mixing and matching 32-bit and 64-bit quantities, and we're
1752 * not mixing references with numerics. (For example, the arguments to
1753 * "a < b" could be integers of different sizes, but they must both be
1754 * integers. Dalvik is less specific about int vs. float, so we treat them
1755 * as equivalent here.)
1756 *
1757 * For category 2 values, "type" must be the "low" half of the value.
1758 *
Andy McFadden62a75162009-04-17 17:23:37 -07001759 * Sets "*pFailure" if something looks wrong.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001760 */
Andy McFadden62a75162009-04-17 17:23:37 -07001761static void checkTypeCategory(RegType type, TypeCategory cat,
1762 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001763{
1764 switch (cat) {
1765 case kTypeCategory1nr:
1766 switch (type) {
1767 case kRegTypeFloat:
1768 case kRegTypeZero:
1769 case kRegTypeOne:
1770 case kRegTypeBoolean:
1771 case kRegTypePosByte:
1772 case kRegTypeByte:
1773 case kRegTypePosShort:
1774 case kRegTypeShort:
1775 case kRegTypeChar:
1776 case kRegTypeInteger:
1777 break;
1778 default:
Andy McFadden62a75162009-04-17 17:23:37 -07001779 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001780 break;
1781 }
1782 break;
1783
1784 case kTypeCategory2:
1785 switch (type) {
1786 case kRegTypeLongLo:
1787 case kRegTypeDoubleLo:
1788 break;
1789 default:
Andy McFadden62a75162009-04-17 17:23:37 -07001790 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001791 break;
1792 }
1793 break;
1794
1795 case kTypeCategoryRef:
1796 if (type != kRegTypeZero && !regTypeIsReference(type))
Andy McFadden62a75162009-04-17 17:23:37 -07001797 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001798 break;
1799
1800 default:
1801 assert(false);
Andy McFadden62a75162009-04-17 17:23:37 -07001802 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001803 break;
1804 }
1805}
1806
1807/*
1808 * For a category 2 register pair, verify that "typeh" is the appropriate
1809 * high part for "typel".
1810 *
1811 * Does not verify that "typel" is in fact the low part of a 64-bit
1812 * register pair.
1813 */
Andy McFadden62a75162009-04-17 17:23:37 -07001814static void checkWidePair(RegType typel, RegType typeh, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001815{
1816 if ((typeh != typel+1))
Andy McFadden62a75162009-04-17 17:23:37 -07001817 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001818}
1819
1820/*
1821 * Implement category-1 "move" instructions. Copy a 32-bit value from
1822 * "vsrc" to "vdst".
1823 *
1824 * "insnRegCount" is the number of registers available. The "vdst" and
1825 * "vsrc" values are checked against this.
1826 */
1827static void copyRegister1(RegType* insnRegs, int insnRegCount, u4 vdst,
Andy McFadden62a75162009-04-17 17:23:37 -07001828 u4 vsrc, TypeCategory cat, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001829{
Andy McFadden62a75162009-04-17 17:23:37 -07001830 RegType type = getRegisterType(insnRegs, insnRegCount, vsrc, pFailure);
1831 if (VERIFY_OK(*pFailure))
1832 checkTypeCategory(type, cat, pFailure);
1833 if (VERIFY_OK(*pFailure))
1834 setRegisterType(insnRegs, insnRegCount, vdst, type, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001835
Andy McFadden62a75162009-04-17 17:23:37 -07001836 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001837 LOG_VFY("VFY: copy1 v%u<-v%u type=%d cat=%d\n", vdst, vsrc, type, cat);
1838 }
1839}
1840
1841/*
1842 * Implement category-2 "move" instructions. Copy a 64-bit value from
1843 * "vsrc" to "vdst". This copies both halves of the register.
1844 */
1845static void copyRegister2(RegType* insnRegs, int insnRegCount, u4 vdst,
Andy McFadden62a75162009-04-17 17:23:37 -07001846 u4 vsrc, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001847{
Andy McFadden62a75162009-04-17 17:23:37 -07001848 RegType typel = getRegisterType(insnRegs, insnRegCount, vsrc, pFailure);
1849 RegType typeh = getRegisterType(insnRegs, insnRegCount, vsrc+1, pFailure);
1850 if (VERIFY_OK(*pFailure)) {
1851 checkTypeCategory(typel, kTypeCategory2, pFailure);
1852 checkWidePair(typel, typeh, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001853 }
Andy McFadden62a75162009-04-17 17:23:37 -07001854 if (VERIFY_OK(*pFailure))
1855 setRegisterType(insnRegs, insnRegCount, vdst, typel, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001856
Andy McFadden62a75162009-04-17 17:23:37 -07001857 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001858 LOG_VFY("VFY: copy2 v%u<-v%u type=%d/%d\n", vdst, vsrc, typel, typeh);
1859 }
1860}
1861
1862/*
1863 * Implement "move-result". Copy the category-1 value from the result
1864 * register to another register, and reset the result register.
1865 *
1866 * We can't just call copyRegister1 with an altered insnRegCount,
1867 * because that would affect the test on "vdst" as well.
1868 */
1869static void copyResultRegister1(RegType* insnRegs, const int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001870 u4 vdst, TypeCategory cat, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001871{
1872 RegType type;
1873 u4 vsrc;
1874
1875 vsrc = RESULT_REGISTER(insnRegCount);
Andy McFadden62a75162009-04-17 17:23:37 -07001876 type = getRegisterType(insnRegs, insnRegCount + kExtraRegs, vsrc, pFailure);
1877 if (VERIFY_OK(*pFailure))
1878 checkTypeCategory(type, cat, pFailure);
1879 if (VERIFY_OK(*pFailure)) {
1880 setRegisterType(insnRegs, insnRegCount, vdst, type, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001881 insnRegs[vsrc] = kRegTypeUnknown;
1882 }
1883
Andy McFadden62a75162009-04-17 17:23:37 -07001884 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001885 LOG_VFY("VFY: copyRes1 v%u<-v%u cat=%d type=%d\n",
1886 vdst, vsrc, cat, type);
1887 }
1888}
1889
1890/*
1891 * Implement "move-result-wide". Copy the category-2 value from the result
1892 * register to another register, and reset the result register.
1893 *
1894 * We can't just call copyRegister2 with an altered insnRegCount,
1895 * because that would affect the test on "vdst" as well.
1896 */
1897static void copyResultRegister2(RegType* insnRegs, const int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001898 u4 vdst, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001899{
1900 RegType typel, typeh;
1901 u4 vsrc;
1902
1903 vsrc = RESULT_REGISTER(insnRegCount);
Andy McFadden62a75162009-04-17 17:23:37 -07001904 typel = getRegisterType(insnRegs, insnRegCount + kExtraRegs, vsrc,
1905 pFailure);
1906 typeh = getRegisterType(insnRegs, insnRegCount + kExtraRegs, vsrc+1,
1907 pFailure);
1908 if (VERIFY_OK(*pFailure)) {
1909 checkTypeCategory(typel, kTypeCategory2, pFailure);
1910 checkWidePair(typel, typeh, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001911 }
Andy McFadden62a75162009-04-17 17:23:37 -07001912 if (VERIFY_OK(*pFailure)) {
1913 setRegisterType(insnRegs, insnRegCount, vdst, typel, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001914 insnRegs[vsrc] = kRegTypeUnknown;
1915 insnRegs[vsrc+1] = kRegTypeUnknown;
1916 }
1917
Andy McFadden62a75162009-04-17 17:23:37 -07001918 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001919 LOG_VFY("VFY: copyRes2 v%u<-v%u type=%d/%d\n",
1920 vdst, vsrc, typel, typeh);
1921 }
1922}
1923
1924/*
1925 * Verify types for a simple two-register instruction (e.g. "neg-int").
1926 * "dstType" is stored into vA, and "srcType" is verified against vB.
1927 */
1928static void checkUnop(RegType* insnRegs, const int insnRegCount,
1929 DecodedInstruction* pDecInsn, RegType dstType, RegType srcType,
Andy McFadden62a75162009-04-17 17:23:37 -07001930 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001931{
Andy McFadden62a75162009-04-17 17:23:37 -07001932 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType, pFailure);
1933 setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001934}
1935
1936/*
1937 * We're performing an operation like "and-int/2addr" that can be
1938 * performed on booleans as well as integers. We get no indication of
1939 * boolean-ness, but we can infer it from the types of the arguments.
1940 *
1941 * Assumes we've already validated reg1/reg2.
1942 *
1943 * Returns true if both args are Boolean, Zero, or One.
1944 */
1945static bool upcastBooleanOp(RegType* insnRegs, const int insnRegCount,
1946 u4 reg1, u4 reg2)
1947{
1948 RegType type1, type2;
1949
1950 type1 = insnRegs[reg1];
1951 type2 = insnRegs[reg2];
1952
1953 if ((type1 == kRegTypeBoolean || type1 == kRegTypeZero ||
1954 type1 == kRegTypeOne) &&
1955 (type2 == kRegTypeBoolean || type2 == kRegTypeZero ||
1956 type2 == kRegTypeOne))
1957 {
1958 return true;
1959 }
1960 return false;
1961}
1962
1963/*
1964 * Verify types for A two-register instruction with a literal constant
1965 * (e.g. "add-int/lit8"). "dstType" is stored into vA, and "srcType" is
1966 * verified against vB.
1967 *
1968 * If "checkBooleanOp" is set, we use the constant value in vC.
1969 */
1970static void checkLitop(RegType* insnRegs, const int insnRegCount,
1971 DecodedInstruction* pDecInsn, RegType dstType, RegType srcType,
Andy McFadden62a75162009-04-17 17:23:37 -07001972 bool checkBooleanOp, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001973{
Andy McFadden62a75162009-04-17 17:23:37 -07001974 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType, pFailure);
1975 if (VERIFY_OK(*pFailure) && checkBooleanOp) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001976 assert(dstType == kRegTypeInteger);
1977 /* check vB with the call, then check the constant manually */
1978 if (upcastBooleanOp(insnRegs, insnRegCount, pDecInsn->vB, pDecInsn->vB)
1979 && (pDecInsn->vC == 0 || pDecInsn->vC == 1))
1980 {
1981 dstType = kRegTypeBoolean;
1982 }
1983 }
Andy McFadden62a75162009-04-17 17:23:37 -07001984 setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001985}
1986
1987/*
1988 * Verify types for a simple three-register instruction (e.g. "add-int").
1989 * "dstType" is stored into vA, and "srcType1"/"srcType2" are verified
1990 * against vB/vC.
1991 */
1992static void checkBinop(RegType* insnRegs, const int insnRegCount,
1993 DecodedInstruction* pDecInsn, RegType dstType, RegType srcType1,
Andy McFadden62a75162009-04-17 17:23:37 -07001994 RegType srcType2, bool checkBooleanOp, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001995{
Andy McFadden62a75162009-04-17 17:23:37 -07001996 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType1,
1997 pFailure);
1998 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vC, srcType2,
1999 pFailure);
2000 if (VERIFY_OK(*pFailure) && checkBooleanOp) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002001 assert(dstType == kRegTypeInteger);
2002 if (upcastBooleanOp(insnRegs, insnRegCount, pDecInsn->vB, pDecInsn->vC))
2003 dstType = kRegTypeBoolean;
2004 }
Andy McFadden62a75162009-04-17 17:23:37 -07002005 setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002006}
2007
2008/*
2009 * Verify types for a binary "2addr" operation. "srcType1"/"srcType2"
2010 * are verified against vA/vB, then "dstType" is stored into vA.
2011 */
2012static void checkBinop2addr(RegType* insnRegs, const int insnRegCount,
2013 DecodedInstruction* pDecInsn, RegType dstType, RegType srcType1,
Andy McFadden62a75162009-04-17 17:23:37 -07002014 RegType srcType2, bool checkBooleanOp, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002015{
Andy McFadden62a75162009-04-17 17:23:37 -07002016 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vA, srcType1,
2017 pFailure);
2018 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType2,
2019 pFailure);
2020 if (VERIFY_OK(*pFailure) && checkBooleanOp) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002021 assert(dstType == kRegTypeInteger);
2022 if (upcastBooleanOp(insnRegs, insnRegCount, pDecInsn->vA, pDecInsn->vB))
2023 dstType = kRegTypeBoolean;
2024 }
Andy McFadden62a75162009-04-17 17:23:37 -07002025 setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002026}
2027
2028
2029/*
2030 * ===========================================================================
2031 * Register merge
2032 * ===========================================================================
2033 */
2034
2035/*
2036 * Compute the "class depth" of a class. This is the distance from the
2037 * class to the top of the tree, chasing superclass links. java.lang.Object
2038 * has a class depth of 0.
2039 */
2040static int getClassDepth(ClassObject* clazz)
2041{
2042 int depth = 0;
2043
2044 while (clazz->super != NULL) {
2045 clazz = clazz->super;
2046 depth++;
2047 }
2048 return depth;
2049}
2050
2051/*
2052 * Given two classes, walk up the superclass tree to find a common
2053 * ancestor. (Called from findCommonSuperclass().)
2054 *
2055 * TODO: consider caching the class depth in the class object so we don't
2056 * have to search for it here.
2057 */
2058static ClassObject* digForSuperclass(ClassObject* c1, ClassObject* c2)
2059{
2060 int depth1, depth2;
2061
2062 depth1 = getClassDepth(c1);
2063 depth2 = getClassDepth(c2);
2064
2065 if (gDebugVerbose) {
2066 LOGVV("COMMON: %s(%d) + %s(%d)\n",
2067 c1->descriptor, depth1, c2->descriptor, depth2);
2068 }
2069
2070 /* pull the deepest one up */
2071 if (depth1 > depth2) {
2072 while (depth1 > depth2) {
2073 c1 = c1->super;
2074 depth1--;
2075 }
2076 } else {
2077 while (depth2 > depth1) {
2078 c2 = c2->super;
2079 depth2--;
2080 }
2081 }
2082
2083 /* walk up in lock-step */
2084 while (c1 != c2) {
2085 c1 = c1->super;
2086 c2 = c2->super;
2087
2088 assert(c1 != NULL && c2 != NULL);
2089 }
2090
2091 if (gDebugVerbose) {
2092 LOGVV(" : --> %s\n", c1->descriptor);
2093 }
2094 return c1;
2095}
2096
2097/*
2098 * Merge two array classes. We can't use the general "walk up to the
2099 * superclass" merge because the superclass of an array is always Object.
2100 * We want String[] + Integer[] = Object[]. This works for higher dimensions
2101 * as well, e.g. String[][] + Integer[][] = Object[][].
2102 *
2103 * If Foo1 and Foo2 are subclasses of Foo, Foo1[] + Foo2[] = Foo[].
2104 *
2105 * If Class implements Type, Class[] + Type[] = Type[].
2106 *
2107 * If the dimensions don't match, we want to convert to an array of Object
2108 * with the least dimension, e.g. String[][] + String[][][][] = Object[][].
2109 *
2110 * This gets a little awkward because we may have to ask the VM to create
2111 * a new array type with the appropriate element and dimensions. However, we
2112 * shouldn't be doing this often.
2113 */
2114static ClassObject* findCommonArraySuperclass(ClassObject* c1, ClassObject* c2)
2115{
2116 ClassObject* arrayClass = NULL;
2117 ClassObject* commonElem;
2118 int i, numDims;
2119
2120 assert(c1->arrayDim > 0);
2121 assert(c2->arrayDim > 0);
2122
2123 if (c1->arrayDim == c2->arrayDim) {
2124 //commonElem = digForSuperclass(c1->elementClass, c2->elementClass);
2125 commonElem = findCommonSuperclass(c1->elementClass, c2->elementClass);
2126 numDims = c1->arrayDim;
2127 } else {
2128 if (c1->arrayDim < c2->arrayDim)
2129 numDims = c1->arrayDim;
2130 else
2131 numDims = c2->arrayDim;
2132 commonElem = c1->super; // == java.lang.Object
2133 }
2134
2135 /* walk from the element to the (multi-)dimensioned array type */
2136 for (i = 0; i < numDims; i++) {
2137 arrayClass = dvmFindArrayClassForElement(commonElem);
2138 commonElem = arrayClass;
2139 }
2140
2141 LOGVV("ArrayMerge '%s' + '%s' --> '%s'\n",
2142 c1->descriptor, c2->descriptor, arrayClass->descriptor);
2143 return arrayClass;
2144}
2145
2146/*
2147 * Find the first common superclass of the two classes. We're not
2148 * interested in common interfaces.
2149 *
2150 * The easiest way to do this for concrete classes is to compute the "class
2151 * depth" of each, move up toward the root of the deepest one until they're
2152 * at the same depth, then walk both up to the root until they match.
2153 *
2154 * If both classes are arrays of non-primitive types, we need to merge
2155 * based on array depth and element type.
2156 *
2157 * If one class is an interface, we check to see if the other class/interface
2158 * (or one of its predecessors) implements the interface. If so, we return
2159 * the interface; otherwise, we return Object.
2160 *
2161 * NOTE: we continue the tradition of "lazy interface handling". To wit,
2162 * suppose we have three classes:
2163 * One implements Fancy, Free
2164 * Two implements Fancy, Free
2165 * Three implements Free
2166 * where Fancy and Free are unrelated interfaces. The code requires us
2167 * to merge One into Two. Ideally we'd use a common interface, which
2168 * gives us a choice between Fancy and Free, and no guidance on which to
2169 * use. If we use Free, we'll be okay when Three gets merged in, but if
2170 * we choose Fancy, we're hosed. The "ideal" solution is to create a
2171 * set of common interfaces and carry that around, merging further references
2172 * into it. This is a pain. The easy solution is to simply boil them
2173 * down to Objects and let the runtime invokeinterface call fail, which
2174 * is what we do.
2175 */
2176static ClassObject* findCommonSuperclass(ClassObject* c1, ClassObject* c2)
2177{
2178 assert(!dvmIsPrimitiveClass(c1) && !dvmIsPrimitiveClass(c2));
2179
2180 if (c1 == c2)
2181 return c1;
2182
2183 if (dvmIsInterfaceClass(c1) && dvmImplements(c2, c1)) {
2184 if (gDebugVerbose)
2185 LOGVV("COMMON/I1: %s + %s --> %s\n",
2186 c1->descriptor, c2->descriptor, c1->descriptor);
2187 return c1;
2188 }
2189 if (dvmIsInterfaceClass(c2) && dvmImplements(c1, c2)) {
2190 if (gDebugVerbose)
2191 LOGVV("COMMON/I2: %s + %s --> %s\n",
2192 c1->descriptor, c2->descriptor, c2->descriptor);
2193 return c2;
2194 }
2195
2196 if (dvmIsArrayClass(c1) && dvmIsArrayClass(c2) &&
2197 !dvmIsPrimitiveClass(c1->elementClass) &&
2198 !dvmIsPrimitiveClass(c2->elementClass))
2199 {
2200 return findCommonArraySuperclass(c1, c2);
2201 }
2202
2203 return digForSuperclass(c1, c2);
2204}
2205
2206/*
2207 * Merge two RegType values.
2208 *
2209 * Sets "*pChanged" to "true" if the result doesn't match "type1".
2210 */
2211static RegType mergeTypes(RegType type1, RegType type2, bool* pChanged)
2212{
2213 RegType result;
2214
2215 /*
2216 * Check for trivial case so we don't have to hit memory.
2217 */
2218 if (type1 == type2)
2219 return type1;
2220
2221 /*
2222 * Use the table if we can, and reject any attempts to merge something
2223 * from the table with a reference type.
2224 *
2225 * The uninitialized table entry at index zero *will* show up as a
2226 * simple kRegTypeUninit value. Since this cannot be merged with
2227 * anything but itself, the rules do the right thing.
2228 */
2229 if (type1 < kRegTypeMAX) {
2230 if (type2 < kRegTypeMAX) {
2231 result = gDvmMergeTab[type1][type2];
2232 } else {
2233 /* simple + reference == conflict, usually */
2234 if (type1 == kRegTypeZero)
2235 result = type2;
2236 else
2237 result = kRegTypeConflict;
2238 }
2239 } else {
2240 if (type2 < kRegTypeMAX) {
2241 /* reference + simple == conflict, usually */
2242 if (type2 == kRegTypeZero)
2243 result = type1;
2244 else
2245 result = kRegTypeConflict;
2246 } else {
2247 /* merging two references */
2248 if (regTypeIsUninitReference(type1) ||
2249 regTypeIsUninitReference(type2))
2250 {
2251 /* can't merge uninit with anything but self */
2252 result = kRegTypeConflict;
2253 } else {
2254 ClassObject* clazz1 = regTypeInitializedReferenceToClass(type1);
2255 ClassObject* clazz2 = regTypeInitializedReferenceToClass(type2);
2256 ClassObject* mergedClass;
2257
2258 mergedClass = findCommonSuperclass(clazz1, clazz2);
2259 assert(mergedClass != NULL);
2260 result = regTypeFromClass(mergedClass);
2261 }
2262 }
2263 }
2264
2265 if (result != type1)
2266 *pChanged = true;
2267 return result;
2268}
2269
2270/*
2271 * Control can transfer to "nextInsn".
2272 *
2273 * Merge the registers from "workRegs" into "regTypes" at "nextInsn", and
2274 * set the "changed" flag on the target address if the registers have changed.
2275 */
2276static void updateRegisters(const Method* meth, InsnFlags* insnFlags,
2277 RegisterTable* regTable, int nextInsn, const RegType* workRegs)
2278{
2279 RegType* targetRegs = getRegisterLine(regTable, nextInsn);
2280 const int insnRegCount = meth->registersSize;
2281
2282#if 0
2283 if (!dvmInsnIsBranchTarget(insnFlags, nextInsn)) {
2284 LOGE("insnFlags[0x%x]=0x%08x\n", nextInsn, insnFlags[nextInsn]);
2285 LOGE(" In %s.%s %s\n",
2286 meth->clazz->descriptor, meth->name, meth->descriptor);
2287 assert(false);
2288 }
2289#endif
2290
2291 if (!dvmInsnIsVisitedOrChanged(insnFlags, nextInsn)) {
2292 /*
2293 * We haven't processed this instruction before, and we haven't
2294 * touched the registers here, so there's nothing to "merge". Copy
2295 * the registers over and mark it as changed. (This is the only
2296 * way a register can transition out of "unknown", so this is not
2297 * just an optimization.)
2298 */
2299 LOGVV("COPY into 0x%04x\n", nextInsn);
2300 copyRegisters(targetRegs, workRegs, insnRegCount + kExtraRegs);
2301 dvmInsnSetChanged(insnFlags, nextInsn, true);
2302 } else {
2303 if (gDebugVerbose) {
2304 LOGVV("MERGE into 0x%04x\n", nextInsn);
2305 //dumpRegTypes(meth, insnFlags, targetRegs, 0, "targ", NULL, 0);
2306 //dumpRegTypes(meth, insnFlags, workRegs, 0, "work", NULL, 0);
2307 }
2308 /* merge registers, set Changed only if different */
2309 bool changed = false;
2310 int i;
2311
2312 for (i = 0; i < insnRegCount + kExtraRegs; i++) {
2313 targetRegs[i] = mergeTypes(targetRegs[i], workRegs[i], &changed);
2314 }
2315
2316 if (gDebugVerbose) {
2317 //LOGI(" RESULT (changed=%d)\n", changed);
2318 //dumpRegTypes(meth, insnFlags, targetRegs, 0, "rslt", NULL, 0);
2319 }
2320
2321 if (changed)
2322 dvmInsnSetChanged(insnFlags, nextInsn, true);
2323 }
2324}
2325
2326
2327/*
2328 * ===========================================================================
2329 * Utility functions
2330 * ===========================================================================
2331 */
2332
2333/*
2334 * Look up an instance field, specified by "fieldIdx", that is going to be
2335 * accessed in object "objType". This resolves the field and then verifies
2336 * that the class containing the field is an instance of the reference in
2337 * "objType".
2338 *
2339 * It is possible for "objType" to be kRegTypeZero, meaning that we might
2340 * have a null reference. This is a runtime problem, so we allow it,
2341 * skipping some of the type checks.
2342 *
2343 * In general, "objType" must be an initialized reference. However, we
2344 * allow it to be uninitialized if this is an "<init>" method and the field
2345 * is declared within the "objType" class.
2346 *
Andy McFadden62a75162009-04-17 17:23:37 -07002347 * Returns an InstField on success, returns NULL and sets "*pFailure"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002348 * on failure.
2349 */
2350static InstField* getInstField(const Method* meth,
2351 const UninitInstanceMap* uninitMap, RegType objType, int fieldIdx,
Andy McFadden62a75162009-04-17 17:23:37 -07002352 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002353{
2354 InstField* instField = NULL;
2355 ClassObject* objClass;
2356 bool mustBeLocal = false;
2357
2358 if (!regTypeIsReference(objType)) {
Andy McFadden62a75162009-04-17 17:23:37 -07002359 LOG_VFY("VFY: attempt to access field in non-reference type %d\n",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002360 objType);
Andy McFadden62a75162009-04-17 17:23:37 -07002361 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002362 goto bail;
2363 }
2364
Andy McFadden62a75162009-04-17 17:23:37 -07002365 instField = dvmOptResolveInstField(meth->clazz, fieldIdx, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002366 if (instField == NULL) {
2367 LOG_VFY("VFY: unable to resolve instance field %u\n", fieldIdx);
Andy McFadden62a75162009-04-17 17:23:37 -07002368 assert(!VERIFY_OK(*pFailure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002369 goto bail;
2370 }
2371
2372 if (objType == kRegTypeZero)
2373 goto bail;
2374
2375 /*
2376 * Access to fields in uninitialized objects is allowed if this is
2377 * the <init> method for the object and the field in question is
2378 * declared by this class.
2379 */
2380 objClass = regTypeReferenceToClass(objType, uninitMap);
2381 assert(objClass != NULL);
2382 if (regTypeIsUninitReference(objType)) {
2383 if (!isInitMethod(meth) || meth->clazz != objClass) {
2384 LOG_VFY("VFY: attempt to access field via uninitialized ref\n");
Andy McFadden62a75162009-04-17 17:23:37 -07002385 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002386 goto bail;
2387 }
2388 mustBeLocal = true;
2389 }
2390
2391 if (!dvmInstanceof(objClass, instField->field.clazz)) {
2392 LOG_VFY("VFY: invalid field access (field %s.%s, through %s ref)\n",
2393 instField->field.clazz->descriptor, instField->field.name,
2394 objClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07002395 *pFailure = VERIFY_ERROR_NO_FIELD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002396 goto bail;
2397 }
2398
2399 if (mustBeLocal) {
2400 /* for uninit ref, make sure it's defined by this class, not super */
2401 if (instField < objClass->ifields ||
2402 instField >= objClass->ifields + objClass->ifieldCount)
2403 {
2404 LOG_VFY("VFY: invalid constructor field access (field %s in %s)\n",
2405 instField->field.name, objClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07002406 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002407 goto bail;
2408 }
2409 }
2410
2411bail:
2412 return instField;
2413}
2414
2415/*
2416 * Look up a static field.
2417 *
Andy McFadden62a75162009-04-17 17:23:37 -07002418 * Returns a StaticField on success, returns NULL and sets "*pFailure"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002419 * on failure.
2420 */
2421static StaticField* getStaticField(const Method* meth, int fieldIdx,
Andy McFadden62a75162009-04-17 17:23:37 -07002422 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002423{
2424 StaticField* staticField;
2425
Andy McFadden62a75162009-04-17 17:23:37 -07002426 staticField = dvmOptResolveStaticField(meth->clazz, fieldIdx, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002427 if (staticField == NULL) {
2428 DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
2429 const DexFieldId* pFieldId;
2430
2431 pFieldId = dexGetFieldId(pDexFile, fieldIdx);
2432
2433 LOG_VFY("VFY: unable to resolve static field %u (%s) in %s\n", fieldIdx,
2434 dexStringById(pDexFile, pFieldId->nameIdx),
2435 dexStringByTypeIdx(pDexFile, pFieldId->classIdx));
Andy McFadden62a75162009-04-17 17:23:37 -07002436 assert(!VERIFY_OK(*pFailure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002437 goto bail;
2438 }
2439
2440bail:
2441 return staticField;
2442}
2443
2444/*
2445 * If "field" is marked "final", make sure this is the either <clinit>
2446 * or <init> as appropriate.
2447 *
Andy McFadden62a75162009-04-17 17:23:37 -07002448 * Sets "*pFailure" on failure.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002449 */
2450static void checkFinalFieldAccess(const Method* meth, const Field* field,
Andy McFadden62a75162009-04-17 17:23:37 -07002451 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002452{
2453 if (!dvmIsFinalField(field))
2454 return;
2455
2456 /* make sure we're in the same class */
2457 if (meth->clazz != field->clazz) {
2458 LOG_VFY_METH(meth, "VFY: can't modify final field %s.%s\n",
2459 field->clazz->descriptor, field->name);
Andy McFadden62a75162009-04-17 17:23:37 -07002460 *pFailure = VERIFY_ERROR_ACCESS;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002461 return;
2462 }
2463
2464 /*
Andy McFadden62a75162009-04-17 17:23:37 -07002465 * The VM spec descriptions of putfield and putstatic say that
2466 * IllegalAccessError is only thrown when the instructions appear
2467 * outside the declaring class. Our earlier attempts to restrict
2468 * final field modification to constructors are, therefore, wrong.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002469 */
2470#if 0
2471 /* make sure we're in the right kind of constructor */
2472 if (dvmIsStaticField(field)) {
2473 if (!isClassInitMethod(meth)) {
2474 LOG_VFY_METH(meth,
2475 "VFY: can't modify final static field outside <clinit>\n");
Andy McFadden62a75162009-04-17 17:23:37 -07002476 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002477 }
2478 } else {
2479 if (!isInitMethod(meth)) {
2480 LOG_VFY_METH(meth,
2481 "VFY: can't modify final field outside <init>\n");
Andy McFadden62a75162009-04-17 17:23:37 -07002482 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002483 }
2484 }
2485#endif
2486}
2487
2488/*
2489 * Make sure that the register type is suitable for use as an array index.
2490 *
Andy McFadden62a75162009-04-17 17:23:37 -07002491 * Sets "*pFailure" if not.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002492 */
2493static void checkArrayIndexType(const Method* meth, RegType regType,
Andy McFadden62a75162009-04-17 17:23:37 -07002494 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002495{
Andy McFadden62a75162009-04-17 17:23:37 -07002496 if (VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002497 /*
2498 * The 1nr types are interchangeable at this level. We could
2499 * do something special if we can definitively identify it as a
2500 * float, but there's no real value in doing so.
2501 */
Andy McFadden62a75162009-04-17 17:23:37 -07002502 checkTypeCategory(regType, kTypeCategory1nr, pFailure);
2503 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002504 LOG_VFY_METH(meth, "Invalid reg type for array index (%d)\n",
2505 regType);
2506 }
2507 }
2508}
2509
2510/*
2511 * Check constraints on constructor return. Specifically, make sure that
2512 * the "this" argument got initialized.
2513 *
2514 * The "this" argument to <init> uses code offset kUninitThisArgAddr, which
2515 * puts it at the start of the list in slot 0. If we see a register with
2516 * an uninitialized slot 0 reference, we know it somehow didn't get
2517 * initialized.
2518 *
2519 * Returns "true" if all is well.
2520 */
2521static bool checkConstructorReturn(const Method* meth, const RegType* insnRegs,
2522 const int insnRegCount)
2523{
2524 int i;
2525
2526 if (!isInitMethod(meth))
2527 return true;
2528
2529 RegType uninitThis = regTypeFromUninitIndex(kUninitThisArgSlot);
2530
2531 for (i = 0; i < insnRegCount; i++) {
2532 if (insnRegs[i] == uninitThis) {
2533 LOG_VFY("VFY: <init> returning without calling superclass init\n");
2534 return false;
2535 }
2536 }
2537 return true;
2538}
2539
2540/*
2541 * Verify that the target instruction is not "move-exception". It's important
2542 * that the only way to execute a move-exception is as the first instruction
2543 * of an exception handler.
2544 *
2545 * Returns "true" if all is well, "false" if the target instruction is
2546 * move-exception.
2547 */
2548static bool checkMoveException(const Method* meth, int insnIdx,
2549 const char* logNote)
2550{
2551 assert(insnIdx >= 0 && insnIdx < (int)dvmGetMethodInsnsSize(meth));
2552
2553 if ((meth->insns[insnIdx] & 0xff) == OP_MOVE_EXCEPTION) {
2554 LOG_VFY("VFY: invalid use of move-exception\n");
2555 return false;
2556 }
2557 return true;
2558}
2559
2560/*
2561 * For the "move-exception" instruction at "insnIdx", which must be at an
2562 * exception handler address, determine the first common superclass of
2563 * all exceptions that can land here. (For javac output, we're probably
2564 * looking at multiple spans of bytecode covered by one "try" that lands
2565 * at an exception-specific "catch", but in general the handler could be
2566 * shared for multiple exceptions.)
2567 *
2568 * Returns NULL if no matching exception handler can be found, or if the
2569 * exception is not a subclass of Throwable.
2570 */
Andy McFadden62a75162009-04-17 17:23:37 -07002571static ClassObject* getCaughtExceptionType(const Method* meth, int insnIdx,
2572 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002573{
Andy McFadden62a75162009-04-17 17:23:37 -07002574 VerifyError localFailure;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002575 const DexCode* pCode;
2576 DexFile* pDexFile;
2577 ClassObject* commonSuper = NULL;
Andy McFadden62a75162009-04-17 17:23:37 -07002578 bool foundPossibleHandler = false;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002579 u4 handlersSize;
2580 u4 offset;
2581 u4 i;
2582
2583 pDexFile = meth->clazz->pDvmDex->pDexFile;
2584 pCode = dvmGetMethodCode(meth);
2585
2586 if (pCode->triesSize != 0) {
2587 handlersSize = dexGetHandlersSize(pCode);
2588 offset = dexGetFirstHandlerOffset(pCode);
2589 } else {
2590 handlersSize = 0;
2591 offset = 0;
2592 }
2593
2594 for (i = 0; i < handlersSize; i++) {
2595 DexCatchIterator iterator;
2596 dexCatchIteratorInit(&iterator, pCode, offset);
2597
2598 for (;;) {
2599 const DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
2600
2601 if (handler == NULL) {
2602 break;
2603 }
2604
2605 if (handler->address == (u4) insnIdx) {
2606 ClassObject* clazz;
Andy McFadden62a75162009-04-17 17:23:37 -07002607 foundPossibleHandler = true;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002608
2609 if (handler->typeIdx == kDexNoIndex)
2610 clazz = gDvm.classJavaLangThrowable;
2611 else
Andy McFadden62a75162009-04-17 17:23:37 -07002612 clazz = dvmOptResolveClass(meth->clazz, handler->typeIdx,
2613 &localFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002614
2615 if (clazz == NULL) {
2616 LOG_VFY("VFY: unable to resolve exception class %u (%s)\n",
2617 handler->typeIdx,
2618 dexStringByTypeIdx(pDexFile, handler->typeIdx));
Andy McFadden62a75162009-04-17 17:23:37 -07002619 /* TODO: do we want to keep going? If we don't fail
2620 * this we run the risk of having a non-Throwable
2621 * introduced at runtime. However, that won't pass
2622 * an instanceof test, so is essentially harmless. */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002623 } else {
2624 if (commonSuper == NULL)
2625 commonSuper = clazz;
2626 else
2627 commonSuper = findCommonSuperclass(clazz, commonSuper);
2628 }
2629 }
2630 }
2631
2632 offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
2633 }
2634
2635 if (commonSuper == NULL) {
Andy McFadden62a75162009-04-17 17:23:37 -07002636 /* no catch blocks, or no catches with classes we can find */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002637 LOG_VFY_METH(meth,
2638 "VFY: unable to find exception handler at addr 0x%x\n", insnIdx);
Andy McFadden62a75162009-04-17 17:23:37 -07002639 *pFailure = VERIFY_ERROR_GENERIC;
2640 } else {
2641 // TODO: verify the class is an instance of Throwable?
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002642 }
2643
2644 return commonSuper;
2645}
2646
2647/*
2648 * Initialize the RegisterTable.
2649 *
2650 * Every instruction address can have a different set of information about
2651 * what's in which register, but for verification purposes we only need to
2652 * store it at branch target addresses (because we merge into that).
2653 *
2654 * By zeroing out the storage we are effectively initializing the register
2655 * information to kRegTypeUnknown.
2656 */
2657static bool initRegisterTable(const Method* meth, const InsnFlags* insnFlags,
2658 RegisterTable* regTable, RegisterTrackingMode trackRegsFor)
2659{
2660 const int insnsSize = dvmGetMethodInsnsSize(meth);
2661 int i;
2662
2663 regTable->insnRegCountPlus = meth->registersSize + kExtraRegs;
2664 regTable->addrRegs = (RegType**) calloc(insnsSize, sizeof(RegType*));
2665 if (regTable->addrRegs == NULL)
2666 return false;
2667
2668 assert(insnsSize > 0);
2669
2670 /*
2671 * "All" means "every address that holds the start of an instruction".
2672 * "Branches" and "GcPoints" mean just those addresses.
2673 *
2674 * "GcPoints" fills about half the addresses, "Branches" about 15%.
2675 */
2676 int interestingCount = 0;
2677 //int insnCount = 0;
2678
2679 for (i = 0; i < insnsSize; i++) {
2680 bool interesting;
2681
2682 switch (trackRegsFor) {
2683 case kTrackRegsAll:
2684 interesting = dvmInsnIsOpcode(insnFlags, i);
2685 break;
2686 case kTrackRegsGcPoints:
2687 interesting = dvmInsnIsGcPoint(insnFlags, i) ||
2688 dvmInsnIsBranchTarget(insnFlags, i);
2689 break;
2690 case kTrackRegsBranches:
2691 interesting = dvmInsnIsBranchTarget(insnFlags, i);
2692 break;
2693 default:
2694 dvmAbort();
2695 return false;
2696 }
2697
2698 if (interesting)
2699 interestingCount++;
2700
2701 /* count instructions, for display only */
2702 //if (dvmInsnIsOpcode(insnFlags, i))
2703 // insnCount++;
2704 }
2705
2706 regTable->regAlloc = (RegType*)
2707 calloc(regTable->insnRegCountPlus * interestingCount, sizeof(RegType));
2708 if (regTable->regAlloc == NULL)
2709 return false;
2710
2711 RegType* regPtr = regTable->regAlloc;
2712 for (i = 0; i < insnsSize; i++) {
2713 bool interesting;
2714
2715 switch (trackRegsFor) {
2716 case kTrackRegsAll:
2717 interesting = dvmInsnIsOpcode(insnFlags, i);
2718 break;
2719 case kTrackRegsGcPoints:
2720 interesting = dvmInsnIsGcPoint(insnFlags, i) ||
2721 dvmInsnIsBranchTarget(insnFlags, i);
2722 break;
2723 case kTrackRegsBranches:
2724 interesting = dvmInsnIsBranchTarget(insnFlags, i);
2725 break;
2726 default:
2727 dvmAbort();
2728 return false;
2729 }
2730
2731 if (interesting) {
2732 regTable->addrRegs[i] = regPtr;
2733 regPtr += regTable->insnRegCountPlus;
2734 }
2735 }
2736
2737 //LOGD("Tracking registers for %d, total %d of %d(%d) (%d%%)\n",
2738 // TRACK_REGS_FOR, interestingCount, insnCount, insnsSize,
2739 // (interestingCount*100) / insnCount);
2740
2741 assert(regPtr - regTable->regAlloc ==
2742 regTable->insnRegCountPlus * interestingCount);
2743 assert(regTable->addrRegs[0] != NULL);
2744 return true;
2745}
2746
2747
2748/*
2749 * Verify that the arguments in a filled-new-array instruction are valid.
2750 *
2751 * "resClass" is the class refered to by pDecInsn->vB.
2752 */
2753static void verifyFilledNewArrayRegs(const Method* meth,
2754 const RegType* insnRegs, const int insnRegCount,
2755 const DecodedInstruction* pDecInsn, ClassObject* resClass, bool isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07002756 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002757{
2758 u4 argCount = pDecInsn->vA;
2759 RegType expectedType;
2760 PrimitiveType elemType;
2761 unsigned int ui;
2762
2763 assert(dvmIsArrayClass(resClass));
2764 elemType = resClass->elementClass->primitiveType;
2765 if (elemType == PRIM_NOT) {
2766 expectedType = regTypeFromClass(resClass->elementClass);
2767 } else {
2768 expectedType = primitiveTypeToRegType(elemType);
2769 }
2770 //LOGI("filled-new-array: %s -> %d\n", resClass->descriptor, expectedType);
2771
2772 /*
2773 * Verify each register. If "argCount" is bad, verifyRegisterType()
2774 * will run off the end of the list and fail. It's legal, if silly,
2775 * for argCount to be zero.
2776 */
2777 for (ui = 0; ui < argCount; ui++) {
2778 u4 getReg;
2779
2780 if (isRange)
2781 getReg = pDecInsn->vC + ui;
2782 else
2783 getReg = pDecInsn->arg[ui];
2784
Andy McFadden62a75162009-04-17 17:23:37 -07002785 verifyRegisterType(insnRegs, insnRegCount, getReg, expectedType,
2786 pFailure);
2787 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002788 LOG_VFY("VFY: filled-new-array arg %u(%u) not valid\n", ui, getReg);
2789 return;
2790 }
2791 }
2792}
2793
2794
2795/*
2796 * ===========================================================================
2797 * Entry point and driver loop
2798 * ===========================================================================
2799 */
2800
2801/*
2802 * Entry point for the detailed code-flow analysis.
2803 */
2804bool dvmVerifyCodeFlow(const Method* meth, InsnFlags* insnFlags,
2805 UninitInstanceMap* uninitMap)
2806{
2807 bool result = false;
2808 const int insnsSize = dvmGetMethodInsnsSize(meth);
2809 const u2* insns = meth->insns;
2810 const bool generateRegisterMap = gDvm.generateRegisterMaps;
2811 int i, offset;
2812 bool isConditional;
2813 RegisterTable regTable;
2814
2815 memset(&regTable, 0, sizeof(regTable));
2816
2817#ifndef NDEBUG
2818 checkMergeTab(); // only need to do this if table gets updated
2819#endif
2820
2821 /*
2822 * We rely on these for verification of const-class, const-string,
2823 * and throw instructions. Make sure we have them.
2824 */
2825 if (gDvm.classJavaLangClass == NULL)
2826 gDvm.classJavaLangClass =
2827 dvmFindSystemClassNoInit("Ljava/lang/Class;");
2828 if (gDvm.classJavaLangString == NULL)
2829 gDvm.classJavaLangString =
2830 dvmFindSystemClassNoInit("Ljava/lang/String;");
2831 if (gDvm.classJavaLangThrowable == NULL)
2832 gDvm.classJavaLangThrowable =
2833 dvmFindSystemClassNoInit("Ljava/lang/Throwable;");
2834 if (gDvm.classJavaLangObject == NULL)
2835 gDvm.classJavaLangObject =
2836 dvmFindSystemClassNoInit("Ljava/lang/Object;");
2837
2838 if (meth->registersSize * insnsSize > 2*1024*1024) {
2839 /* should probably base this on actual memory requirements */
2840 LOG_VFY_METH(meth,
2841 "VFY: arbitrarily rejecting large method (regs=%d count=%d)\n",
2842 meth->registersSize, insnsSize);
2843 goto bail;
2844 }
2845
2846 /*
2847 * Create register lists, and initialize them to "Unknown". If we're
2848 * also going to create the register map, we need to retain the
2849 * register lists for a larger set of addresses.
2850 */
2851 if (!initRegisterTable(meth, insnFlags, &regTable,
2852 generateRegisterMap ? kTrackRegsGcPoints : kTrackRegsBranches))
2853 goto bail;
2854
2855 /*
2856 * Initialize the types of the registers that correspond to the
2857 * method arguments. We can determine this from the method signature.
2858 */
2859 if (!setTypesFromSignature(meth, regTable.addrRegs[0], uninitMap))
2860 goto bail;
2861
2862 /*
2863 * Run the verifier.
2864 */
2865 if (!doCodeVerification(meth, insnFlags, &regTable, uninitMap))
2866 goto bail;
2867
2868 /*
2869 * Generate a register map.
2870 */
2871 if (generateRegisterMap) {
2872 RegisterMap* pMap;
2873 VerifierData vd;
2874
2875 vd.method = meth;
2876 vd.insnsSize = insnsSize;
2877 vd.insnRegCount = meth->registersSize;
2878 vd.insnFlags = insnFlags;
2879 vd.addrRegs = regTable.addrRegs;
2880
2881 pMap = dvmGenerateRegisterMapV(&vd);
2882 if (pMap != NULL) {
2883 /*
2884 * Tuck it into the Method struct. It will either get used
2885 * directly or, if we're in dexopt, will be packed up and
2886 * appended to the DEX file.
2887 */
2888 dvmSetRegisterMap((Method*)meth, pMap);
2889 }
2890 }
2891
2892 /*
2893 * Success.
2894 */
2895 result = true;
2896
2897bail:
2898 free(regTable.addrRegs);
2899 free(regTable.regAlloc);
2900 return result;
2901}
2902
2903/*
2904 * Grind through the instructions.
2905 *
2906 * The basic strategy is as outlined in v3 4.11.1.2: set the "changed" bit
2907 * on the first instruction, process it (setting additional "changed" bits),
2908 * and repeat until there are no more.
2909 *
2910 * v3 4.11.1.1
2911 * - (N/A) operand stack is always the same size
2912 * - operand stack [registers] contain the correct types of values
2913 * - local variables [registers] contain the correct types of values
2914 * - methods are invoked with the appropriate arguments
2915 * - fields are assigned using values of appropriate types
2916 * - opcodes have the correct type values in operand registers
2917 * - there is never an uninitialized class instance in a local variable in
2918 * code protected by an exception handler (operand stack is okay, because
2919 * the operand stack is discarded when an exception is thrown) [can't
2920 * know what's a local var w/o the debug info -- should fall out of
2921 * register typing]
2922 *
2923 * v3 4.11.1.2
2924 * - execution cannot fall off the end of the code
2925 *
2926 * (We also do many of the items described in the "static checks" sections,
2927 * because it's easier to do them here.)
2928 *
2929 * We need an array of RegType values, one per register, for every
2930 * instruction. In theory this could become quite large -- up to several
2931 * megabytes for a monster function. For self-preservation we reject
2932 * anything that requires more than a certain amount of memory. (Typical
2933 * "large" should be on the order of 4K code units * 8 registers.) This
2934 * will likely have to be adjusted.
2935 *
2936 *
2937 * The spec forbids backward branches when there's an uninitialized reference
2938 * in a register. The idea is to prevent something like this:
2939 * loop:
2940 * move r1, r0
2941 * new-instance r0, MyClass
2942 * ...
2943 * if-eq rN, loop // once
2944 * initialize r0
2945 *
2946 * This leaves us with two different instances, both allocated by the
2947 * same instruction, but only one is initialized. The scheme outlined in
2948 * v3 4.11.1.4 wouldn't catch this, so they work around it by preventing
2949 * backward branches. We achieve identical results without restricting
2950 * code reordering by specifying that you can't execute the new-instance
2951 * instruction if a register contains an uninitialized instance created
2952 * by that same instrutcion.
2953 */
2954static bool doCodeVerification(const Method* meth, InsnFlags* insnFlags,
2955 RegisterTable* regTable, UninitInstanceMap* uninitMap)
2956{
2957 const int insnsSize = dvmGetMethodInsnsSize(meth);
2958 const u2* insns = meth->insns;
2959 RegType workRegs[meth->registersSize + kExtraRegs];
2960 bool result = false;
2961 bool debugVerbose = false;
2962 int insnIdx, startGuess, prevAddr;
2963
2964 /*
2965 * Begin by marking the first instruction as "changed".
2966 */
2967 dvmInsnSetChanged(insnFlags, 0, true);
2968
2969 if (doVerboseLogging(meth)) {
2970 IF_LOGI() {
2971 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
2972 LOGI("Now verifying: %s.%s %s (ins=%d regs=%d)\n",
2973 meth->clazz->descriptor, meth->name, desc,
2974 meth->insSize, meth->registersSize);
2975 LOGI(" ------ [0 4 8 12 16 20 24 28 32 36\n");
2976 free(desc);
2977 }
2978 debugVerbose = true;
2979 gDebugVerbose = true;
2980 } else {
2981 gDebugVerbose = false;
2982 }
2983
2984 startGuess = 0;
2985
2986 /*
2987 * Continue until no instructions are marked "changed".
2988 */
2989 while (true) {
2990 /*
2991 * Find the first marked one. Use "startGuess" as a way to find
2992 * one quickly.
2993 */
2994 for (insnIdx = startGuess; insnIdx < insnsSize; insnIdx++) {
2995 if (dvmInsnIsChanged(insnFlags, insnIdx))
2996 break;
2997 }
2998
2999 if (insnIdx == insnsSize) {
3000 if (startGuess != 0) {
3001 /* try again, starting from the top */
3002 startGuess = 0;
3003 continue;
3004 } else {
3005 /* all flags are clear */
3006 break;
3007 }
3008 }
3009
3010 /*
3011 * We carry the working set of registers from instruction to
3012 * instruction. If this address can be the target of a branch
3013 * (or throw) instruction, or if we're skipping around chasing
3014 * "changed" flags, we need to load the set of registers from
3015 * the table.
3016 *
3017 * Because we always prefer to continue on to the next instruction,
3018 * we should never have a situation where we have a stray
3019 * "changed" flag set on an instruction that isn't a branch target.
3020 */
3021 if (dvmInsnIsBranchTarget(insnFlags, insnIdx)) {
3022 RegType* insnRegs = getRegisterLine(regTable, insnIdx);
3023 assert(insnRegs != NULL);
3024 copyRegisters(workRegs, insnRegs, meth->registersSize + kExtraRegs);
3025
3026 if (debugVerbose) {
3027 dumpRegTypes(meth, insnFlags, workRegs, insnIdx, NULL,uninitMap,
3028 SHOW_REG_DETAILS);
3029 }
3030
3031 } else {
3032 if (debugVerbose) {
3033 dumpRegTypes(meth, insnFlags, workRegs, insnIdx, NULL,uninitMap,
3034 SHOW_REG_DETAILS);
3035 }
3036
3037#ifndef NDEBUG
3038 /*
3039 * Sanity check: retrieve the stored register line (assuming
3040 * a full table) and make sure it actually matches.
3041 */
3042 RegType* insnRegs = getRegisterLine(regTable, insnIdx);
3043 if (insnRegs != NULL &&
3044 compareRegisters(workRegs, insnRegs,
3045 meth->registersSize + kExtraRegs) != 0)
3046 {
3047 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
3048 LOG_VFY("HUH? workRegs diverged in %s.%s %s\n",
3049 meth->clazz->descriptor, meth->name, desc);
3050 free(desc);
3051 dumpRegTypes(meth, insnFlags, workRegs, 0, "work",
3052 uninitMap, DRT_SHOW_REF_TYPES | DRT_SHOW_LOCALS);
3053 dumpRegTypes(meth, insnFlags, insnRegs, 0, "insn",
3054 uninitMap, DRT_SHOW_REF_TYPES | DRT_SHOW_LOCALS);
3055 }
3056#endif
3057 }
3058
3059 //LOGI("process %s.%s %s %d\n",
3060 // meth->clazz->descriptor, meth->name, meth->descriptor, insnIdx);
3061 if (!verifyInstruction(meth, insnFlags, regTable, workRegs, insnIdx,
3062 uninitMap, &startGuess))
3063 {
3064 //LOGD("+++ %s bailing at %d\n", meth->name, insnIdx);
3065 goto bail;
3066 }
3067
3068#if 0
3069 {
3070 static const int gcMask = kInstrCanBranch | kInstrCanSwitch |
3071 kInstrCanThrow | kInstrCanReturn;
3072 OpCode opCode = *(meth->insns + insnIdx) & 0xff;
3073 int flags = dexGetInstrFlags(gDvm.instrFlags, opCode);
3074
3075 /* 8, 16, 32, or 32*n -bit regs */
3076 int regWidth = (meth->registersSize + 7) / 8;
3077 if (regWidth == 3)
3078 regWidth = 4;
3079 if (regWidth > 4) {
3080 regWidth = ((regWidth + 3) / 4) * 4;
3081 if (false) {
3082 LOGW("WOW: %d regs -> %d %s.%s\n",
3083 meth->registersSize, regWidth,
3084 meth->clazz->descriptor, meth->name);
3085 //x = true;
3086 }
3087 }
3088
3089 if ((flags & gcMask) != 0) {
3090 /* this is a potential GC point */
3091 gDvm__gcInstr++;
3092
3093 if (insnsSize < 256)
3094 gDvm__gcData += 1;
3095 else
3096 gDvm__gcData += 2;
3097 gDvm__gcData += regWidth;
3098 }
3099 gDvm__gcSimpleData += regWidth;
3100
3101 gDvm__totalInstr++;
3102 }
3103#endif
3104
3105 /*
3106 * Clear "changed" and mark as visited.
3107 */
3108 dvmInsnSetVisited(insnFlags, insnIdx, true);
3109 dvmInsnSetChanged(insnFlags, insnIdx, false);
3110 }
3111
3112 if (DEAD_CODE_SCAN) {
3113 /*
3114 * Scan for dead code. There's nothing "evil" about dead code, but it
3115 * indicates a flaw somewhere down the line, possibly in the verifier.
3116 */
3117 int deadStart = -1;
3118 for (insnIdx = 0; insnIdx < insnsSize;
3119 insnIdx += dvmInsnGetWidth(insnFlags, insnIdx))
3120 {
3121 /*
3122 * Switch-statement data doesn't get "visited" by scanner. It
3123 * may or may not be preceded by a padding NOP.
3124 */
3125 int instr = meth->insns[insnIdx];
3126 if (instr == kPackedSwitchSignature ||
3127 instr == kSparseSwitchSignature ||
3128 instr == kArrayDataSignature ||
3129 (instr == OP_NOP &&
3130 (meth->insns[insnIdx+1] == kPackedSwitchSignature ||
3131 meth->insns[insnIdx+1] == kSparseSwitchSignature ||
3132 meth->insns[insnIdx+1] == kArrayDataSignature)))
3133 {
3134 dvmInsnSetVisited(insnFlags, insnIdx, true);
3135 }
3136
3137 if (!dvmInsnIsVisited(insnFlags, insnIdx)) {
3138 if (deadStart < 0)
3139 deadStart = insnIdx;
3140 } else if (deadStart >= 0) {
3141 IF_LOGD() {
3142 char* desc =
3143 dexProtoCopyMethodDescriptor(&meth->prototype);
3144 LOGD("VFY: dead code 0x%04x-%04x in %s.%s %s\n",
3145 deadStart, insnIdx-1,
3146 meth->clazz->descriptor, meth->name, desc);
3147 free(desc);
3148 }
3149
3150 deadStart = -1;
3151 }
3152 }
3153 if (deadStart >= 0) {
3154 IF_LOGD() {
3155 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
3156 LOGD("VFY: dead code 0x%04x-%04x in %s.%s %s\n",
3157 deadStart, insnIdx-1,
3158 meth->clazz->descriptor, meth->name, desc);
3159 free(desc);
3160 }
3161 }
3162 }
3163
3164 result = true;
3165
3166bail:
3167 return result;
3168}
3169
3170
3171/*
3172 * Perform verification for a single instruction.
3173 *
3174 * This requires fully decoding the instruction to determine the effect
3175 * it has on registers.
3176 *
3177 * Finds zero or more following instructions and sets the "changed" flag
3178 * if execution at that point needs to be (re-)evaluated. Register changes
3179 * are merged into "regTypes" at the target addresses. Does not set or
3180 * clear any other flags in "insnFlags".
3181 */
3182static bool verifyInstruction(const Method* meth, InsnFlags* insnFlags,
3183 RegisterTable* regTable, RegType* workRegs, int insnIdx,
3184 UninitInstanceMap* uninitMap, int* pStartGuess)
3185{
3186 const int insnsSize = dvmGetMethodInsnsSize(meth);
3187 const u2* insns = meth->insns + insnIdx;
3188 bool result = false;
3189
3190 /*
3191 * Once we finish decoding the instruction, we need to figure out where
3192 * we can go from here. There are three possible ways to transfer
3193 * control to another statement:
3194 *
3195 * (1) Continue to the next instruction. Applies to all but
3196 * unconditional branches, method returns, and exception throws.
3197 * (2) Branch to one or more possible locations. Applies to branches
3198 * and switch statements.
3199 * (3) Exception handlers. Applies to any instruction that can
3200 * throw an exception that is handled by an encompassing "try"
3201 * block. (We simplify this to be any instruction that can
3202 * throw any exception.)
3203 *
3204 * We can also return, in which case there is no successor instruction
3205 * from this point.
3206 *
3207 * The behavior can be determined from the InstrFlags.
3208 */
3209
3210 const DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
3211 RegType entryRegs[meth->registersSize + kExtraRegs];
3212 ClassObject* resClass;
3213 const char* className;
3214 int branchTarget = 0;
3215 const int insnRegCount = meth->registersSize;
3216 RegType tmpType;
3217 DecodedInstruction decInsn;
3218 bool justSetResult = false;
Andy McFadden62a75162009-04-17 17:23:37 -07003219 VerifyError failure = VERIFY_ERROR_NONE;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003220
3221#ifndef NDEBUG
3222 memset(&decInsn, 0x81, sizeof(decInsn));
3223#endif
3224 dexDecodeInstruction(gDvm.instrFormat, insns, &decInsn);
3225
3226 const int nextFlags = dexGetInstrFlags(gDvm.instrFlags, decInsn.opCode);
3227
3228 /*
3229 * Make a copy of the previous register state. If the instruction
3230 * throws an exception, we merge *this* into the destination rather
3231 * than workRegs, because we don't want the result from the "successful"
3232 * code path (e.g. a check-cast that "improves" a type) to be visible
3233 * to the exception handler.
3234 */
3235 if ((nextFlags & kInstrCanThrow) != 0 && dvmInsnIsInTry(insnFlags, insnIdx))
3236 {
3237 copyRegisters(entryRegs, workRegs, meth->registersSize + kExtraRegs);
3238 } else {
3239#ifndef NDEBUG
3240 memset(entryRegs, 0xdd,
3241 (meth->registersSize + kExtraRegs) * sizeof(RegType));
3242#endif
3243 }
3244
3245 switch (decInsn.opCode) {
3246 case OP_NOP:
3247 /*
3248 * A "pure" NOP has no effect on anything. Data tables start with
3249 * a signature that looks like a NOP; if we see one of these in
3250 * the course of executing code then we have a problem.
3251 */
3252 if (decInsn.vA != 0) {
3253 LOG_VFY("VFY: encountered data table in instruction stream\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003254 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003255 }
3256 break;
3257
3258 case OP_MOVE:
3259 case OP_MOVE_FROM16:
3260 case OP_MOVE_16:
3261 copyRegister1(workRegs, insnRegCount, decInsn.vA, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07003262 kTypeCategory1nr, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003263 break;
3264 case OP_MOVE_WIDE:
3265 case OP_MOVE_WIDE_FROM16:
3266 case OP_MOVE_WIDE_16:
Andy McFadden62a75162009-04-17 17:23:37 -07003267 copyRegister2(workRegs, insnRegCount, decInsn.vA, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003268 break;
3269 case OP_MOVE_OBJECT:
3270 case OP_MOVE_OBJECT_FROM16:
3271 case OP_MOVE_OBJECT_16:
3272 copyRegister1(workRegs, insnRegCount, decInsn.vA, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07003273 kTypeCategoryRef, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003274 break;
3275
3276 /*
3277 * The move-result instructions copy data out of a "pseudo-register"
3278 * with the results from the last method invocation. In practice we
3279 * might want to hold the result in an actual CPU register, so the
3280 * Dalvik spec requires that these only appear immediately after an
3281 * invoke or filled-new-array.
3282 *
3283 * These calls invalidate the "result" register. (This is now
3284 * redundant with the reset done below, but it can make the debug info
3285 * easier to read in some cases.)
3286 */
3287 case OP_MOVE_RESULT:
3288 copyResultRegister1(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003289 kTypeCategory1nr, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003290 break;
3291 case OP_MOVE_RESULT_WIDE:
Andy McFadden62a75162009-04-17 17:23:37 -07003292 copyResultRegister2(workRegs, insnRegCount, decInsn.vA, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003293 break;
3294 case OP_MOVE_RESULT_OBJECT:
3295 copyResultRegister1(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003296 kTypeCategoryRef, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003297 break;
3298
3299 case OP_MOVE_EXCEPTION:
3300 /*
3301 * This statement can only appear as the first instruction in an
3302 * exception handler (though not all exception handlers need to
3303 * have one of these). We verify that as part of extracting the
3304 * exception type from the catch block list.
3305 *
3306 * "resClass" will hold the closest common superclass of all
3307 * exceptions that can be handled here.
3308 */
Andy McFadden62a75162009-04-17 17:23:37 -07003309 resClass = getCaughtExceptionType(meth, insnIdx, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003310 if (resClass == NULL) {
Andy McFadden62a75162009-04-17 17:23:37 -07003311 assert(!VERIFY_OK(failure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003312 } else {
3313 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003314 regTypeFromClass(resClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003315 }
3316 break;
3317
3318 case OP_RETURN_VOID:
Andy McFadden62a75162009-04-17 17:23:37 -07003319 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3320 failure = VERIFY_ERROR_GENERIC;
3321 } else if (getMethodReturnType(meth) != kRegTypeUnknown) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003322 LOG_VFY("VFY: return-void not expected\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003323 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003324 }
3325 break;
3326 case OP_RETURN:
Andy McFadden62a75162009-04-17 17:23:37 -07003327 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3328 failure = VERIFY_ERROR_GENERIC;
3329 } else {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003330 /* check the method signature */
3331 RegType returnType = getMethodReturnType(meth);
Andy McFadden62a75162009-04-17 17:23:37 -07003332 checkTypeCategory(returnType, kTypeCategory1nr, &failure);
3333 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003334 LOG_VFY("VFY: return-32 not expected\n");
3335
3336 /* check the register contents */
3337 returnType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003338 &failure);
3339 checkTypeCategory(returnType, kTypeCategory1nr, &failure);
3340 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003341 LOG_VFY("VFY: return-32 on invalid register v%d\n", decInsn.vA);
3342 }
3343 break;
3344 case OP_RETURN_WIDE:
Andy McFadden62a75162009-04-17 17:23:37 -07003345 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3346 failure = VERIFY_ERROR_GENERIC;
3347 } else {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003348 RegType returnType, returnTypeHi;
3349
3350 /* check the method signature */
3351 returnType = getMethodReturnType(meth);
Andy McFadden62a75162009-04-17 17:23:37 -07003352 checkTypeCategory(returnType, kTypeCategory2, &failure);
3353 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003354 LOG_VFY("VFY: return-wide not expected\n");
3355
3356 /* check the register contents */
3357 returnType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003358 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003359 returnTypeHi = getRegisterType(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003360 decInsn.vA +1, &failure);
3361 if (VERIFY_OK(failure)) {
3362 checkTypeCategory(returnType, kTypeCategory2, &failure);
3363 checkWidePair(returnType, returnTypeHi, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003364 }
Andy McFadden62a75162009-04-17 17:23:37 -07003365 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003366 LOG_VFY("VFY: return-wide on invalid register pair v%d\n",
3367 decInsn.vA);
3368 }
3369 }
3370 break;
3371 case OP_RETURN_OBJECT:
Andy McFadden62a75162009-04-17 17:23:37 -07003372 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3373 failure = VERIFY_ERROR_GENERIC;
3374 } else {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003375 RegType returnType = getMethodReturnType(meth);
Andy McFadden62a75162009-04-17 17:23:37 -07003376 checkTypeCategory(returnType, kTypeCategoryRef, &failure);
3377 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003378 LOG_VFY("VFY: return-object not expected\n");
3379 break;
3380 }
3381
3382 /* returnType is the *expected* return type, not register value */
3383 assert(returnType != kRegTypeZero);
3384 assert(!regTypeIsUninitReference(returnType));
3385
3386 /*
3387 * Verify that the reference in vAA is an instance of the type
3388 * in "returnType". The Zero type is allowed here. If the
3389 * method is declared to return an interface, then any
3390 * initialized reference is acceptable.
3391 *
3392 * Note getClassFromRegister fails if the register holds an
3393 * uninitialized reference, so we do not allow them to be
3394 * returned.
3395 */
3396 ClassObject* declClass;
3397
3398 declClass = regTypeInitializedReferenceToClass(returnType);
3399 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003400 decInsn.vA, &failure);
3401 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003402 break;
3403 if (resClass != NULL) {
3404 if (!dvmIsInterfaceClass(declClass) &&
3405 !dvmInstanceof(resClass, declClass))
3406 {
3407 LOG_VFY("VFY: returning %s, declared %s\n",
3408 resClass->descriptor, declClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003409 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003410 break;
3411 }
3412 }
3413 }
3414 break;
3415
3416 case OP_CONST_4:
3417 case OP_CONST_16:
3418 case OP_CONST:
3419 /* could be boolean, int, float, or a null reference */
3420 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003421 dvmDetermineCat1Const((s4)decInsn.vB), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003422 break;
3423 case OP_CONST_HIGH16:
3424 /* could be boolean, int, float, or a null reference */
3425 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003426 dvmDetermineCat1Const((s4) decInsn.vB << 16), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003427 break;
3428 case OP_CONST_WIDE_16:
3429 case OP_CONST_WIDE_32:
3430 case OP_CONST_WIDE:
3431 case OP_CONST_WIDE_HIGH16:
3432 /* could be long or double; default to long and allow conversion */
3433 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003434 kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003435 break;
3436 case OP_CONST_STRING:
3437 case OP_CONST_STRING_JUMBO:
3438 assert(gDvm.classJavaLangString != NULL);
3439 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003440 regTypeFromClass(gDvm.classJavaLangString), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003441 break;
3442 case OP_CONST_CLASS:
3443 assert(gDvm.classJavaLangClass != NULL);
3444 /* make sure we can resolve the class; access check is important */
Andy McFadden62a75162009-04-17 17:23:37 -07003445 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003446 if (resClass == NULL) {
3447 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3448 dvmLogUnableToResolveClass(badClassDesc, meth);
3449 LOG_VFY("VFY: unable to resolve const-class %d (%s) in %s\n",
3450 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003451 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003452 } else {
3453 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003454 regTypeFromClass(gDvm.classJavaLangClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003455 }
3456 break;
3457
3458 case OP_MONITOR_ENTER:
3459 case OP_MONITOR_EXIT:
Andy McFadden62a75162009-04-17 17:23:37 -07003460 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
3461 if (VERIFY_OK(failure)) {
3462 if (!regTypeIsReference(tmpType)) {
3463 LOG_VFY("VFY: monitor op on non-object\n");
3464 failure = VERIFY_ERROR_GENERIC;
3465 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003466 }
3467 break;
3468
3469 case OP_CHECK_CAST:
3470 /*
3471 * If this instruction succeeds, we will promote register vA to
3472 * the type in vB. (This could be a demotion -- not expected, so
3473 * we don't try to address it.)
3474 *
3475 * If it fails, an exception is thrown, which we deal with later
3476 * by ignoring the update to decInsn.vA when branching to a handler.
3477 */
Andy McFadden62a75162009-04-17 17:23:37 -07003478 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003479 if (resClass == NULL) {
3480 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3481 dvmLogUnableToResolveClass(badClassDesc, meth);
3482 LOG_VFY("VFY: unable to resolve check-cast %d (%s) in %s\n",
3483 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003484 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003485 } else {
3486 RegType origType;
3487
3488 origType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003489 &failure);
3490 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003491 break;
3492 if (!regTypeIsReference(origType)) {
3493 LOG_VFY("VFY: check-cast on non-reference in v%u\n",decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07003494 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003495 break;
3496 }
3497 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003498 regTypeFromClass(resClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003499 }
3500 break;
3501 case OP_INSTANCE_OF:
3502 /* make sure we're checking a reference type */
Andy McFadden62a75162009-04-17 17:23:37 -07003503 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vB, &failure);
3504 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003505 break;
3506 if (!regTypeIsReference(tmpType)) {
3507 LOG_VFY("VFY: vB not a reference (%d)\n", tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07003508 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003509 break;
3510 }
3511
3512 /* make sure we can resolve the class; access check is important */
Andy McFadden62a75162009-04-17 17:23:37 -07003513 resClass = dvmOptResolveClass(meth->clazz, decInsn.vC, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003514 if (resClass == NULL) {
3515 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vC);
3516 dvmLogUnableToResolveClass(badClassDesc, meth);
3517 LOG_VFY("VFY: unable to resolve instanceof %d (%s) in %s\n",
3518 decInsn.vC, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003519 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003520 } else {
3521 /* result is boolean */
3522 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003523 kRegTypeBoolean, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003524 }
3525 break;
3526
3527 case OP_ARRAY_LENGTH:
3528 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003529 decInsn.vB, &failure);
3530 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003531 break;
3532 if (resClass != NULL && !dvmIsArrayClass(resClass)) {
3533 LOG_VFY("VFY: array-length on non-array\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003534 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003535 break;
3536 }
3537 setRegisterType(workRegs, insnRegCount, decInsn.vA, kRegTypeInteger,
Andy McFadden62a75162009-04-17 17:23:37 -07003538 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003539 break;
3540
3541 case OP_NEW_INSTANCE:
3542 /*
3543 * We can check for interface and abstract classes here, but we
3544 * can't reject them. We can ask the optimizer to replace the
3545 * instructions with a magic "always throw InstantiationError"
3546 * instruction. (Not enough bytes to sub in a method call.)
3547 */
Andy McFadden62a75162009-04-17 17:23:37 -07003548 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003549 if (resClass == NULL) {
3550 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3551 dvmLogUnableToResolveClass(badClassDesc, meth);
3552 LOG_VFY("VFY: unable to resolve new-instance %d (%s) in %s\n",
3553 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003554 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003555 } else {
3556 RegType uninitType;
3557
3558 /* add resolved class to uninit map if not already there */
3559 int uidx = dvmSetUninitInstance(uninitMap, insnIdx, resClass);
3560 assert(uidx >= 0);
3561 uninitType = regTypeFromUninitIndex(uidx);
3562
3563 /*
3564 * Any registers holding previous allocations from this address
3565 * that have not yet been initialized must be marked invalid.
3566 */
3567 markUninitRefsAsInvalid(workRegs, insnRegCount, uninitMap,
3568 uninitType);
3569
3570 /* add the new uninitialized reference to the register ste */
3571 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003572 uninitType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003573 }
3574 break;
3575 case OP_NEW_ARRAY:
Andy McFadden62a75162009-04-17 17:23:37 -07003576 resClass = dvmOptResolveClass(meth->clazz, decInsn.vC, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003577 if (resClass == NULL) {
3578 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vC);
3579 dvmLogUnableToResolveClass(badClassDesc, meth);
3580 LOG_VFY("VFY: unable to resolve new-array %d (%s) in %s\n",
3581 decInsn.vC, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003582 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003583 } else if (!dvmIsArrayClass(resClass)) {
3584 LOG_VFY("VFY: new-array on non-array class\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003585 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003586 } else {
3587 /* make sure "size" register is valid type */
3588 verifyRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07003589 kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003590 /* set register type to array class */
3591 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003592 regTypeFromClass(resClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003593 }
3594 break;
3595 case OP_FILLED_NEW_ARRAY:
3596 case OP_FILLED_NEW_ARRAY_RANGE:
Andy McFadden62a75162009-04-17 17:23:37 -07003597 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003598 if (resClass == NULL) {
3599 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3600 dvmLogUnableToResolveClass(badClassDesc, meth);
3601 LOG_VFY("VFY: unable to resolve filled-array %d (%s) in %s\n",
3602 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003603 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003604 } else if (!dvmIsArrayClass(resClass)) {
3605 LOG_VFY("VFY: filled-new-array on non-array class\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003606 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003607 } else {
3608 bool isRange = (decInsn.opCode == OP_FILLED_NEW_ARRAY_RANGE);
3609
3610 /* check the arguments to the instruction */
3611 verifyFilledNewArrayRegs(meth, workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07003612 resClass, isRange, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003613 /* filled-array result goes into "result" register */
3614 setResultRegisterType(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003615 regTypeFromClass(resClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003616 justSetResult = true;
3617 }
3618 break;
3619
3620 case OP_CMPL_FLOAT:
3621 case OP_CMPG_FLOAT:
3622 verifyRegisterType(workRegs, insnRegCount, decInsn.vB, kRegTypeFloat,
Andy McFadden62a75162009-04-17 17:23:37 -07003623 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003624 verifyRegisterType(workRegs, insnRegCount, decInsn.vC, kRegTypeFloat,
Andy McFadden62a75162009-04-17 17:23:37 -07003625 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003626 setRegisterType(workRegs, insnRegCount, decInsn.vA, kRegTypeBoolean,
Andy McFadden62a75162009-04-17 17:23:37 -07003627 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003628 break;
3629 case OP_CMPL_DOUBLE:
3630 case OP_CMPG_DOUBLE:
3631 verifyRegisterType(workRegs, insnRegCount, decInsn.vB, kRegTypeDoubleLo,
Andy McFadden62a75162009-04-17 17:23:37 -07003632 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003633 verifyRegisterType(workRegs, insnRegCount, decInsn.vC, kRegTypeDoubleLo,
Andy McFadden62a75162009-04-17 17:23:37 -07003634 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003635 setRegisterType(workRegs, insnRegCount, decInsn.vA, kRegTypeBoolean,
Andy McFadden62a75162009-04-17 17:23:37 -07003636 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003637 break;
3638 case OP_CMP_LONG:
3639 verifyRegisterType(workRegs, insnRegCount, decInsn.vB, kRegTypeLongLo,
Andy McFadden62a75162009-04-17 17:23:37 -07003640 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003641 verifyRegisterType(workRegs, insnRegCount, decInsn.vC, kRegTypeLongLo,
Andy McFadden62a75162009-04-17 17:23:37 -07003642 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003643 setRegisterType(workRegs, insnRegCount, decInsn.vA, kRegTypeBoolean,
Andy McFadden62a75162009-04-17 17:23:37 -07003644 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003645 break;
3646
3647 case OP_THROW:
3648 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003649 decInsn.vA, &failure);
3650 if (VERIFY_OK(failure) && resClass != NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003651 if (!dvmInstanceof(resClass, gDvm.classJavaLangThrowable)) {
3652 LOG_VFY("VFY: thrown class %s not instanceof Throwable\n",
3653 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003654 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003655 }
3656 }
3657 break;
3658
3659 case OP_GOTO:
3660 case OP_GOTO_16:
3661 case OP_GOTO_32:
3662 /* no effect on or use of registers */
3663 break;
3664
3665 case OP_PACKED_SWITCH:
3666 case OP_SPARSE_SWITCH:
3667 /* verify that vAA is an integer, or can be converted to one */
3668 verifyRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003669 kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003670 break;
3671
3672 case OP_FILL_ARRAY_DATA:
3673 {
3674 RegType valueType;
3675 const u2 *arrayData;
3676 u2 elemWidth;
3677
3678 /* Similar to the verification done for APUT */
3679 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003680 decInsn.vA, &failure);
3681 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003682 break;
3683
3684 /* resClass can be null if the reg type is Zero */
3685 if (resClass == NULL)
3686 break;
3687
3688 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
3689 resClass->elementClass->primitiveType == PRIM_NOT ||
3690 resClass->elementClass->primitiveType == PRIM_VOID)
3691 {
3692 LOG_VFY("VFY: invalid fill-array-data on %s\n",
3693 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003694 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003695 break;
3696 }
3697
3698 valueType = primitiveTypeToRegType(
3699 resClass->elementClass->primitiveType);
3700 assert(valueType != kRegTypeUnknown);
3701
3702 /*
3703 * Now verify if the element width in the table matches the element
3704 * width declared in the array
3705 */
3706 arrayData = insns + (insns[1] | (((s4)insns[2]) << 16));
3707 if (arrayData[0] != kArrayDataSignature) {
3708 LOG_VFY("VFY: invalid magic for array-data\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003709 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003710 break;
3711 }
3712
3713 switch (resClass->elementClass->primitiveType) {
3714 case PRIM_BOOLEAN:
3715 case PRIM_BYTE:
3716 elemWidth = 1;
3717 break;
3718 case PRIM_CHAR:
3719 case PRIM_SHORT:
3720 elemWidth = 2;
3721 break;
3722 case PRIM_FLOAT:
3723 case PRIM_INT:
3724 elemWidth = 4;
3725 break;
3726 case PRIM_DOUBLE:
3727 case PRIM_LONG:
3728 elemWidth = 8;
3729 break;
3730 default:
3731 elemWidth = 0;
3732 break;
3733 }
3734
3735 /*
3736 * Since we don't compress the data in Dex, expect to see equal
3737 * width of data stored in the table and expected from the array
3738 * class.
3739 */
3740 if (arrayData[1] != elemWidth) {
3741 LOG_VFY("VFY: array-data size mismatch (%d vs %d)\n",
3742 arrayData[1], elemWidth);
Andy McFadden62a75162009-04-17 17:23:37 -07003743 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003744 }
3745 }
3746 break;
3747
3748 case OP_IF_EQ:
3749 case OP_IF_NE:
3750 {
3751 RegType type1, type2;
3752 bool tmpResult;
3753
Andy McFadden62a75162009-04-17 17:23:37 -07003754 type1 = getRegisterType(workRegs, insnRegCount, decInsn.vA,
3755 &failure);
3756 type2 = getRegisterType(workRegs, insnRegCount, decInsn.vB,
3757 &failure);
3758 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003759 break;
3760
3761 /* both references? */
3762 if (regTypeIsReference(type1) && regTypeIsReference(type2))
3763 break;
3764
3765 /* both category-1nr? */
Andy McFadden62a75162009-04-17 17:23:37 -07003766 checkTypeCategory(type1, kTypeCategory1nr, &failure);
3767 checkTypeCategory(type2, kTypeCategory1nr, &failure);
3768 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003769 LOG_VFY("VFY: args to if-eq/if-ne must both be refs or cat1\n");
3770 break;
3771 }
3772 }
3773 break;
3774 case OP_IF_LT:
3775 case OP_IF_GE:
3776 case OP_IF_GT:
3777 case OP_IF_LE:
Andy McFadden62a75162009-04-17 17:23:37 -07003778 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
3779 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003780 break;
Andy McFadden62a75162009-04-17 17:23:37 -07003781 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
3782 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003783 LOG_VFY("VFY: args to 'if' must be cat-1nr\n");
3784 break;
3785 }
Andy McFadden62a75162009-04-17 17:23:37 -07003786 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vB, &failure);
3787 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003788 break;
Andy McFadden62a75162009-04-17 17:23:37 -07003789 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
3790 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003791 LOG_VFY("VFY: args to 'if' must be cat-1nr\n");
3792 break;
3793 }
3794 break;
3795 case OP_IF_EQZ:
3796 case OP_IF_NEZ:
Andy McFadden62a75162009-04-17 17:23:37 -07003797 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
3798 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003799 break;
3800 if (regTypeIsReference(tmpType))
3801 break;
Andy McFadden62a75162009-04-17 17:23:37 -07003802 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
3803 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003804 LOG_VFY("VFY: expected cat-1 arg to if\n");
3805 break;
3806 case OP_IF_LTZ:
3807 case OP_IF_GEZ:
3808 case OP_IF_GTZ:
3809 case OP_IF_LEZ:
Andy McFadden62a75162009-04-17 17:23:37 -07003810 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
3811 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003812 break;
Andy McFadden62a75162009-04-17 17:23:37 -07003813 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
3814 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003815 LOG_VFY("VFY: expected cat-1 arg to if\n");
3816 break;
3817
3818 case OP_AGET:
3819 tmpType = kRegTypeInteger;
3820 goto aget_1nr_common;
3821 case OP_AGET_BOOLEAN:
3822 tmpType = kRegTypeBoolean;
3823 goto aget_1nr_common;
3824 case OP_AGET_BYTE:
3825 tmpType = kRegTypeByte;
3826 goto aget_1nr_common;
3827 case OP_AGET_CHAR:
3828 tmpType = kRegTypeChar;
3829 goto aget_1nr_common;
3830 case OP_AGET_SHORT:
3831 tmpType = kRegTypeShort;
3832 goto aget_1nr_common;
3833aget_1nr_common:
3834 {
3835 RegType srcType, indexType;
3836
3837 indexType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07003838 &failure);
3839 checkArrayIndexType(meth, indexType, &failure);
3840 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003841 break;
3842
3843 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003844 decInsn.vB, &failure);
3845 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003846 break;
3847 if (resClass != NULL) {
3848 /* verify the class */
3849 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
3850 resClass->elementClass->primitiveType == PRIM_NOT)
3851 {
3852 LOG_VFY("VFY: invalid aget-1nr target %s\n",
3853 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003854 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003855 break;
3856 }
3857
3858 /* make sure array type matches instruction */
3859 srcType = primitiveTypeToRegType(
3860 resClass->elementClass->primitiveType);
3861
3862 if (!checkFieldArrayStore1nr(tmpType, srcType)) {
3863 LOG_VFY("VFY: invalid aget-1nr, array type=%d with"
3864 " inst type=%d (on %s)\n",
3865 srcType, tmpType, resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003866 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003867 break;
3868 }
3869
3870 }
3871 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003872 tmpType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003873 }
3874 break;
3875
3876 case OP_AGET_WIDE:
3877 {
3878 RegType dstType, indexType;
3879
3880 indexType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07003881 &failure);
3882 checkArrayIndexType(meth, indexType, &failure);
3883 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003884 break;
3885
3886 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003887 decInsn.vB, &failure);
3888 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003889 break;
3890 if (resClass != NULL) {
3891 /* verify the class */
3892 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
3893 resClass->elementClass->primitiveType == PRIM_NOT)
3894 {
3895 LOG_VFY("VFY: invalid aget-wide target %s\n",
3896 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003897 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003898 break;
3899 }
3900
3901 /* try to refine "dstType" */
3902 switch (resClass->elementClass->primitiveType) {
3903 case PRIM_LONG:
3904 dstType = kRegTypeLongLo;
3905 break;
3906 case PRIM_DOUBLE:
3907 dstType = kRegTypeDoubleLo;
3908 break;
3909 default:
3910 LOG_VFY("VFY: invalid aget-wide on %s\n",
3911 resClass->descriptor);
3912 dstType = kRegTypeUnknown;
Andy McFadden62a75162009-04-17 17:23:37 -07003913 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003914 break;
3915 }
3916 } else {
3917 /*
3918 * Null array ref; this code path will fail at runtime. We
3919 * know this is either long or double, and we don't really
3920 * discriminate between those during verification, so we
3921 * call it a long.
3922 */
3923 dstType = kRegTypeLongLo;
3924 }
3925 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003926 dstType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003927 }
3928 break;
3929
3930 case OP_AGET_OBJECT:
3931 {
3932 RegType dstType, indexType;
3933
3934 indexType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07003935 &failure);
3936 checkArrayIndexType(meth, indexType, &failure);
3937 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003938 break;
3939
3940 /* get the class of the array we're pulling an object from */
3941 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003942 decInsn.vB, &failure);
3943 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003944 break;
3945 if (resClass != NULL) {
3946 ClassObject* elementClass;
3947
3948 assert(resClass != NULL);
3949 if (!dvmIsArrayClass(resClass)) {
3950 LOG_VFY("VFY: aget-object on non-array class\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003951 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003952 break;
3953 }
3954 assert(resClass->elementClass != NULL);
3955
3956 /*
3957 * Find the element class. resClass->elementClass indicates
3958 * the basic type, which won't be what we want for a
3959 * multi-dimensional array.
3960 */
3961 if (resClass->descriptor[1] == '[') {
3962 assert(resClass->arrayDim > 1);
3963 elementClass = dvmFindArrayClass(&resClass->descriptor[1],
3964 resClass->classLoader);
3965 } else if (resClass->descriptor[1] == 'L') {
3966 assert(resClass->arrayDim == 1);
3967 elementClass = resClass->elementClass;
3968 } else {
3969 LOG_VFY("VFY: aget-object on non-ref array class (%s)\n",
3970 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003971 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003972 break;
3973 }
3974
3975 dstType = regTypeFromClass(elementClass);
3976 } else {
3977 /*
3978 * The array reference is NULL, so the current code path will
3979 * throw an exception. For proper merging with later code
3980 * paths, and correct handling of "if-eqz" tests on the
3981 * result of the array get, we want to treat this as a null
3982 * reference.
3983 */
3984 dstType = kRegTypeZero;
3985 }
3986 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003987 dstType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003988 }
3989 break;
3990 case OP_APUT:
3991 tmpType = kRegTypeInteger;
3992 goto aput_1nr_common;
3993 case OP_APUT_BOOLEAN:
3994 tmpType = kRegTypeBoolean;
3995 goto aput_1nr_common;
3996 case OP_APUT_BYTE:
3997 tmpType = kRegTypeByte;
3998 goto aput_1nr_common;
3999 case OP_APUT_CHAR:
4000 tmpType = kRegTypeChar;
4001 goto aput_1nr_common;
4002 case OP_APUT_SHORT:
4003 tmpType = kRegTypeShort;
4004 goto aput_1nr_common;
4005aput_1nr_common:
4006 {
4007 RegType srcType, dstType, indexType;
4008
4009 indexType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004010 &failure);
4011 checkArrayIndexType(meth, indexType, &failure);
4012 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004013 break;
4014
4015 /* make sure the source register has the correct type */
4016 srcType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004017 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004018 if (!canConvertTo1nr(srcType, tmpType)) {
4019 LOG_VFY("VFY: invalid reg type %d on aput instr (need %d)\n",
4020 srcType, tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07004021 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004022 break;
4023 }
4024
4025 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004026 decInsn.vB, &failure);
4027 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004028 break;
4029
4030 /* resClass can be null if the reg type is Zero */
4031 if (resClass == NULL)
4032 break;
4033
4034 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4035 resClass->elementClass->primitiveType == PRIM_NOT)
4036 {
4037 LOG_VFY("VFY: invalid aput-1nr on %s\n", resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004038 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004039 break;
4040 }
4041
4042 /* verify that instruction matches array */
4043 dstType = primitiveTypeToRegType(
4044 resClass->elementClass->primitiveType);
4045 assert(dstType != kRegTypeUnknown);
4046
4047 if (!checkFieldArrayStore1nr(tmpType, dstType)) {
4048 LOG_VFY("VFY: invalid aput-1nr on %s (inst=%d dst=%d)\n",
4049 resClass->descriptor, tmpType, dstType);
Andy McFadden62a75162009-04-17 17:23:37 -07004050 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004051 break;
4052 }
4053 }
4054 break;
4055 case OP_APUT_WIDE:
4056 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004057 &failure);
4058 checkArrayIndexType(meth, tmpType, &failure);
4059 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004060 break;
4061
Andy McFadden62a75162009-04-17 17:23:37 -07004062 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4063 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004064 RegType typeHi =
Andy McFadden62a75162009-04-17 17:23:37 -07004065 getRegisterType(workRegs, insnRegCount, decInsn.vA+1, &failure);
4066 checkTypeCategory(tmpType, kTypeCategory2, &failure);
4067 checkWidePair(tmpType, typeHi, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004068 }
Andy McFadden62a75162009-04-17 17:23:37 -07004069 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004070 break;
4071
4072 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004073 decInsn.vB, &failure);
4074 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004075 break;
4076 if (resClass != NULL) {
4077 /* verify the class and try to refine "dstType" */
4078 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4079 resClass->elementClass->primitiveType == PRIM_NOT)
4080 {
4081 LOG_VFY("VFY: invalid aput-wide on %s\n",
4082 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004083 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004084 break;
4085 }
4086
4087 switch (resClass->elementClass->primitiveType) {
4088 case PRIM_LONG:
4089 case PRIM_DOUBLE:
4090 /* these are okay */
4091 break;
4092 default:
4093 LOG_VFY("VFY: invalid aput-wide on %s\n",
4094 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004095 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004096 break;
4097 }
4098 }
4099 break;
4100 case OP_APUT_OBJECT:
4101 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004102 &failure);
4103 checkArrayIndexType(meth, tmpType, &failure);
4104 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004105 break;
4106
4107 /* get the ref we're storing; Zero is okay, Uninit is not */
4108 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004109 decInsn.vA, &failure);
4110 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004111 break;
4112 if (resClass != NULL) {
4113 ClassObject* arrayClass;
4114 ClassObject* elementClass;
4115
4116 /*
4117 * Get the array class. If the array ref is null, we won't
4118 * have type information (and we'll crash at runtime with a
4119 * null pointer exception).
4120 */
4121 arrayClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004122 decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004123
4124 if (arrayClass != NULL) {
4125 /* see if the array holds a compatible type */
4126 if (!dvmIsArrayClass(arrayClass)) {
4127 LOG_VFY("VFY: invalid aput-object on %s\n",
4128 arrayClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004129 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004130 break;
4131 }
4132
4133 /*
4134 * Find the element class. resClass->elementClass indicates
4135 * the basic type, which won't be what we want for a
4136 * multi-dimensional array.
4137 *
4138 * All we want to check here is that the element type is a
4139 * reference class. We *don't* check instanceof here, because
4140 * you can still put a String into a String[] after the latter
4141 * has been cast to an Object[].
4142 */
4143 if (arrayClass->descriptor[1] == '[') {
4144 assert(arrayClass->arrayDim > 1);
4145 elementClass = dvmFindArrayClass(&arrayClass->descriptor[1],
4146 arrayClass->classLoader);
4147 } else {
4148 assert(arrayClass->arrayDim == 1);
4149 elementClass = arrayClass->elementClass;
4150 }
4151 if (elementClass->primitiveType != PRIM_NOT) {
4152 LOG_VFY("VFY: invalid aput-object of %s into %s\n",
4153 resClass->descriptor, arrayClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004154 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004155 break;
4156 }
4157 }
4158 }
4159 break;
4160
4161 case OP_IGET:
4162 tmpType = kRegTypeInteger;
4163 goto iget_1nr_common;
4164 case OP_IGET_BOOLEAN:
4165 tmpType = kRegTypeBoolean;
4166 goto iget_1nr_common;
4167 case OP_IGET_BYTE:
4168 tmpType = kRegTypeByte;
4169 goto iget_1nr_common;
4170 case OP_IGET_CHAR:
4171 tmpType = kRegTypeChar;
4172 goto iget_1nr_common;
4173 case OP_IGET_SHORT:
4174 tmpType = kRegTypeShort;
4175 goto iget_1nr_common;
4176iget_1nr_common:
4177 {
4178 ClassObject* fieldClass;
4179 InstField* instField;
4180 RegType objType, fieldType;
4181
4182 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004183 &failure);
4184 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004185 break;
4186 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004187 &failure);
4188 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004189 break;
4190
4191 /* make sure the field's type is compatible with expectation */
4192 fieldType = primSigCharToRegType(instField->field.signature[0]);
4193 if (fieldType == kRegTypeUnknown ||
4194 !checkFieldArrayStore1nr(tmpType, fieldType))
4195 {
4196 LOG_VFY("VFY: invalid iget-1nr of %s.%s (inst=%d field=%d)\n",
4197 instField->field.clazz->descriptor,
4198 instField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004199 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004200 break;
4201 }
4202
Andy McFadden62a75162009-04-17 17:23:37 -07004203 setRegisterType(workRegs, insnRegCount, decInsn.vA, tmpType,
4204 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004205 }
4206 break;
4207 case OP_IGET_WIDE:
4208 {
4209 RegType dstType;
4210 ClassObject* fieldClass;
4211 InstField* instField;
4212 RegType objType;
4213
4214 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004215 &failure);
4216 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004217 break;
4218 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004219 &failure);
4220 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004221 break;
4222 /* check the type, which should be prim */
4223 switch (instField->field.signature[0]) {
4224 case 'D':
4225 dstType = kRegTypeDoubleLo;
4226 break;
4227 case 'J':
4228 dstType = kRegTypeLongLo;
4229 break;
4230 default:
4231 LOG_VFY("VFY: invalid iget-wide of %s.%s\n",
4232 instField->field.clazz->descriptor,
4233 instField->field.name);
4234 dstType = kRegTypeUnknown;
Andy McFadden62a75162009-04-17 17:23:37 -07004235 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004236 break;
4237 }
Andy McFadden62a75162009-04-17 17:23:37 -07004238 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004239 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004240 dstType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004241 }
4242 }
4243 break;
4244 case OP_IGET_OBJECT:
4245 {
4246 ClassObject* fieldClass;
4247 InstField* instField;
4248 RegType objType;
4249
4250 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004251 &failure);
4252 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004253 break;
4254 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004255 &failure);
4256 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004257 break;
4258 fieldClass = getFieldClass(meth, &instField->field);
4259 if (fieldClass == NULL) {
4260 /* class not found or primitive type */
4261 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4262 instField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004263 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004264 break;
4265 }
Andy McFadden62a75162009-04-17 17:23:37 -07004266 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004267 assert(!dvmIsPrimitiveClass(fieldClass));
4268 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004269 regTypeFromClass(fieldClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004270 }
4271 }
4272 break;
4273 case OP_IPUT:
4274 tmpType = kRegTypeInteger;
4275 goto iput_1nr_common;
4276 case OP_IPUT_BOOLEAN:
4277 tmpType = kRegTypeBoolean;
4278 goto iput_1nr_common;
4279 case OP_IPUT_BYTE:
4280 tmpType = kRegTypeByte;
4281 goto iput_1nr_common;
4282 case OP_IPUT_CHAR:
4283 tmpType = kRegTypeChar;
4284 goto iput_1nr_common;
4285 case OP_IPUT_SHORT:
4286 tmpType = kRegTypeShort;
4287 goto iput_1nr_common;
4288iput_1nr_common:
4289 {
4290 RegType srcType, fieldType, objType;
4291 ClassObject* fieldClass;
4292 InstField* instField;
4293
4294 /* make sure the source register has the correct type */
4295 srcType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004296 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004297 if (!canConvertTo1nr(srcType, tmpType)) {
4298 LOG_VFY("VFY: invalid reg type %d on iput instr (need %d)\n",
4299 srcType, tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07004300 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004301 break;
4302 }
4303
4304 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004305 &failure);
4306 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004307 break;
4308 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004309 &failure);
4310 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004311 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004312 checkFinalFieldAccess(meth, &instField->field, &failure);
4313 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004314 break;
4315
4316 /* get type of field we're storing into */
4317 fieldType = primSigCharToRegType(instField->field.signature[0]);
4318 if (fieldType == kRegTypeUnknown ||
4319 !checkFieldArrayStore1nr(tmpType, fieldType))
4320 {
4321 LOG_VFY("VFY: invalid iput-1nr of %s.%s (inst=%d field=%d)\n",
4322 instField->field.clazz->descriptor,
4323 instField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004324 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004325 break;
4326 }
4327 }
4328 break;
4329 case OP_IPUT_WIDE:
Andy McFadden62a75162009-04-17 17:23:37 -07004330 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4331 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004332 RegType typeHi =
Andy McFadden62a75162009-04-17 17:23:37 -07004333 getRegisterType(workRegs, insnRegCount, decInsn.vA+1, &failure);
4334 checkTypeCategory(tmpType, kTypeCategory2, &failure);
4335 checkWidePair(tmpType, typeHi, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004336 }
Andy McFadden62a75162009-04-17 17:23:37 -07004337 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004338 ClassObject* fieldClass;
4339 InstField* instField;
4340 RegType objType;
4341
4342 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004343 &failure);
4344 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004345 break;
4346 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004347 &failure);
4348 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004349 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004350 checkFinalFieldAccess(meth, &instField->field, &failure);
4351 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004352 break;
4353
4354 /* check the type, which should be prim */
4355 switch (instField->field.signature[0]) {
4356 case 'D':
4357 case 'J':
4358 /* these are okay (and interchangeable) */
4359 break;
4360 default:
4361 LOG_VFY("VFY: invalid iput-wide of %s.%s\n",
4362 instField->field.clazz->descriptor,
4363 instField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07004364 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004365 break;
4366 }
4367 }
4368 break;
4369 case OP_IPUT_OBJECT:
4370 {
4371 ClassObject* fieldClass;
4372 ClassObject* valueClass;
4373 InstField* instField;
4374 RegType objType, valueType;
4375
4376 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004377 &failure);
4378 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004379 break;
4380 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004381 &failure);
4382 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004383 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004384 checkFinalFieldAccess(meth, &instField->field, &failure);
4385 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004386 break;
4387
4388 fieldClass = getFieldClass(meth, &instField->field);
4389 if (fieldClass == NULL) {
4390 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4391 instField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004392 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004393 break;
4394 }
4395
4396 valueType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004397 &failure);
4398 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004399 break;
4400 if (!regTypeIsReference(valueType)) {
4401 LOG_VFY("VFY: storing non-ref v%d into ref field '%s' (%s)\n",
4402 decInsn.vA, instField->field.name,
4403 fieldClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004404 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004405 break;
4406 }
4407 if (valueType != kRegTypeZero) {
4408 valueClass = regTypeInitializedReferenceToClass(valueType);
4409 if (valueClass == NULL) {
4410 LOG_VFY("VFY: storing uninit ref v%d into ref field\n",
4411 decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07004412 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004413 break;
4414 }
4415 /* allow if field is any interface or field is base class */
4416 if (!dvmIsInterfaceClass(fieldClass) &&
4417 !dvmInstanceof(valueClass, fieldClass))
4418 {
4419 LOG_VFY("VFY: storing type '%s' into field type '%s' (%s.%s)\n",
4420 valueClass->descriptor, fieldClass->descriptor,
4421 instField->field.clazz->descriptor,
4422 instField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07004423 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004424 break;
4425 }
4426 }
4427 }
4428 break;
4429
4430 case OP_SGET:
4431 tmpType = kRegTypeInteger;
4432 goto sget_1nr_common;
4433 case OP_SGET_BOOLEAN:
4434 tmpType = kRegTypeBoolean;
4435 goto sget_1nr_common;
4436 case OP_SGET_BYTE:
4437 tmpType = kRegTypeByte;
4438 goto sget_1nr_common;
4439 case OP_SGET_CHAR:
4440 tmpType = kRegTypeChar;
4441 goto sget_1nr_common;
4442 case OP_SGET_SHORT:
4443 tmpType = kRegTypeShort;
4444 goto sget_1nr_common;
4445sget_1nr_common:
4446 {
4447 StaticField* staticField;
4448 RegType fieldType;
4449
Andy McFadden62a75162009-04-17 17:23:37 -07004450 staticField = getStaticField(meth, decInsn.vB, &failure);
4451 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004452 break;
4453
4454 /*
4455 * Make sure the field's type is compatible with expectation.
4456 * We can get ourselves into trouble if we mix & match loads
4457 * and stores with different widths, so rather than just checking
4458 * "canConvertTo1nr" we require that the field types have equal
4459 * widths. (We can't generally require an exact type match,
4460 * because e.g. "int" and "float" are interchangeable.)
4461 */
4462 fieldType = primSigCharToRegType(staticField->field.signature[0]);
4463 if (!checkFieldArrayStore1nr(tmpType, fieldType)) {
4464 LOG_VFY("VFY: invalid sget-1nr of %s.%s (inst=%d actual=%d)\n",
4465 staticField->field.clazz->descriptor,
4466 staticField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004467 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004468 break;
4469 }
4470
Andy McFadden62a75162009-04-17 17:23:37 -07004471 setRegisterType(workRegs, insnRegCount, decInsn.vA, tmpType,
4472 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004473 }
4474 break;
4475 case OP_SGET_WIDE:
4476 {
4477 StaticField* staticField;
4478 RegType dstType;
4479
Andy McFadden62a75162009-04-17 17:23:37 -07004480 staticField = getStaticField(meth, decInsn.vB, &failure);
4481 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004482 break;
4483 /* check the type, which should be prim */
4484 switch (staticField->field.signature[0]) {
4485 case 'D':
4486 dstType = kRegTypeDoubleLo;
4487 break;
4488 case 'J':
4489 dstType = kRegTypeLongLo;
4490 break;
4491 default:
4492 LOG_VFY("VFY: invalid sget-wide of %s.%s\n",
4493 staticField->field.clazz->descriptor,
4494 staticField->field.name);
4495 dstType = kRegTypeUnknown;
Andy McFadden62a75162009-04-17 17:23:37 -07004496 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004497 break;
4498 }
Andy McFadden62a75162009-04-17 17:23:37 -07004499 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004500 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004501 dstType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004502 }
4503 }
4504 break;
4505 case OP_SGET_OBJECT:
4506 {
4507 StaticField* staticField;
4508 ClassObject* fieldClass;
4509
Andy McFadden62a75162009-04-17 17:23:37 -07004510 staticField = getStaticField(meth, decInsn.vB, &failure);
4511 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004512 break;
4513 fieldClass = getFieldClass(meth, &staticField->field);
4514 if (fieldClass == NULL) {
4515 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4516 staticField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004517 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004518 break;
4519 }
4520 if (dvmIsPrimitiveClass(fieldClass)) {
4521 LOG_VFY("VFY: attempt to get prim field with sget-object\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004522 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004523 break;
4524 }
4525 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004526 regTypeFromClass(fieldClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004527 }
4528 break;
4529 case OP_SPUT:
4530 tmpType = kRegTypeInteger;
4531 goto sput_1nr_common;
4532 case OP_SPUT_BOOLEAN:
4533 tmpType = kRegTypeBoolean;
4534 goto sput_1nr_common;
4535 case OP_SPUT_BYTE:
4536 tmpType = kRegTypeByte;
4537 goto sput_1nr_common;
4538 case OP_SPUT_CHAR:
4539 tmpType = kRegTypeChar;
4540 goto sput_1nr_common;
4541 case OP_SPUT_SHORT:
4542 tmpType = kRegTypeShort;
4543 goto sput_1nr_common;
4544sput_1nr_common:
4545 {
4546 RegType srcType, fieldType;
4547 StaticField* staticField;
4548
4549 /* make sure the source register has the correct type */
4550 srcType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004551 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004552 if (!canConvertTo1nr(srcType, tmpType)) {
4553 LOG_VFY("VFY: invalid reg type %d on iput instr (need %d)\n",
4554 srcType, tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07004555 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004556 break;
4557 }
4558
Andy McFadden62a75162009-04-17 17:23:37 -07004559 staticField = getStaticField(meth, decInsn.vB, &failure);
4560 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004561 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004562 checkFinalFieldAccess(meth, &staticField->field, &failure);
4563 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004564 break;
4565
4566 /*
4567 * Get type of field we're storing into. We know that the
4568 * contents of the register match the instruction, but we also
4569 * need to ensure that the instruction matches the field type.
4570 * Using e.g. sput-short to write into a 32-bit integer field
4571 * can lead to trouble if we do 16-bit writes.
4572 */
4573 fieldType = primSigCharToRegType(staticField->field.signature[0]);
4574 if (!checkFieldArrayStore1nr(tmpType, fieldType)) {
4575 LOG_VFY("VFY: invalid sput-1nr of %s.%s (inst=%d actual=%d)\n",
4576 staticField->field.clazz->descriptor,
4577 staticField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004578 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004579 break;
4580 }
4581 }
4582 break;
4583 case OP_SPUT_WIDE:
Andy McFadden62a75162009-04-17 17:23:37 -07004584 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4585 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004586 RegType typeHi =
Andy McFadden62a75162009-04-17 17:23:37 -07004587 getRegisterType(workRegs, insnRegCount, decInsn.vA+1, &failure);
4588 checkTypeCategory(tmpType, kTypeCategory2, &failure);
4589 checkWidePair(tmpType, typeHi, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004590 }
Andy McFadden62a75162009-04-17 17:23:37 -07004591 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004592 StaticField* staticField;
4593
Andy McFadden62a75162009-04-17 17:23:37 -07004594 staticField = getStaticField(meth, decInsn.vB, &failure);
4595 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004596 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004597 checkFinalFieldAccess(meth, &staticField->field, &failure);
4598 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004599 break;
4600
4601 /* check the type, which should be prim */
4602 switch (staticField->field.signature[0]) {
4603 case 'D':
4604 case 'J':
4605 /* these are okay */
4606 break;
4607 default:
4608 LOG_VFY("VFY: invalid sput-wide of %s.%s\n",
4609 staticField->field.clazz->descriptor,
4610 staticField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07004611 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004612 break;
4613 }
4614 }
4615 break;
4616 case OP_SPUT_OBJECT:
4617 {
4618 ClassObject* fieldClass;
4619 ClassObject* valueClass;
4620 StaticField* staticField;
4621 RegType valueType;
4622
Andy McFadden62a75162009-04-17 17:23:37 -07004623 staticField = getStaticField(meth, decInsn.vB, &failure);
4624 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004625 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004626 checkFinalFieldAccess(meth, &staticField->field, &failure);
4627 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004628 break;
4629
4630 fieldClass = getFieldClass(meth, &staticField->field);
4631 if (fieldClass == NULL) {
4632 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4633 staticField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004634 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004635 break;
4636 }
4637
4638 valueType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004639 &failure);
4640 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004641 break;
4642 if (!regTypeIsReference(valueType)) {
4643 LOG_VFY("VFY: storing non-ref v%d into ref field '%s' (%s)\n",
4644 decInsn.vA, staticField->field.name,
4645 fieldClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004646 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004647 break;
4648 }
4649 if (valueType != kRegTypeZero) {
4650 valueClass = regTypeInitializedReferenceToClass(valueType);
4651 if (valueClass == NULL) {
4652 LOG_VFY("VFY: storing uninit ref v%d into ref field\n",
4653 decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07004654 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004655 break;
4656 }
4657 /* allow if field is any interface or field is base class */
4658 if (!dvmIsInterfaceClass(fieldClass) &&
4659 !dvmInstanceof(valueClass, fieldClass))
4660 {
4661 LOG_VFY("VFY: storing type '%s' into field type '%s' (%s.%s)\n",
4662 valueClass->descriptor, fieldClass->descriptor,
4663 staticField->field.clazz->descriptor,
4664 staticField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07004665 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004666 break;
4667 }
4668 }
4669 }
4670 break;
4671
4672 case OP_INVOKE_VIRTUAL:
4673 case OP_INVOKE_VIRTUAL_RANGE:
4674 case OP_INVOKE_SUPER:
4675 case OP_INVOKE_SUPER_RANGE:
4676 {
4677 Method* calledMethod;
4678 RegType returnType;
4679 bool isRange;
4680 bool isSuper;
4681
4682 isRange = (decInsn.opCode == OP_INVOKE_VIRTUAL_RANGE ||
4683 decInsn.opCode == OP_INVOKE_SUPER_RANGE);
4684 isSuper = (decInsn.opCode == OP_INVOKE_SUPER ||
4685 decInsn.opCode == OP_INVOKE_SUPER_RANGE);
4686
4687 calledMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
4688 &decInsn, uninitMap, METHOD_VIRTUAL, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07004689 isSuper, &failure);
4690 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004691 break;
4692 returnType = getMethodReturnType(calledMethod);
Andy McFadden62a75162009-04-17 17:23:37 -07004693 setResultRegisterType(workRegs, insnRegCount, returnType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004694 justSetResult = true;
4695 }
4696 break;
4697 case OP_INVOKE_DIRECT:
4698 case OP_INVOKE_DIRECT_RANGE:
4699 {
4700 RegType returnType;
4701 Method* calledMethod;
4702 bool isRange;
4703
4704 isRange = (decInsn.opCode == OP_INVOKE_DIRECT_RANGE);
4705 calledMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
4706 &decInsn, uninitMap, METHOD_DIRECT, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07004707 false, &failure);
4708 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004709 break;
4710
4711 /*
4712 * Some additional checks when calling <init>. We know from
4713 * the invocation arg check that the "this" argument is an
4714 * instance of calledMethod->clazz. Now we further restrict
4715 * that to require that calledMethod->clazz is the same as
4716 * this->clazz or this->super, allowing the latter only if
4717 * the "this" argument is the same as the "this" argument to
4718 * this method (which implies that we're in <init> ourselves).
4719 */
4720 if (isInitMethod(calledMethod)) {
4721 RegType thisType;
4722 thisType = getInvocationThis(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004723 &decInsn, &failure);
4724 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004725 break;
4726
4727 /* no null refs allowed (?) */
4728 if (thisType == kRegTypeZero) {
4729 LOG_VFY("VFY: unable to initialize null ref\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004730 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004731 break;
4732 }
4733
4734 ClassObject* thisClass;
4735
4736 thisClass = regTypeReferenceToClass(thisType, uninitMap);
4737 assert(thisClass != NULL);
4738
4739 /* must be in same class or in superclass */
4740 if (calledMethod->clazz == thisClass->super) {
4741 if (thisClass != meth->clazz) {
4742 LOG_VFY("VFY: invoke-direct <init> on super only "
4743 "allowed for 'this' in <init>");
Andy McFadden62a75162009-04-17 17:23:37 -07004744 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004745 break;
4746 }
4747 } else if (calledMethod->clazz != thisClass) {
4748 LOG_VFY("VFY: invoke-direct <init> must be on current "
4749 "class or super\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004750 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004751 break;
4752 }
4753
4754 /* arg must be an uninitialized reference */
4755 if (!regTypeIsUninitReference(thisType)) {
4756 LOG_VFY("VFY: can only initialize the uninitialized\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004757 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004758 break;
4759 }
4760
4761 /*
4762 * Replace the uninitialized reference with an initialized
4763 * one, and clear the entry in the uninit map. We need to
4764 * do this for all registers that have the same object
4765 * instance in them, not just the "this" register.
4766 */
4767 int uidx = regTypeToUninitIndex(thisType);
4768 markRefsAsInitialized(workRegs, insnRegCount, uninitMap,
Andy McFadden62a75162009-04-17 17:23:37 -07004769 thisType, &failure);
4770 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004771 break;
4772 }
4773 returnType = getMethodReturnType(calledMethod);
4774 setResultRegisterType(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004775 returnType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004776 justSetResult = true;
4777 }
4778 break;
4779 case OP_INVOKE_STATIC:
4780 case OP_INVOKE_STATIC_RANGE:
4781 {
4782 RegType returnType;
4783 Method* calledMethod;
4784 bool isRange;
4785
4786 isRange = (decInsn.opCode == OP_INVOKE_STATIC_RANGE);
4787 calledMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
4788 &decInsn, uninitMap, METHOD_STATIC, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07004789 false, &failure);
4790 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004791 break;
4792
4793 returnType = getMethodReturnType(calledMethod);
Andy McFadden62a75162009-04-17 17:23:37 -07004794 setResultRegisterType(workRegs, insnRegCount, returnType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004795 justSetResult = true;
4796 }
4797 break;
4798 case OP_INVOKE_INTERFACE:
4799 case OP_INVOKE_INTERFACE_RANGE:
4800 {
4801 RegType /*thisType,*/ returnType;
4802 Method* absMethod;
4803 bool isRange;
4804
4805 isRange = (decInsn.opCode == OP_INVOKE_INTERFACE_RANGE);
4806 absMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
4807 &decInsn, uninitMap, METHOD_INTERFACE, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07004808 false, &failure);
4809 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004810 break;
4811
4812#if 0 /* can't do this here, fails on dalvik test 052-verifier-fun */
4813 /*
4814 * Get the type of the "this" arg, which should always be an
4815 * interface class. Because we don't do a full merge on
4816 * interface classes, this might have reduced to Object.
4817 */
4818 thisType = getInvocationThis(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004819 &decInsn, &failure);
4820 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004821 break;
4822
4823 if (thisType == kRegTypeZero) {
4824 /* null pointer always passes (and always fails at runtime) */
4825 } else {
4826 ClassObject* thisClass;
4827
4828 thisClass = regTypeInitializedReferenceToClass(thisType);
4829 if (thisClass == NULL) {
4830 LOG_VFY("VFY: interface call on uninitialized\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004831 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004832 break;
4833 }
4834
4835 /*
4836 * Either "thisClass" needs to be the interface class that
4837 * defined absMethod, or absMethod's class needs to be one
4838 * of the interfaces implemented by "thisClass". (Or, if
4839 * we couldn't complete the merge, this will be Object.)
4840 */
4841 if (thisClass != absMethod->clazz &&
4842 thisClass != gDvm.classJavaLangObject &&
4843 !dvmImplements(thisClass, absMethod->clazz))
4844 {
4845 LOG_VFY("VFY: unable to match absMethod '%s' with %s interfaces\n",
4846 absMethod->name, thisClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004847 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004848 break;
4849 }
4850 }
4851#endif
4852
4853 /*
4854 * We don't have an object instance, so we can't find the
4855 * concrete method. However, all of the type information is
4856 * in the abstract method, so we're good.
4857 */
4858 returnType = getMethodReturnType(absMethod);
Andy McFadden62a75162009-04-17 17:23:37 -07004859 setResultRegisterType(workRegs, insnRegCount, returnType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004860 justSetResult = true;
4861 }
4862 break;
4863
4864 case OP_NEG_INT:
4865 case OP_NOT_INT:
4866 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07004867 kRegTypeInteger, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004868 break;
4869 case OP_NEG_LONG:
4870 case OP_NOT_LONG:
4871 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07004872 kRegTypeLongLo, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004873 break;
4874 case OP_NEG_FLOAT:
4875 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07004876 kRegTypeFloat, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004877 break;
4878 case OP_NEG_DOUBLE:
4879 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07004880 kRegTypeDoubleLo, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004881 break;
4882 case OP_INT_TO_LONG:
4883 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07004884 kRegTypeLongLo, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004885 break;
4886 case OP_INT_TO_FLOAT:
4887 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07004888 kRegTypeFloat, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004889 break;
4890 case OP_INT_TO_DOUBLE:
4891 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07004892 kRegTypeDoubleLo, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004893 break;
4894 case OP_LONG_TO_INT:
4895 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07004896 kRegTypeInteger, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004897 break;
4898 case OP_LONG_TO_FLOAT:
4899 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07004900 kRegTypeFloat, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004901 break;
4902 case OP_LONG_TO_DOUBLE:
4903 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07004904 kRegTypeDoubleLo, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004905 break;
4906 case OP_FLOAT_TO_INT:
4907 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07004908 kRegTypeInteger, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004909 break;
4910 case OP_FLOAT_TO_LONG:
4911 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07004912 kRegTypeLongLo, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004913 break;
4914 case OP_FLOAT_TO_DOUBLE:
4915 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07004916 kRegTypeDoubleLo, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004917 break;
4918 case OP_DOUBLE_TO_INT:
4919 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07004920 kRegTypeInteger, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004921 break;
4922 case OP_DOUBLE_TO_LONG:
4923 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07004924 kRegTypeLongLo, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004925 break;
4926 case OP_DOUBLE_TO_FLOAT:
4927 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07004928 kRegTypeFloat, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004929 break;
4930 case OP_INT_TO_BYTE:
4931 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07004932 kRegTypeByte, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004933 break;
4934 case OP_INT_TO_CHAR:
4935 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07004936 kRegTypeChar, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004937 break;
4938 case OP_INT_TO_SHORT:
4939 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07004940 kRegTypeShort, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004941 break;
4942
4943 case OP_ADD_INT:
4944 case OP_SUB_INT:
4945 case OP_MUL_INT:
4946 case OP_REM_INT:
4947 case OP_DIV_INT:
4948 case OP_SHL_INT:
4949 case OP_SHR_INT:
4950 case OP_USHR_INT:
4951 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07004952 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004953 break;
4954 case OP_AND_INT:
4955 case OP_OR_INT:
4956 case OP_XOR_INT:
4957 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07004958 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004959 break;
4960 case OP_ADD_LONG:
4961 case OP_SUB_LONG:
4962 case OP_MUL_LONG:
4963 case OP_DIV_LONG:
4964 case OP_REM_LONG:
4965 case OP_AND_LONG:
4966 case OP_OR_LONG:
4967 case OP_XOR_LONG:
4968 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07004969 kRegTypeLongLo, kRegTypeLongLo, kRegTypeLongLo, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004970 break;
4971 case OP_SHL_LONG:
4972 case OP_SHR_LONG:
4973 case OP_USHR_LONG:
4974 /* shift distance is Int, making these different from other binops */
4975 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07004976 kRegTypeLongLo, kRegTypeLongLo, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004977 break;
4978 case OP_ADD_FLOAT:
4979 case OP_SUB_FLOAT:
4980 case OP_MUL_FLOAT:
4981 case OP_DIV_FLOAT:
4982 case OP_REM_FLOAT:
4983 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07004984 kRegTypeFloat, kRegTypeFloat, kRegTypeFloat, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004985 break;
4986 case OP_ADD_DOUBLE:
4987 case OP_SUB_DOUBLE:
4988 case OP_MUL_DOUBLE:
4989 case OP_DIV_DOUBLE:
4990 case OP_REM_DOUBLE:
4991 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07004992 kRegTypeDoubleLo, kRegTypeDoubleLo, kRegTypeDoubleLo, false,
4993 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004994 break;
4995 case OP_ADD_INT_2ADDR:
4996 case OP_SUB_INT_2ADDR:
4997 case OP_MUL_INT_2ADDR:
4998 case OP_REM_INT_2ADDR:
4999 case OP_SHL_INT_2ADDR:
5000 case OP_SHR_INT_2ADDR:
5001 case OP_USHR_INT_2ADDR:
5002 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005003 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005004 break;
5005 case OP_AND_INT_2ADDR:
5006 case OP_OR_INT_2ADDR:
5007 case OP_XOR_INT_2ADDR:
5008 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005009 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005010 break;
5011 case OP_DIV_INT_2ADDR:
5012 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005013 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005014 break;
5015 case OP_ADD_LONG_2ADDR:
5016 case OP_SUB_LONG_2ADDR:
5017 case OP_MUL_LONG_2ADDR:
5018 case OP_DIV_LONG_2ADDR:
5019 case OP_REM_LONG_2ADDR:
5020 case OP_AND_LONG_2ADDR:
5021 case OP_OR_LONG_2ADDR:
5022 case OP_XOR_LONG_2ADDR:
5023 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005024 kRegTypeLongLo, kRegTypeLongLo, kRegTypeLongLo, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005025 break;
5026 case OP_SHL_LONG_2ADDR:
5027 case OP_SHR_LONG_2ADDR:
5028 case OP_USHR_LONG_2ADDR:
5029 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005030 kRegTypeLongLo, kRegTypeLongLo, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005031 break;
5032 case OP_ADD_FLOAT_2ADDR:
5033 case OP_SUB_FLOAT_2ADDR:
5034 case OP_MUL_FLOAT_2ADDR:
5035 case OP_DIV_FLOAT_2ADDR:
5036 case OP_REM_FLOAT_2ADDR:
5037 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005038 kRegTypeFloat, kRegTypeFloat, kRegTypeFloat, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005039 break;
5040 case OP_ADD_DOUBLE_2ADDR:
5041 case OP_SUB_DOUBLE_2ADDR:
5042 case OP_MUL_DOUBLE_2ADDR:
5043 case OP_DIV_DOUBLE_2ADDR:
5044 case OP_REM_DOUBLE_2ADDR:
5045 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005046 kRegTypeDoubleLo, kRegTypeDoubleLo, kRegTypeDoubleLo, false,
5047 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005048 break;
5049 case OP_ADD_INT_LIT16:
5050 case OP_RSUB_INT:
5051 case OP_MUL_INT_LIT16:
5052 case OP_DIV_INT_LIT16:
5053 case OP_REM_INT_LIT16:
5054 checkLitop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005055 kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005056 break;
5057 case OP_AND_INT_LIT16:
5058 case OP_OR_INT_LIT16:
5059 case OP_XOR_INT_LIT16:
5060 checkLitop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005061 kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005062 break;
5063 case OP_ADD_INT_LIT8:
5064 case OP_RSUB_INT_LIT8:
5065 case OP_MUL_INT_LIT8:
5066 case OP_DIV_INT_LIT8:
5067 case OP_REM_INT_LIT8:
5068 case OP_SHL_INT_LIT8:
5069 case OP_SHR_INT_LIT8:
5070 case OP_USHR_INT_LIT8:
5071 checkLitop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005072 kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005073 break;
5074 case OP_AND_INT_LIT8:
5075 case OP_OR_INT_LIT8:
5076 case OP_XOR_INT_LIT8:
5077 checkLitop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005078 kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005079 break;
5080
5081
5082 /*
5083 * Verifying "quickened" instructions is tricky, because we have
5084 * discarded the original field/method information. The byte offsets
5085 * and vtable indices only have meaning in the context of an object
5086 * instance.
5087 *
5088 * If a piece of code declares a local reference variable, assigns
5089 * null to it, and then issues a virtual method call on it, we
5090 * cannot evaluate the method call during verification. This situation
5091 * isn't hard to handle, since we know the call will always result in an
5092 * NPE, and the arguments and return value don't matter. Any code that
5093 * depends on the result of the method call is inaccessible, so the
5094 * fact that we can't fully verify anything that comes after the bad
5095 * call is not a problem.
5096 *
5097 * We must also consider the case of multiple code paths, only some of
5098 * which involve a null reference. We can completely verify the method
5099 * if we sidestep the results of executing with a null reference.
5100 * For example, if on the first pass through the code we try to do a
5101 * virtual method invocation through a null ref, we have to skip the
5102 * method checks and have the method return a "wildcard" type (which
5103 * merges with anything to become that other thing). The move-result
5104 * will tell us if it's a reference, single-word numeric, or double-word
5105 * value. We continue to perform the verification, and at the end of
5106 * the function any invocations that were never fully exercised are
5107 * marked as null-only.
5108 *
5109 * We would do something similar for the field accesses. The field's
5110 * type, once known, can be used to recover the width of short integers.
5111 * If the object reference was null, the field-get returns the "wildcard"
5112 * type, which is acceptable for any operation.
5113 */
5114 case OP_EXECUTE_INLINE:
5115 case OP_INVOKE_DIRECT_EMPTY:
5116 case OP_IGET_QUICK:
5117 case OP_IGET_WIDE_QUICK:
5118 case OP_IGET_OBJECT_QUICK:
5119 case OP_IPUT_QUICK:
5120 case OP_IPUT_WIDE_QUICK:
5121 case OP_IPUT_OBJECT_QUICK:
5122 case OP_INVOKE_VIRTUAL_QUICK:
5123 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
5124 case OP_INVOKE_SUPER_QUICK:
5125 case OP_INVOKE_SUPER_QUICK_RANGE:
Andy McFadden62a75162009-04-17 17:23:37 -07005126 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005127 break;
5128
5129 /* these should never appear */
5130 case OP_UNUSED_3E:
5131 case OP_UNUSED_3F:
5132 case OP_UNUSED_40:
5133 case OP_UNUSED_41:
5134 case OP_UNUSED_42:
5135 case OP_UNUSED_43:
5136 case OP_UNUSED_73:
5137 case OP_UNUSED_79:
5138 case OP_UNUSED_7A:
5139 case OP_UNUSED_E3:
5140 case OP_UNUSED_E4:
5141 case OP_UNUSED_E5:
5142 case OP_UNUSED_E6:
5143 case OP_UNUSED_E7:
5144 case OP_UNUSED_E8:
5145 case OP_UNUSED_E9:
5146 case OP_UNUSED_EA:
5147 case OP_UNUSED_EB:
5148 case OP_UNUSED_EC:
5149 case OP_UNUSED_ED:
5150 case OP_UNUSED_EF:
5151 case OP_UNUSED_F1:
5152 case OP_UNUSED_FC:
5153 case OP_UNUSED_FD:
5154 case OP_UNUSED_FE:
5155 case OP_UNUSED_FF:
Andy McFadden62a75162009-04-17 17:23:37 -07005156 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005157 break;
5158
5159 /*
5160 * DO NOT add a "default" clause here. Without it the compiler will
5161 * complain if an instruction is missing (which is desirable).
5162 */
5163 }
5164
Andy McFadden62a75162009-04-17 17:23:37 -07005165 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005166 LOG_VFY_METH(meth, "VFY: rejecting opcode 0x%02x at 0x%04x\n",
5167 decInsn.opCode, insnIdx);
5168 goto bail;
5169 }
5170
5171 /*
5172 * If we didn't just set the result register, clear it out. This
5173 * ensures that you can only use "move-result" immediately after the
5174 * result is set.
5175 */
5176 if (!justSetResult) {
5177 int reg = RESULT_REGISTER(insnRegCount);
5178 workRegs[reg] = workRegs[reg+1] = kRegTypeUnknown;
5179 }
5180
5181 /*
5182 * Handle "continue". Tag the next consecutive instruction.
5183 */
5184 if ((nextFlags & kInstrCanContinue) != 0) {
5185 int insnWidth = dvmInsnGetWidth(insnFlags, insnIdx);
5186 if (insnIdx+insnWidth >= insnsSize) {
5187 LOG_VFY_METH(meth,
5188 "VFY: execution can walk off end of code area (from 0x%x)\n",
5189 insnIdx);
5190 goto bail;
5191 }
5192
5193 /*
5194 * The only way to get to a move-exception instruction is to get
5195 * thrown there. Make sure the next instruction isn't one.
5196 */
5197 if (!checkMoveException(meth, insnIdx+insnWidth, "next"))
5198 goto bail;
5199
5200 /*
5201 * We want to update the registers and set the "changed" flag on the
5202 * next instruction (if necessary). We may not be storing register
5203 * changes for all addresses, so for non-branch targets we just
5204 * compare "entry" vs. "work" to see if we've changed anything.
5205 */
5206 if (getRegisterLine(regTable, insnIdx+insnWidth) != NULL) {
5207 updateRegisters(meth, insnFlags, regTable, insnIdx+insnWidth,
5208 workRegs);
5209 } else {
The Android Open Source Project99409882009-03-18 22:20:24 -07005210 /*
5211 * We didn't record register data for the next entry, so we have
5212 * to assume that something has changed and re-evaluate it.
5213 */
5214 dvmInsnSetChanged(insnFlags, insnIdx+insnWidth, true);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005215 }
5216 }
5217
5218 /*
5219 * Handle "branch". Tag the branch target.
5220 *
5221 * NOTE: instructions like OP_EQZ provide information about the state
5222 * of the register when the branch is taken or not taken. For example,
5223 * somebody could get a reference field, check it for zero, and if the
5224 * branch is taken immediately store that register in a boolean field
5225 * since the value is known to be zero. We do not currently account for
5226 * that, and will reject the code.
5227 */
5228 if ((nextFlags & kInstrCanBranch) != 0) {
5229 bool isConditional;
5230
5231 if (!dvmGetBranchTarget(meth, insnFlags, insnIdx, &branchTarget,
5232 &isConditional))
5233 {
5234 /* should never happen after static verification */
5235 LOG_VFY_METH(meth, "VFY: bad branch at %d\n", insnIdx);
5236 goto bail;
5237 }
5238 assert(isConditional || (nextFlags & kInstrCanContinue) == 0);
5239 assert(!isConditional || (nextFlags & kInstrCanContinue) != 0);
5240
5241 if (!checkMoveException(meth, insnIdx+branchTarget, "branch"))
5242 goto bail;
5243
The Android Open Source Project99409882009-03-18 22:20:24 -07005244 /* update branch target, set "changed" if appropriate */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005245 updateRegisters(meth, insnFlags, regTable, insnIdx+branchTarget,
5246 workRegs);
5247 }
5248
5249 /*
5250 * Handle "switch". Tag all possible branch targets.
5251 *
5252 * We've already verified that the table is structurally sound, so we
5253 * just need to walk through and tag the targets.
5254 */
5255 if ((nextFlags & kInstrCanSwitch) != 0) {
5256 int offsetToSwitch = insns[1] | (((s4)insns[2]) << 16);
5257 const u2* switchInsns = insns + offsetToSwitch;
5258 int switchCount = switchInsns[1];
5259 int offsetToTargets, targ;
5260
5261 if ((*insns & 0xff) == OP_PACKED_SWITCH) {
5262 /* 0=sig, 1=count, 2/3=firstKey */
5263 offsetToTargets = 4;
5264 } else {
5265 /* 0=sig, 1=count, 2..count*2 = keys */
5266 assert((*insns & 0xff) == OP_SPARSE_SWITCH);
5267 offsetToTargets = 2 + 2*switchCount;
5268 }
5269
5270 /* verify each switch target */
5271 for (targ = 0; targ < switchCount; targ++) {
5272 int offset, absOffset;
5273
5274 /* offsets are 32-bit, and only partly endian-swapped */
5275 offset = switchInsns[offsetToTargets + targ*2] |
5276 (((s4) switchInsns[offsetToTargets + targ*2 +1]) << 16);
5277 absOffset = insnIdx + offset;
5278
5279 assert(absOffset >= 0 && absOffset < insnsSize);
5280
5281 if (!checkMoveException(meth, absOffset, "switch"))
5282 goto bail;
5283
5284 updateRegisters(meth, insnFlags, regTable, absOffset, workRegs);
5285 }
5286 }
5287
5288 /*
5289 * Handle instructions that can throw and that are sitting in a
5290 * "try" block. (If they're not in a "try" block when they throw,
5291 * control transfers out of the method.)
5292 */
5293 if ((nextFlags & kInstrCanThrow) != 0 && dvmInsnIsInTry(insnFlags, insnIdx))
5294 {
5295 DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
5296 const DexCode* pCode = dvmGetMethodCode(meth);
5297 DexCatchIterator iterator;
5298
5299 if (dexFindCatchHandler(&iterator, pCode, insnIdx)) {
5300 for (;;) {
5301 DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
5302
5303 if (handler == NULL) {
5304 break;
5305 }
5306
5307 /* note we use entryRegs, not workRegs */
5308 updateRegisters(meth, insnFlags, regTable, handler->address,
5309 entryRegs);
5310 }
5311 }
5312 }
5313
5314 /*
5315 * Update startGuess. Advance to the next instruction of that's
5316 * possible, otherwise use the branch target if one was found. If
5317 * neither of those exists we're in a return or throw; leave startGuess
5318 * alone and let the caller sort it out.
5319 */
5320 if ((nextFlags & kInstrCanContinue) != 0) {
5321 *pStartGuess = insnIdx + dvmInsnGetWidth(insnFlags, insnIdx);
5322 } else if ((nextFlags & kInstrCanBranch) != 0) {
5323 /* we're still okay if branchTarget is zero */
5324 *pStartGuess = insnIdx + branchTarget;
5325 }
5326
5327 assert(*pStartGuess >= 0 && *pStartGuess < insnsSize &&
5328 dvmInsnGetWidth(insnFlags, *pStartGuess) != 0);
5329
5330 result = true;
5331
5332bail:
5333 return result;
5334}
5335
5336/*
5337 * callback function used in dumpRegTypes to print local vars
5338 * valid at a given address.
5339 */
5340static void logLocalsCb(void *cnxt, u2 reg, u4 startAddress, u4 endAddress,
5341 const char *name, const char *descriptor,
5342 const char *signature)
5343{
5344 int addr = *((int *)cnxt);
5345
5346 if (addr >= (int) startAddress && addr < (int) endAddress)
5347 {
5348 LOGI(" %2d: '%s' %s\n", reg, name, descriptor);
5349 }
5350}
5351
5352/*
5353 * Dump the register types for the specifed address to the log file.
5354 */
5355static void dumpRegTypes(const Method* meth, const InsnFlags* insnFlags,
5356 const RegType* addrRegs, int addr, const char* addrName,
5357 const UninitInstanceMap* uninitMap, int displayFlags)
5358{
5359 int regCount = meth->registersSize;
5360 int fullRegCount = regCount + kExtraRegs;
5361 bool branchTarget = dvmInsnIsBranchTarget(insnFlags, addr);
5362 int i;
5363
5364 assert(addr >= 0 && addr < (int) dvmGetMethodInsnsSize(meth));
5365
5366 int regCharSize = fullRegCount + (fullRegCount-1)/4 + 2 +1;
5367 char regChars[regCharSize +1];
5368 memset(regChars, ' ', regCharSize);
5369 regChars[0] = '[';
5370 if (regCount == 0)
5371 regChars[1] = ']';
5372 else
5373 regChars[1 + (regCount-1) + (regCount-1)/4 +1] = ']';
5374 regChars[regCharSize] = '\0';
5375
5376 //const RegType* addrRegs = getRegisterLine(regTable, addr);
5377
5378 for (i = 0; i < regCount + kExtraRegs; i++) {
5379 char tch;
5380
5381 switch (addrRegs[i]) {
5382 case kRegTypeUnknown: tch = '.'; break;
5383 case kRegTypeConflict: tch = 'X'; break;
5384 case kRegTypeFloat: tch = 'F'; break;
5385 case kRegTypeZero: tch = '0'; break;
5386 case kRegTypeOne: tch = '1'; break;
5387 case kRegTypeBoolean: tch = 'Z'; break;
5388 case kRegTypePosByte: tch = 'b'; break;
5389 case kRegTypeByte: tch = 'B'; break;
5390 case kRegTypePosShort: tch = 's'; break;
5391 case kRegTypeShort: tch = 'S'; break;
5392 case kRegTypeChar: tch = 'C'; break;
5393 case kRegTypeInteger: tch = 'I'; break;
5394 case kRegTypeLongLo: tch = 'J'; break;
5395 case kRegTypeLongHi: tch = 'j'; break;
5396 case kRegTypeDoubleLo: tch = 'D'; break;
5397 case kRegTypeDoubleHi: tch = 'd'; break;
5398 default:
5399 if (regTypeIsReference(addrRegs[i])) {
5400 if (regTypeIsUninitReference(addrRegs[i]))
5401 tch = 'U';
5402 else
5403 tch = 'L';
5404 } else {
5405 tch = '*';
5406 assert(false);
5407 }
5408 break;
5409 }
5410
5411 if (i < regCount)
5412 regChars[1 + i + (i/4)] = tch;
5413 else
5414 regChars[1 + i + (i/4) + 2] = tch;
5415 }
5416
5417 if (addr == 0 && addrName != NULL)
5418 LOGI("%c%s %s\n", branchTarget ? '>' : ' ', addrName, regChars);
5419 else
5420 LOGI("%c0x%04x %s\n", branchTarget ? '>' : ' ', addr, regChars);
5421
5422 if (displayFlags & DRT_SHOW_REF_TYPES) {
5423 for (i = 0; i < regCount + kExtraRegs; i++) {
5424 if (regTypeIsReference(addrRegs[i]) && addrRegs[i] != kRegTypeZero)
5425 {
5426 ClassObject* clazz;
5427
5428 clazz = regTypeReferenceToClass(addrRegs[i], uninitMap);
5429 assert(dvmValidateObject((Object*)clazz));
5430 if (i < regCount) {
5431 LOGI(" %2d: 0x%08x %s%s\n",
5432 i, addrRegs[i],
5433 regTypeIsUninitReference(addrRegs[i]) ? "[U]" : "",
5434 clazz->descriptor);
5435 } else {
5436 LOGI(" RS: 0x%08x %s%s\n",
5437 addrRegs[i],
5438 regTypeIsUninitReference(addrRegs[i]) ? "[U]" : "",
5439 clazz->descriptor);
5440 }
5441 }
5442 }
5443 }
5444 if (displayFlags & DRT_SHOW_LOCALS) {
5445 dexDecodeDebugInfo(meth->clazz->pDvmDex->pDexFile,
5446 dvmGetMethodCode(meth),
5447 meth->clazz->descriptor,
5448 meth->prototype.protoIdx,
5449 meth->accessFlags,
5450 NULL, logLocalsCb, &addr);
5451 }
5452}
5453