blob: 5bb546ae2f997ea73611f9e4b5f92343e2376c32 [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);
Andy McFaddenb51ea112009-05-08 16:50:17 -0700123static bool doCodeVerification(Method* meth, InsnFlags* insnFlags,\
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800124 RegisterTable* regTable, UninitInstanceMap* uninitMap);
Andy McFaddenb51ea112009-05-08 16:50:17 -0700125static bool verifyInstruction(Method* meth, InsnFlags* insnFlags,\
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800126 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
Andy McFaddenb51ea112009-05-08 16:50:17 -07001058 LOGI("Could not find method %s.%s, referenced from "
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001059 "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 McFaddenb51ea112009-05-08 16:50:17 -07001072 if (VERIFY_OK(*pFailure)) /* not set for interface resolve */
1073 *pFailure = VERIFY_ERROR_NO_METHOD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001074 goto fail;
1075 }
1076
1077 /*
1078 * Only time you can explicitly call a method starting with '<' is when
1079 * making a "direct" invocation on "<init>". There are additional
1080 * restrictions but we don't enforce them here.
1081 */
1082 if (resMethod->name[0] == '<') {
1083 if (methodType != METHOD_DIRECT || !isInitMethod(resMethod)) {
1084 LOG_VFY("VFY: invalid call to %s.%s\n",
1085 resMethod->clazz->descriptor, resMethod->name);
1086 goto bad_sig;
1087 }
1088 }
1089
1090 /*
1091 * If we're using invoke-super(method), make sure that the executing
1092 * method's class' superclass has a vtable entry for the target method.
1093 */
1094 if (isSuper) {
1095 assert(methodType == METHOD_VIRTUAL);
1096 ClassObject* super = meth->clazz->super;
1097 if (super == NULL || resMethod->methodIndex > super->vtableCount) {
1098 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1099 LOG_VFY("VFY: invalid invoke-super from %s.%s to super %s.%s %s\n",
1100 meth->clazz->descriptor, meth->name,
1101 (super == NULL) ? "-" : super->descriptor,
1102 resMethod->name, desc);
1103 free(desc);
Andy McFadden62a75162009-04-17 17:23:37 -07001104 *pFailure = VERIFY_ERROR_NO_METHOD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001105 goto fail;
1106 }
1107 }
1108
1109 /*
1110 * We use vAA as our expected arg count, rather than resMethod->insSize,
1111 * because we need to match the call to the signature. Also, we might
1112 * might be calling through an abstract method definition (which doesn't
1113 * have register count values).
1114 */
1115 sigOriginal = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1116 const char* sig = sigOriginal;
1117 int expectedArgs = pDecInsn->vA;
1118 int actualArgs = 0;
1119
1120 if (!isRange && expectedArgs > 5) {
1121 LOG_VFY("VFY: invalid arg count in non-range invoke (%d)\n",
1122 pDecInsn->vA);
1123 goto fail;
1124 }
1125 if (expectedArgs > meth->outsSize) {
1126 LOG_VFY("VFY: invalid arg count (%d) exceeds outsSize (%d)\n",
1127 expectedArgs, meth->outsSize);
1128 goto fail;
1129 }
1130
1131 if (*sig++ != '(')
1132 goto bad_sig;
1133
1134 /*
1135 * Check the "this" argument, which must be an instance of the class
1136 * that declared the method. For an interface class, we don't do the
1137 * full interface merge, so we can't do a rigorous check here (which
1138 * is okay since we have to do it at runtime).
1139 */
1140 if (!dvmIsStaticMethod(resMethod)) {
1141 ClassObject* actualThisRef;
1142 RegType actualArgType;
1143
1144 actualArgType = getInvocationThis(insnRegs, insnRegCount, pDecInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07001145 pFailure);
1146 if (!VERIFY_OK(*pFailure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001147 goto fail;
1148
1149 if (regTypeIsUninitReference(actualArgType) && resMethod->name[0] != '<')
1150 {
1151 LOG_VFY("VFY: 'this' arg must be initialized\n");
1152 goto fail;
1153 }
1154 if (methodType != METHOD_INTERFACE && actualArgType != kRegTypeZero) {
1155 actualThisRef = regTypeReferenceToClass(actualArgType, uninitMap);
1156 if (!dvmInstanceof(actualThisRef, resMethod->clazz)) {
1157 LOG_VFY("VFY: 'this' arg '%s' not instance of '%s'\n",
1158 actualThisRef->descriptor,
1159 resMethod->clazz->descriptor);
1160 goto fail;
1161 }
1162 }
1163 actualArgs++;
1164 }
1165
1166 /*
1167 * Process the target method's signature. This signature may or may not
1168 * have been verified, so we can't assume it's properly formed.
1169 */
1170 while (*sig != '\0' && *sig != ')') {
1171 if (actualArgs >= expectedArgs) {
1172 LOG_VFY("VFY: expected %d args, found more (%c)\n",
1173 expectedArgs, *sig);
1174 goto bad_sig;
1175 }
1176
1177 u4 getReg;
1178 if (isRange)
1179 getReg = pDecInsn->vC + actualArgs;
1180 else
1181 getReg = pDecInsn->arg[actualArgs];
1182
1183 switch (*sig) {
1184 case 'L':
1185 {
Andy McFadden62a75162009-04-17 17:23:37 -07001186 ClassObject* clazz = lookupSignatureClass(meth, &sig, pFailure);
1187 if (!VERIFY_OK(*pFailure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001188 goto bad_sig;
1189 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001190 regTypeFromClass(clazz), pFailure);
1191 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001192 LOG_VFY("VFY: bad arg %d (into %s)\n",
1193 actualArgs, clazz->descriptor);
1194 goto bad_sig;
1195 }
1196 }
1197 actualArgs++;
1198 break;
1199 case '[':
1200 {
1201 ClassObject* clazz =
Andy McFadden62a75162009-04-17 17:23:37 -07001202 lookupSignatureArrayClass(meth, &sig, pFailure);
1203 if (!VERIFY_OK(*pFailure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001204 goto bad_sig;
1205 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001206 regTypeFromClass(clazz), pFailure);
1207 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001208 LOG_VFY("VFY: bad arg %d (into %s)\n",
1209 actualArgs, clazz->descriptor);
1210 goto bad_sig;
1211 }
1212 }
1213 actualArgs++;
1214 break;
1215 case 'Z':
1216 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001217 kRegTypeBoolean, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001218 actualArgs++;
1219 break;
1220 case 'C':
1221 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001222 kRegTypeChar, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001223 actualArgs++;
1224 break;
1225 case 'B':
1226 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001227 kRegTypeByte, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001228 actualArgs++;
1229 break;
1230 case 'I':
1231 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001232 kRegTypeInteger, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001233 actualArgs++;
1234 break;
1235 case 'S':
1236 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001237 kRegTypeShort, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001238 actualArgs++;
1239 break;
1240 case 'F':
1241 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001242 kRegTypeFloat, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001243 actualArgs++;
1244 break;
1245 case 'D':
1246 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001247 kRegTypeDoubleLo, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001248 actualArgs += 2;
1249 break;
1250 case 'J':
1251 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001252 kRegTypeLongLo, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001253 actualArgs += 2;
1254 break;
1255 default:
1256 LOG_VFY("VFY: invocation target: bad signature type char '%c'\n",
1257 *sig);
1258 goto bad_sig;
1259 }
1260
1261 sig++;
1262 }
1263 if (*sig != ')') {
1264 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1265 LOG_VFY("VFY: invocation target: bad signature '%s'\n", desc);
1266 free(desc);
1267 goto bad_sig;
1268 }
1269
1270 if (actualArgs != expectedArgs) {
1271 LOG_VFY("VFY: expected %d args, found %d\n", expectedArgs, actualArgs);
1272 goto bad_sig;
1273 }
1274
1275 free(sigOriginal);
1276 return resMethod;
1277
1278bad_sig:
1279 if (resMethod != NULL) {
1280 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1281 LOG_VFY("VFY: rejecting call to %s.%s %s\n",
Andy McFadden62a75162009-04-17 17:23:37 -07001282 resMethod->clazz->descriptor, resMethod->name, desc);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001283 free(desc);
1284 }
1285
1286fail:
1287 free(sigOriginal);
Andy McFadden62a75162009-04-17 17:23:37 -07001288 if (*pFailure == VERIFY_ERROR_NONE)
1289 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001290 return NULL;
1291}
1292
1293/*
1294 * Get the class object for the type of data stored in a field. This isn't
1295 * stored in the Field struct, so we have to recover it from the signature.
1296 *
1297 * This only works for reference types. Don't call this for primitive types.
1298 *
1299 * If we can't find the class, we return java.lang.Object, so that
1300 * verification can continue if a field is only accessed in trivial ways.
1301 */
1302static ClassObject* getFieldClass(const Method* meth, const Field* field)
1303{
1304 ClassObject* fieldClass;
1305 const char* signature = field->signature;
1306
1307 if ((*signature == 'L') || (*signature == '[')) {
1308 fieldClass = dvmFindClassNoInit(signature,
1309 meth->clazz->classLoader);
1310 } else {
1311 return NULL;
1312 }
1313
1314 if (fieldClass == NULL) {
1315 dvmClearOptException(dvmThreadSelf());
1316 LOGV("VFY: unable to find class '%s' for field %s.%s, trying Object\n",
1317 field->signature, meth->clazz->descriptor, field->name);
1318 fieldClass = gDvm.classJavaLangObject;
1319 } else {
1320 assert(!dvmIsPrimitiveClass(fieldClass));
1321 }
1322 return fieldClass;
1323}
1324
1325
1326/*
1327 * ===========================================================================
1328 * Register operations
1329 * ===========================================================================
1330 */
1331
1332/*
1333 * Get the type of register N, verifying that the register is valid.
1334 *
Andy McFadden62a75162009-04-17 17:23:37 -07001335 * Sets "*pFailure" appropriately if the register number is out of range.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001336 */
1337static inline RegType getRegisterType(const RegType* insnRegs,
Andy McFadden62a75162009-04-17 17:23:37 -07001338 const int insnRegCount, u4 vsrc, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001339{
1340 RegType type;
1341
1342 if (vsrc >= (u4) insnRegCount) {
Andy McFadden62a75162009-04-17 17:23:37 -07001343 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001344 return kRegTypeUnknown;
1345 } else {
1346 return insnRegs[vsrc];
1347 }
1348}
1349
1350/*
1351 * Get the value from a register, and cast it to a ClassObject. Sets
Andy McFadden62a75162009-04-17 17:23:37 -07001352 * "*pFailure" if something fails.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001353 *
1354 * This fails if the register holds an uninitialized class.
1355 *
1356 * If the register holds kRegTypeZero, this returns a NULL pointer.
1357 */
1358static ClassObject* getClassFromRegister(const RegType* insnRegs,
Andy McFadden62a75162009-04-17 17:23:37 -07001359 const int insnRegCount, u4 vsrc, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001360{
1361 ClassObject* clazz = NULL;
1362 RegType type;
1363
1364 /* get the element type of the array held in vsrc */
Andy McFadden62a75162009-04-17 17:23:37 -07001365 type = getRegisterType(insnRegs, insnRegCount, vsrc, pFailure);
1366 if (!VERIFY_OK(*pFailure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001367 goto bail;
1368
1369 /* if "always zero", we allow it to fail at runtime */
1370 if (type == kRegTypeZero)
1371 goto bail;
1372
1373 if (!regTypeIsReference(type)) {
1374 LOG_VFY("VFY: tried to get class from non-ref register v%d (type=%d)\n",
1375 vsrc, type);
Andy McFadden62a75162009-04-17 17:23:37 -07001376 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001377 goto bail;
1378 }
1379 if (regTypeIsUninitReference(type)) {
1380 LOG_VFY("VFY: register %u holds uninitialized reference\n", vsrc);
Andy McFadden62a75162009-04-17 17:23:37 -07001381 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001382 goto bail;
1383 }
1384
1385 clazz = regTypeInitializedReferenceToClass(type);
1386
1387bail:
1388 return clazz;
1389}
1390
1391/*
1392 * Get the "this" pointer from a non-static method invocation. This
1393 * returns the RegType so the caller can decide whether it needs the
1394 * reference to be initialized or not. (Can also return kRegTypeZero
1395 * if the reference can only be zero at this point.)
1396 *
1397 * The argument count is in vA, and the first argument is in vC, for both
1398 * "simple" and "range" versions. We just need to make sure vA is >= 1
1399 * and then return vC.
1400 */
1401static RegType getInvocationThis(const RegType* insnRegs,
Andy McFadden62a75162009-04-17 17:23:37 -07001402 const int insnRegCount, const DecodedInstruction* pDecInsn,
1403 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001404{
1405 RegType thisType = kRegTypeUnknown;
1406
1407 if (pDecInsn->vA < 1) {
1408 LOG_VFY("VFY: invoke lacks 'this'\n");
Andy McFadden62a75162009-04-17 17:23:37 -07001409 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001410 goto bail;
1411 }
1412
1413 /* get the element type of the array held in vsrc */
Andy McFadden62a75162009-04-17 17:23:37 -07001414 thisType = getRegisterType(insnRegs, insnRegCount, pDecInsn->vC, pFailure);
1415 if (!VERIFY_OK(*pFailure)) {
1416 LOG_VFY("VFY: failed to get 'this' from register %u\n", pDecInsn->vC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001417 goto bail;
1418 }
1419
1420 if (!regTypeIsReference(thisType)) {
1421 LOG_VFY("VFY: tried to get class from non-ref register v%d (type=%d)\n",
1422 pDecInsn->vC, thisType);
Andy McFadden62a75162009-04-17 17:23:37 -07001423 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001424 goto bail;
1425 }
1426
1427bail:
1428 return thisType;
1429}
1430
1431/*
1432 * Set the type of register N, verifying that the register is valid. If
1433 * "newType" is the "Lo" part of a 64-bit value, register N+1 will be
1434 * set to "newType+1".
1435 *
Andy McFadden62a75162009-04-17 17:23:37 -07001436 * Sets "*pFailure" if the register number is out of range.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001437 */
1438static void setRegisterType(RegType* insnRegs, const int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001439 u4 vdst, RegType newType, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001440{
1441 //LOGD("set-reg v%u = %d\n", vdst, newType);
1442 switch (newType) {
1443 case kRegTypeUnknown:
1444 case kRegTypeBoolean:
1445 case kRegTypeOne:
1446 case kRegTypeByte:
1447 case kRegTypePosByte:
1448 case kRegTypeShort:
1449 case kRegTypePosShort:
1450 case kRegTypeChar:
1451 case kRegTypeInteger:
1452 case kRegTypeFloat:
1453 case kRegTypeZero:
1454 if (vdst >= (u4) insnRegCount) {
Andy McFadden62a75162009-04-17 17:23:37 -07001455 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001456 } else {
1457 insnRegs[vdst] = newType;
1458 }
1459 break;
1460 case kRegTypeLongLo:
1461 case kRegTypeDoubleLo:
1462 if (vdst+1 >= (u4) insnRegCount) {
Andy McFadden62a75162009-04-17 17:23:37 -07001463 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001464 } else {
1465 insnRegs[vdst] = newType;
1466 insnRegs[vdst+1] = newType+1;
1467 }
1468 break;
1469 case kRegTypeLongHi:
1470 case kRegTypeDoubleHi:
1471 /* should never set these explicitly */
Andy McFadden62a75162009-04-17 17:23:37 -07001472 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001473 break;
1474
1475 case kRegTypeUninit:
1476 default:
1477 if (regTypeIsReference(newType)) {
1478 if (vdst >= (u4) insnRegCount) {
Andy McFadden62a75162009-04-17 17:23:37 -07001479 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001480 break;
1481 }
1482 insnRegs[vdst] = newType;
1483
1484 /*
1485 * In most circumstances we won't see a reference to a primitive
1486 * class here (e.g. "D"), since that would mean the object in the
1487 * register is actually a primitive type. It can happen as the
1488 * result of an assumed-successful check-cast instruction in
1489 * which the second argument refers to a primitive class. (In
1490 * practice, such an instruction will always throw an exception.)
1491 *
1492 * This is not an issue for instructions like const-class, where
1493 * the object in the register is a java.lang.Class instance.
1494 */
1495 break;
1496 }
1497 /* bad - fall through */
1498
1499 case kRegTypeConflict: // should only be set during a merge
1500 LOG_VFY("Unexpected set type %d\n", newType);
1501 assert(false);
Andy McFadden62a75162009-04-17 17:23:37 -07001502 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001503 break;
1504 }
1505}
1506
1507/*
1508 * Verify that the contents of the specified register have the specified
1509 * type (or can be converted to it through an implicit widening conversion).
1510 *
1511 * In theory we could use this to modify the type of the source register,
1512 * e.g. a generic 32-bit constant, once used as a float, would thereafter
1513 * remain a float. There is no compelling reason to require this though.
1514 *
1515 * If "vsrc" is a reference, both it and the "vsrc" register must be
1516 * initialized ("vsrc" may be Zero). This will verify that the value in
1517 * the register is an instance of checkType, or if checkType is an
1518 * interface, verify that the register implements checkType.
1519 */
1520static void verifyRegisterType(const RegType* insnRegs, const int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001521 u4 vsrc, RegType checkType, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001522{
1523 if (vsrc >= (u4) insnRegCount) {
Andy McFadden62a75162009-04-17 17:23:37 -07001524 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001525 return;
1526 }
1527
1528 RegType srcType = insnRegs[vsrc];
1529
1530 //LOGD("check-reg v%u = %d\n", vsrc, checkType);
1531 switch (checkType) {
1532 case kRegTypeFloat:
1533 case kRegTypeBoolean:
1534 case kRegTypePosByte:
1535 case kRegTypeByte:
1536 case kRegTypePosShort:
1537 case kRegTypeShort:
1538 case kRegTypeChar:
1539 case kRegTypeInteger:
1540 if (!canConvertTo1nr(srcType, checkType)) {
1541 LOG_VFY("VFY: register1 v%u type %d, wanted %d\n",
1542 vsrc, srcType, checkType);
Andy McFadden62a75162009-04-17 17:23:37 -07001543 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001544 }
1545 break;
1546 case kRegTypeLongLo:
1547 case kRegTypeDoubleLo:
1548 if (vsrc+1 >= (u4) insnRegCount) {
1549 LOG_VFY("VFY: register2 v%u out of range (%d)\n",
1550 vsrc, insnRegCount);
Andy McFadden62a75162009-04-17 17:23:37 -07001551 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001552 } else if (insnRegs[vsrc+1] != srcType+1) {
1553 LOG_VFY("VFY: register2 v%u-%u values %d,%d\n",
1554 vsrc, vsrc+1, insnRegs[vsrc], insnRegs[vsrc+1]);
Andy McFadden62a75162009-04-17 17:23:37 -07001555 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001556 } else if (!canConvertTo2(srcType, checkType)) {
1557 LOG_VFY("VFY: register2 v%u type %d, wanted %d\n",
1558 vsrc, srcType, checkType);
Andy McFadden62a75162009-04-17 17:23:37 -07001559 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001560 }
1561 break;
1562
1563 case kRegTypeLongHi:
1564 case kRegTypeDoubleHi:
1565 case kRegTypeZero:
1566 case kRegTypeOne:
1567 case kRegTypeUnknown:
1568 case kRegTypeConflict:
1569 /* should never be checking for these explicitly */
1570 assert(false);
Andy McFadden62a75162009-04-17 17:23:37 -07001571 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001572 return;
1573 case kRegTypeUninit:
1574 default:
1575 /* make sure checkType is initialized reference */
1576 if (!regTypeIsReference(checkType)) {
1577 LOG_VFY("VFY: unexpected check type %d\n", checkType);
1578 assert(false);
Andy McFadden62a75162009-04-17 17:23:37 -07001579 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001580 break;
1581 }
1582 if (regTypeIsUninitReference(checkType)) {
1583 LOG_VFY("VFY: uninitialized ref not expected as reg check\n");
Andy McFadden62a75162009-04-17 17:23:37 -07001584 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001585 break;
1586 }
1587 /* make sure srcType is initialized reference or always-NULL */
1588 if (!regTypeIsReference(srcType)) {
1589 LOG_VFY("VFY: register1 v%u type %d, wanted ref\n", vsrc, srcType);
Andy McFadden62a75162009-04-17 17:23:37 -07001590 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001591 break;
1592 }
1593 if (regTypeIsUninitReference(srcType)) {
1594 LOG_VFY("VFY: register1 v%u holds uninitialized ref\n", vsrc);
Andy McFadden62a75162009-04-17 17:23:37 -07001595 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001596 break;
1597 }
1598 /* if the register isn't Zero, make sure it's an instance of check */
1599 if (srcType != kRegTypeZero) {
1600 ClassObject* srcClass = regTypeInitializedReferenceToClass(srcType);
1601 ClassObject* checkClass = regTypeInitializedReferenceToClass(checkType);
1602 assert(srcClass != NULL);
1603 assert(checkClass != NULL);
1604
1605 if (dvmIsInterfaceClass(checkClass)) {
1606 /*
1607 * All objects implement all interfaces as far as the
1608 * verifier is concerned. The runtime has to sort it out.
1609 * See comments above findCommonSuperclass.
1610 */
1611 /*
1612 if (srcClass != checkClass &&
1613 !dvmImplements(srcClass, checkClass))
1614 {
1615 LOG_VFY("VFY: %s does not implement %s\n",
1616 srcClass->descriptor, checkClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07001617 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001618 }
1619 */
1620 } else {
1621 if (!dvmInstanceof(srcClass, checkClass)) {
1622 LOG_VFY("VFY: %s is not instance of %s\n",
1623 srcClass->descriptor, checkClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07001624 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001625 }
1626 }
1627 }
1628 break;
1629 }
1630}
1631
1632/*
1633 * Set the type of the "result" register. Mostly this exists to expand
1634 * "insnRegCount" to encompass the result register.
1635 */
1636static void setResultRegisterType(RegType* insnRegs, const int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001637 RegType newType, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001638{
1639 setRegisterType(insnRegs, insnRegCount + kExtraRegs,
Andy McFadden62a75162009-04-17 17:23:37 -07001640 RESULT_REGISTER(insnRegCount), newType, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001641}
1642
1643
1644/*
1645 * Update all registers holding "uninitType" to instead hold the
1646 * corresponding initialized reference type. This is called when an
1647 * appropriate <init> method is invoked -- all copies of the reference
1648 * must be marked as initialized.
1649 */
1650static void markRefsAsInitialized(RegType* insnRegs, int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001651 UninitInstanceMap* uninitMap, RegType uninitType, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001652{
1653 ClassObject* clazz;
1654 RegType initType;
1655 int i, changed;
1656
1657 clazz = dvmGetUninitInstance(uninitMap, regTypeToUninitIndex(uninitType));
1658 if (clazz == NULL) {
1659 LOGE("VFY: unable to find type=0x%x (idx=%d)\n",
1660 uninitType, regTypeToUninitIndex(uninitType));
Andy McFadden62a75162009-04-17 17:23:37 -07001661 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001662 return;
1663 }
1664 initType = regTypeFromClass(clazz);
1665
1666 changed = 0;
1667 for (i = 0; i < insnRegCount; i++) {
1668 if (insnRegs[i] == uninitType) {
1669 insnRegs[i] = initType;
1670 changed++;
1671 }
1672 }
1673 //LOGD("VFY: marked %d registers as initialized\n", changed);
1674 assert(changed > 0);
1675
1676 return;
1677}
1678
1679/*
1680 * We're creating a new instance of class C at address A. Any registers
1681 * holding instances previously created at address A must be initialized
1682 * by now. If not, we mark them as "conflict" to prevent them from being
1683 * used (otherwise, markRefsAsInitialized would mark the old ones and the
1684 * new ones at the same time).
1685 */
1686static void markUninitRefsAsInvalid(RegType* insnRegs, int insnRegCount,
1687 UninitInstanceMap* uninitMap, RegType uninitType)
1688{
1689 int i, changed;
1690
1691 changed = 0;
1692 for (i = 0; i < insnRegCount; i++) {
1693 if (insnRegs[i] == uninitType) {
1694 insnRegs[i] = kRegTypeConflict;
1695 changed++;
1696 }
1697 }
1698
1699 //if (changed)
1700 // LOGD("VFY: marked %d uninitialized registers as invalid\n", changed);
1701}
1702
1703/*
1704 * Find the start of the register set for the specified instruction in
1705 * the current method.
1706 */
1707static inline RegType* getRegisterLine(const RegisterTable* regTable,
1708 int insnIdx)
1709{
1710 return regTable->addrRegs[insnIdx];
1711}
1712
1713/*
1714 * Copy a bunch of registers.
1715 */
1716static inline void copyRegisters(RegType* dst, const RegType* src,
1717 int numRegs)
1718{
1719 memcpy(dst, src, numRegs * sizeof(RegType));
1720}
1721
1722/*
1723 * Compare a bunch of registers.
1724 *
1725 * Returns 0 if they match. Using this for a sort is unwise, since the
1726 * value can change based on machine endianness.
1727 */
1728static inline int compareRegisters(const RegType* src1, const RegType* src2,
1729 int numRegs)
1730{
1731 return memcmp(src1, src2, numRegs * sizeof(RegType));
1732}
1733
1734/*
1735 * Register type categories, for type checking.
1736 *
1737 * The spec says category 1 includes boolean, byte, char, short, int, float,
1738 * reference, and returnAddress. Category 2 includes long and double.
1739 *
1740 * We treat object references separately, so we have "category1nr". We
1741 * don't support jsr/ret, so there is no "returnAddress" type.
1742 */
1743typedef enum TypeCategory {
1744 kTypeCategoryUnknown = 0,
1745 kTypeCategory1nr, // byte, char, int, float, boolean
1746 kTypeCategory2, // long, double
1747 kTypeCategoryRef, // object reference
1748} TypeCategory;
1749
1750/*
1751 * See if "type" matches "cat". All we're really looking for here is that
1752 * we're not mixing and matching 32-bit and 64-bit quantities, and we're
1753 * not mixing references with numerics. (For example, the arguments to
1754 * "a < b" could be integers of different sizes, but they must both be
1755 * integers. Dalvik is less specific about int vs. float, so we treat them
1756 * as equivalent here.)
1757 *
1758 * For category 2 values, "type" must be the "low" half of the value.
1759 *
Andy McFadden62a75162009-04-17 17:23:37 -07001760 * Sets "*pFailure" if something looks wrong.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001761 */
Andy McFadden62a75162009-04-17 17:23:37 -07001762static void checkTypeCategory(RegType type, TypeCategory cat,
1763 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001764{
1765 switch (cat) {
1766 case kTypeCategory1nr:
1767 switch (type) {
1768 case kRegTypeFloat:
1769 case kRegTypeZero:
1770 case kRegTypeOne:
1771 case kRegTypeBoolean:
1772 case kRegTypePosByte:
1773 case kRegTypeByte:
1774 case kRegTypePosShort:
1775 case kRegTypeShort:
1776 case kRegTypeChar:
1777 case kRegTypeInteger:
1778 break;
1779 default:
Andy McFadden62a75162009-04-17 17:23:37 -07001780 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001781 break;
1782 }
1783 break;
1784
1785 case kTypeCategory2:
1786 switch (type) {
1787 case kRegTypeLongLo:
1788 case kRegTypeDoubleLo:
1789 break;
1790 default:
Andy McFadden62a75162009-04-17 17:23:37 -07001791 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001792 break;
1793 }
1794 break;
1795
1796 case kTypeCategoryRef:
1797 if (type != kRegTypeZero && !regTypeIsReference(type))
Andy McFadden62a75162009-04-17 17:23:37 -07001798 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001799 break;
1800
1801 default:
1802 assert(false);
Andy McFadden62a75162009-04-17 17:23:37 -07001803 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001804 break;
1805 }
1806}
1807
1808/*
1809 * For a category 2 register pair, verify that "typeh" is the appropriate
1810 * high part for "typel".
1811 *
1812 * Does not verify that "typel" is in fact the low part of a 64-bit
1813 * register pair.
1814 */
Andy McFadden62a75162009-04-17 17:23:37 -07001815static void checkWidePair(RegType typel, RegType typeh, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001816{
1817 if ((typeh != typel+1))
Andy McFadden62a75162009-04-17 17:23:37 -07001818 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001819}
1820
1821/*
1822 * Implement category-1 "move" instructions. Copy a 32-bit value from
1823 * "vsrc" to "vdst".
1824 *
1825 * "insnRegCount" is the number of registers available. The "vdst" and
1826 * "vsrc" values are checked against this.
1827 */
1828static void copyRegister1(RegType* insnRegs, int insnRegCount, u4 vdst,
Andy McFadden62a75162009-04-17 17:23:37 -07001829 u4 vsrc, TypeCategory cat, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001830{
Andy McFadden62a75162009-04-17 17:23:37 -07001831 RegType type = getRegisterType(insnRegs, insnRegCount, vsrc, pFailure);
1832 if (VERIFY_OK(*pFailure))
1833 checkTypeCategory(type, cat, pFailure);
1834 if (VERIFY_OK(*pFailure))
1835 setRegisterType(insnRegs, insnRegCount, vdst, type, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001836
Andy McFadden62a75162009-04-17 17:23:37 -07001837 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001838 LOG_VFY("VFY: copy1 v%u<-v%u type=%d cat=%d\n", vdst, vsrc, type, cat);
1839 }
1840}
1841
1842/*
1843 * Implement category-2 "move" instructions. Copy a 64-bit value from
1844 * "vsrc" to "vdst". This copies both halves of the register.
1845 */
1846static void copyRegister2(RegType* insnRegs, int insnRegCount, u4 vdst,
Andy McFadden62a75162009-04-17 17:23:37 -07001847 u4 vsrc, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001848{
Andy McFadden62a75162009-04-17 17:23:37 -07001849 RegType typel = getRegisterType(insnRegs, insnRegCount, vsrc, pFailure);
1850 RegType typeh = getRegisterType(insnRegs, insnRegCount, vsrc+1, pFailure);
1851 if (VERIFY_OK(*pFailure)) {
1852 checkTypeCategory(typel, kTypeCategory2, pFailure);
1853 checkWidePair(typel, typeh, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001854 }
Andy McFadden62a75162009-04-17 17:23:37 -07001855 if (VERIFY_OK(*pFailure))
1856 setRegisterType(insnRegs, insnRegCount, vdst, typel, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001857
Andy McFadden62a75162009-04-17 17:23:37 -07001858 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001859 LOG_VFY("VFY: copy2 v%u<-v%u type=%d/%d\n", vdst, vsrc, typel, typeh);
1860 }
1861}
1862
1863/*
1864 * Implement "move-result". Copy the category-1 value from the result
1865 * register to another register, and reset the result register.
1866 *
1867 * We can't just call copyRegister1 with an altered insnRegCount,
1868 * because that would affect the test on "vdst" as well.
1869 */
1870static void copyResultRegister1(RegType* insnRegs, const int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001871 u4 vdst, TypeCategory cat, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001872{
1873 RegType type;
1874 u4 vsrc;
1875
1876 vsrc = RESULT_REGISTER(insnRegCount);
Andy McFadden62a75162009-04-17 17:23:37 -07001877 type = getRegisterType(insnRegs, insnRegCount + kExtraRegs, vsrc, pFailure);
1878 if (VERIFY_OK(*pFailure))
1879 checkTypeCategory(type, cat, pFailure);
1880 if (VERIFY_OK(*pFailure)) {
1881 setRegisterType(insnRegs, insnRegCount, vdst, type, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001882 insnRegs[vsrc] = kRegTypeUnknown;
1883 }
1884
Andy McFadden62a75162009-04-17 17:23:37 -07001885 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001886 LOG_VFY("VFY: copyRes1 v%u<-v%u cat=%d type=%d\n",
1887 vdst, vsrc, cat, type);
1888 }
1889}
1890
1891/*
1892 * Implement "move-result-wide". Copy the category-2 value from the result
1893 * register to another register, and reset the result register.
1894 *
1895 * We can't just call copyRegister2 with an altered insnRegCount,
1896 * because that would affect the test on "vdst" as well.
1897 */
1898static void copyResultRegister2(RegType* insnRegs, const int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001899 u4 vdst, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001900{
1901 RegType typel, typeh;
1902 u4 vsrc;
1903
1904 vsrc = RESULT_REGISTER(insnRegCount);
Andy McFadden62a75162009-04-17 17:23:37 -07001905 typel = getRegisterType(insnRegs, insnRegCount + kExtraRegs, vsrc,
1906 pFailure);
1907 typeh = getRegisterType(insnRegs, insnRegCount + kExtraRegs, vsrc+1,
1908 pFailure);
1909 if (VERIFY_OK(*pFailure)) {
1910 checkTypeCategory(typel, kTypeCategory2, pFailure);
1911 checkWidePair(typel, typeh, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001912 }
Andy McFadden62a75162009-04-17 17:23:37 -07001913 if (VERIFY_OK(*pFailure)) {
1914 setRegisterType(insnRegs, insnRegCount, vdst, typel, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001915 insnRegs[vsrc] = kRegTypeUnknown;
1916 insnRegs[vsrc+1] = kRegTypeUnknown;
1917 }
1918
Andy McFadden62a75162009-04-17 17:23:37 -07001919 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001920 LOG_VFY("VFY: copyRes2 v%u<-v%u type=%d/%d\n",
1921 vdst, vsrc, typel, typeh);
1922 }
1923}
1924
1925/*
1926 * Verify types for a simple two-register instruction (e.g. "neg-int").
1927 * "dstType" is stored into vA, and "srcType" is verified against vB.
1928 */
1929static void checkUnop(RegType* insnRegs, const int insnRegCount,
1930 DecodedInstruction* pDecInsn, RegType dstType, RegType srcType,
Andy McFadden62a75162009-04-17 17:23:37 -07001931 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001932{
Andy McFadden62a75162009-04-17 17:23:37 -07001933 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType, pFailure);
1934 setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001935}
1936
1937/*
1938 * We're performing an operation like "and-int/2addr" that can be
1939 * performed on booleans as well as integers. We get no indication of
1940 * boolean-ness, but we can infer it from the types of the arguments.
1941 *
1942 * Assumes we've already validated reg1/reg2.
1943 *
Andy McFaddenb5f64bc2009-06-10 14:11:07 -07001944 * TODO: consider generalizing this. The key principle is that the
1945 * result of a bitwise operation can only be as wide as the widest of
1946 * the operands. You can safely AND/OR/XOR two chars together and know
1947 * you still have a char, so it's reasonable for the compiler or "dx"
1948 * to skip the int-to-char instruction. (We need to do this for boolean
1949 * because there is no int-to-boolean operation.)
1950 *
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001951 * Returns true if both args are Boolean, Zero, or One.
1952 */
1953static bool upcastBooleanOp(RegType* insnRegs, const int insnRegCount,
1954 u4 reg1, u4 reg2)
1955{
1956 RegType type1, type2;
1957
1958 type1 = insnRegs[reg1];
1959 type2 = insnRegs[reg2];
1960
1961 if ((type1 == kRegTypeBoolean || type1 == kRegTypeZero ||
1962 type1 == kRegTypeOne) &&
1963 (type2 == kRegTypeBoolean || type2 == kRegTypeZero ||
1964 type2 == kRegTypeOne))
1965 {
1966 return true;
1967 }
1968 return false;
1969}
1970
1971/*
1972 * Verify types for A two-register instruction with a literal constant
1973 * (e.g. "add-int/lit8"). "dstType" is stored into vA, and "srcType" is
1974 * verified against vB.
1975 *
1976 * If "checkBooleanOp" is set, we use the constant value in vC.
1977 */
1978static void checkLitop(RegType* insnRegs, const int insnRegCount,
1979 DecodedInstruction* pDecInsn, RegType dstType, RegType srcType,
Andy McFadden62a75162009-04-17 17:23:37 -07001980 bool checkBooleanOp, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001981{
Andy McFadden62a75162009-04-17 17:23:37 -07001982 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType, pFailure);
1983 if (VERIFY_OK(*pFailure) && checkBooleanOp) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001984 assert(dstType == kRegTypeInteger);
1985 /* check vB with the call, then check the constant manually */
1986 if (upcastBooleanOp(insnRegs, insnRegCount, pDecInsn->vB, pDecInsn->vB)
1987 && (pDecInsn->vC == 0 || pDecInsn->vC == 1))
1988 {
1989 dstType = kRegTypeBoolean;
1990 }
1991 }
Andy McFadden62a75162009-04-17 17:23:37 -07001992 setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001993}
1994
1995/*
1996 * Verify types for a simple three-register instruction (e.g. "add-int").
1997 * "dstType" is stored into vA, and "srcType1"/"srcType2" are verified
1998 * against vB/vC.
1999 */
2000static void checkBinop(RegType* insnRegs, const int insnRegCount,
2001 DecodedInstruction* pDecInsn, RegType dstType, RegType srcType1,
Andy McFadden62a75162009-04-17 17:23:37 -07002002 RegType srcType2, bool checkBooleanOp, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002003{
Andy McFadden62a75162009-04-17 17:23:37 -07002004 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType1,
2005 pFailure);
2006 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vC, srcType2,
2007 pFailure);
2008 if (VERIFY_OK(*pFailure) && checkBooleanOp) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002009 assert(dstType == kRegTypeInteger);
2010 if (upcastBooleanOp(insnRegs, insnRegCount, pDecInsn->vB, pDecInsn->vC))
2011 dstType = kRegTypeBoolean;
2012 }
Andy McFadden62a75162009-04-17 17:23:37 -07002013 setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002014}
2015
2016/*
2017 * Verify types for a binary "2addr" operation. "srcType1"/"srcType2"
2018 * are verified against vA/vB, then "dstType" is stored into vA.
2019 */
2020static void checkBinop2addr(RegType* insnRegs, const int insnRegCount,
2021 DecodedInstruction* pDecInsn, RegType dstType, RegType srcType1,
Andy McFadden62a75162009-04-17 17:23:37 -07002022 RegType srcType2, bool checkBooleanOp, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002023{
Andy McFadden62a75162009-04-17 17:23:37 -07002024 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vA, srcType1,
2025 pFailure);
2026 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType2,
2027 pFailure);
2028 if (VERIFY_OK(*pFailure) && checkBooleanOp) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002029 assert(dstType == kRegTypeInteger);
2030 if (upcastBooleanOp(insnRegs, insnRegCount, pDecInsn->vA, pDecInsn->vB))
2031 dstType = kRegTypeBoolean;
2032 }
Andy McFadden62a75162009-04-17 17:23:37 -07002033 setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002034}
2035
2036
2037/*
2038 * ===========================================================================
2039 * Register merge
2040 * ===========================================================================
2041 */
2042
2043/*
2044 * Compute the "class depth" of a class. This is the distance from the
2045 * class to the top of the tree, chasing superclass links. java.lang.Object
2046 * has a class depth of 0.
2047 */
2048static int getClassDepth(ClassObject* clazz)
2049{
2050 int depth = 0;
2051
2052 while (clazz->super != NULL) {
2053 clazz = clazz->super;
2054 depth++;
2055 }
2056 return depth;
2057}
2058
2059/*
2060 * Given two classes, walk up the superclass tree to find a common
2061 * ancestor. (Called from findCommonSuperclass().)
2062 *
2063 * TODO: consider caching the class depth in the class object so we don't
2064 * have to search for it here.
2065 */
2066static ClassObject* digForSuperclass(ClassObject* c1, ClassObject* c2)
2067{
2068 int depth1, depth2;
2069
2070 depth1 = getClassDepth(c1);
2071 depth2 = getClassDepth(c2);
2072
2073 if (gDebugVerbose) {
2074 LOGVV("COMMON: %s(%d) + %s(%d)\n",
2075 c1->descriptor, depth1, c2->descriptor, depth2);
2076 }
2077
2078 /* pull the deepest one up */
2079 if (depth1 > depth2) {
2080 while (depth1 > depth2) {
2081 c1 = c1->super;
2082 depth1--;
2083 }
2084 } else {
2085 while (depth2 > depth1) {
2086 c2 = c2->super;
2087 depth2--;
2088 }
2089 }
2090
2091 /* walk up in lock-step */
2092 while (c1 != c2) {
2093 c1 = c1->super;
2094 c2 = c2->super;
2095
2096 assert(c1 != NULL && c2 != NULL);
2097 }
2098
2099 if (gDebugVerbose) {
2100 LOGVV(" : --> %s\n", c1->descriptor);
2101 }
2102 return c1;
2103}
2104
2105/*
2106 * Merge two array classes. We can't use the general "walk up to the
2107 * superclass" merge because the superclass of an array is always Object.
2108 * We want String[] + Integer[] = Object[]. This works for higher dimensions
2109 * as well, e.g. String[][] + Integer[][] = Object[][].
2110 *
2111 * If Foo1 and Foo2 are subclasses of Foo, Foo1[] + Foo2[] = Foo[].
2112 *
2113 * If Class implements Type, Class[] + Type[] = Type[].
2114 *
2115 * If the dimensions don't match, we want to convert to an array of Object
2116 * with the least dimension, e.g. String[][] + String[][][][] = Object[][].
2117 *
2118 * This gets a little awkward because we may have to ask the VM to create
2119 * a new array type with the appropriate element and dimensions. However, we
2120 * shouldn't be doing this often.
2121 */
2122static ClassObject* findCommonArraySuperclass(ClassObject* c1, ClassObject* c2)
2123{
2124 ClassObject* arrayClass = NULL;
2125 ClassObject* commonElem;
2126 int i, numDims;
2127
2128 assert(c1->arrayDim > 0);
2129 assert(c2->arrayDim > 0);
2130
2131 if (c1->arrayDim == c2->arrayDim) {
2132 //commonElem = digForSuperclass(c1->elementClass, c2->elementClass);
2133 commonElem = findCommonSuperclass(c1->elementClass, c2->elementClass);
2134 numDims = c1->arrayDim;
2135 } else {
2136 if (c1->arrayDim < c2->arrayDim)
2137 numDims = c1->arrayDim;
2138 else
2139 numDims = c2->arrayDim;
2140 commonElem = c1->super; // == java.lang.Object
2141 }
2142
2143 /* walk from the element to the (multi-)dimensioned array type */
2144 for (i = 0; i < numDims; i++) {
2145 arrayClass = dvmFindArrayClassForElement(commonElem);
2146 commonElem = arrayClass;
2147 }
2148
2149 LOGVV("ArrayMerge '%s' + '%s' --> '%s'\n",
2150 c1->descriptor, c2->descriptor, arrayClass->descriptor);
2151 return arrayClass;
2152}
2153
2154/*
2155 * Find the first common superclass of the two classes. We're not
2156 * interested in common interfaces.
2157 *
2158 * The easiest way to do this for concrete classes is to compute the "class
2159 * depth" of each, move up toward the root of the deepest one until they're
2160 * at the same depth, then walk both up to the root until they match.
2161 *
2162 * If both classes are arrays of non-primitive types, we need to merge
2163 * based on array depth and element type.
2164 *
2165 * If one class is an interface, we check to see if the other class/interface
2166 * (or one of its predecessors) implements the interface. If so, we return
2167 * the interface; otherwise, we return Object.
2168 *
2169 * NOTE: we continue the tradition of "lazy interface handling". To wit,
2170 * suppose we have three classes:
2171 * One implements Fancy, Free
2172 * Two implements Fancy, Free
2173 * Three implements Free
2174 * where Fancy and Free are unrelated interfaces. The code requires us
2175 * to merge One into Two. Ideally we'd use a common interface, which
2176 * gives us a choice between Fancy and Free, and no guidance on which to
2177 * use. If we use Free, we'll be okay when Three gets merged in, but if
2178 * we choose Fancy, we're hosed. The "ideal" solution is to create a
2179 * set of common interfaces and carry that around, merging further references
2180 * into it. This is a pain. The easy solution is to simply boil them
2181 * down to Objects and let the runtime invokeinterface call fail, which
2182 * is what we do.
2183 */
2184static ClassObject* findCommonSuperclass(ClassObject* c1, ClassObject* c2)
2185{
2186 assert(!dvmIsPrimitiveClass(c1) && !dvmIsPrimitiveClass(c2));
2187
2188 if (c1 == c2)
2189 return c1;
2190
2191 if (dvmIsInterfaceClass(c1) && dvmImplements(c2, c1)) {
2192 if (gDebugVerbose)
2193 LOGVV("COMMON/I1: %s + %s --> %s\n",
2194 c1->descriptor, c2->descriptor, c1->descriptor);
2195 return c1;
2196 }
2197 if (dvmIsInterfaceClass(c2) && dvmImplements(c1, c2)) {
2198 if (gDebugVerbose)
2199 LOGVV("COMMON/I2: %s + %s --> %s\n",
2200 c1->descriptor, c2->descriptor, c2->descriptor);
2201 return c2;
2202 }
2203
2204 if (dvmIsArrayClass(c1) && dvmIsArrayClass(c2) &&
2205 !dvmIsPrimitiveClass(c1->elementClass) &&
2206 !dvmIsPrimitiveClass(c2->elementClass))
2207 {
2208 return findCommonArraySuperclass(c1, c2);
2209 }
2210
2211 return digForSuperclass(c1, c2);
2212}
2213
2214/*
2215 * Merge two RegType values.
2216 *
2217 * Sets "*pChanged" to "true" if the result doesn't match "type1".
2218 */
2219static RegType mergeTypes(RegType type1, RegType type2, bool* pChanged)
2220{
2221 RegType result;
2222
2223 /*
2224 * Check for trivial case so we don't have to hit memory.
2225 */
2226 if (type1 == type2)
2227 return type1;
2228
2229 /*
2230 * Use the table if we can, and reject any attempts to merge something
2231 * from the table with a reference type.
2232 *
2233 * The uninitialized table entry at index zero *will* show up as a
2234 * simple kRegTypeUninit value. Since this cannot be merged with
2235 * anything but itself, the rules do the right thing.
2236 */
2237 if (type1 < kRegTypeMAX) {
2238 if (type2 < kRegTypeMAX) {
2239 result = gDvmMergeTab[type1][type2];
2240 } else {
2241 /* simple + reference == conflict, usually */
2242 if (type1 == kRegTypeZero)
2243 result = type2;
2244 else
2245 result = kRegTypeConflict;
2246 }
2247 } else {
2248 if (type2 < kRegTypeMAX) {
2249 /* reference + simple == conflict, usually */
2250 if (type2 == kRegTypeZero)
2251 result = type1;
2252 else
2253 result = kRegTypeConflict;
2254 } else {
2255 /* merging two references */
2256 if (regTypeIsUninitReference(type1) ||
2257 regTypeIsUninitReference(type2))
2258 {
2259 /* can't merge uninit with anything but self */
2260 result = kRegTypeConflict;
2261 } else {
2262 ClassObject* clazz1 = regTypeInitializedReferenceToClass(type1);
2263 ClassObject* clazz2 = regTypeInitializedReferenceToClass(type2);
2264 ClassObject* mergedClass;
2265
2266 mergedClass = findCommonSuperclass(clazz1, clazz2);
2267 assert(mergedClass != NULL);
2268 result = regTypeFromClass(mergedClass);
2269 }
2270 }
2271 }
2272
2273 if (result != type1)
2274 *pChanged = true;
2275 return result;
2276}
2277
2278/*
2279 * Control can transfer to "nextInsn".
2280 *
2281 * Merge the registers from "workRegs" into "regTypes" at "nextInsn", and
2282 * set the "changed" flag on the target address if the registers have changed.
2283 */
2284static void updateRegisters(const Method* meth, InsnFlags* insnFlags,
2285 RegisterTable* regTable, int nextInsn, const RegType* workRegs)
2286{
2287 RegType* targetRegs = getRegisterLine(regTable, nextInsn);
2288 const int insnRegCount = meth->registersSize;
2289
2290#if 0
2291 if (!dvmInsnIsBranchTarget(insnFlags, nextInsn)) {
2292 LOGE("insnFlags[0x%x]=0x%08x\n", nextInsn, insnFlags[nextInsn]);
2293 LOGE(" In %s.%s %s\n",
2294 meth->clazz->descriptor, meth->name, meth->descriptor);
2295 assert(false);
2296 }
2297#endif
2298
2299 if (!dvmInsnIsVisitedOrChanged(insnFlags, nextInsn)) {
2300 /*
2301 * We haven't processed this instruction before, and we haven't
2302 * touched the registers here, so there's nothing to "merge". Copy
2303 * the registers over and mark it as changed. (This is the only
2304 * way a register can transition out of "unknown", so this is not
2305 * just an optimization.)
2306 */
2307 LOGVV("COPY into 0x%04x\n", nextInsn);
2308 copyRegisters(targetRegs, workRegs, insnRegCount + kExtraRegs);
2309 dvmInsnSetChanged(insnFlags, nextInsn, true);
2310 } else {
2311 if (gDebugVerbose) {
2312 LOGVV("MERGE into 0x%04x\n", nextInsn);
2313 //dumpRegTypes(meth, insnFlags, targetRegs, 0, "targ", NULL, 0);
2314 //dumpRegTypes(meth, insnFlags, workRegs, 0, "work", NULL, 0);
2315 }
2316 /* merge registers, set Changed only if different */
2317 bool changed = false;
2318 int i;
2319
2320 for (i = 0; i < insnRegCount + kExtraRegs; i++) {
2321 targetRegs[i] = mergeTypes(targetRegs[i], workRegs[i], &changed);
2322 }
2323
2324 if (gDebugVerbose) {
2325 //LOGI(" RESULT (changed=%d)\n", changed);
2326 //dumpRegTypes(meth, insnFlags, targetRegs, 0, "rslt", NULL, 0);
2327 }
2328
2329 if (changed)
2330 dvmInsnSetChanged(insnFlags, nextInsn, true);
2331 }
2332}
2333
2334
2335/*
2336 * ===========================================================================
2337 * Utility functions
2338 * ===========================================================================
2339 */
2340
2341/*
2342 * Look up an instance field, specified by "fieldIdx", that is going to be
2343 * accessed in object "objType". This resolves the field and then verifies
2344 * that the class containing the field is an instance of the reference in
2345 * "objType".
2346 *
2347 * It is possible for "objType" to be kRegTypeZero, meaning that we might
2348 * have a null reference. This is a runtime problem, so we allow it,
2349 * skipping some of the type checks.
2350 *
2351 * In general, "objType" must be an initialized reference. However, we
2352 * allow it to be uninitialized if this is an "<init>" method and the field
2353 * is declared within the "objType" class.
2354 *
Andy McFadden62a75162009-04-17 17:23:37 -07002355 * Returns an InstField on success, returns NULL and sets "*pFailure"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002356 * on failure.
2357 */
2358static InstField* getInstField(const Method* meth,
2359 const UninitInstanceMap* uninitMap, RegType objType, int fieldIdx,
Andy McFadden62a75162009-04-17 17:23:37 -07002360 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002361{
2362 InstField* instField = NULL;
2363 ClassObject* objClass;
2364 bool mustBeLocal = false;
2365
2366 if (!regTypeIsReference(objType)) {
Andy McFadden62a75162009-04-17 17:23:37 -07002367 LOG_VFY("VFY: attempt to access field in non-reference type %d\n",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002368 objType);
Andy McFadden62a75162009-04-17 17:23:37 -07002369 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002370 goto bail;
2371 }
2372
Andy McFadden62a75162009-04-17 17:23:37 -07002373 instField = dvmOptResolveInstField(meth->clazz, fieldIdx, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002374 if (instField == NULL) {
2375 LOG_VFY("VFY: unable to resolve instance field %u\n", fieldIdx);
Andy McFadden62a75162009-04-17 17:23:37 -07002376 assert(!VERIFY_OK(*pFailure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002377 goto bail;
2378 }
2379
2380 if (objType == kRegTypeZero)
2381 goto bail;
2382
2383 /*
2384 * Access to fields in uninitialized objects is allowed if this is
2385 * the <init> method for the object and the field in question is
2386 * declared by this class.
2387 */
2388 objClass = regTypeReferenceToClass(objType, uninitMap);
2389 assert(objClass != NULL);
2390 if (regTypeIsUninitReference(objType)) {
2391 if (!isInitMethod(meth) || meth->clazz != objClass) {
2392 LOG_VFY("VFY: attempt to access field via uninitialized ref\n");
Andy McFadden62a75162009-04-17 17:23:37 -07002393 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002394 goto bail;
2395 }
2396 mustBeLocal = true;
2397 }
2398
2399 if (!dvmInstanceof(objClass, instField->field.clazz)) {
2400 LOG_VFY("VFY: invalid field access (field %s.%s, through %s ref)\n",
2401 instField->field.clazz->descriptor, instField->field.name,
2402 objClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07002403 *pFailure = VERIFY_ERROR_NO_FIELD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002404 goto bail;
2405 }
2406
2407 if (mustBeLocal) {
2408 /* for uninit ref, make sure it's defined by this class, not super */
2409 if (instField < objClass->ifields ||
2410 instField >= objClass->ifields + objClass->ifieldCount)
2411 {
2412 LOG_VFY("VFY: invalid constructor field access (field %s in %s)\n",
2413 instField->field.name, objClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07002414 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002415 goto bail;
2416 }
2417 }
2418
2419bail:
2420 return instField;
2421}
2422
2423/*
2424 * Look up a static field.
2425 *
Andy McFadden62a75162009-04-17 17:23:37 -07002426 * Returns a StaticField on success, returns NULL and sets "*pFailure"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002427 * on failure.
2428 */
2429static StaticField* getStaticField(const Method* meth, int fieldIdx,
Andy McFadden62a75162009-04-17 17:23:37 -07002430 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002431{
2432 StaticField* staticField;
2433
Andy McFadden62a75162009-04-17 17:23:37 -07002434 staticField = dvmOptResolveStaticField(meth->clazz, fieldIdx, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002435 if (staticField == NULL) {
2436 DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
2437 const DexFieldId* pFieldId;
2438
2439 pFieldId = dexGetFieldId(pDexFile, fieldIdx);
2440
2441 LOG_VFY("VFY: unable to resolve static field %u (%s) in %s\n", fieldIdx,
2442 dexStringById(pDexFile, pFieldId->nameIdx),
2443 dexStringByTypeIdx(pDexFile, pFieldId->classIdx));
Andy McFadden62a75162009-04-17 17:23:37 -07002444 assert(!VERIFY_OK(*pFailure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002445 goto bail;
2446 }
2447
2448bail:
2449 return staticField;
2450}
2451
2452/*
2453 * If "field" is marked "final", make sure this is the either <clinit>
2454 * or <init> as appropriate.
2455 *
Andy McFadden62a75162009-04-17 17:23:37 -07002456 * Sets "*pFailure" on failure.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002457 */
2458static void checkFinalFieldAccess(const Method* meth, const Field* field,
Andy McFadden62a75162009-04-17 17:23:37 -07002459 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002460{
2461 if (!dvmIsFinalField(field))
2462 return;
2463
2464 /* make sure we're in the same class */
2465 if (meth->clazz != field->clazz) {
2466 LOG_VFY_METH(meth, "VFY: can't modify final field %s.%s\n",
2467 field->clazz->descriptor, field->name);
Andy McFaddenb51ea112009-05-08 16:50:17 -07002468 *pFailure = VERIFY_ERROR_ACCESS_FIELD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002469 return;
2470 }
2471
2472 /*
Andy McFadden62a75162009-04-17 17:23:37 -07002473 * The VM spec descriptions of putfield and putstatic say that
2474 * IllegalAccessError is only thrown when the instructions appear
2475 * outside the declaring class. Our earlier attempts to restrict
2476 * final field modification to constructors are, therefore, wrong.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002477 */
2478#if 0
2479 /* make sure we're in the right kind of constructor */
2480 if (dvmIsStaticField(field)) {
2481 if (!isClassInitMethod(meth)) {
2482 LOG_VFY_METH(meth,
2483 "VFY: can't modify final static field outside <clinit>\n");
Andy McFadden62a75162009-04-17 17:23:37 -07002484 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002485 }
2486 } else {
2487 if (!isInitMethod(meth)) {
2488 LOG_VFY_METH(meth,
2489 "VFY: can't modify final field outside <init>\n");
Andy McFadden62a75162009-04-17 17:23:37 -07002490 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002491 }
2492 }
2493#endif
2494}
2495
2496/*
2497 * Make sure that the register type is suitable for use as an array index.
2498 *
Andy McFadden62a75162009-04-17 17:23:37 -07002499 * Sets "*pFailure" if not.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002500 */
2501static void checkArrayIndexType(const Method* meth, RegType regType,
Andy McFadden62a75162009-04-17 17:23:37 -07002502 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002503{
Andy McFadden62a75162009-04-17 17:23:37 -07002504 if (VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002505 /*
2506 * The 1nr types are interchangeable at this level. We could
2507 * do something special if we can definitively identify it as a
2508 * float, but there's no real value in doing so.
2509 */
Andy McFadden62a75162009-04-17 17:23:37 -07002510 checkTypeCategory(regType, kTypeCategory1nr, pFailure);
2511 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002512 LOG_VFY_METH(meth, "Invalid reg type for array index (%d)\n",
2513 regType);
2514 }
2515 }
2516}
2517
2518/*
2519 * Check constraints on constructor return. Specifically, make sure that
2520 * the "this" argument got initialized.
2521 *
2522 * The "this" argument to <init> uses code offset kUninitThisArgAddr, which
2523 * puts it at the start of the list in slot 0. If we see a register with
2524 * an uninitialized slot 0 reference, we know it somehow didn't get
2525 * initialized.
2526 *
2527 * Returns "true" if all is well.
2528 */
2529static bool checkConstructorReturn(const Method* meth, const RegType* insnRegs,
2530 const int insnRegCount)
2531{
2532 int i;
2533
2534 if (!isInitMethod(meth))
2535 return true;
2536
2537 RegType uninitThis = regTypeFromUninitIndex(kUninitThisArgSlot);
2538
2539 for (i = 0; i < insnRegCount; i++) {
2540 if (insnRegs[i] == uninitThis) {
2541 LOG_VFY("VFY: <init> returning without calling superclass init\n");
2542 return false;
2543 }
2544 }
2545 return true;
2546}
2547
2548/*
2549 * Verify that the target instruction is not "move-exception". It's important
2550 * that the only way to execute a move-exception is as the first instruction
2551 * of an exception handler.
2552 *
2553 * Returns "true" if all is well, "false" if the target instruction is
2554 * move-exception.
2555 */
2556static bool checkMoveException(const Method* meth, int insnIdx,
2557 const char* logNote)
2558{
2559 assert(insnIdx >= 0 && insnIdx < (int)dvmGetMethodInsnsSize(meth));
2560
2561 if ((meth->insns[insnIdx] & 0xff) == OP_MOVE_EXCEPTION) {
2562 LOG_VFY("VFY: invalid use of move-exception\n");
2563 return false;
2564 }
2565 return true;
2566}
2567
2568/*
2569 * For the "move-exception" instruction at "insnIdx", which must be at an
2570 * exception handler address, determine the first common superclass of
2571 * all exceptions that can land here. (For javac output, we're probably
2572 * looking at multiple spans of bytecode covered by one "try" that lands
2573 * at an exception-specific "catch", but in general the handler could be
2574 * shared for multiple exceptions.)
2575 *
2576 * Returns NULL if no matching exception handler can be found, or if the
2577 * exception is not a subclass of Throwable.
2578 */
Andy McFadden62a75162009-04-17 17:23:37 -07002579static ClassObject* getCaughtExceptionType(const Method* meth, int insnIdx,
2580 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002581{
Andy McFadden62a75162009-04-17 17:23:37 -07002582 VerifyError localFailure;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002583 const DexCode* pCode;
2584 DexFile* pDexFile;
2585 ClassObject* commonSuper = NULL;
Andy McFadden62a75162009-04-17 17:23:37 -07002586 bool foundPossibleHandler = false;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002587 u4 handlersSize;
2588 u4 offset;
2589 u4 i;
2590
2591 pDexFile = meth->clazz->pDvmDex->pDexFile;
2592 pCode = dvmGetMethodCode(meth);
2593
2594 if (pCode->triesSize != 0) {
2595 handlersSize = dexGetHandlersSize(pCode);
2596 offset = dexGetFirstHandlerOffset(pCode);
2597 } else {
2598 handlersSize = 0;
2599 offset = 0;
2600 }
2601
2602 for (i = 0; i < handlersSize; i++) {
2603 DexCatchIterator iterator;
2604 dexCatchIteratorInit(&iterator, pCode, offset);
2605
2606 for (;;) {
2607 const DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
2608
2609 if (handler == NULL) {
2610 break;
2611 }
2612
2613 if (handler->address == (u4) insnIdx) {
2614 ClassObject* clazz;
Andy McFadden62a75162009-04-17 17:23:37 -07002615 foundPossibleHandler = true;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002616
2617 if (handler->typeIdx == kDexNoIndex)
2618 clazz = gDvm.classJavaLangThrowable;
2619 else
Andy McFadden62a75162009-04-17 17:23:37 -07002620 clazz = dvmOptResolveClass(meth->clazz, handler->typeIdx,
2621 &localFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002622
2623 if (clazz == NULL) {
2624 LOG_VFY("VFY: unable to resolve exception class %u (%s)\n",
2625 handler->typeIdx,
2626 dexStringByTypeIdx(pDexFile, handler->typeIdx));
Andy McFadden62a75162009-04-17 17:23:37 -07002627 /* TODO: do we want to keep going? If we don't fail
2628 * this we run the risk of having a non-Throwable
2629 * introduced at runtime. However, that won't pass
2630 * an instanceof test, so is essentially harmless. */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002631 } else {
2632 if (commonSuper == NULL)
2633 commonSuper = clazz;
2634 else
2635 commonSuper = findCommonSuperclass(clazz, commonSuper);
2636 }
2637 }
2638 }
2639
2640 offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
2641 }
2642
2643 if (commonSuper == NULL) {
Andy McFadden62a75162009-04-17 17:23:37 -07002644 /* no catch blocks, or no catches with classes we can find */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002645 LOG_VFY_METH(meth,
2646 "VFY: unable to find exception handler at addr 0x%x\n", insnIdx);
Andy McFadden62a75162009-04-17 17:23:37 -07002647 *pFailure = VERIFY_ERROR_GENERIC;
2648 } else {
2649 // TODO: verify the class is an instance of Throwable?
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002650 }
2651
2652 return commonSuper;
2653}
2654
2655/*
2656 * Initialize the RegisterTable.
2657 *
2658 * Every instruction address can have a different set of information about
2659 * what's in which register, but for verification purposes we only need to
2660 * store it at branch target addresses (because we merge into that).
2661 *
2662 * By zeroing out the storage we are effectively initializing the register
2663 * information to kRegTypeUnknown.
2664 */
2665static bool initRegisterTable(const Method* meth, const InsnFlags* insnFlags,
2666 RegisterTable* regTable, RegisterTrackingMode trackRegsFor)
2667{
2668 const int insnsSize = dvmGetMethodInsnsSize(meth);
2669 int i;
2670
2671 regTable->insnRegCountPlus = meth->registersSize + kExtraRegs;
2672 regTable->addrRegs = (RegType**) calloc(insnsSize, sizeof(RegType*));
2673 if (regTable->addrRegs == NULL)
2674 return false;
2675
2676 assert(insnsSize > 0);
2677
2678 /*
2679 * "All" means "every address that holds the start of an instruction".
2680 * "Branches" and "GcPoints" mean just those addresses.
2681 *
2682 * "GcPoints" fills about half the addresses, "Branches" about 15%.
2683 */
2684 int interestingCount = 0;
2685 //int insnCount = 0;
2686
2687 for (i = 0; i < insnsSize; i++) {
2688 bool interesting;
2689
2690 switch (trackRegsFor) {
2691 case kTrackRegsAll:
2692 interesting = dvmInsnIsOpcode(insnFlags, i);
2693 break;
2694 case kTrackRegsGcPoints:
2695 interesting = dvmInsnIsGcPoint(insnFlags, i) ||
2696 dvmInsnIsBranchTarget(insnFlags, i);
2697 break;
2698 case kTrackRegsBranches:
2699 interesting = dvmInsnIsBranchTarget(insnFlags, i);
2700 break;
2701 default:
2702 dvmAbort();
2703 return false;
2704 }
2705
2706 if (interesting)
2707 interestingCount++;
2708
2709 /* count instructions, for display only */
2710 //if (dvmInsnIsOpcode(insnFlags, i))
2711 // insnCount++;
2712 }
2713
2714 regTable->regAlloc = (RegType*)
2715 calloc(regTable->insnRegCountPlus * interestingCount, sizeof(RegType));
2716 if (regTable->regAlloc == NULL)
2717 return false;
2718
2719 RegType* regPtr = regTable->regAlloc;
2720 for (i = 0; i < insnsSize; i++) {
2721 bool interesting;
2722
2723 switch (trackRegsFor) {
2724 case kTrackRegsAll:
2725 interesting = dvmInsnIsOpcode(insnFlags, i);
2726 break;
2727 case kTrackRegsGcPoints:
2728 interesting = dvmInsnIsGcPoint(insnFlags, i) ||
2729 dvmInsnIsBranchTarget(insnFlags, i);
2730 break;
2731 case kTrackRegsBranches:
2732 interesting = dvmInsnIsBranchTarget(insnFlags, i);
2733 break;
2734 default:
2735 dvmAbort();
2736 return false;
2737 }
2738
2739 if (interesting) {
2740 regTable->addrRegs[i] = regPtr;
2741 regPtr += regTable->insnRegCountPlus;
2742 }
2743 }
2744
2745 //LOGD("Tracking registers for %d, total %d of %d(%d) (%d%%)\n",
2746 // TRACK_REGS_FOR, interestingCount, insnCount, insnsSize,
2747 // (interestingCount*100) / insnCount);
2748
2749 assert(regPtr - regTable->regAlloc ==
2750 regTable->insnRegCountPlus * interestingCount);
2751 assert(regTable->addrRegs[0] != NULL);
2752 return true;
2753}
2754
2755
2756/*
2757 * Verify that the arguments in a filled-new-array instruction are valid.
2758 *
2759 * "resClass" is the class refered to by pDecInsn->vB.
2760 */
2761static void verifyFilledNewArrayRegs(const Method* meth,
2762 const RegType* insnRegs, const int insnRegCount,
2763 const DecodedInstruction* pDecInsn, ClassObject* resClass, bool isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07002764 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002765{
2766 u4 argCount = pDecInsn->vA;
2767 RegType expectedType;
2768 PrimitiveType elemType;
2769 unsigned int ui;
2770
2771 assert(dvmIsArrayClass(resClass));
2772 elemType = resClass->elementClass->primitiveType;
2773 if (elemType == PRIM_NOT) {
2774 expectedType = regTypeFromClass(resClass->elementClass);
2775 } else {
2776 expectedType = primitiveTypeToRegType(elemType);
2777 }
2778 //LOGI("filled-new-array: %s -> %d\n", resClass->descriptor, expectedType);
2779
2780 /*
2781 * Verify each register. If "argCount" is bad, verifyRegisterType()
2782 * will run off the end of the list and fail. It's legal, if silly,
2783 * for argCount to be zero.
2784 */
2785 for (ui = 0; ui < argCount; ui++) {
2786 u4 getReg;
2787
2788 if (isRange)
2789 getReg = pDecInsn->vC + ui;
2790 else
2791 getReg = pDecInsn->arg[ui];
2792
Andy McFadden62a75162009-04-17 17:23:37 -07002793 verifyRegisterType(insnRegs, insnRegCount, getReg, expectedType,
2794 pFailure);
2795 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002796 LOG_VFY("VFY: filled-new-array arg %u(%u) not valid\n", ui, getReg);
2797 return;
2798 }
2799 }
2800}
2801
2802
2803/*
Andy McFaddenb51ea112009-05-08 16:50:17 -07002804 * Replace an instruction with "throw-verification-error". This allows us to
2805 * defer error reporting until the code path is first used.
2806 *
2807 * The throw-verification-error instruction requires two code units. Some
2808 * of the replaced instructions require three; the third code unit will
2809 * receive a "nop". The instruction's length will be left unchanged
2810 * in "insnFlags".
2811 *
2812 * IMPORTANT: this may replace meth->insns with a pointer to a new copy of
2813 * the instructions.
2814 *
2815 * Returns "true" on success.
2816 */
2817static bool replaceFailingInstruction(Method* meth, InsnFlags* insnFlags,
2818 int insnIdx, VerifyError failure)
2819{
2820 const u2* oldInsns = meth->insns + insnIdx;
2821 u2 oldInsn = *oldInsns;
2822 bool result = false;
2823
2824 dvmMakeCodeReadWrite(meth);
2825
2826 //LOGD(" was 0x%04x\n", oldInsn);
2827 u2* newInsns = (u2*) meth->insns + insnIdx;
2828
2829 /*
2830 * Generate the new instruction out of the old.
2831 *
2832 * First, make sure this is an instruction we're expecting to stomp on.
2833 */
2834 switch (oldInsn & 0xff) {
2835 case OP_CONST_CLASS: // insn[1] == class ref, 2 bytes
2836 case OP_CHECK_CAST:
2837 case OP_INSTANCE_OF:
2838 case OP_NEW_INSTANCE:
2839 case OP_NEW_ARRAY:
2840
2841 case OP_FILLED_NEW_ARRAY: // insn[1] == class ref, 3 bytes
2842 case OP_FILLED_NEW_ARRAY_RANGE:
2843
2844 case OP_IGET: // insn[1] == field ref, 2 bytes
2845 case OP_IGET_BOOLEAN:
2846 case OP_IGET_BYTE:
2847 case OP_IGET_CHAR:
2848 case OP_IGET_SHORT:
2849 case OP_IGET_WIDE:
2850 case OP_IGET_OBJECT:
2851 case OP_IPUT:
2852 case OP_IPUT_BOOLEAN:
2853 case OP_IPUT_BYTE:
2854 case OP_IPUT_CHAR:
2855 case OP_IPUT_SHORT:
2856 case OP_IPUT_WIDE:
2857 case OP_IPUT_OBJECT:
2858 case OP_SGET:
2859 case OP_SGET_BOOLEAN:
2860 case OP_SGET_BYTE:
2861 case OP_SGET_CHAR:
2862 case OP_SGET_SHORT:
2863 case OP_SGET_WIDE:
2864 case OP_SGET_OBJECT:
2865 case OP_SPUT:
2866 case OP_SPUT_BOOLEAN:
2867 case OP_SPUT_BYTE:
2868 case OP_SPUT_CHAR:
2869 case OP_SPUT_SHORT:
2870 case OP_SPUT_WIDE:
2871 case OP_SPUT_OBJECT:
2872
2873 case OP_INVOKE_VIRTUAL: // insn[1] == method ref, 3 bytes
2874 case OP_INVOKE_VIRTUAL_RANGE:
2875 case OP_INVOKE_SUPER:
2876 case OP_INVOKE_SUPER_RANGE:
2877 case OP_INVOKE_DIRECT:
2878 case OP_INVOKE_DIRECT_RANGE:
2879 case OP_INVOKE_STATIC:
2880 case OP_INVOKE_STATIC_RANGE:
2881 case OP_INVOKE_INTERFACE:
2882 case OP_INVOKE_INTERFACE_RANGE:
2883 break;
2884 default:
2885 /* could handle this in a generic way, but this is probably safer */
2886 LOG_VFY("GLITCH: verifier asked to replace opcode 0x%02x\n",
2887 oldInsn & 0xff);
2888 goto bail;
2889 }
2890
2891 /* write a NOP over the third code unit, if necessary */
2892 int width = dvmInsnGetWidth(insnFlags, insnIdx);
2893 switch (width) {
2894 case 2:
2895 /* nothing to do */
2896 break;
2897 case 3:
2898 newInsns[2] = OP_NOP;
2899 break;
2900 default:
2901 /* whoops */
2902 LOGE("ERROR: stomped a %d-unit instruction with a verifier error\n",
2903 width);
2904 dvmAbort();
2905 }
2906
2907 /* encode the opcode, with the failure code in the high byte */
2908 newInsns[0] = OP_THROW_VERIFICATION_ERROR | (failure << 8);
2909
2910 result = true;
2911
2912bail:
2913 dvmMakeCodeReadOnly(meth);
2914 return result;
2915}
2916
2917
2918/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002919 * ===========================================================================
2920 * Entry point and driver loop
2921 * ===========================================================================
2922 */
2923
2924/*
2925 * Entry point for the detailed code-flow analysis.
2926 */
Andy McFaddenb51ea112009-05-08 16:50:17 -07002927bool dvmVerifyCodeFlow(Method* meth, InsnFlags* insnFlags,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002928 UninitInstanceMap* uninitMap)
2929{
2930 bool result = false;
2931 const int insnsSize = dvmGetMethodInsnsSize(meth);
2932 const u2* insns = meth->insns;
2933 const bool generateRegisterMap = gDvm.generateRegisterMaps;
2934 int i, offset;
2935 bool isConditional;
2936 RegisterTable regTable;
2937
2938 memset(&regTable, 0, sizeof(regTable));
2939
2940#ifndef NDEBUG
2941 checkMergeTab(); // only need to do this if table gets updated
2942#endif
2943
2944 /*
2945 * We rely on these for verification of const-class, const-string,
2946 * and throw instructions. Make sure we have them.
2947 */
2948 if (gDvm.classJavaLangClass == NULL)
2949 gDvm.classJavaLangClass =
2950 dvmFindSystemClassNoInit("Ljava/lang/Class;");
2951 if (gDvm.classJavaLangString == NULL)
2952 gDvm.classJavaLangString =
2953 dvmFindSystemClassNoInit("Ljava/lang/String;");
Andy McFadden686e1e22009-05-26 16:56:30 -07002954 if (gDvm.classJavaLangThrowable == NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002955 gDvm.classJavaLangThrowable =
2956 dvmFindSystemClassNoInit("Ljava/lang/Throwable;");
Andy McFadden686e1e22009-05-26 16:56:30 -07002957 gDvm.offJavaLangThrowable_cause =
2958 dvmFindFieldOffset(gDvm.classJavaLangThrowable,
2959 "cause", "Ljava/lang/Throwable;");
2960 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002961 if (gDvm.classJavaLangObject == NULL)
2962 gDvm.classJavaLangObject =
2963 dvmFindSystemClassNoInit("Ljava/lang/Object;");
2964
2965 if (meth->registersSize * insnsSize > 2*1024*1024) {
2966 /* should probably base this on actual memory requirements */
2967 LOG_VFY_METH(meth,
2968 "VFY: arbitrarily rejecting large method (regs=%d count=%d)\n",
2969 meth->registersSize, insnsSize);
2970 goto bail;
2971 }
2972
2973 /*
2974 * Create register lists, and initialize them to "Unknown". If we're
2975 * also going to create the register map, we need to retain the
2976 * register lists for a larger set of addresses.
2977 */
2978 if (!initRegisterTable(meth, insnFlags, &regTable,
2979 generateRegisterMap ? kTrackRegsGcPoints : kTrackRegsBranches))
2980 goto bail;
2981
2982 /*
2983 * Initialize the types of the registers that correspond to the
2984 * method arguments. We can determine this from the method signature.
2985 */
2986 if (!setTypesFromSignature(meth, regTable.addrRegs[0], uninitMap))
2987 goto bail;
2988
2989 /*
2990 * Run the verifier.
2991 */
2992 if (!doCodeVerification(meth, insnFlags, &regTable, uninitMap))
2993 goto bail;
2994
2995 /*
2996 * Generate a register map.
2997 */
2998 if (generateRegisterMap) {
2999 RegisterMap* pMap;
3000 VerifierData vd;
3001
3002 vd.method = meth;
3003 vd.insnsSize = insnsSize;
3004 vd.insnRegCount = meth->registersSize;
3005 vd.insnFlags = insnFlags;
3006 vd.addrRegs = regTable.addrRegs;
3007
3008 pMap = dvmGenerateRegisterMapV(&vd);
3009 if (pMap != NULL) {
3010 /*
3011 * Tuck it into the Method struct. It will either get used
3012 * directly or, if we're in dexopt, will be packed up and
3013 * appended to the DEX file.
3014 */
3015 dvmSetRegisterMap((Method*)meth, pMap);
3016 }
3017 }
3018
3019 /*
3020 * Success.
3021 */
3022 result = true;
3023
3024bail:
3025 free(regTable.addrRegs);
3026 free(regTable.regAlloc);
3027 return result;
3028}
3029
3030/*
3031 * Grind through the instructions.
3032 *
3033 * The basic strategy is as outlined in v3 4.11.1.2: set the "changed" bit
3034 * on the first instruction, process it (setting additional "changed" bits),
3035 * and repeat until there are no more.
3036 *
3037 * v3 4.11.1.1
3038 * - (N/A) operand stack is always the same size
3039 * - operand stack [registers] contain the correct types of values
3040 * - local variables [registers] contain the correct types of values
3041 * - methods are invoked with the appropriate arguments
3042 * - fields are assigned using values of appropriate types
3043 * - opcodes have the correct type values in operand registers
3044 * - there is never an uninitialized class instance in a local variable in
3045 * code protected by an exception handler (operand stack is okay, because
3046 * the operand stack is discarded when an exception is thrown) [can't
3047 * know what's a local var w/o the debug info -- should fall out of
3048 * register typing]
3049 *
3050 * v3 4.11.1.2
3051 * - execution cannot fall off the end of the code
3052 *
3053 * (We also do many of the items described in the "static checks" sections,
3054 * because it's easier to do them here.)
3055 *
3056 * We need an array of RegType values, one per register, for every
3057 * instruction. In theory this could become quite large -- up to several
3058 * megabytes for a monster function. For self-preservation we reject
3059 * anything that requires more than a certain amount of memory. (Typical
3060 * "large" should be on the order of 4K code units * 8 registers.) This
3061 * will likely have to be adjusted.
3062 *
3063 *
3064 * The spec forbids backward branches when there's an uninitialized reference
3065 * in a register. The idea is to prevent something like this:
3066 * loop:
3067 * move r1, r0
3068 * new-instance r0, MyClass
3069 * ...
3070 * if-eq rN, loop // once
3071 * initialize r0
3072 *
3073 * This leaves us with two different instances, both allocated by the
3074 * same instruction, but only one is initialized. The scheme outlined in
3075 * v3 4.11.1.4 wouldn't catch this, so they work around it by preventing
3076 * backward branches. We achieve identical results without restricting
3077 * code reordering by specifying that you can't execute the new-instance
3078 * instruction if a register contains an uninitialized instance created
3079 * by that same instrutcion.
3080 */
Andy McFaddenb51ea112009-05-08 16:50:17 -07003081static bool doCodeVerification(Method* meth, InsnFlags* insnFlags,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003082 RegisterTable* regTable, UninitInstanceMap* uninitMap)
3083{
3084 const int insnsSize = dvmGetMethodInsnsSize(meth);
3085 const u2* insns = meth->insns;
3086 RegType workRegs[meth->registersSize + kExtraRegs];
3087 bool result = false;
3088 bool debugVerbose = false;
3089 int insnIdx, startGuess, prevAddr;
3090
3091 /*
3092 * Begin by marking the first instruction as "changed".
3093 */
3094 dvmInsnSetChanged(insnFlags, 0, true);
3095
3096 if (doVerboseLogging(meth)) {
3097 IF_LOGI() {
3098 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
3099 LOGI("Now verifying: %s.%s %s (ins=%d regs=%d)\n",
3100 meth->clazz->descriptor, meth->name, desc,
3101 meth->insSize, meth->registersSize);
3102 LOGI(" ------ [0 4 8 12 16 20 24 28 32 36\n");
3103 free(desc);
3104 }
3105 debugVerbose = true;
3106 gDebugVerbose = true;
3107 } else {
3108 gDebugVerbose = false;
3109 }
3110
3111 startGuess = 0;
3112
3113 /*
3114 * Continue until no instructions are marked "changed".
3115 */
3116 while (true) {
3117 /*
3118 * Find the first marked one. Use "startGuess" as a way to find
3119 * one quickly.
3120 */
3121 for (insnIdx = startGuess; insnIdx < insnsSize; insnIdx++) {
3122 if (dvmInsnIsChanged(insnFlags, insnIdx))
3123 break;
3124 }
3125
3126 if (insnIdx == insnsSize) {
3127 if (startGuess != 0) {
3128 /* try again, starting from the top */
3129 startGuess = 0;
3130 continue;
3131 } else {
3132 /* all flags are clear */
3133 break;
3134 }
3135 }
3136
3137 /*
3138 * We carry the working set of registers from instruction to
3139 * instruction. If this address can be the target of a branch
3140 * (or throw) instruction, or if we're skipping around chasing
3141 * "changed" flags, we need to load the set of registers from
3142 * the table.
3143 *
3144 * Because we always prefer to continue on to the next instruction,
3145 * we should never have a situation where we have a stray
3146 * "changed" flag set on an instruction that isn't a branch target.
3147 */
3148 if (dvmInsnIsBranchTarget(insnFlags, insnIdx)) {
3149 RegType* insnRegs = getRegisterLine(regTable, insnIdx);
3150 assert(insnRegs != NULL);
3151 copyRegisters(workRegs, insnRegs, meth->registersSize + kExtraRegs);
3152
3153 if (debugVerbose) {
3154 dumpRegTypes(meth, insnFlags, workRegs, insnIdx, NULL,uninitMap,
3155 SHOW_REG_DETAILS);
3156 }
3157
3158 } else {
3159 if (debugVerbose) {
3160 dumpRegTypes(meth, insnFlags, workRegs, insnIdx, NULL,uninitMap,
3161 SHOW_REG_DETAILS);
3162 }
3163
3164#ifndef NDEBUG
3165 /*
3166 * Sanity check: retrieve the stored register line (assuming
3167 * a full table) and make sure it actually matches.
3168 */
3169 RegType* insnRegs = getRegisterLine(regTable, insnIdx);
3170 if (insnRegs != NULL &&
3171 compareRegisters(workRegs, insnRegs,
3172 meth->registersSize + kExtraRegs) != 0)
3173 {
3174 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
3175 LOG_VFY("HUH? workRegs diverged in %s.%s %s\n",
3176 meth->clazz->descriptor, meth->name, desc);
3177 free(desc);
3178 dumpRegTypes(meth, insnFlags, workRegs, 0, "work",
3179 uninitMap, DRT_SHOW_REF_TYPES | DRT_SHOW_LOCALS);
3180 dumpRegTypes(meth, insnFlags, insnRegs, 0, "insn",
3181 uninitMap, DRT_SHOW_REF_TYPES | DRT_SHOW_LOCALS);
3182 }
3183#endif
3184 }
3185
3186 //LOGI("process %s.%s %s %d\n",
3187 // meth->clazz->descriptor, meth->name, meth->descriptor, insnIdx);
3188 if (!verifyInstruction(meth, insnFlags, regTable, workRegs, insnIdx,
3189 uninitMap, &startGuess))
3190 {
3191 //LOGD("+++ %s bailing at %d\n", meth->name, insnIdx);
3192 goto bail;
3193 }
3194
3195#if 0
3196 {
3197 static const int gcMask = kInstrCanBranch | kInstrCanSwitch |
3198 kInstrCanThrow | kInstrCanReturn;
3199 OpCode opCode = *(meth->insns + insnIdx) & 0xff;
3200 int flags = dexGetInstrFlags(gDvm.instrFlags, opCode);
3201
3202 /* 8, 16, 32, or 32*n -bit regs */
3203 int regWidth = (meth->registersSize + 7) / 8;
3204 if (regWidth == 3)
3205 regWidth = 4;
3206 if (regWidth > 4) {
3207 regWidth = ((regWidth + 3) / 4) * 4;
3208 if (false) {
3209 LOGW("WOW: %d regs -> %d %s.%s\n",
3210 meth->registersSize, regWidth,
3211 meth->clazz->descriptor, meth->name);
3212 //x = true;
3213 }
3214 }
3215
3216 if ((flags & gcMask) != 0) {
3217 /* this is a potential GC point */
3218 gDvm__gcInstr++;
3219
3220 if (insnsSize < 256)
3221 gDvm__gcData += 1;
3222 else
3223 gDvm__gcData += 2;
3224 gDvm__gcData += regWidth;
3225 }
3226 gDvm__gcSimpleData += regWidth;
3227
3228 gDvm__totalInstr++;
3229 }
3230#endif
3231
3232 /*
3233 * Clear "changed" and mark as visited.
3234 */
3235 dvmInsnSetVisited(insnFlags, insnIdx, true);
3236 dvmInsnSetChanged(insnFlags, insnIdx, false);
3237 }
3238
Andy McFaddenb51ea112009-05-08 16:50:17 -07003239 if (DEAD_CODE_SCAN && !IS_METHOD_FLAG_SET(meth, METHOD_ISWRITABLE)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003240 /*
Andy McFaddenb51ea112009-05-08 16:50:17 -07003241 * Scan for dead code. There's nothing "evil" about dead code
3242 * (besides the wasted space), but it indicates a flaw somewhere
3243 * down the line, possibly in the verifier.
3244 *
3245 * If we've rewritten "always throw" instructions into the stream,
3246 * we are almost certainly going to have some dead code.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003247 */
3248 int deadStart = -1;
3249 for (insnIdx = 0; insnIdx < insnsSize;
3250 insnIdx += dvmInsnGetWidth(insnFlags, insnIdx))
3251 {
3252 /*
3253 * Switch-statement data doesn't get "visited" by scanner. It
3254 * may or may not be preceded by a padding NOP.
3255 */
3256 int instr = meth->insns[insnIdx];
3257 if (instr == kPackedSwitchSignature ||
3258 instr == kSparseSwitchSignature ||
3259 instr == kArrayDataSignature ||
3260 (instr == OP_NOP &&
3261 (meth->insns[insnIdx+1] == kPackedSwitchSignature ||
3262 meth->insns[insnIdx+1] == kSparseSwitchSignature ||
3263 meth->insns[insnIdx+1] == kArrayDataSignature)))
3264 {
3265 dvmInsnSetVisited(insnFlags, insnIdx, true);
3266 }
3267
3268 if (!dvmInsnIsVisited(insnFlags, insnIdx)) {
3269 if (deadStart < 0)
3270 deadStart = insnIdx;
3271 } else if (deadStart >= 0) {
3272 IF_LOGD() {
3273 char* desc =
3274 dexProtoCopyMethodDescriptor(&meth->prototype);
3275 LOGD("VFY: dead code 0x%04x-%04x in %s.%s %s\n",
3276 deadStart, insnIdx-1,
3277 meth->clazz->descriptor, meth->name, desc);
3278 free(desc);
3279 }
3280
3281 deadStart = -1;
3282 }
3283 }
3284 if (deadStart >= 0) {
3285 IF_LOGD() {
3286 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
3287 LOGD("VFY: dead code 0x%04x-%04x in %s.%s %s\n",
3288 deadStart, insnIdx-1,
3289 meth->clazz->descriptor, meth->name, desc);
3290 free(desc);
3291 }
3292 }
3293 }
3294
3295 result = true;
3296
3297bail:
3298 return result;
3299}
3300
3301
3302/*
3303 * Perform verification for a single instruction.
3304 *
3305 * This requires fully decoding the instruction to determine the effect
3306 * it has on registers.
3307 *
3308 * Finds zero or more following instructions and sets the "changed" flag
3309 * if execution at that point needs to be (re-)evaluated. Register changes
3310 * are merged into "regTypes" at the target addresses. Does not set or
3311 * clear any other flags in "insnFlags".
Andy McFaddenb51ea112009-05-08 16:50:17 -07003312 *
3313 * This may alter meth->insns if we need to replace an instruction with
3314 * throw-verification-error.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003315 */
Andy McFaddenb51ea112009-05-08 16:50:17 -07003316static bool verifyInstruction(Method* meth, InsnFlags* insnFlags,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003317 RegisterTable* regTable, RegType* workRegs, int insnIdx,
3318 UninitInstanceMap* uninitMap, int* pStartGuess)
3319{
3320 const int insnsSize = dvmGetMethodInsnsSize(meth);
3321 const u2* insns = meth->insns + insnIdx;
3322 bool result = false;
3323
3324 /*
3325 * Once we finish decoding the instruction, we need to figure out where
3326 * we can go from here. There are three possible ways to transfer
3327 * control to another statement:
3328 *
3329 * (1) Continue to the next instruction. Applies to all but
3330 * unconditional branches, method returns, and exception throws.
3331 * (2) Branch to one or more possible locations. Applies to branches
3332 * and switch statements.
3333 * (3) Exception handlers. Applies to any instruction that can
3334 * throw an exception that is handled by an encompassing "try"
3335 * block. (We simplify this to be any instruction that can
3336 * throw any exception.)
3337 *
3338 * We can also return, in which case there is no successor instruction
3339 * from this point.
3340 *
3341 * The behavior can be determined from the InstrFlags.
3342 */
3343
3344 const DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
3345 RegType entryRegs[meth->registersSize + kExtraRegs];
3346 ClassObject* resClass;
3347 const char* className;
3348 int branchTarget = 0;
3349 const int insnRegCount = meth->registersSize;
3350 RegType tmpType;
3351 DecodedInstruction decInsn;
3352 bool justSetResult = false;
Andy McFadden62a75162009-04-17 17:23:37 -07003353 VerifyError failure = VERIFY_ERROR_NONE;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003354
3355#ifndef NDEBUG
3356 memset(&decInsn, 0x81, sizeof(decInsn));
3357#endif
3358 dexDecodeInstruction(gDvm.instrFormat, insns, &decInsn);
3359
Andy McFaddenb51ea112009-05-08 16:50:17 -07003360 int nextFlags = dexGetInstrFlags(gDvm.instrFlags, decInsn.opCode);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003361
3362 /*
3363 * Make a copy of the previous register state. If the instruction
3364 * throws an exception, we merge *this* into the destination rather
3365 * than workRegs, because we don't want the result from the "successful"
3366 * code path (e.g. a check-cast that "improves" a type) to be visible
3367 * to the exception handler.
3368 */
3369 if ((nextFlags & kInstrCanThrow) != 0 && dvmInsnIsInTry(insnFlags, insnIdx))
3370 {
3371 copyRegisters(entryRegs, workRegs, meth->registersSize + kExtraRegs);
3372 } else {
3373#ifndef NDEBUG
3374 memset(entryRegs, 0xdd,
3375 (meth->registersSize + kExtraRegs) * sizeof(RegType));
3376#endif
3377 }
3378
3379 switch (decInsn.opCode) {
3380 case OP_NOP:
3381 /*
3382 * A "pure" NOP has no effect on anything. Data tables start with
3383 * a signature that looks like a NOP; if we see one of these in
3384 * the course of executing code then we have a problem.
3385 */
3386 if (decInsn.vA != 0) {
3387 LOG_VFY("VFY: encountered data table in instruction stream\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003388 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003389 }
3390 break;
3391
3392 case OP_MOVE:
3393 case OP_MOVE_FROM16:
3394 case OP_MOVE_16:
3395 copyRegister1(workRegs, insnRegCount, decInsn.vA, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07003396 kTypeCategory1nr, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003397 break;
3398 case OP_MOVE_WIDE:
3399 case OP_MOVE_WIDE_FROM16:
3400 case OP_MOVE_WIDE_16:
Andy McFadden62a75162009-04-17 17:23:37 -07003401 copyRegister2(workRegs, insnRegCount, decInsn.vA, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003402 break;
3403 case OP_MOVE_OBJECT:
3404 case OP_MOVE_OBJECT_FROM16:
3405 case OP_MOVE_OBJECT_16:
3406 copyRegister1(workRegs, insnRegCount, decInsn.vA, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07003407 kTypeCategoryRef, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003408 break;
3409
3410 /*
3411 * The move-result instructions copy data out of a "pseudo-register"
3412 * with the results from the last method invocation. In practice we
3413 * might want to hold the result in an actual CPU register, so the
3414 * Dalvik spec requires that these only appear immediately after an
3415 * invoke or filled-new-array.
3416 *
3417 * These calls invalidate the "result" register. (This is now
3418 * redundant with the reset done below, but it can make the debug info
3419 * easier to read in some cases.)
3420 */
3421 case OP_MOVE_RESULT:
3422 copyResultRegister1(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003423 kTypeCategory1nr, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003424 break;
3425 case OP_MOVE_RESULT_WIDE:
Andy McFadden62a75162009-04-17 17:23:37 -07003426 copyResultRegister2(workRegs, insnRegCount, decInsn.vA, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003427 break;
3428 case OP_MOVE_RESULT_OBJECT:
3429 copyResultRegister1(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003430 kTypeCategoryRef, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003431 break;
3432
3433 case OP_MOVE_EXCEPTION:
3434 /*
3435 * This statement can only appear as the first instruction in an
3436 * exception handler (though not all exception handlers need to
3437 * have one of these). We verify that as part of extracting the
3438 * exception type from the catch block list.
3439 *
3440 * "resClass" will hold the closest common superclass of all
3441 * exceptions that can be handled here.
3442 */
Andy McFadden62a75162009-04-17 17:23:37 -07003443 resClass = getCaughtExceptionType(meth, insnIdx, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003444 if (resClass == NULL) {
Andy McFadden62a75162009-04-17 17:23:37 -07003445 assert(!VERIFY_OK(failure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003446 } else {
3447 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003448 regTypeFromClass(resClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003449 }
3450 break;
3451
3452 case OP_RETURN_VOID:
Andy McFadden62a75162009-04-17 17:23:37 -07003453 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3454 failure = VERIFY_ERROR_GENERIC;
3455 } else if (getMethodReturnType(meth) != kRegTypeUnknown) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003456 LOG_VFY("VFY: return-void not expected\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003457 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003458 }
3459 break;
3460 case OP_RETURN:
Andy McFadden62a75162009-04-17 17:23:37 -07003461 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3462 failure = VERIFY_ERROR_GENERIC;
3463 } else {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003464 /* check the method signature */
3465 RegType returnType = getMethodReturnType(meth);
Andy McFadden62a75162009-04-17 17:23:37 -07003466 checkTypeCategory(returnType, kTypeCategory1nr, &failure);
3467 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003468 LOG_VFY("VFY: return-32 not expected\n");
3469
3470 /* check the register contents */
3471 returnType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003472 &failure);
3473 checkTypeCategory(returnType, kTypeCategory1nr, &failure);
3474 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003475 LOG_VFY("VFY: return-32 on invalid register v%d\n", decInsn.vA);
3476 }
3477 break;
3478 case OP_RETURN_WIDE:
Andy McFadden62a75162009-04-17 17:23:37 -07003479 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3480 failure = VERIFY_ERROR_GENERIC;
3481 } else {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003482 RegType returnType, returnTypeHi;
3483
3484 /* check the method signature */
3485 returnType = getMethodReturnType(meth);
Andy McFadden62a75162009-04-17 17:23:37 -07003486 checkTypeCategory(returnType, kTypeCategory2, &failure);
3487 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003488 LOG_VFY("VFY: return-wide not expected\n");
3489
3490 /* check the register contents */
3491 returnType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003492 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003493 returnTypeHi = getRegisterType(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003494 decInsn.vA +1, &failure);
3495 if (VERIFY_OK(failure)) {
3496 checkTypeCategory(returnType, kTypeCategory2, &failure);
3497 checkWidePair(returnType, returnTypeHi, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003498 }
Andy McFadden62a75162009-04-17 17:23:37 -07003499 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003500 LOG_VFY("VFY: return-wide on invalid register pair v%d\n",
3501 decInsn.vA);
3502 }
3503 }
3504 break;
3505 case OP_RETURN_OBJECT:
Andy McFadden62a75162009-04-17 17:23:37 -07003506 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3507 failure = VERIFY_ERROR_GENERIC;
3508 } else {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003509 RegType returnType = getMethodReturnType(meth);
Andy McFadden62a75162009-04-17 17:23:37 -07003510 checkTypeCategory(returnType, kTypeCategoryRef, &failure);
3511 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003512 LOG_VFY("VFY: return-object not expected\n");
3513 break;
3514 }
3515
3516 /* returnType is the *expected* return type, not register value */
3517 assert(returnType != kRegTypeZero);
3518 assert(!regTypeIsUninitReference(returnType));
3519
3520 /*
3521 * Verify that the reference in vAA is an instance of the type
3522 * in "returnType". The Zero type is allowed here. If the
3523 * method is declared to return an interface, then any
3524 * initialized reference is acceptable.
3525 *
3526 * Note getClassFromRegister fails if the register holds an
3527 * uninitialized reference, so we do not allow them to be
3528 * returned.
3529 */
3530 ClassObject* declClass;
3531
3532 declClass = regTypeInitializedReferenceToClass(returnType);
3533 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003534 decInsn.vA, &failure);
3535 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003536 break;
3537 if (resClass != NULL) {
3538 if (!dvmIsInterfaceClass(declClass) &&
3539 !dvmInstanceof(resClass, declClass))
3540 {
Andy McFadden86c86432009-05-27 14:40:12 -07003541 LOG_VFY("VFY: returning %s (cl=%p), declared %s (cl=%p)\n",
3542 resClass->descriptor, resClass->classLoader,
3543 declClass->descriptor, declClass->classLoader);
Andy McFadden62a75162009-04-17 17:23:37 -07003544 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003545 break;
3546 }
3547 }
3548 }
3549 break;
3550
3551 case OP_CONST_4:
3552 case OP_CONST_16:
3553 case OP_CONST:
3554 /* could be boolean, int, float, or a null reference */
3555 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003556 dvmDetermineCat1Const((s4)decInsn.vB), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003557 break;
3558 case OP_CONST_HIGH16:
3559 /* could be boolean, int, float, or a null reference */
3560 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003561 dvmDetermineCat1Const((s4) decInsn.vB << 16), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003562 break;
3563 case OP_CONST_WIDE_16:
3564 case OP_CONST_WIDE_32:
3565 case OP_CONST_WIDE:
3566 case OP_CONST_WIDE_HIGH16:
3567 /* could be long or double; default to long and allow conversion */
3568 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003569 kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003570 break;
3571 case OP_CONST_STRING:
3572 case OP_CONST_STRING_JUMBO:
3573 assert(gDvm.classJavaLangString != NULL);
3574 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003575 regTypeFromClass(gDvm.classJavaLangString), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003576 break;
3577 case OP_CONST_CLASS:
3578 assert(gDvm.classJavaLangClass != NULL);
3579 /* make sure we can resolve the class; access check is important */
Andy McFadden62a75162009-04-17 17:23:37 -07003580 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003581 if (resClass == NULL) {
3582 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3583 dvmLogUnableToResolveClass(badClassDesc, meth);
3584 LOG_VFY("VFY: unable to resolve const-class %d (%s) in %s\n",
3585 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003586 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003587 } else {
3588 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003589 regTypeFromClass(gDvm.classJavaLangClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003590 }
3591 break;
3592
3593 case OP_MONITOR_ENTER:
3594 case OP_MONITOR_EXIT:
Andy McFadden62a75162009-04-17 17:23:37 -07003595 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
3596 if (VERIFY_OK(failure)) {
3597 if (!regTypeIsReference(tmpType)) {
3598 LOG_VFY("VFY: monitor op on non-object\n");
3599 failure = VERIFY_ERROR_GENERIC;
3600 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003601 }
3602 break;
3603
3604 case OP_CHECK_CAST:
3605 /*
3606 * If this instruction succeeds, we will promote register vA to
3607 * the type in vB. (This could be a demotion -- not expected, so
3608 * we don't try to address it.)
3609 *
3610 * If it fails, an exception is thrown, which we deal with later
3611 * by ignoring the update to decInsn.vA when branching to a handler.
3612 */
Andy McFadden62a75162009-04-17 17:23:37 -07003613 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003614 if (resClass == NULL) {
3615 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3616 dvmLogUnableToResolveClass(badClassDesc, meth);
3617 LOG_VFY("VFY: unable to resolve check-cast %d (%s) in %s\n",
3618 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003619 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003620 } else {
3621 RegType origType;
3622
3623 origType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003624 &failure);
3625 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003626 break;
3627 if (!regTypeIsReference(origType)) {
3628 LOG_VFY("VFY: check-cast on non-reference in v%u\n",decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07003629 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003630 break;
3631 }
3632 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003633 regTypeFromClass(resClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003634 }
3635 break;
3636 case OP_INSTANCE_OF:
3637 /* make sure we're checking a reference type */
Andy McFadden62a75162009-04-17 17:23:37 -07003638 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vB, &failure);
3639 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003640 break;
3641 if (!regTypeIsReference(tmpType)) {
3642 LOG_VFY("VFY: vB not a reference (%d)\n", tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07003643 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003644 break;
3645 }
3646
3647 /* make sure we can resolve the class; access check is important */
Andy McFadden62a75162009-04-17 17:23:37 -07003648 resClass = dvmOptResolveClass(meth->clazz, decInsn.vC, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003649 if (resClass == NULL) {
3650 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vC);
3651 dvmLogUnableToResolveClass(badClassDesc, meth);
3652 LOG_VFY("VFY: unable to resolve instanceof %d (%s) in %s\n",
3653 decInsn.vC, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003654 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003655 } else {
3656 /* result is boolean */
3657 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003658 kRegTypeBoolean, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003659 }
3660 break;
3661
3662 case OP_ARRAY_LENGTH:
3663 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003664 decInsn.vB, &failure);
3665 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003666 break;
3667 if (resClass != NULL && !dvmIsArrayClass(resClass)) {
3668 LOG_VFY("VFY: array-length on non-array\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003669 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003670 break;
3671 }
3672 setRegisterType(workRegs, insnRegCount, decInsn.vA, kRegTypeInteger,
Andy McFadden62a75162009-04-17 17:23:37 -07003673 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003674 break;
3675
3676 case OP_NEW_INSTANCE:
Andy McFadden62a75162009-04-17 17:23:37 -07003677 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003678 if (resClass == NULL) {
3679 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3680 dvmLogUnableToResolveClass(badClassDesc, meth);
3681 LOG_VFY("VFY: unable to resolve new-instance %d (%s) in %s\n",
3682 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003683 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003684 } else {
3685 RegType uninitType;
3686
Andy McFaddenb51ea112009-05-08 16:50:17 -07003687 /* can't create an instance of an interface or abstract class */
3688 if (dvmIsAbstractClass(resClass) || dvmIsInterfaceClass(resClass)) {
3689 LOG_VFY("VFY: new-instance on interface or abstract class %s\n",
3690 resClass->descriptor);
3691 failure = VERIFY_ERROR_INSTANTIATION;
3692 break;
3693 }
3694
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003695 /* add resolved class to uninit map if not already there */
3696 int uidx = dvmSetUninitInstance(uninitMap, insnIdx, resClass);
3697 assert(uidx >= 0);
3698 uninitType = regTypeFromUninitIndex(uidx);
3699
3700 /*
3701 * Any registers holding previous allocations from this address
3702 * that have not yet been initialized must be marked invalid.
3703 */
3704 markUninitRefsAsInvalid(workRegs, insnRegCount, uninitMap,
3705 uninitType);
3706
3707 /* add the new uninitialized reference to the register ste */
3708 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003709 uninitType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003710 }
3711 break;
3712 case OP_NEW_ARRAY:
Andy McFadden62a75162009-04-17 17:23:37 -07003713 resClass = dvmOptResolveClass(meth->clazz, decInsn.vC, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003714 if (resClass == NULL) {
3715 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vC);
3716 dvmLogUnableToResolveClass(badClassDesc, meth);
3717 LOG_VFY("VFY: unable to resolve new-array %d (%s) in %s\n",
3718 decInsn.vC, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003719 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003720 } else if (!dvmIsArrayClass(resClass)) {
3721 LOG_VFY("VFY: new-array on non-array class\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003722 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003723 } else {
3724 /* make sure "size" register is valid type */
3725 verifyRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07003726 kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003727 /* set register type to array class */
3728 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003729 regTypeFromClass(resClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003730 }
3731 break;
3732 case OP_FILLED_NEW_ARRAY:
3733 case OP_FILLED_NEW_ARRAY_RANGE:
Andy McFadden62a75162009-04-17 17:23:37 -07003734 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003735 if (resClass == NULL) {
3736 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3737 dvmLogUnableToResolveClass(badClassDesc, meth);
3738 LOG_VFY("VFY: unable to resolve filled-array %d (%s) in %s\n",
3739 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003740 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003741 } else if (!dvmIsArrayClass(resClass)) {
3742 LOG_VFY("VFY: filled-new-array on non-array class\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003743 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003744 } else {
3745 bool isRange = (decInsn.opCode == OP_FILLED_NEW_ARRAY_RANGE);
3746
3747 /* check the arguments to the instruction */
3748 verifyFilledNewArrayRegs(meth, workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07003749 resClass, isRange, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003750 /* filled-array result goes into "result" register */
3751 setResultRegisterType(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003752 regTypeFromClass(resClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003753 justSetResult = true;
3754 }
3755 break;
3756
3757 case OP_CMPL_FLOAT:
3758 case OP_CMPG_FLOAT:
3759 verifyRegisterType(workRegs, insnRegCount, decInsn.vB, kRegTypeFloat,
Andy McFadden62a75162009-04-17 17:23:37 -07003760 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003761 verifyRegisterType(workRegs, insnRegCount, decInsn.vC, kRegTypeFloat,
Andy McFadden62a75162009-04-17 17:23:37 -07003762 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003763 setRegisterType(workRegs, insnRegCount, decInsn.vA, kRegTypeBoolean,
Andy McFadden62a75162009-04-17 17:23:37 -07003764 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003765 break;
3766 case OP_CMPL_DOUBLE:
3767 case OP_CMPG_DOUBLE:
3768 verifyRegisterType(workRegs, insnRegCount, decInsn.vB, kRegTypeDoubleLo,
Andy McFadden62a75162009-04-17 17:23:37 -07003769 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003770 verifyRegisterType(workRegs, insnRegCount, decInsn.vC, kRegTypeDoubleLo,
Andy McFadden62a75162009-04-17 17:23:37 -07003771 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003772 setRegisterType(workRegs, insnRegCount, decInsn.vA, kRegTypeBoolean,
Andy McFadden62a75162009-04-17 17:23:37 -07003773 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003774 break;
3775 case OP_CMP_LONG:
3776 verifyRegisterType(workRegs, insnRegCount, decInsn.vB, kRegTypeLongLo,
Andy McFadden62a75162009-04-17 17:23:37 -07003777 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003778 verifyRegisterType(workRegs, insnRegCount, decInsn.vC, kRegTypeLongLo,
Andy McFadden62a75162009-04-17 17:23:37 -07003779 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003780 setRegisterType(workRegs, insnRegCount, decInsn.vA, kRegTypeBoolean,
Andy McFadden62a75162009-04-17 17:23:37 -07003781 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003782 break;
3783
3784 case OP_THROW:
3785 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003786 decInsn.vA, &failure);
3787 if (VERIFY_OK(failure) && resClass != NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003788 if (!dvmInstanceof(resClass, gDvm.classJavaLangThrowable)) {
3789 LOG_VFY("VFY: thrown class %s not instanceof Throwable\n",
3790 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003791 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003792 }
3793 }
3794 break;
3795
3796 case OP_GOTO:
3797 case OP_GOTO_16:
3798 case OP_GOTO_32:
3799 /* no effect on or use of registers */
3800 break;
3801
3802 case OP_PACKED_SWITCH:
3803 case OP_SPARSE_SWITCH:
3804 /* verify that vAA is an integer, or can be converted to one */
3805 verifyRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003806 kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003807 break;
3808
3809 case OP_FILL_ARRAY_DATA:
3810 {
3811 RegType valueType;
3812 const u2 *arrayData;
3813 u2 elemWidth;
3814
3815 /* Similar to the verification done for APUT */
3816 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003817 decInsn.vA, &failure);
3818 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003819 break;
3820
3821 /* resClass can be null if the reg type is Zero */
3822 if (resClass == NULL)
3823 break;
3824
3825 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
3826 resClass->elementClass->primitiveType == PRIM_NOT ||
3827 resClass->elementClass->primitiveType == PRIM_VOID)
3828 {
3829 LOG_VFY("VFY: invalid fill-array-data on %s\n",
3830 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003831 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003832 break;
3833 }
3834
3835 valueType = primitiveTypeToRegType(
3836 resClass->elementClass->primitiveType);
3837 assert(valueType != kRegTypeUnknown);
3838
3839 /*
3840 * Now verify if the element width in the table matches the element
3841 * width declared in the array
3842 */
3843 arrayData = insns + (insns[1] | (((s4)insns[2]) << 16));
3844 if (arrayData[0] != kArrayDataSignature) {
3845 LOG_VFY("VFY: invalid magic for array-data\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003846 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003847 break;
3848 }
3849
3850 switch (resClass->elementClass->primitiveType) {
3851 case PRIM_BOOLEAN:
3852 case PRIM_BYTE:
3853 elemWidth = 1;
3854 break;
3855 case PRIM_CHAR:
3856 case PRIM_SHORT:
3857 elemWidth = 2;
3858 break;
3859 case PRIM_FLOAT:
3860 case PRIM_INT:
3861 elemWidth = 4;
3862 break;
3863 case PRIM_DOUBLE:
3864 case PRIM_LONG:
3865 elemWidth = 8;
3866 break;
3867 default:
3868 elemWidth = 0;
3869 break;
3870 }
3871
3872 /*
3873 * Since we don't compress the data in Dex, expect to see equal
3874 * width of data stored in the table and expected from the array
3875 * class.
3876 */
3877 if (arrayData[1] != elemWidth) {
3878 LOG_VFY("VFY: array-data size mismatch (%d vs %d)\n",
3879 arrayData[1], elemWidth);
Andy McFadden62a75162009-04-17 17:23:37 -07003880 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003881 }
3882 }
3883 break;
3884
3885 case OP_IF_EQ:
3886 case OP_IF_NE:
3887 {
3888 RegType type1, type2;
3889 bool tmpResult;
3890
Andy McFadden62a75162009-04-17 17:23:37 -07003891 type1 = getRegisterType(workRegs, insnRegCount, decInsn.vA,
3892 &failure);
3893 type2 = getRegisterType(workRegs, insnRegCount, decInsn.vB,
3894 &failure);
3895 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003896 break;
3897
3898 /* both references? */
3899 if (regTypeIsReference(type1) && regTypeIsReference(type2))
3900 break;
3901
3902 /* both category-1nr? */
Andy McFadden62a75162009-04-17 17:23:37 -07003903 checkTypeCategory(type1, kTypeCategory1nr, &failure);
3904 checkTypeCategory(type2, kTypeCategory1nr, &failure);
3905 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003906 LOG_VFY("VFY: args to if-eq/if-ne must both be refs or cat1\n");
3907 break;
3908 }
3909 }
3910 break;
3911 case OP_IF_LT:
3912 case OP_IF_GE:
3913 case OP_IF_GT:
3914 case OP_IF_LE:
Andy McFadden62a75162009-04-17 17:23:37 -07003915 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
3916 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003917 break;
Andy McFadden62a75162009-04-17 17:23:37 -07003918 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
3919 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003920 LOG_VFY("VFY: args to 'if' must be cat-1nr\n");
3921 break;
3922 }
Andy McFadden62a75162009-04-17 17:23:37 -07003923 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vB, &failure);
3924 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003925 break;
Andy McFadden62a75162009-04-17 17:23:37 -07003926 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
3927 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003928 LOG_VFY("VFY: args to 'if' must be cat-1nr\n");
3929 break;
3930 }
3931 break;
3932 case OP_IF_EQZ:
3933 case OP_IF_NEZ:
Andy McFadden62a75162009-04-17 17:23:37 -07003934 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
3935 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003936 break;
3937 if (regTypeIsReference(tmpType))
3938 break;
Andy McFadden62a75162009-04-17 17:23:37 -07003939 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
3940 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003941 LOG_VFY("VFY: expected cat-1 arg to if\n");
3942 break;
3943 case OP_IF_LTZ:
3944 case OP_IF_GEZ:
3945 case OP_IF_GTZ:
3946 case OP_IF_LEZ:
Andy McFadden62a75162009-04-17 17:23:37 -07003947 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
3948 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003949 break;
Andy McFadden62a75162009-04-17 17:23:37 -07003950 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
3951 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003952 LOG_VFY("VFY: expected cat-1 arg to if\n");
3953 break;
3954
3955 case OP_AGET:
3956 tmpType = kRegTypeInteger;
3957 goto aget_1nr_common;
3958 case OP_AGET_BOOLEAN:
3959 tmpType = kRegTypeBoolean;
3960 goto aget_1nr_common;
3961 case OP_AGET_BYTE:
3962 tmpType = kRegTypeByte;
3963 goto aget_1nr_common;
3964 case OP_AGET_CHAR:
3965 tmpType = kRegTypeChar;
3966 goto aget_1nr_common;
3967 case OP_AGET_SHORT:
3968 tmpType = kRegTypeShort;
3969 goto aget_1nr_common;
3970aget_1nr_common:
3971 {
3972 RegType srcType, indexType;
3973
3974 indexType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07003975 &failure);
3976 checkArrayIndexType(meth, indexType, &failure);
3977 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003978 break;
3979
3980 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003981 decInsn.vB, &failure);
3982 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003983 break;
3984 if (resClass != NULL) {
3985 /* verify the class */
3986 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
3987 resClass->elementClass->primitiveType == PRIM_NOT)
3988 {
3989 LOG_VFY("VFY: invalid aget-1nr target %s\n",
3990 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003991 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003992 break;
3993 }
3994
3995 /* make sure array type matches instruction */
3996 srcType = primitiveTypeToRegType(
3997 resClass->elementClass->primitiveType);
3998
3999 if (!checkFieldArrayStore1nr(tmpType, srcType)) {
4000 LOG_VFY("VFY: invalid aget-1nr, array type=%d with"
4001 " inst type=%d (on %s)\n",
4002 srcType, tmpType, resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004003 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004004 break;
4005 }
4006
4007 }
4008 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004009 tmpType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004010 }
4011 break;
4012
4013 case OP_AGET_WIDE:
4014 {
4015 RegType dstType, indexType;
4016
4017 indexType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004018 &failure);
4019 checkArrayIndexType(meth, indexType, &failure);
4020 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004021 break;
4022
4023 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004024 decInsn.vB, &failure);
4025 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004026 break;
4027 if (resClass != NULL) {
4028 /* verify the class */
4029 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4030 resClass->elementClass->primitiveType == PRIM_NOT)
4031 {
4032 LOG_VFY("VFY: invalid aget-wide target %s\n",
4033 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004034 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004035 break;
4036 }
4037
4038 /* try to refine "dstType" */
4039 switch (resClass->elementClass->primitiveType) {
4040 case PRIM_LONG:
4041 dstType = kRegTypeLongLo;
4042 break;
4043 case PRIM_DOUBLE:
4044 dstType = kRegTypeDoubleLo;
4045 break;
4046 default:
4047 LOG_VFY("VFY: invalid aget-wide on %s\n",
4048 resClass->descriptor);
4049 dstType = kRegTypeUnknown;
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 } else {
4054 /*
4055 * Null array ref; this code path will fail at runtime. We
4056 * know this is either long or double, and we don't really
4057 * discriminate between those during verification, so we
4058 * call it a long.
4059 */
4060 dstType = kRegTypeLongLo;
4061 }
4062 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004063 dstType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004064 }
4065 break;
4066
4067 case OP_AGET_OBJECT:
4068 {
4069 RegType dstType, indexType;
4070
4071 indexType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004072 &failure);
4073 checkArrayIndexType(meth, indexType, &failure);
4074 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004075 break;
4076
4077 /* get the class of the array we're pulling an object from */
4078 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004079 decInsn.vB, &failure);
4080 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004081 break;
4082 if (resClass != NULL) {
4083 ClassObject* elementClass;
4084
4085 assert(resClass != NULL);
4086 if (!dvmIsArrayClass(resClass)) {
4087 LOG_VFY("VFY: aget-object on non-array class\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004088 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004089 break;
4090 }
4091 assert(resClass->elementClass != NULL);
4092
4093 /*
4094 * Find the element class. resClass->elementClass indicates
4095 * the basic type, which won't be what we want for a
4096 * multi-dimensional array.
4097 */
4098 if (resClass->descriptor[1] == '[') {
4099 assert(resClass->arrayDim > 1);
4100 elementClass = dvmFindArrayClass(&resClass->descriptor[1],
4101 resClass->classLoader);
4102 } else if (resClass->descriptor[1] == 'L') {
4103 assert(resClass->arrayDim == 1);
4104 elementClass = resClass->elementClass;
4105 } else {
4106 LOG_VFY("VFY: aget-object on non-ref array class (%s)\n",
4107 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004108 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004109 break;
4110 }
4111
4112 dstType = regTypeFromClass(elementClass);
4113 } else {
4114 /*
4115 * The array reference is NULL, so the current code path will
4116 * throw an exception. For proper merging with later code
4117 * paths, and correct handling of "if-eqz" tests on the
4118 * result of the array get, we want to treat this as a null
4119 * reference.
4120 */
4121 dstType = kRegTypeZero;
4122 }
4123 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004124 dstType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004125 }
4126 break;
4127 case OP_APUT:
4128 tmpType = kRegTypeInteger;
4129 goto aput_1nr_common;
4130 case OP_APUT_BOOLEAN:
4131 tmpType = kRegTypeBoolean;
4132 goto aput_1nr_common;
4133 case OP_APUT_BYTE:
4134 tmpType = kRegTypeByte;
4135 goto aput_1nr_common;
4136 case OP_APUT_CHAR:
4137 tmpType = kRegTypeChar;
4138 goto aput_1nr_common;
4139 case OP_APUT_SHORT:
4140 tmpType = kRegTypeShort;
4141 goto aput_1nr_common;
4142aput_1nr_common:
4143 {
4144 RegType srcType, dstType, indexType;
4145
4146 indexType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004147 &failure);
4148 checkArrayIndexType(meth, indexType, &failure);
4149 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004150 break;
4151
4152 /* make sure the source register has the correct type */
4153 srcType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004154 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004155 if (!canConvertTo1nr(srcType, tmpType)) {
4156 LOG_VFY("VFY: invalid reg type %d on aput instr (need %d)\n",
4157 srcType, tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07004158 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004159 break;
4160 }
4161
4162 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004163 decInsn.vB, &failure);
4164 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004165 break;
4166
4167 /* resClass can be null if the reg type is Zero */
4168 if (resClass == NULL)
4169 break;
4170
4171 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4172 resClass->elementClass->primitiveType == PRIM_NOT)
4173 {
4174 LOG_VFY("VFY: invalid aput-1nr on %s\n", resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004175 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004176 break;
4177 }
4178
4179 /* verify that instruction matches array */
4180 dstType = primitiveTypeToRegType(
4181 resClass->elementClass->primitiveType);
4182 assert(dstType != kRegTypeUnknown);
4183
4184 if (!checkFieldArrayStore1nr(tmpType, dstType)) {
4185 LOG_VFY("VFY: invalid aput-1nr on %s (inst=%d dst=%d)\n",
4186 resClass->descriptor, tmpType, dstType);
Andy McFadden62a75162009-04-17 17:23:37 -07004187 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004188 break;
4189 }
4190 }
4191 break;
4192 case OP_APUT_WIDE:
4193 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004194 &failure);
4195 checkArrayIndexType(meth, tmpType, &failure);
4196 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004197 break;
4198
Andy McFadden62a75162009-04-17 17:23:37 -07004199 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4200 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004201 RegType typeHi =
Andy McFadden62a75162009-04-17 17:23:37 -07004202 getRegisterType(workRegs, insnRegCount, decInsn.vA+1, &failure);
4203 checkTypeCategory(tmpType, kTypeCategory2, &failure);
4204 checkWidePair(tmpType, typeHi, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004205 }
Andy McFadden62a75162009-04-17 17:23:37 -07004206 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004207 break;
4208
4209 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004210 decInsn.vB, &failure);
4211 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004212 break;
4213 if (resClass != NULL) {
4214 /* verify the class and try to refine "dstType" */
4215 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4216 resClass->elementClass->primitiveType == PRIM_NOT)
4217 {
4218 LOG_VFY("VFY: invalid aput-wide on %s\n",
4219 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004220 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004221 break;
4222 }
4223
4224 switch (resClass->elementClass->primitiveType) {
4225 case PRIM_LONG:
4226 case PRIM_DOUBLE:
4227 /* these are okay */
4228 break;
4229 default:
4230 LOG_VFY("VFY: invalid aput-wide on %s\n",
4231 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004232 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004233 break;
4234 }
4235 }
4236 break;
4237 case OP_APUT_OBJECT:
4238 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004239 &failure);
4240 checkArrayIndexType(meth, tmpType, &failure);
4241 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004242 break;
4243
4244 /* get the ref we're storing; Zero is okay, Uninit is not */
4245 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004246 decInsn.vA, &failure);
4247 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004248 break;
4249 if (resClass != NULL) {
4250 ClassObject* arrayClass;
4251 ClassObject* elementClass;
4252
4253 /*
4254 * Get the array class. If the array ref is null, we won't
4255 * have type information (and we'll crash at runtime with a
4256 * null pointer exception).
4257 */
4258 arrayClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004259 decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004260
4261 if (arrayClass != NULL) {
4262 /* see if the array holds a compatible type */
4263 if (!dvmIsArrayClass(arrayClass)) {
4264 LOG_VFY("VFY: invalid aput-object on %s\n",
4265 arrayClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004266 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004267 break;
4268 }
4269
4270 /*
4271 * Find the element class. resClass->elementClass indicates
4272 * the basic type, which won't be what we want for a
4273 * multi-dimensional array.
4274 *
4275 * All we want to check here is that the element type is a
4276 * reference class. We *don't* check instanceof here, because
4277 * you can still put a String into a String[] after the latter
4278 * has been cast to an Object[].
4279 */
4280 if (arrayClass->descriptor[1] == '[') {
4281 assert(arrayClass->arrayDim > 1);
4282 elementClass = dvmFindArrayClass(&arrayClass->descriptor[1],
4283 arrayClass->classLoader);
4284 } else {
4285 assert(arrayClass->arrayDim == 1);
4286 elementClass = arrayClass->elementClass;
4287 }
4288 if (elementClass->primitiveType != PRIM_NOT) {
4289 LOG_VFY("VFY: invalid aput-object of %s into %s\n",
4290 resClass->descriptor, arrayClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004291 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004292 break;
4293 }
4294 }
4295 }
4296 break;
4297
4298 case OP_IGET:
4299 tmpType = kRegTypeInteger;
4300 goto iget_1nr_common;
4301 case OP_IGET_BOOLEAN:
4302 tmpType = kRegTypeBoolean;
4303 goto iget_1nr_common;
4304 case OP_IGET_BYTE:
4305 tmpType = kRegTypeByte;
4306 goto iget_1nr_common;
4307 case OP_IGET_CHAR:
4308 tmpType = kRegTypeChar;
4309 goto iget_1nr_common;
4310 case OP_IGET_SHORT:
4311 tmpType = kRegTypeShort;
4312 goto iget_1nr_common;
4313iget_1nr_common:
4314 {
4315 ClassObject* fieldClass;
4316 InstField* instField;
4317 RegType objType, fieldType;
4318
4319 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004320 &failure);
4321 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004322 break;
4323 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004324 &failure);
4325 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004326 break;
4327
4328 /* make sure the field's type is compatible with expectation */
4329 fieldType = primSigCharToRegType(instField->field.signature[0]);
4330 if (fieldType == kRegTypeUnknown ||
4331 !checkFieldArrayStore1nr(tmpType, fieldType))
4332 {
4333 LOG_VFY("VFY: invalid iget-1nr of %s.%s (inst=%d field=%d)\n",
4334 instField->field.clazz->descriptor,
4335 instField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004336 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004337 break;
4338 }
4339
Andy McFadden62a75162009-04-17 17:23:37 -07004340 setRegisterType(workRegs, insnRegCount, decInsn.vA, tmpType,
4341 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004342 }
4343 break;
4344 case OP_IGET_WIDE:
4345 {
4346 RegType dstType;
4347 ClassObject* fieldClass;
4348 InstField* instField;
4349 RegType objType;
4350
4351 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004352 &failure);
4353 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004354 break;
4355 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004356 &failure);
4357 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004358 break;
4359 /* check the type, which should be prim */
4360 switch (instField->field.signature[0]) {
4361 case 'D':
4362 dstType = kRegTypeDoubleLo;
4363 break;
4364 case 'J':
4365 dstType = kRegTypeLongLo;
4366 break;
4367 default:
4368 LOG_VFY("VFY: invalid iget-wide of %s.%s\n",
4369 instField->field.clazz->descriptor,
4370 instField->field.name);
4371 dstType = kRegTypeUnknown;
Andy McFadden62a75162009-04-17 17:23:37 -07004372 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004373 break;
4374 }
Andy McFadden62a75162009-04-17 17:23:37 -07004375 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004376 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004377 dstType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004378 }
4379 }
4380 break;
4381 case OP_IGET_OBJECT:
4382 {
4383 ClassObject* fieldClass;
4384 InstField* instField;
4385 RegType objType;
4386
4387 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004388 &failure);
4389 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004390 break;
4391 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004392 &failure);
4393 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004394 break;
4395 fieldClass = getFieldClass(meth, &instField->field);
4396 if (fieldClass == NULL) {
4397 /* class not found or primitive type */
4398 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4399 instField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004400 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004401 break;
4402 }
Andy McFadden62a75162009-04-17 17:23:37 -07004403 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004404 assert(!dvmIsPrimitiveClass(fieldClass));
4405 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004406 regTypeFromClass(fieldClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004407 }
4408 }
4409 break;
4410 case OP_IPUT:
4411 tmpType = kRegTypeInteger;
4412 goto iput_1nr_common;
4413 case OP_IPUT_BOOLEAN:
4414 tmpType = kRegTypeBoolean;
4415 goto iput_1nr_common;
4416 case OP_IPUT_BYTE:
4417 tmpType = kRegTypeByte;
4418 goto iput_1nr_common;
4419 case OP_IPUT_CHAR:
4420 tmpType = kRegTypeChar;
4421 goto iput_1nr_common;
4422 case OP_IPUT_SHORT:
4423 tmpType = kRegTypeShort;
4424 goto iput_1nr_common;
4425iput_1nr_common:
4426 {
4427 RegType srcType, fieldType, objType;
4428 ClassObject* fieldClass;
4429 InstField* instField;
4430
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004431 srcType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004432 &failure);
Andy McFaddenb5f64bc2009-06-10 14:11:07 -07004433
4434 /*
4435 * javac generates synthetic functions that write byte values
4436 * into boolean fields.
4437 */
4438 if (tmpType == kRegTypeBoolean && srcType == kRegTypeByte)
4439 srcType = kRegTypeBoolean;
4440
4441 /* make sure the source register has the correct type */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004442 if (!canConvertTo1nr(srcType, tmpType)) {
4443 LOG_VFY("VFY: invalid reg type %d on iput instr (need %d)\n",
4444 srcType, tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07004445 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004446 break;
4447 }
4448
4449 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004450 &failure);
4451 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004452 break;
4453 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004454 &failure);
4455 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004456 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004457 checkFinalFieldAccess(meth, &instField->field, &failure);
4458 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004459 break;
4460
4461 /* get type of field we're storing into */
4462 fieldType = primSigCharToRegType(instField->field.signature[0]);
4463 if (fieldType == kRegTypeUnknown ||
4464 !checkFieldArrayStore1nr(tmpType, fieldType))
4465 {
4466 LOG_VFY("VFY: invalid iput-1nr of %s.%s (inst=%d field=%d)\n",
4467 instField->field.clazz->descriptor,
4468 instField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004469 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004470 break;
4471 }
4472 }
4473 break;
4474 case OP_IPUT_WIDE:
Andy McFadden62a75162009-04-17 17:23:37 -07004475 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4476 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004477 RegType typeHi =
Andy McFadden62a75162009-04-17 17:23:37 -07004478 getRegisterType(workRegs, insnRegCount, decInsn.vA+1, &failure);
4479 checkTypeCategory(tmpType, kTypeCategory2, &failure);
4480 checkWidePair(tmpType, typeHi, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004481 }
Andy McFadden62a75162009-04-17 17:23:37 -07004482 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004483 ClassObject* fieldClass;
4484 InstField* instField;
4485 RegType objType;
4486
4487 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004488 &failure);
4489 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004490 break;
4491 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004492 &failure);
4493 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004494 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004495 checkFinalFieldAccess(meth, &instField->field, &failure);
4496 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004497 break;
4498
4499 /* check the type, which should be prim */
4500 switch (instField->field.signature[0]) {
4501 case 'D':
4502 case 'J':
4503 /* these are okay (and interchangeable) */
4504 break;
4505 default:
4506 LOG_VFY("VFY: invalid iput-wide of %s.%s\n",
4507 instField->field.clazz->descriptor,
4508 instField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07004509 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004510 break;
4511 }
4512 }
4513 break;
4514 case OP_IPUT_OBJECT:
4515 {
4516 ClassObject* fieldClass;
4517 ClassObject* valueClass;
4518 InstField* instField;
4519 RegType objType, valueType;
4520
4521 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004522 &failure);
4523 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004524 break;
4525 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004526 &failure);
4527 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004528 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004529 checkFinalFieldAccess(meth, &instField->field, &failure);
4530 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004531 break;
4532
4533 fieldClass = getFieldClass(meth, &instField->field);
4534 if (fieldClass == NULL) {
4535 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4536 instField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004537 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004538 break;
4539 }
4540
4541 valueType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004542 &failure);
4543 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004544 break;
4545 if (!regTypeIsReference(valueType)) {
4546 LOG_VFY("VFY: storing non-ref v%d into ref field '%s' (%s)\n",
4547 decInsn.vA, instField->field.name,
4548 fieldClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004549 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004550 break;
4551 }
4552 if (valueType != kRegTypeZero) {
4553 valueClass = regTypeInitializedReferenceToClass(valueType);
4554 if (valueClass == NULL) {
4555 LOG_VFY("VFY: storing uninit ref v%d into ref field\n",
4556 decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07004557 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004558 break;
4559 }
4560 /* allow if field is any interface or field is base class */
4561 if (!dvmIsInterfaceClass(fieldClass) &&
4562 !dvmInstanceof(valueClass, fieldClass))
4563 {
4564 LOG_VFY("VFY: storing type '%s' into field type '%s' (%s.%s)\n",
4565 valueClass->descriptor, fieldClass->descriptor,
4566 instField->field.clazz->descriptor,
4567 instField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07004568 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004569 break;
4570 }
4571 }
4572 }
4573 break;
4574
4575 case OP_SGET:
4576 tmpType = kRegTypeInteger;
4577 goto sget_1nr_common;
4578 case OP_SGET_BOOLEAN:
4579 tmpType = kRegTypeBoolean;
4580 goto sget_1nr_common;
4581 case OP_SGET_BYTE:
4582 tmpType = kRegTypeByte;
4583 goto sget_1nr_common;
4584 case OP_SGET_CHAR:
4585 tmpType = kRegTypeChar;
4586 goto sget_1nr_common;
4587 case OP_SGET_SHORT:
4588 tmpType = kRegTypeShort;
4589 goto sget_1nr_common;
4590sget_1nr_common:
4591 {
4592 StaticField* staticField;
4593 RegType fieldType;
4594
Andy McFadden62a75162009-04-17 17:23:37 -07004595 staticField = getStaticField(meth, decInsn.vB, &failure);
4596 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004597 break;
4598
4599 /*
4600 * Make sure the field's type is compatible with expectation.
4601 * We can get ourselves into trouble if we mix & match loads
4602 * and stores with different widths, so rather than just checking
4603 * "canConvertTo1nr" we require that the field types have equal
4604 * widths. (We can't generally require an exact type match,
4605 * because e.g. "int" and "float" are interchangeable.)
4606 */
4607 fieldType = primSigCharToRegType(staticField->field.signature[0]);
4608 if (!checkFieldArrayStore1nr(tmpType, fieldType)) {
4609 LOG_VFY("VFY: invalid sget-1nr of %s.%s (inst=%d actual=%d)\n",
4610 staticField->field.clazz->descriptor,
4611 staticField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004612 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004613 break;
4614 }
4615
Andy McFadden62a75162009-04-17 17:23:37 -07004616 setRegisterType(workRegs, insnRegCount, decInsn.vA, tmpType,
4617 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004618 }
4619 break;
4620 case OP_SGET_WIDE:
4621 {
4622 StaticField* staticField;
4623 RegType dstType;
4624
Andy McFadden62a75162009-04-17 17:23:37 -07004625 staticField = getStaticField(meth, decInsn.vB, &failure);
4626 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004627 break;
4628 /* check the type, which should be prim */
4629 switch (staticField->field.signature[0]) {
4630 case 'D':
4631 dstType = kRegTypeDoubleLo;
4632 break;
4633 case 'J':
4634 dstType = kRegTypeLongLo;
4635 break;
4636 default:
4637 LOG_VFY("VFY: invalid sget-wide of %s.%s\n",
4638 staticField->field.clazz->descriptor,
4639 staticField->field.name);
4640 dstType = kRegTypeUnknown;
Andy McFadden62a75162009-04-17 17:23:37 -07004641 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004642 break;
4643 }
Andy McFadden62a75162009-04-17 17:23:37 -07004644 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004645 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004646 dstType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004647 }
4648 }
4649 break;
4650 case OP_SGET_OBJECT:
4651 {
4652 StaticField* staticField;
4653 ClassObject* fieldClass;
4654
Andy McFadden62a75162009-04-17 17:23:37 -07004655 staticField = getStaticField(meth, decInsn.vB, &failure);
4656 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004657 break;
4658 fieldClass = getFieldClass(meth, &staticField->field);
4659 if (fieldClass == NULL) {
4660 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4661 staticField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004662 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004663 break;
4664 }
4665 if (dvmIsPrimitiveClass(fieldClass)) {
4666 LOG_VFY("VFY: attempt to get prim field with sget-object\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004667 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004668 break;
4669 }
4670 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004671 regTypeFromClass(fieldClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004672 }
4673 break;
4674 case OP_SPUT:
4675 tmpType = kRegTypeInteger;
4676 goto sput_1nr_common;
4677 case OP_SPUT_BOOLEAN:
4678 tmpType = kRegTypeBoolean;
4679 goto sput_1nr_common;
4680 case OP_SPUT_BYTE:
4681 tmpType = kRegTypeByte;
4682 goto sput_1nr_common;
4683 case OP_SPUT_CHAR:
4684 tmpType = kRegTypeChar;
4685 goto sput_1nr_common;
4686 case OP_SPUT_SHORT:
4687 tmpType = kRegTypeShort;
4688 goto sput_1nr_common;
4689sput_1nr_common:
4690 {
4691 RegType srcType, fieldType;
4692 StaticField* staticField;
4693
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004694 srcType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004695 &failure);
Andy McFaddenb5f64bc2009-06-10 14:11:07 -07004696
4697 /*
4698 * javac generates synthetic functions that write byte values
4699 * into boolean fields.
4700 */
4701 if (tmpType == kRegTypeBoolean && srcType == kRegTypeByte)
4702 srcType = kRegTypeBoolean;
4703
4704 /* make sure the source register has the correct type */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004705 if (!canConvertTo1nr(srcType, tmpType)) {
Andy McFaddenb5f64bc2009-06-10 14:11:07 -07004706 LOG_VFY("VFY: invalid reg type %d on sput instr (need %d)\n",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004707 srcType, tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07004708 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004709 break;
4710 }
4711
Andy McFadden62a75162009-04-17 17:23:37 -07004712 staticField = getStaticField(meth, decInsn.vB, &failure);
4713 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004714 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004715 checkFinalFieldAccess(meth, &staticField->field, &failure);
4716 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004717 break;
4718
4719 /*
4720 * Get type of field we're storing into. We know that the
4721 * contents of the register match the instruction, but we also
4722 * need to ensure that the instruction matches the field type.
4723 * Using e.g. sput-short to write into a 32-bit integer field
4724 * can lead to trouble if we do 16-bit writes.
4725 */
4726 fieldType = primSigCharToRegType(staticField->field.signature[0]);
4727 if (!checkFieldArrayStore1nr(tmpType, fieldType)) {
4728 LOG_VFY("VFY: invalid sput-1nr of %s.%s (inst=%d actual=%d)\n",
4729 staticField->field.clazz->descriptor,
4730 staticField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004731 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004732 break;
4733 }
4734 }
4735 break;
4736 case OP_SPUT_WIDE:
Andy McFadden62a75162009-04-17 17:23:37 -07004737 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4738 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004739 RegType typeHi =
Andy McFadden62a75162009-04-17 17:23:37 -07004740 getRegisterType(workRegs, insnRegCount, decInsn.vA+1, &failure);
4741 checkTypeCategory(tmpType, kTypeCategory2, &failure);
4742 checkWidePair(tmpType, typeHi, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004743 }
Andy McFadden62a75162009-04-17 17:23:37 -07004744 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004745 StaticField* staticField;
4746
Andy McFadden62a75162009-04-17 17:23:37 -07004747 staticField = getStaticField(meth, decInsn.vB, &failure);
4748 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004749 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004750 checkFinalFieldAccess(meth, &staticField->field, &failure);
4751 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004752 break;
4753
4754 /* check the type, which should be prim */
4755 switch (staticField->field.signature[0]) {
4756 case 'D':
4757 case 'J':
4758 /* these are okay */
4759 break;
4760 default:
4761 LOG_VFY("VFY: invalid sput-wide of %s.%s\n",
4762 staticField->field.clazz->descriptor,
4763 staticField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07004764 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004765 break;
4766 }
4767 }
4768 break;
4769 case OP_SPUT_OBJECT:
4770 {
4771 ClassObject* fieldClass;
4772 ClassObject* valueClass;
4773 StaticField* staticField;
4774 RegType valueType;
4775
Andy McFadden62a75162009-04-17 17:23:37 -07004776 staticField = getStaticField(meth, decInsn.vB, &failure);
4777 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004778 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004779 checkFinalFieldAccess(meth, &staticField->field, &failure);
4780 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004781 break;
4782
4783 fieldClass = getFieldClass(meth, &staticField->field);
4784 if (fieldClass == NULL) {
4785 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4786 staticField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004787 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004788 break;
4789 }
4790
4791 valueType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004792 &failure);
4793 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004794 break;
4795 if (!regTypeIsReference(valueType)) {
4796 LOG_VFY("VFY: storing non-ref v%d into ref field '%s' (%s)\n",
4797 decInsn.vA, staticField->field.name,
4798 fieldClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004799 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004800 break;
4801 }
4802 if (valueType != kRegTypeZero) {
4803 valueClass = regTypeInitializedReferenceToClass(valueType);
4804 if (valueClass == NULL) {
4805 LOG_VFY("VFY: storing uninit ref v%d into ref field\n",
4806 decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07004807 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004808 break;
4809 }
4810 /* allow if field is any interface or field is base class */
4811 if (!dvmIsInterfaceClass(fieldClass) &&
4812 !dvmInstanceof(valueClass, fieldClass))
4813 {
4814 LOG_VFY("VFY: storing type '%s' into field type '%s' (%s.%s)\n",
4815 valueClass->descriptor, fieldClass->descriptor,
4816 staticField->field.clazz->descriptor,
4817 staticField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07004818 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004819 break;
4820 }
4821 }
4822 }
4823 break;
4824
4825 case OP_INVOKE_VIRTUAL:
4826 case OP_INVOKE_VIRTUAL_RANGE:
4827 case OP_INVOKE_SUPER:
4828 case OP_INVOKE_SUPER_RANGE:
4829 {
4830 Method* calledMethod;
4831 RegType returnType;
4832 bool isRange;
4833 bool isSuper;
4834
4835 isRange = (decInsn.opCode == OP_INVOKE_VIRTUAL_RANGE ||
4836 decInsn.opCode == OP_INVOKE_SUPER_RANGE);
4837 isSuper = (decInsn.opCode == OP_INVOKE_SUPER ||
4838 decInsn.opCode == OP_INVOKE_SUPER_RANGE);
4839
4840 calledMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
4841 &decInsn, uninitMap, METHOD_VIRTUAL, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07004842 isSuper, &failure);
4843 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004844 break;
4845 returnType = getMethodReturnType(calledMethod);
Andy McFadden62a75162009-04-17 17:23:37 -07004846 setResultRegisterType(workRegs, insnRegCount, returnType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004847 justSetResult = true;
4848 }
4849 break;
4850 case OP_INVOKE_DIRECT:
4851 case OP_INVOKE_DIRECT_RANGE:
4852 {
4853 RegType returnType;
4854 Method* calledMethod;
4855 bool isRange;
4856
4857 isRange = (decInsn.opCode == OP_INVOKE_DIRECT_RANGE);
4858 calledMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
4859 &decInsn, uninitMap, METHOD_DIRECT, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07004860 false, &failure);
4861 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004862 break;
4863
4864 /*
4865 * Some additional checks when calling <init>. We know from
4866 * the invocation arg check that the "this" argument is an
4867 * instance of calledMethod->clazz. Now we further restrict
4868 * that to require that calledMethod->clazz is the same as
4869 * this->clazz or this->super, allowing the latter only if
4870 * the "this" argument is the same as the "this" argument to
4871 * this method (which implies that we're in <init> ourselves).
4872 */
4873 if (isInitMethod(calledMethod)) {
4874 RegType thisType;
4875 thisType = getInvocationThis(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004876 &decInsn, &failure);
4877 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004878 break;
4879
4880 /* no null refs allowed (?) */
4881 if (thisType == kRegTypeZero) {
4882 LOG_VFY("VFY: unable to initialize null ref\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004883 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004884 break;
4885 }
4886
4887 ClassObject* thisClass;
4888
4889 thisClass = regTypeReferenceToClass(thisType, uninitMap);
4890 assert(thisClass != NULL);
4891
4892 /* must be in same class or in superclass */
4893 if (calledMethod->clazz == thisClass->super) {
4894 if (thisClass != meth->clazz) {
4895 LOG_VFY("VFY: invoke-direct <init> on super only "
4896 "allowed for 'this' in <init>");
Andy McFadden62a75162009-04-17 17:23:37 -07004897 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004898 break;
4899 }
4900 } else if (calledMethod->clazz != thisClass) {
4901 LOG_VFY("VFY: invoke-direct <init> must be on current "
4902 "class or super\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004903 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004904 break;
4905 }
4906
4907 /* arg must be an uninitialized reference */
4908 if (!regTypeIsUninitReference(thisType)) {
4909 LOG_VFY("VFY: can only initialize the uninitialized\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004910 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004911 break;
4912 }
4913
4914 /*
4915 * Replace the uninitialized reference with an initialized
4916 * one, and clear the entry in the uninit map. We need to
4917 * do this for all registers that have the same object
4918 * instance in them, not just the "this" register.
4919 */
4920 int uidx = regTypeToUninitIndex(thisType);
4921 markRefsAsInitialized(workRegs, insnRegCount, uninitMap,
Andy McFadden62a75162009-04-17 17:23:37 -07004922 thisType, &failure);
4923 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004924 break;
4925 }
4926 returnType = getMethodReturnType(calledMethod);
4927 setResultRegisterType(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004928 returnType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004929 justSetResult = true;
4930 }
4931 break;
4932 case OP_INVOKE_STATIC:
4933 case OP_INVOKE_STATIC_RANGE:
4934 {
4935 RegType returnType;
4936 Method* calledMethod;
4937 bool isRange;
4938
4939 isRange = (decInsn.opCode == OP_INVOKE_STATIC_RANGE);
4940 calledMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
4941 &decInsn, uninitMap, METHOD_STATIC, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07004942 false, &failure);
4943 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004944 break;
4945
4946 returnType = getMethodReturnType(calledMethod);
Andy McFadden62a75162009-04-17 17:23:37 -07004947 setResultRegisterType(workRegs, insnRegCount, returnType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004948 justSetResult = true;
4949 }
4950 break;
4951 case OP_INVOKE_INTERFACE:
4952 case OP_INVOKE_INTERFACE_RANGE:
4953 {
4954 RegType /*thisType,*/ returnType;
4955 Method* absMethod;
4956 bool isRange;
4957
4958 isRange = (decInsn.opCode == OP_INVOKE_INTERFACE_RANGE);
4959 absMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
4960 &decInsn, uninitMap, METHOD_INTERFACE, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07004961 false, &failure);
4962 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004963 break;
4964
4965#if 0 /* can't do this here, fails on dalvik test 052-verifier-fun */
4966 /*
4967 * Get the type of the "this" arg, which should always be an
4968 * interface class. Because we don't do a full merge on
4969 * interface classes, this might have reduced to Object.
4970 */
4971 thisType = getInvocationThis(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004972 &decInsn, &failure);
4973 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004974 break;
4975
4976 if (thisType == kRegTypeZero) {
4977 /* null pointer always passes (and always fails at runtime) */
4978 } else {
4979 ClassObject* thisClass;
4980
4981 thisClass = regTypeInitializedReferenceToClass(thisType);
4982 if (thisClass == NULL) {
4983 LOG_VFY("VFY: interface call on uninitialized\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004984 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004985 break;
4986 }
4987
4988 /*
4989 * Either "thisClass" needs to be the interface class that
4990 * defined absMethod, or absMethod's class needs to be one
4991 * of the interfaces implemented by "thisClass". (Or, if
4992 * we couldn't complete the merge, this will be Object.)
4993 */
4994 if (thisClass != absMethod->clazz &&
4995 thisClass != gDvm.classJavaLangObject &&
4996 !dvmImplements(thisClass, absMethod->clazz))
4997 {
4998 LOG_VFY("VFY: unable to match absMethod '%s' with %s interfaces\n",
4999 absMethod->name, thisClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07005000 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005001 break;
5002 }
5003 }
5004#endif
5005
5006 /*
5007 * We don't have an object instance, so we can't find the
5008 * concrete method. However, all of the type information is
5009 * in the abstract method, so we're good.
5010 */
5011 returnType = getMethodReturnType(absMethod);
Andy McFadden62a75162009-04-17 17:23:37 -07005012 setResultRegisterType(workRegs, insnRegCount, returnType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005013 justSetResult = true;
5014 }
5015 break;
5016
5017 case OP_NEG_INT:
5018 case OP_NOT_INT:
5019 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005020 kRegTypeInteger, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005021 break;
5022 case OP_NEG_LONG:
5023 case OP_NOT_LONG:
5024 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005025 kRegTypeLongLo, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005026 break;
5027 case OP_NEG_FLOAT:
5028 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005029 kRegTypeFloat, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005030 break;
5031 case OP_NEG_DOUBLE:
5032 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005033 kRegTypeDoubleLo, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005034 break;
5035 case OP_INT_TO_LONG:
5036 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005037 kRegTypeLongLo, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005038 break;
5039 case OP_INT_TO_FLOAT:
5040 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005041 kRegTypeFloat, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005042 break;
5043 case OP_INT_TO_DOUBLE:
5044 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005045 kRegTypeDoubleLo, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005046 break;
5047 case OP_LONG_TO_INT:
5048 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005049 kRegTypeInteger, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005050 break;
5051 case OP_LONG_TO_FLOAT:
5052 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005053 kRegTypeFloat, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005054 break;
5055 case OP_LONG_TO_DOUBLE:
5056 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005057 kRegTypeDoubleLo, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005058 break;
5059 case OP_FLOAT_TO_INT:
5060 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005061 kRegTypeInteger, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005062 break;
5063 case OP_FLOAT_TO_LONG:
5064 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005065 kRegTypeLongLo, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005066 break;
5067 case OP_FLOAT_TO_DOUBLE:
5068 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005069 kRegTypeDoubleLo, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005070 break;
5071 case OP_DOUBLE_TO_INT:
5072 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005073 kRegTypeInteger, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005074 break;
5075 case OP_DOUBLE_TO_LONG:
5076 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005077 kRegTypeLongLo, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005078 break;
5079 case OP_DOUBLE_TO_FLOAT:
5080 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005081 kRegTypeFloat, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005082 break;
5083 case OP_INT_TO_BYTE:
5084 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005085 kRegTypeByte, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005086 break;
5087 case OP_INT_TO_CHAR:
5088 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005089 kRegTypeChar, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005090 break;
5091 case OP_INT_TO_SHORT:
5092 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005093 kRegTypeShort, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005094 break;
5095
5096 case OP_ADD_INT:
5097 case OP_SUB_INT:
5098 case OP_MUL_INT:
5099 case OP_REM_INT:
5100 case OP_DIV_INT:
5101 case OP_SHL_INT:
5102 case OP_SHR_INT:
5103 case OP_USHR_INT:
5104 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005105 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005106 break;
5107 case OP_AND_INT:
5108 case OP_OR_INT:
5109 case OP_XOR_INT:
5110 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005111 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005112 break;
5113 case OP_ADD_LONG:
5114 case OP_SUB_LONG:
5115 case OP_MUL_LONG:
5116 case OP_DIV_LONG:
5117 case OP_REM_LONG:
5118 case OP_AND_LONG:
5119 case OP_OR_LONG:
5120 case OP_XOR_LONG:
5121 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005122 kRegTypeLongLo, kRegTypeLongLo, kRegTypeLongLo, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005123 break;
5124 case OP_SHL_LONG:
5125 case OP_SHR_LONG:
5126 case OP_USHR_LONG:
5127 /* shift distance is Int, making these different from other binops */
5128 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005129 kRegTypeLongLo, kRegTypeLongLo, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005130 break;
5131 case OP_ADD_FLOAT:
5132 case OP_SUB_FLOAT:
5133 case OP_MUL_FLOAT:
5134 case OP_DIV_FLOAT:
5135 case OP_REM_FLOAT:
5136 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005137 kRegTypeFloat, kRegTypeFloat, kRegTypeFloat, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005138 break;
5139 case OP_ADD_DOUBLE:
5140 case OP_SUB_DOUBLE:
5141 case OP_MUL_DOUBLE:
5142 case OP_DIV_DOUBLE:
5143 case OP_REM_DOUBLE:
5144 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005145 kRegTypeDoubleLo, kRegTypeDoubleLo, kRegTypeDoubleLo, false,
5146 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005147 break;
5148 case OP_ADD_INT_2ADDR:
5149 case OP_SUB_INT_2ADDR:
5150 case OP_MUL_INT_2ADDR:
5151 case OP_REM_INT_2ADDR:
5152 case OP_SHL_INT_2ADDR:
5153 case OP_SHR_INT_2ADDR:
5154 case OP_USHR_INT_2ADDR:
5155 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005156 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005157 break;
5158 case OP_AND_INT_2ADDR:
5159 case OP_OR_INT_2ADDR:
5160 case OP_XOR_INT_2ADDR:
5161 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005162 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005163 break;
5164 case OP_DIV_INT_2ADDR:
5165 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005166 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005167 break;
5168 case OP_ADD_LONG_2ADDR:
5169 case OP_SUB_LONG_2ADDR:
5170 case OP_MUL_LONG_2ADDR:
5171 case OP_DIV_LONG_2ADDR:
5172 case OP_REM_LONG_2ADDR:
5173 case OP_AND_LONG_2ADDR:
5174 case OP_OR_LONG_2ADDR:
5175 case OP_XOR_LONG_2ADDR:
5176 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005177 kRegTypeLongLo, kRegTypeLongLo, kRegTypeLongLo, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005178 break;
5179 case OP_SHL_LONG_2ADDR:
5180 case OP_SHR_LONG_2ADDR:
5181 case OP_USHR_LONG_2ADDR:
5182 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005183 kRegTypeLongLo, kRegTypeLongLo, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005184 break;
5185 case OP_ADD_FLOAT_2ADDR:
5186 case OP_SUB_FLOAT_2ADDR:
5187 case OP_MUL_FLOAT_2ADDR:
5188 case OP_DIV_FLOAT_2ADDR:
5189 case OP_REM_FLOAT_2ADDR:
5190 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005191 kRegTypeFloat, kRegTypeFloat, kRegTypeFloat, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005192 break;
5193 case OP_ADD_DOUBLE_2ADDR:
5194 case OP_SUB_DOUBLE_2ADDR:
5195 case OP_MUL_DOUBLE_2ADDR:
5196 case OP_DIV_DOUBLE_2ADDR:
5197 case OP_REM_DOUBLE_2ADDR:
5198 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005199 kRegTypeDoubleLo, kRegTypeDoubleLo, kRegTypeDoubleLo, false,
5200 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005201 break;
5202 case OP_ADD_INT_LIT16:
5203 case OP_RSUB_INT:
5204 case OP_MUL_INT_LIT16:
5205 case OP_DIV_INT_LIT16:
5206 case OP_REM_INT_LIT16:
5207 checkLitop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005208 kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005209 break;
5210 case OP_AND_INT_LIT16:
5211 case OP_OR_INT_LIT16:
5212 case OP_XOR_INT_LIT16:
5213 checkLitop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005214 kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005215 break;
5216 case OP_ADD_INT_LIT8:
5217 case OP_RSUB_INT_LIT8:
5218 case OP_MUL_INT_LIT8:
5219 case OP_DIV_INT_LIT8:
5220 case OP_REM_INT_LIT8:
5221 case OP_SHL_INT_LIT8:
5222 case OP_SHR_INT_LIT8:
5223 case OP_USHR_INT_LIT8:
5224 checkLitop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005225 kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005226 break;
5227 case OP_AND_INT_LIT8:
5228 case OP_OR_INT_LIT8:
5229 case OP_XOR_INT_LIT8:
5230 checkLitop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005231 kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005232 break;
5233
Andy McFaddenb51ea112009-05-08 16:50:17 -07005234 /*
5235 * This falls into the general category of "optimized" instructions,
5236 * which don't generally appear during verification. Because it's
5237 * inserted in the course of verification, we can expect to see it here.
5238 */
5239 case OP_THROW_VERIFICATION_ERROR:
5240 break;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005241
5242 /*
5243 * Verifying "quickened" instructions is tricky, because we have
5244 * discarded the original field/method information. The byte offsets
5245 * and vtable indices only have meaning in the context of an object
5246 * instance.
5247 *
5248 * If a piece of code declares a local reference variable, assigns
5249 * null to it, and then issues a virtual method call on it, we
5250 * cannot evaluate the method call during verification. This situation
5251 * isn't hard to handle, since we know the call will always result in an
5252 * NPE, and the arguments and return value don't matter. Any code that
5253 * depends on the result of the method call is inaccessible, so the
5254 * fact that we can't fully verify anything that comes after the bad
5255 * call is not a problem.
5256 *
5257 * We must also consider the case of multiple code paths, only some of
5258 * which involve a null reference. We can completely verify the method
5259 * if we sidestep the results of executing with a null reference.
5260 * For example, if on the first pass through the code we try to do a
5261 * virtual method invocation through a null ref, we have to skip the
5262 * method checks and have the method return a "wildcard" type (which
5263 * merges with anything to become that other thing). The move-result
5264 * will tell us if it's a reference, single-word numeric, or double-word
5265 * value. We continue to perform the verification, and at the end of
5266 * the function any invocations that were never fully exercised are
5267 * marked as null-only.
5268 *
5269 * We would do something similar for the field accesses. The field's
5270 * type, once known, can be used to recover the width of short integers.
5271 * If the object reference was null, the field-get returns the "wildcard"
5272 * type, which is acceptable for any operation.
5273 */
5274 case OP_EXECUTE_INLINE:
5275 case OP_INVOKE_DIRECT_EMPTY:
5276 case OP_IGET_QUICK:
5277 case OP_IGET_WIDE_QUICK:
5278 case OP_IGET_OBJECT_QUICK:
5279 case OP_IPUT_QUICK:
5280 case OP_IPUT_WIDE_QUICK:
5281 case OP_IPUT_OBJECT_QUICK:
5282 case OP_INVOKE_VIRTUAL_QUICK:
5283 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
5284 case OP_INVOKE_SUPER_QUICK:
5285 case OP_INVOKE_SUPER_QUICK_RANGE:
Andy McFadden62a75162009-04-17 17:23:37 -07005286 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005287 break;
5288
5289 /* these should never appear */
5290 case OP_UNUSED_3E:
5291 case OP_UNUSED_3F:
5292 case OP_UNUSED_40:
5293 case OP_UNUSED_41:
5294 case OP_UNUSED_42:
5295 case OP_UNUSED_43:
5296 case OP_UNUSED_73:
5297 case OP_UNUSED_79:
5298 case OP_UNUSED_7A:
5299 case OP_UNUSED_E3:
5300 case OP_UNUSED_E4:
5301 case OP_UNUSED_E5:
5302 case OP_UNUSED_E6:
5303 case OP_UNUSED_E7:
5304 case OP_UNUSED_E8:
5305 case OP_UNUSED_E9:
5306 case OP_UNUSED_EA:
5307 case OP_UNUSED_EB:
5308 case OP_UNUSED_EC:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005309 case OP_UNUSED_EF:
5310 case OP_UNUSED_F1:
5311 case OP_UNUSED_FC:
5312 case OP_UNUSED_FD:
5313 case OP_UNUSED_FE:
5314 case OP_UNUSED_FF:
Andy McFadden62a75162009-04-17 17:23:37 -07005315 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005316 break;
5317
5318 /*
5319 * DO NOT add a "default" clause here. Without it the compiler will
5320 * complain if an instruction is missing (which is desirable).
5321 */
5322 }
5323
Andy McFadden62a75162009-04-17 17:23:37 -07005324 if (!VERIFY_OK(failure)) {
Andy McFaddenb51ea112009-05-08 16:50:17 -07005325 if (failure == VERIFY_ERROR_GENERIC || gDvm.optimizing) {
5326 /* immediate failure, reject class */
5327 LOG_VFY_METH(meth, "VFY: rejecting opcode 0x%02x at 0x%04x\n",
5328 decInsn.opCode, insnIdx);
5329 goto bail;
5330 } else {
5331 /* replace opcode and continue on */
5332 LOGD("VFY: replacing opcode 0x%02x at 0x%04x\n",
5333 decInsn.opCode, insnIdx);
5334 if (!replaceFailingInstruction(meth, insnFlags, insnIdx, failure)) {
5335 LOG_VFY_METH(meth, "VFY: rejecting opcode 0x%02x at 0x%04x\n",
5336 decInsn.opCode, insnIdx);
5337 goto bail;
5338 }
5339 /* IMPORTANT: meth->insns may have been changed */
5340 insns = meth->insns + insnIdx;
5341
5342 /* continue on as if we just handled a throw-verification-error */
5343 failure = VERIFY_ERROR_NONE;
5344 nextFlags = kInstrCanThrow;
5345 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005346 }
5347
5348 /*
5349 * If we didn't just set the result register, clear it out. This
5350 * ensures that you can only use "move-result" immediately after the
5351 * result is set.
5352 */
5353 if (!justSetResult) {
5354 int reg = RESULT_REGISTER(insnRegCount);
5355 workRegs[reg] = workRegs[reg+1] = kRegTypeUnknown;
5356 }
5357
5358 /*
5359 * Handle "continue". Tag the next consecutive instruction.
5360 */
5361 if ((nextFlags & kInstrCanContinue) != 0) {
5362 int insnWidth = dvmInsnGetWidth(insnFlags, insnIdx);
5363 if (insnIdx+insnWidth >= insnsSize) {
5364 LOG_VFY_METH(meth,
5365 "VFY: execution can walk off end of code area (from 0x%x)\n",
5366 insnIdx);
5367 goto bail;
5368 }
5369
5370 /*
5371 * The only way to get to a move-exception instruction is to get
5372 * thrown there. Make sure the next instruction isn't one.
5373 */
5374 if (!checkMoveException(meth, insnIdx+insnWidth, "next"))
5375 goto bail;
5376
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005377 if (getRegisterLine(regTable, insnIdx+insnWidth) != NULL) {
Andy McFadden06b7a282009-05-11 10:44:52 -07005378 /*
5379 * Merge registers into what we have for the next instruction,
5380 * and set the "changed" flag if needed.
5381 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005382 updateRegisters(meth, insnFlags, regTable, insnIdx+insnWidth,
5383 workRegs);
5384 } else {
The Android Open Source Project99409882009-03-18 22:20:24 -07005385 /*
Andy McFadden06b7a282009-05-11 10:44:52 -07005386 * We're not recording register data for the next instruction,
5387 * so we don't know what the prior state was. We have to
5388 * assume that something has changed and re-evaluate it.
The Android Open Source Project99409882009-03-18 22:20:24 -07005389 */
5390 dvmInsnSetChanged(insnFlags, insnIdx+insnWidth, true);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005391 }
5392 }
5393
5394 /*
5395 * Handle "branch". Tag the branch target.
5396 *
5397 * NOTE: instructions like OP_EQZ provide information about the state
5398 * of the register when the branch is taken or not taken. For example,
5399 * somebody could get a reference field, check it for zero, and if the
5400 * branch is taken immediately store that register in a boolean field
5401 * since the value is known to be zero. We do not currently account for
5402 * that, and will reject the code.
5403 */
5404 if ((nextFlags & kInstrCanBranch) != 0) {
5405 bool isConditional;
5406
5407 if (!dvmGetBranchTarget(meth, insnFlags, insnIdx, &branchTarget,
5408 &isConditional))
5409 {
5410 /* should never happen after static verification */
5411 LOG_VFY_METH(meth, "VFY: bad branch at %d\n", insnIdx);
5412 goto bail;
5413 }
5414 assert(isConditional || (nextFlags & kInstrCanContinue) == 0);
5415 assert(!isConditional || (nextFlags & kInstrCanContinue) != 0);
5416
5417 if (!checkMoveException(meth, insnIdx+branchTarget, "branch"))
5418 goto bail;
5419
The Android Open Source Project99409882009-03-18 22:20:24 -07005420 /* update branch target, set "changed" if appropriate */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005421 updateRegisters(meth, insnFlags, regTable, insnIdx+branchTarget,
5422 workRegs);
5423 }
5424
5425 /*
5426 * Handle "switch". Tag all possible branch targets.
5427 *
5428 * We've already verified that the table is structurally sound, so we
5429 * just need to walk through and tag the targets.
5430 */
5431 if ((nextFlags & kInstrCanSwitch) != 0) {
5432 int offsetToSwitch = insns[1] | (((s4)insns[2]) << 16);
5433 const u2* switchInsns = insns + offsetToSwitch;
5434 int switchCount = switchInsns[1];
5435 int offsetToTargets, targ;
5436
5437 if ((*insns & 0xff) == OP_PACKED_SWITCH) {
5438 /* 0=sig, 1=count, 2/3=firstKey */
5439 offsetToTargets = 4;
5440 } else {
5441 /* 0=sig, 1=count, 2..count*2 = keys */
5442 assert((*insns & 0xff) == OP_SPARSE_SWITCH);
5443 offsetToTargets = 2 + 2*switchCount;
5444 }
5445
5446 /* verify each switch target */
5447 for (targ = 0; targ < switchCount; targ++) {
5448 int offset, absOffset;
5449
5450 /* offsets are 32-bit, and only partly endian-swapped */
5451 offset = switchInsns[offsetToTargets + targ*2] |
5452 (((s4) switchInsns[offsetToTargets + targ*2 +1]) << 16);
5453 absOffset = insnIdx + offset;
5454
5455 assert(absOffset >= 0 && absOffset < insnsSize);
5456
5457 if (!checkMoveException(meth, absOffset, "switch"))
5458 goto bail;
5459
5460 updateRegisters(meth, insnFlags, regTable, absOffset, workRegs);
5461 }
5462 }
5463
5464 /*
5465 * Handle instructions that can throw and that are sitting in a
5466 * "try" block. (If they're not in a "try" block when they throw,
5467 * control transfers out of the method.)
5468 */
5469 if ((nextFlags & kInstrCanThrow) != 0 && dvmInsnIsInTry(insnFlags, insnIdx))
5470 {
5471 DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
5472 const DexCode* pCode = dvmGetMethodCode(meth);
5473 DexCatchIterator iterator;
5474
5475 if (dexFindCatchHandler(&iterator, pCode, insnIdx)) {
5476 for (;;) {
5477 DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
5478
5479 if (handler == NULL) {
5480 break;
5481 }
5482
5483 /* note we use entryRegs, not workRegs */
5484 updateRegisters(meth, insnFlags, regTable, handler->address,
5485 entryRegs);
5486 }
5487 }
5488 }
5489
5490 /*
5491 * Update startGuess. Advance to the next instruction of that's
5492 * possible, otherwise use the branch target if one was found. If
5493 * neither of those exists we're in a return or throw; leave startGuess
5494 * alone and let the caller sort it out.
5495 */
5496 if ((nextFlags & kInstrCanContinue) != 0) {
5497 *pStartGuess = insnIdx + dvmInsnGetWidth(insnFlags, insnIdx);
5498 } else if ((nextFlags & kInstrCanBranch) != 0) {
5499 /* we're still okay if branchTarget is zero */
5500 *pStartGuess = insnIdx + branchTarget;
5501 }
5502
5503 assert(*pStartGuess >= 0 && *pStartGuess < insnsSize &&
5504 dvmInsnGetWidth(insnFlags, *pStartGuess) != 0);
5505
5506 result = true;
5507
5508bail:
5509 return result;
5510}
5511
Andy McFaddenb51ea112009-05-08 16:50:17 -07005512
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005513/*
5514 * callback function used in dumpRegTypes to print local vars
5515 * valid at a given address.
5516 */
5517static void logLocalsCb(void *cnxt, u2 reg, u4 startAddress, u4 endAddress,
5518 const char *name, const char *descriptor,
5519 const char *signature)
5520{
5521 int addr = *((int *)cnxt);
5522
5523 if (addr >= (int) startAddress && addr < (int) endAddress)
5524 {
5525 LOGI(" %2d: '%s' %s\n", reg, name, descriptor);
5526 }
5527}
5528
5529/*
5530 * Dump the register types for the specifed address to the log file.
5531 */
5532static void dumpRegTypes(const Method* meth, const InsnFlags* insnFlags,
5533 const RegType* addrRegs, int addr, const char* addrName,
5534 const UninitInstanceMap* uninitMap, int displayFlags)
5535{
5536 int regCount = meth->registersSize;
5537 int fullRegCount = regCount + kExtraRegs;
5538 bool branchTarget = dvmInsnIsBranchTarget(insnFlags, addr);
5539 int i;
5540
5541 assert(addr >= 0 && addr < (int) dvmGetMethodInsnsSize(meth));
5542
5543 int regCharSize = fullRegCount + (fullRegCount-1)/4 + 2 +1;
5544 char regChars[regCharSize +1];
5545 memset(regChars, ' ', regCharSize);
5546 regChars[0] = '[';
5547 if (regCount == 0)
5548 regChars[1] = ']';
5549 else
5550 regChars[1 + (regCount-1) + (regCount-1)/4 +1] = ']';
5551 regChars[regCharSize] = '\0';
5552
5553 //const RegType* addrRegs = getRegisterLine(regTable, addr);
5554
5555 for (i = 0; i < regCount + kExtraRegs; i++) {
5556 char tch;
5557
5558 switch (addrRegs[i]) {
5559 case kRegTypeUnknown: tch = '.'; break;
5560 case kRegTypeConflict: tch = 'X'; break;
5561 case kRegTypeFloat: tch = 'F'; break;
5562 case kRegTypeZero: tch = '0'; break;
5563 case kRegTypeOne: tch = '1'; break;
5564 case kRegTypeBoolean: tch = 'Z'; break;
5565 case kRegTypePosByte: tch = 'b'; break;
5566 case kRegTypeByte: tch = 'B'; break;
5567 case kRegTypePosShort: tch = 's'; break;
5568 case kRegTypeShort: tch = 'S'; break;
5569 case kRegTypeChar: tch = 'C'; break;
5570 case kRegTypeInteger: tch = 'I'; break;
5571 case kRegTypeLongLo: tch = 'J'; break;
5572 case kRegTypeLongHi: tch = 'j'; break;
5573 case kRegTypeDoubleLo: tch = 'D'; break;
5574 case kRegTypeDoubleHi: tch = 'd'; break;
5575 default:
5576 if (regTypeIsReference(addrRegs[i])) {
5577 if (regTypeIsUninitReference(addrRegs[i]))
5578 tch = 'U';
5579 else
5580 tch = 'L';
5581 } else {
5582 tch = '*';
5583 assert(false);
5584 }
5585 break;
5586 }
5587
5588 if (i < regCount)
5589 regChars[1 + i + (i/4)] = tch;
5590 else
5591 regChars[1 + i + (i/4) + 2] = tch;
5592 }
5593
5594 if (addr == 0 && addrName != NULL)
5595 LOGI("%c%s %s\n", branchTarget ? '>' : ' ', addrName, regChars);
5596 else
5597 LOGI("%c0x%04x %s\n", branchTarget ? '>' : ' ', addr, regChars);
5598
5599 if (displayFlags & DRT_SHOW_REF_TYPES) {
5600 for (i = 0; i < regCount + kExtraRegs; i++) {
5601 if (regTypeIsReference(addrRegs[i]) && addrRegs[i] != kRegTypeZero)
5602 {
5603 ClassObject* clazz;
5604
5605 clazz = regTypeReferenceToClass(addrRegs[i], uninitMap);
5606 assert(dvmValidateObject((Object*)clazz));
5607 if (i < regCount) {
5608 LOGI(" %2d: 0x%08x %s%s\n",
5609 i, addrRegs[i],
5610 regTypeIsUninitReference(addrRegs[i]) ? "[U]" : "",
5611 clazz->descriptor);
5612 } else {
5613 LOGI(" RS: 0x%08x %s%s\n",
5614 addrRegs[i],
5615 regTypeIsUninitReference(addrRegs[i]) ? "[U]" : "",
5616 clazz->descriptor);
5617 }
5618 }
5619 }
5620 }
5621 if (displayFlags & DRT_SHOW_LOCALS) {
5622 dexDecodeDebugInfo(meth->clazz->pDvmDex->pDexFile,
5623 dvmGetMethodCode(meth),
5624 meth->clazz->descriptor,
5625 meth->prototype.protoIdx,
5626 meth->accessFlags,
5627 NULL, logLocalsCb, &addr);
5628 }
5629}
5630