blob: 3986aee450b6be6491d50ad75974927c9793a130 [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"
Andy McFadden2e1ee502010-03-24 13:25:53 -070032#include "analysis/Optimize.h"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080033#include "analysis/RegisterMap.h"
34#include "libdex/DexCatch.h"
35#include "libdex/InstrUtils.h"
36
37#include <stddef.h>
38
39
40/*
41 * We don't need to store the register data for many instructions, because
42 * we either only need it at branch points (for verification) or GC points
43 * and branches (for verification + type-precise register analysis).
44 */
45typedef enum RegisterTrackingMode {
46 kTrackRegsBranches,
47 kTrackRegsGcPoints,
48 kTrackRegsAll
49} RegisterTrackingMode;
50
51/*
52 * Set this to enable dead code scanning. This is not required, but it's
53 * very useful when testing changes to the verifier (to make sure we're not
54 * skipping over stuff) and for checking the optimized output from "dx".
55 * The only reason not to do it is that it slightly increases the time
56 * required to perform verification.
57 */
58#define DEAD_CODE_SCAN true
59
60static bool gDebugVerbose = false; // TODO: remove this
61
62#if 0
63int gDvm__totalInstr = 0;
64int gDvm__gcInstr = 0;
65int gDvm__gcData = 0;
66int gDvm__gcSimpleData = 0;
67#endif
68
69/*
70 * Selectively enable verbose debug logging -- use this to activate
71 * dumpRegTypes() calls for all instructions in the specified method.
72 */
73static inline bool doVerboseLogging(const Method* meth) {
74 return false; /* COMMENT OUT to enable verbose debugging */
75
The Android Open Source Project99409882009-03-18 22:20:24 -070076 const char* cd = "Landroid/net/http/Request;";
77 const char* mn = "readResponse";
78 const char* sg = "(Landroid/net/http/AndroidHttpClientConnection;)V";
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080079 return (strcmp(meth->clazz->descriptor, cd) == 0 &&
80 dvmCompareNameDescriptorAndMethod(mn, sg, meth) == 0);
81}
82
83#define SHOW_REG_DETAILS (0 /*| DRT_SHOW_REF_TYPES | DRT_SHOW_LOCALS*/)
84
85/*
86 * We need an extra "pseudo register" to hold the return type briefly. It
87 * can be category 1 or 2, so we need two slots.
88 */
89#define kExtraRegs 2
90#define RESULT_REGISTER(_insnRegCount) (_insnRegCount)
91
92/*
93 * Big fat collection of registers.
94 */
95typedef struct RegisterTable {
96 /*
97 * Array of RegType arrays, one per address in the method. We only
98 * set the pointers for certain addresses, based on what we're trying
99 * to accomplish.
100 */
101 RegType** addrRegs;
102
103 /*
104 * Number of registers we track for each instruction. This is equal
105 * to the method's declared "registersSize" plus kExtraRegs.
106 */
107 int insnRegCountPlus;
108
109 /*
110 * A single large alloc, with all of the storage needed for addrRegs.
111 */
112 RegType* regAlloc;
113} RegisterTable;
114
115
116/* fwd */
Carl Shapiroe3c01da2010-05-20 22:54:18 -0700117#ifndef NDEBUG
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800118static void checkMergeTab(void);
Carl Shapiroe3c01da2010-05-20 22:54:18 -0700119#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800120static bool isInitMethod(const Method* meth);
121static RegType getInvocationThis(const RegType* insnRegs,\
Andy McFaddend3250112010-11-03 14:32:42 -0700122 const DecodedInstruction* pDecInsn, VerifyError* pFailure);
123static void verifyRegisterType(const RegType* insnRegs, \
Andy McFadden62a75162009-04-17 17:23:37 -0700124 u4 vsrc, RegType checkType, VerifyError* pFailure);
Andy McFadden228a6b02010-05-04 15:02:32 -0700125static bool doCodeVerification(const Method* meth, InsnFlags* insnFlags,\
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800126 RegisterTable* regTable, UninitInstanceMap* uninitMap);
Andy McFadden228a6b02010-05-04 15:02:32 -0700127static bool verifyInstruction(const Method* meth, InsnFlags* insnFlags,\
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800128 RegisterTable* regTable, RegType* workRegs, int insnIdx,
129 UninitInstanceMap* uninitMap, int* pStartGuess);
130static ClassObject* findCommonSuperclass(ClassObject* c1, ClassObject* c2);
131static void dumpRegTypes(const Method* meth, const InsnFlags* insnFlags,\
132 const RegType* addrRegs, int addr, const char* addrName,
133 const UninitInstanceMap* uninitMap, int displayFlags);
134
135/* bit values for dumpRegTypes() "displayFlags" */
136enum {
137 DRT_SIMPLE = 0,
138 DRT_SHOW_REF_TYPES = 0x01,
139 DRT_SHOW_LOCALS = 0x02,
140};
141
142
143/*
144 * ===========================================================================
145 * RegType and UninitInstanceMap utility functions
146 * ===========================================================================
147 */
148
149#define __ kRegTypeUnknown
150#define _U kRegTypeUninit
151#define _X kRegTypeConflict
152#define _F kRegTypeFloat
153#define _0 kRegTypeZero
154#define _1 kRegTypeOne
155#define _Z kRegTypeBoolean
156#define _b kRegTypePosByte
157#define _B kRegTypeByte
158#define _s kRegTypePosShort
159#define _S kRegTypeShort
160#define _C kRegTypeChar
161#define _I kRegTypeInteger
162#define _J kRegTypeLongLo
163#define _j kRegTypeLongHi
164#define _D kRegTypeDoubleLo
165#define _d kRegTypeDoubleHi
166
167/*
168 * Merge result table for primitive values. The table is symmetric along
169 * the diagonal.
170 *
171 * Note that 32-bit int/float do not merge into 64-bit long/double. This
172 * is a register merge, not a widening conversion. Only the "implicit"
173 * widening within a category, e.g. byte to short, is allowed.
174 *
175 * Because Dalvik does not draw a distinction between int and float, we
176 * have to allow free exchange between 32-bit int/float and 64-bit
177 * long/double.
178 *
179 * Note that Uninit+Uninit=Uninit. This holds true because we only
180 * use this when the RegType value is exactly equal to kRegTypeUninit, which
181 * can only happen for the zeroeth entry in the table.
182 *
183 * "Unknown" never merges with anything known. The only time a register
184 * transitions from "unknown" to "known" is when we're executing code
185 * for the first time, and we handle that with a simple copy.
186 */
187const char gDvmMergeTab[kRegTypeMAX][kRegTypeMAX] =
188{
189 /* chk: _ U X F 0 1 Z b B s S C I J j D d */
190 { /*_*/ __,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X },
191 { /*U*/ _X,_U,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X },
192 { /*X*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X },
193 { /*F*/ _X,_X,_X,_F,_F,_F,_F,_F,_F,_F,_F,_F,_F,_X,_X,_X,_X },
194 { /*0*/ _X,_X,_X,_F,_0,_Z,_Z,_b,_B,_s,_S,_C,_I,_X,_X,_X,_X },
195 { /*1*/ _X,_X,_X,_F,_Z,_1,_Z,_b,_B,_s,_S,_C,_I,_X,_X,_X,_X },
196 { /*Z*/ _X,_X,_X,_F,_Z,_Z,_Z,_b,_B,_s,_S,_C,_I,_X,_X,_X,_X },
197 { /*b*/ _X,_X,_X,_F,_b,_b,_b,_b,_B,_s,_S,_C,_I,_X,_X,_X,_X },
198 { /*B*/ _X,_X,_X,_F,_B,_B,_B,_B,_B,_S,_S,_I,_I,_X,_X,_X,_X },
199 { /*s*/ _X,_X,_X,_F,_s,_s,_s,_s,_S,_s,_S,_C,_I,_X,_X,_X,_X },
200 { /*S*/ _X,_X,_X,_F,_S,_S,_S,_S,_S,_S,_S,_I,_I,_X,_X,_X,_X },
201 { /*C*/ _X,_X,_X,_F,_C,_C,_C,_C,_I,_C,_I,_C,_I,_X,_X,_X,_X },
202 { /*I*/ _X,_X,_X,_F,_I,_I,_I,_I,_I,_I,_I,_I,_I,_X,_X,_X,_X },
203 { /*J*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_J,_X,_J,_X },
204 { /*j*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_j,_X,_j },
205 { /*D*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_J,_X,_D,_X },
206 { /*d*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_j,_X,_d },
207};
208
209#undef __
210#undef _U
211#undef _X
212#undef _F
213#undef _0
214#undef _1
215#undef _Z
216#undef _b
217#undef _B
218#undef _s
219#undef _S
220#undef _C
221#undef _I
222#undef _J
223#undef _j
224#undef _D
225#undef _d
226
227#ifndef NDEBUG
228/*
229 * Verify symmetry in the conversion table.
230 */
231static void checkMergeTab(void)
232{
233 int i, j;
234
235 for (i = 0; i < kRegTypeMAX; i++) {
236 for (j = i; j < kRegTypeMAX; j++) {
237 if (gDvmMergeTab[i][j] != gDvmMergeTab[j][i]) {
238 LOGE("Symmetry violation: %d,%d vs %d,%d\n", i, j, j, i);
239 dvmAbort();
240 }
241 }
242 }
243}
244#endif
245
246/*
247 * Determine whether we can convert "srcType" to "checkType", where
248 * "checkType" is one of the category-1 non-reference types.
249 *
250 * 32-bit int and float are interchangeable.
251 */
252static bool canConvertTo1nr(RegType srcType, RegType checkType)
253{
254 static const char convTab
255 [kRegType1nrEND-kRegType1nrSTART+1][kRegType1nrEND-kRegType1nrSTART+1] =
256 {
257 /* chk: F 0 1 Z b B s S C I */
258 { /*F*/ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
259 { /*0*/ 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
260 { /*1*/ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 },
261 { /*Z*/ 1, 0, 0, 1, 1, 1, 1, 1, 1, 1 },
262 { /*b*/ 1, 0, 0, 0, 1, 1, 1, 1, 1, 1 },
263 { /*B*/ 1, 0, 0, 0, 0, 1, 0, 1, 0, 1 },
264 { /*s*/ 1, 0, 0, 0, 0, 0, 1, 1, 1, 1 },
265 { /*S*/ 1, 0, 0, 0, 0, 0, 0, 1, 0, 1 },
266 { /*C*/ 1, 0, 0, 0, 0, 0, 0, 0, 1, 1 },
267 { /*I*/ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
268 };
269
270 assert(checkType >= kRegType1nrSTART && checkType <= kRegType1nrEND);
271#if 0
272 if (checkType < kRegType1nrSTART || checkType > kRegType1nrEND) {
273 LOG_VFY("Unexpected checkType %d (srcType=%d)\n", checkType, srcType);
274 assert(false);
275 return false;
276 }
277#endif
278
279 //printf("convTab[%d][%d] = %d\n", srcType, checkType,
280 // convTab[srcType-kRegType1nrSTART][checkType-kRegType1nrSTART]);
281 if (srcType >= kRegType1nrSTART && srcType <= kRegType1nrEND)
282 return (bool) convTab[srcType-kRegType1nrSTART][checkType-kRegType1nrSTART];
283
284 return false;
285}
286
287/*
288 * Determine whether the types are compatible. In Dalvik, 64-bit doubles
289 * and longs are interchangeable.
290 */
291static bool canConvertTo2(RegType srcType, RegType checkType)
292{
293 return ((srcType == kRegTypeLongLo || srcType == kRegTypeDoubleLo) &&
294 (checkType == kRegTypeLongLo || checkType == kRegTypeDoubleLo));
295}
296
297/*
298 * Determine whether or not "instrType" and "targetType" are compatible,
299 * for purposes of getting or setting a value in a field or array. The
300 * idea is that an instruction with a category 1nr type (say, aget-short
301 * or iput-boolean) is accessing a static field, instance field, or array
302 * entry, and we want to make sure sure that the operation is legal.
303 *
304 * At a minimum, source and destination must have the same width. We
305 * further refine this to assert that "short" and "char" are not
306 * compatible, because the sign-extension is different on the "get"
307 * operations. As usual, "float" and "int" are interoperable.
308 *
309 * We're not considering the actual contents of the register, so we'll
310 * never get "pseudo-types" like kRegTypeZero or kRegTypePosShort. We
311 * could get kRegTypeUnknown in "targetType" if a field or array class
312 * lookup failed. Category 2 types and references are checked elsewhere.
313 */
314static bool checkFieldArrayStore1nr(RegType instrType, RegType targetType)
315{
316 if (instrType == targetType)
317 return true; /* quick positive; most common case */
318
319 if ((instrType == kRegTypeInteger && targetType == kRegTypeFloat) ||
320 (instrType == kRegTypeFloat && targetType == kRegTypeInteger))
321 {
322 return true;
323 }
324
325 return false;
326}
327
328/*
329 * Convert a VM PrimitiveType enum value to the equivalent RegType value.
330 */
331static RegType primitiveTypeToRegType(PrimitiveType primType)
332{
The Android Open Source Project99409882009-03-18 22:20:24 -0700333 static const struct {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800334 RegType regType; /* type equivalent */
335 PrimitiveType primType; /* verification */
336 } convTab[] = {
337 /* must match order of enum in Object.h */
338 { kRegTypeBoolean, PRIM_BOOLEAN },
339 { kRegTypeChar, PRIM_CHAR },
340 { kRegTypeFloat, PRIM_FLOAT },
341 { kRegTypeDoubleLo, PRIM_DOUBLE },
342 { kRegTypeByte, PRIM_BYTE },
343 { kRegTypeShort, PRIM_SHORT },
344 { kRegTypeInteger, PRIM_INT },
345 { kRegTypeLongLo, PRIM_LONG },
346 // PRIM_VOID
347 };
348
349 if (primType < 0 || primType > (int) (sizeof(convTab) / sizeof(convTab[0])))
350 {
351 assert(false);
352 return kRegTypeUnknown;
353 }
354
355 assert(convTab[primType].primType == primType);
356 return convTab[primType].regType;
357}
358
359/*
Andy McFadden470cbbb2010-11-04 16:31:37 -0700360 * Given a 32-bit constant, return the most-restricted RegType enum entry
361 * that can hold the value.
362 */
363static char determineCat1Const(s4 value)
364{
365 if (value < -32768)
366 return kRegTypeInteger;
367 else if (value < -128)
368 return kRegTypeShort;
369 else if (value < 0)
370 return kRegTypeByte;
371 else if (value == 0)
372 return kRegTypeZero;
373 else if (value == 1)
374 return kRegTypeOne;
375 else if (value < 128)
376 return kRegTypePosByte;
377 else if (value < 32768)
378 return kRegTypePosShort;
379 else if (value < 65536)
380 return kRegTypeChar;
381 else
382 return kRegTypeInteger;
383}
384
385/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800386 * Create a new uninitialized instance map.
387 *
388 * The map is allocated and populated with address entries. The addresses
389 * appear in ascending order to allow binary searching.
390 *
391 * Very few methods have 10 or more new-instance instructions; the
392 * majority have 0 or 1. Occasionally a static initializer will have 200+.
393 */
394UninitInstanceMap* dvmCreateUninitInstanceMap(const Method* meth,
395 const InsnFlags* insnFlags, int newInstanceCount)
396{
397 const int insnsSize = dvmGetMethodInsnsSize(meth);
398 const u2* insns = meth->insns;
399 UninitInstanceMap* uninitMap;
400 bool isInit = false;
401 int idx, addr;
402
403 if (isInitMethod(meth)) {
404 newInstanceCount++;
405 isInit = true;
406 }
407
408 /*
409 * Allocate the header and map as a single unit.
410 *
411 * TODO: consider having a static instance so we can avoid allocations.
412 * I don't think the verifier is guaranteed to be single-threaded when
413 * running in the VM (rather than dexopt), so that must be taken into
414 * account.
415 */
416 int size = offsetof(UninitInstanceMap, map) +
417 newInstanceCount * sizeof(uninitMap->map[0]);
418 uninitMap = calloc(1, size);
419 if (uninitMap == NULL)
420 return NULL;
421 uninitMap->numEntries = newInstanceCount;
422
423 idx = 0;
424 if (isInit) {
425 uninitMap->map[idx++].addr = kUninitThisArgAddr;
426 }
427
428 /*
429 * Run through and find the new-instance instructions.
430 */
431 for (addr = 0; addr < insnsSize; /**/) {
432 int width = dvmInsnGetWidth(insnFlags, addr);
433
434 if ((*insns & 0xff) == OP_NEW_INSTANCE)
435 uninitMap->map[idx++].addr = addr;
436
437 addr += width;
438 insns += width;
439 }
440
441 assert(idx == newInstanceCount);
442 return uninitMap;
443}
444
445/*
446 * Free the map.
447 */
448void dvmFreeUninitInstanceMap(UninitInstanceMap* uninitMap)
449{
450 free(uninitMap);
451}
452
453/*
454 * Set the class object associated with the instruction at "addr".
455 *
456 * Returns the map slot index, or -1 if the address isn't listed in the map
457 * (shouldn't happen) or if a class is already associated with the address
458 * (bad bytecode).
459 *
460 * Entries, once set, do not change -- a given address can only allocate
461 * one type of object.
462 */
463int dvmSetUninitInstance(UninitInstanceMap* uninitMap, int addr,
464 ClassObject* clazz)
465{
466 int idx;
467
468 assert(clazz != NULL);
469
470 /* TODO: binary search when numEntries > 8 */
471 for (idx = uninitMap->numEntries - 1; idx >= 0; idx--) {
472 if (uninitMap->map[idx].addr == addr) {
473 if (uninitMap->map[idx].clazz != NULL &&
474 uninitMap->map[idx].clazz != clazz)
475 {
476 LOG_VFY("VFY: addr %d already set to %p, not setting to %p\n",
477 addr, uninitMap->map[idx].clazz, clazz);
478 return -1; // already set to something else??
479 }
480 uninitMap->map[idx].clazz = clazz;
481 return idx;
482 }
483 }
484
485 LOG_VFY("VFY: addr %d not found in uninit map\n", addr);
486 assert(false); // shouldn't happen
487 return -1;
488}
489
490/*
491 * Get the class object at the specified index.
492 */
493ClassObject* dvmGetUninitInstance(const UninitInstanceMap* uninitMap, int idx)
494{
495 assert(idx >= 0 && idx < uninitMap->numEntries);
496 return uninitMap->map[idx].clazz;
497}
498
499/* determine if "type" is actually an object reference (init/uninit/zero) */
500static inline bool regTypeIsReference(RegType type) {
501 return (type > kRegTypeMAX || type == kRegTypeUninit ||
502 type == kRegTypeZero);
503}
504
505/* determine if "type" is an uninitialized object reference */
506static inline bool regTypeIsUninitReference(RegType type) {
507 return ((type & kRegTypeUninitMask) == kRegTypeUninit);
508}
509
510/* convert the initialized reference "type" to a ClassObject pointer */
511/* (does not expect uninit ref types or "zero") */
512static ClassObject* regTypeInitializedReferenceToClass(RegType type)
513{
514 assert(regTypeIsReference(type) && type != kRegTypeZero);
515 if ((type & 0x01) == 0) {
516 return (ClassObject*) type;
517 } else {
518 //LOG_VFY("VFY: attempted to use uninitialized reference\n");
519 return NULL;
520 }
521}
522
523/* extract the index into the uninitialized instance map table */
524static inline int regTypeToUninitIndex(RegType type) {
525 assert(regTypeIsUninitReference(type));
526 return (type & ~kRegTypeUninitMask) >> kRegTypeUninitShift;
527}
528
529/* convert the reference "type" to a ClassObject pointer */
530static ClassObject* regTypeReferenceToClass(RegType type,
531 const UninitInstanceMap* uninitMap)
532{
533 assert(regTypeIsReference(type) && type != kRegTypeZero);
534 if (regTypeIsUninitReference(type)) {
535 assert(uninitMap != NULL);
536 return dvmGetUninitInstance(uninitMap, regTypeToUninitIndex(type));
537 } else {
538 return (ClassObject*) type;
539 }
540}
541
542/* convert the ClassObject pointer to an (initialized) register type */
543static inline RegType regTypeFromClass(ClassObject* clazz) {
544 return (u4) clazz;
545}
546
547/* return the RegType for the uninitialized reference in slot "uidx" */
548static RegType regTypeFromUninitIndex(int uidx) {
549 return (u4) (kRegTypeUninit | (uidx << kRegTypeUninitShift));
550}
551
552
553/*
554 * ===========================================================================
555 * Signature operations
556 * ===========================================================================
557 */
558
559/*
560 * Is this method a constructor?
561 */
562static bool isInitMethod(const Method* meth)
563{
564 return (*meth->name == '<' && strcmp(meth->name+1, "init>") == 0);
565}
566
567/*
568 * Is this method a class initializer?
569 */
Carl Shapiroe3c01da2010-05-20 22:54:18 -0700570#if 0
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800571static bool isClassInitMethod(const Method* meth)
572{
573 return (*meth->name == '<' && strcmp(meth->name+1, "clinit>") == 0);
574}
Carl Shapiroe3c01da2010-05-20 22:54:18 -0700575#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800576
577/*
578 * Look up a class reference given as a simple string descriptor.
Andy McFadden62a75162009-04-17 17:23:37 -0700579 *
580 * If we can't find it, return a generic substitute when possible.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800581 */
582static ClassObject* lookupClassByDescriptor(const Method* meth,
Andy McFadden62a75162009-04-17 17:23:37 -0700583 const char* pDescriptor, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800584{
585 /*
586 * The javac compiler occasionally puts references to nonexistent
587 * classes in signatures. For example, if you have a non-static
588 * inner class with no constructor, the compiler provides
589 * a private <init> for you. Constructing the class
590 * requires <init>(parent), but the outer class can't call
591 * that because the method is private. So the compiler
592 * generates a package-scope <init>(parent,bogus) method that
593 * just calls the regular <init> (the "bogus" part being necessary
594 * to distinguish the signature of the synthetic method).
595 * Treating the bogus class as an instance of java.lang.Object
596 * allows the verifier to process the class successfully.
597 */
598
599 //LOGI("Looking up '%s'\n", typeStr);
600 ClassObject* clazz;
601 clazz = dvmFindClassNoInit(pDescriptor, meth->clazz->classLoader);
602 if (clazz == NULL) {
603 dvmClearOptException(dvmThreadSelf());
604 if (strchr(pDescriptor, '$') != NULL) {
605 LOGV("VFY: unable to find class referenced in signature (%s)\n",
606 pDescriptor);
607 } else {
608 LOG_VFY("VFY: unable to find class referenced in signature (%s)\n",
609 pDescriptor);
610 }
611
612 if (pDescriptor[0] == '[') {
613 /* We are looking at an array descriptor. */
614
615 /*
616 * There should never be a problem loading primitive arrays.
617 */
618 if (pDescriptor[1] != 'L' && pDescriptor[1] != '[') {
619 LOG_VFY("VFY: invalid char in signature in '%s'\n",
620 pDescriptor);
Andy McFadden62a75162009-04-17 17:23:37 -0700621 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800622 }
623
624 /*
625 * Try to continue with base array type. This will let
626 * us pass basic stuff (e.g. get array len) that wouldn't
627 * fly with an Object. This is NOT correct if the
628 * missing type is a primitive array, but we should never
629 * have a problem loading those. (I'm not convinced this
630 * is correct or even useful. Just use Object here?)
631 */
632 clazz = dvmFindClassNoInit("[Ljava/lang/Object;",
633 meth->clazz->classLoader);
634 } else if (pDescriptor[0] == 'L') {
635 /*
636 * We are looking at a non-array reference descriptor;
637 * try to continue with base reference type.
638 */
639 clazz = gDvm.classJavaLangObject;
640 } else {
641 /* We are looking at a primitive type. */
642 LOG_VFY("VFY: invalid char in signature in '%s'\n", pDescriptor);
Andy McFadden62a75162009-04-17 17:23:37 -0700643 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800644 }
645
646 if (clazz == NULL) {
Andy McFadden62a75162009-04-17 17:23:37 -0700647 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800648 }
649 }
650
651 if (dvmIsPrimitiveClass(clazz)) {
652 LOG_VFY("VFY: invalid use of primitive type '%s'\n", pDescriptor);
Andy McFadden62a75162009-04-17 17:23:37 -0700653 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800654 clazz = NULL;
655 }
656
657 return clazz;
658}
659
660/*
661 * Look up a class reference in a signature. Could be an arg or the
662 * return value.
663 *
664 * Advances "*pSig" to the last character in the signature (that is, to
665 * the ';').
666 *
667 * NOTE: this is also expected to verify the signature.
668 */
669static ClassObject* lookupSignatureClass(const Method* meth, const char** pSig,
Andy McFadden62a75162009-04-17 17:23:37 -0700670 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800671{
672 const char* sig = *pSig;
673 const char* endp = sig;
674
675 assert(sig != NULL && *sig == 'L');
676
677 while (*++endp != ';' && *endp != '\0')
678 ;
679 if (*endp != ';') {
680 LOG_VFY("VFY: bad signature component '%s' (missing ';')\n", sig);
Andy McFadden62a75162009-04-17 17:23:37 -0700681 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800682 return NULL;
683 }
684
685 endp++; /* Advance past the ';'. */
686 int typeLen = endp - sig;
687 char typeStr[typeLen+1]; /* +1 for the '\0' */
688 memcpy(typeStr, sig, typeLen);
689 typeStr[typeLen] = '\0';
690
691 *pSig = endp - 1; /* - 1 so that *pSig points at, not past, the ';' */
692
Andy McFadden62a75162009-04-17 17:23:37 -0700693 return lookupClassByDescriptor(meth, typeStr, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800694}
695
696/*
697 * Look up an array class reference in a signature. Could be an arg or the
698 * return value.
699 *
700 * Advances "*pSig" to the last character in the signature.
701 *
702 * NOTE: this is also expected to verify the signature.
703 */
704static ClassObject* lookupSignatureArrayClass(const Method* meth,
Andy McFadden62a75162009-04-17 17:23:37 -0700705 const char** pSig, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800706{
707 const char* sig = *pSig;
708 const char* endp = sig;
709
710 assert(sig != NULL && *sig == '[');
711
712 /* find the end */
713 while (*++endp == '[' && *endp != '\0')
714 ;
715
716 if (*endp == 'L') {
717 while (*++endp != ';' && *endp != '\0')
718 ;
719 if (*endp != ';') {
720 LOG_VFY("VFY: bad signature component '%s' (missing ';')\n", sig);
Andy McFadden62a75162009-04-17 17:23:37 -0700721 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800722 return NULL;
723 }
724 }
725
726 int typeLen = endp - sig +1;
727 char typeStr[typeLen+1];
728 memcpy(typeStr, sig, typeLen);
729 typeStr[typeLen] = '\0';
730
731 *pSig = endp;
732
Andy McFadden62a75162009-04-17 17:23:37 -0700733 return lookupClassByDescriptor(meth, typeStr, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800734}
735
736/*
737 * Set the register types for the first instruction in the method based on
738 * the method signature.
739 *
740 * This has the side-effect of validating the signature.
741 *
742 * Returns "true" on success.
743 */
744static bool setTypesFromSignature(const Method* meth, RegType* regTypes,
745 UninitInstanceMap* uninitMap)
746{
747 DexParameterIterator iterator;
748 int actualArgs, expectedArgs, argStart;
Andy McFadden62a75162009-04-17 17:23:37 -0700749 VerifyError failure = VERIFY_ERROR_NONE;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800750
751 dexParameterIteratorInit(&iterator, &meth->prototype);
752 argStart = meth->registersSize - meth->insSize;
753 expectedArgs = meth->insSize; /* long/double count as two */
754 actualArgs = 0;
755
756 assert(argStart >= 0); /* should have been verified earlier */
757
758 /*
759 * Include the "this" pointer.
760 */
761 if (!dvmIsStaticMethod(meth)) {
762 /*
763 * If this is a constructor for a class other than java.lang.Object,
764 * mark the first ("this") argument as uninitialized. This restricts
765 * field access until the superclass constructor is called.
766 */
767 if (isInitMethod(meth) && meth->clazz != gDvm.classJavaLangObject) {
768 int uidx = dvmSetUninitInstance(uninitMap, kUninitThisArgAddr,
769 meth->clazz);
770 assert(uidx == 0);
771 regTypes[argStart + actualArgs] = regTypeFromUninitIndex(uidx);
772 } else {
773 regTypes[argStart + actualArgs] = regTypeFromClass(meth->clazz);
774 }
775 actualArgs++;
776 }
777
778 for (;;) {
779 const char* descriptor = dexParameterIteratorNextDescriptor(&iterator);
780
781 if (descriptor == NULL) {
782 break;
783 }
784
785 if (actualArgs >= expectedArgs) {
786 LOG_VFY("VFY: expected %d args, found more (%s)\n",
787 expectedArgs, descriptor);
788 goto bad_sig;
789 }
790
791 switch (*descriptor) {
792 case 'L':
793 case '[':
794 /*
795 * We assume that reference arguments are initialized. The
796 * only way it could be otherwise (assuming the caller was
797 * verified) is if the current method is <init>, but in that
798 * case it's effectively considered initialized the instant
799 * we reach here (in the sense that we can return without
800 * doing anything or call virtual methods).
801 */
802 {
803 ClassObject* clazz =
Andy McFadden62a75162009-04-17 17:23:37 -0700804 lookupClassByDescriptor(meth, descriptor, &failure);
805 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800806 goto bad_sig;
807 regTypes[argStart + actualArgs] = regTypeFromClass(clazz);
808 }
809 actualArgs++;
810 break;
811 case 'Z':
812 regTypes[argStart + actualArgs] = kRegTypeBoolean;
813 actualArgs++;
814 break;
815 case 'C':
816 regTypes[argStart + actualArgs] = kRegTypeChar;
817 actualArgs++;
818 break;
819 case 'B':
820 regTypes[argStart + actualArgs] = kRegTypeByte;
821 actualArgs++;
822 break;
823 case 'I':
824 regTypes[argStart + actualArgs] = kRegTypeInteger;
825 actualArgs++;
826 break;
827 case 'S':
828 regTypes[argStart + actualArgs] = kRegTypeShort;
829 actualArgs++;
830 break;
831 case 'F':
832 regTypes[argStart + actualArgs] = kRegTypeFloat;
833 actualArgs++;
834 break;
835 case 'D':
836 regTypes[argStart + actualArgs] = kRegTypeDoubleLo;
837 regTypes[argStart + actualArgs +1] = kRegTypeDoubleHi;
838 actualArgs += 2;
839 break;
840 case 'J':
841 regTypes[argStart + actualArgs] = kRegTypeLongLo;
842 regTypes[argStart + actualArgs +1] = kRegTypeLongHi;
843 actualArgs += 2;
844 break;
845 default:
846 LOG_VFY("VFY: unexpected signature type char '%c'\n", *descriptor);
847 goto bad_sig;
848 }
849 }
850
851 if (actualArgs != expectedArgs) {
852 LOG_VFY("VFY: expected %d args, found %d\n", expectedArgs, actualArgs);
853 goto bad_sig;
854 }
855
856 const char* descriptor = dexProtoGetReturnType(&meth->prototype);
857
858 /*
859 * Validate return type. We don't do the type lookup; just want to make
860 * sure that it has the right format. Only major difference from the
861 * method argument format is that 'V' is supported.
862 */
863 switch (*descriptor) {
864 case 'I':
865 case 'C':
866 case 'S':
867 case 'B':
868 case 'Z':
869 case 'V':
870 case 'F':
871 case 'D':
872 case 'J':
873 if (*(descriptor+1) != '\0')
874 goto bad_sig;
875 break;
876 case '[':
877 /* single/multi, object/primitive */
878 while (*++descriptor == '[')
879 ;
880 if (*descriptor == 'L') {
881 while (*++descriptor != ';' && *descriptor != '\0')
882 ;
883 if (*descriptor != ';')
884 goto bad_sig;
885 } else {
886 if (*(descriptor+1) != '\0')
887 goto bad_sig;
888 }
889 break;
890 case 'L':
891 /* could be more thorough here, but shouldn't be required */
892 while (*++descriptor != ';' && *descriptor != '\0')
893 ;
894 if (*descriptor != ';')
895 goto bad_sig;
896 break;
897 default:
898 goto bad_sig;
899 }
900
901 return true;
902
903//fail:
904// LOG_VFY_METH(meth, "VFY: bad sig\n");
905// return false;
906
907bad_sig:
908 {
909 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
910 LOG_VFY("VFY: bad signature '%s' for %s.%s\n",
911 desc, meth->clazz->descriptor, meth->name);
912 free(desc);
913 }
914 return false;
915}
916
917/*
918 * Return the register type for the method. We can't just use the
919 * already-computed DalvikJniReturnType, because if it's a reference type
920 * we need to do the class lookup.
921 *
922 * Returned references are assumed to be initialized.
923 *
924 * Returns kRegTypeUnknown for "void".
925 */
926static RegType getMethodReturnType(const Method* meth)
927{
928 RegType type;
929 const char* descriptor = dexProtoGetReturnType(&meth->prototype);
930
931 switch (*descriptor) {
932 case 'I':
933 type = kRegTypeInteger;
934 break;
935 case 'C':
936 type = kRegTypeChar;
937 break;
938 case 'S':
939 type = kRegTypeShort;
940 break;
941 case 'B':
942 type = kRegTypeByte;
943 break;
944 case 'Z':
945 type = kRegTypeBoolean;
946 break;
947 case 'V':
948 type = kRegTypeUnknown;
949 break;
950 case 'F':
951 type = kRegTypeFloat;
952 break;
953 case 'D':
954 type = kRegTypeDoubleLo;
955 break;
956 case 'J':
957 type = kRegTypeLongLo;
958 break;
959 case 'L':
960 case '[':
961 {
Andy McFadden62a75162009-04-17 17:23:37 -0700962 VerifyError failure = VERIFY_ERROR_NONE;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800963 ClassObject* clazz =
Andy McFadden62a75162009-04-17 17:23:37 -0700964 lookupClassByDescriptor(meth, descriptor, &failure);
965 assert(VERIFY_OK(failure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800966 type = regTypeFromClass(clazz);
967 }
968 break;
969 default:
970 /* we verified signature return type earlier, so this is impossible */
971 assert(false);
972 type = kRegTypeConflict;
973 break;
974 }
975
976 return type;
977}
978
979/*
980 * Convert a single-character signature value (i.e. a primitive type) to
981 * the corresponding RegType. This is intended for access to object fields
982 * holding primitive types.
983 *
984 * Returns kRegTypeUnknown for objects, arrays, and void.
985 */
986static RegType primSigCharToRegType(char sigChar)
987{
988 RegType type;
989
990 switch (sigChar) {
991 case 'I':
992 type = kRegTypeInteger;
993 break;
994 case 'C':
995 type = kRegTypeChar;
996 break;
997 case 'S':
998 type = kRegTypeShort;
999 break;
1000 case 'B':
1001 type = kRegTypeByte;
1002 break;
1003 case 'Z':
1004 type = kRegTypeBoolean;
1005 break;
1006 case 'F':
1007 type = kRegTypeFloat;
1008 break;
1009 case 'D':
1010 type = kRegTypeDoubleLo;
1011 break;
1012 case 'J':
1013 type = kRegTypeLongLo;
1014 break;
1015 case 'V':
1016 case 'L':
1017 case '[':
1018 type = kRegTypeUnknown;
1019 break;
1020 default:
1021 assert(false);
1022 type = kRegTypeUnknown;
1023 break;
1024 }
1025
1026 return type;
1027}
1028
1029/*
Andy McFadden99a33e72010-10-10 12:59:11 -07001030 * See if the method matches the MethodType.
1031 */
1032static bool isCorrectInvokeKind(MethodType methodType, Method* resMethod)
1033{
1034 switch (methodType) {
1035 case METHOD_DIRECT:
1036 return dvmIsDirectMethod(resMethod);
1037 case METHOD_STATIC:
1038 return dvmIsStaticMethod(resMethod);
1039 case METHOD_VIRTUAL:
1040 case METHOD_INTERFACE:
1041 return !dvmIsDirectMethod(resMethod);
1042 default:
1043 return false;
1044 }
1045}
1046
1047/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001048 * Verify the arguments to a method. We're executing in "method", making
1049 * a call to the method reference in vB.
1050 *
1051 * If this is a "direct" invoke, we allow calls to <init>. For calls to
1052 * <init>, the first argument may be an uninitialized reference. Otherwise,
1053 * calls to anything starting with '<' will be rejected, as will any
1054 * uninitialized reference arguments.
1055 *
1056 * For non-static method calls, this will verify that the method call is
1057 * appropriate for the "this" argument.
1058 *
1059 * The method reference is in vBBBB. The "isRange" parameter determines
1060 * whether we use 0-4 "args" values or a range of registers defined by
1061 * vAA and vCCCC.
1062 *
1063 * Widening conversions on integers and references are allowed, but
1064 * narrowing conversions are not.
1065 *
Andy McFadden62a75162009-04-17 17:23:37 -07001066 * Returns the resolved method on success, NULL on failure (with *pFailure
1067 * set appropriately).
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001068 */
1069static Method* verifyInvocationArgs(const Method* meth, const RegType* insnRegs,
1070 const int insnRegCount, const DecodedInstruction* pDecInsn,
1071 UninitInstanceMap* uninitMap, MethodType methodType, bool isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07001072 bool isSuper, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001073{
1074 Method* resMethod;
1075 char* sigOriginal = NULL;
1076
1077 /*
1078 * Resolve the method. This could be an abstract or concrete method
1079 * depending on what sort of call we're making.
1080 */
1081 if (methodType == METHOD_INTERFACE) {
1082 resMethod = dvmOptResolveInterfaceMethod(meth->clazz, pDecInsn->vB);
1083 } else {
Andy McFadden62a75162009-04-17 17:23:37 -07001084 resMethod = dvmOptResolveMethod(meth->clazz, pDecInsn->vB, methodType,
1085 pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001086 }
1087 if (resMethod == NULL) {
1088 /* failed; print a meaningful failure message */
1089 DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
1090 const DexMethodId* pMethodId;
1091 const char* methodName;
1092 char* methodDesc;
1093 const char* classDescriptor;
1094
1095 pMethodId = dexGetMethodId(pDexFile, pDecInsn->vB);
1096 methodName = dexStringById(pDexFile, pMethodId->nameIdx);
1097 methodDesc = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
1098 classDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
1099
1100 if (!gDvm.optimizing) {
1101 char* dotMissingClass = dvmDescriptorToDot(classDescriptor);
1102 char* dotMethClass = dvmDescriptorToDot(meth->clazz->descriptor);
1103 //char* curMethodDesc =
1104 // dexProtoCopyMethodDescriptor(&meth->prototype);
1105
Andy McFadden99a33e72010-10-10 12:59:11 -07001106 LOGI("Could not find method %s.%s, referenced from method %s.%s\n",
1107 dotMissingClass, methodName/*, methodDesc*/,
1108 dotMethClass, meth->name/*, curMethodDesc*/);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001109
1110 free(dotMissingClass);
1111 free(dotMethClass);
1112 //free(curMethodDesc);
1113 }
1114
1115 LOG_VFY("VFY: unable to resolve %s method %u: %s.%s %s\n",
1116 dvmMethodTypeStr(methodType), pDecInsn->vB,
1117 classDescriptor, methodName, methodDesc);
1118 free(methodDesc);
Andy McFaddenb51ea112009-05-08 16:50:17 -07001119 if (VERIFY_OK(*pFailure)) /* not set for interface resolve */
1120 *pFailure = VERIFY_ERROR_NO_METHOD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001121 goto fail;
1122 }
1123
1124 /*
1125 * Only time you can explicitly call a method starting with '<' is when
1126 * making a "direct" invocation on "<init>". There are additional
1127 * restrictions but we don't enforce them here.
1128 */
1129 if (resMethod->name[0] == '<') {
1130 if (methodType != METHOD_DIRECT || !isInitMethod(resMethod)) {
1131 LOG_VFY("VFY: invalid call to %s.%s\n",
1132 resMethod->clazz->descriptor, resMethod->name);
1133 goto bad_sig;
1134 }
1135 }
1136
1137 /*
Andy McFadden99a33e72010-10-10 12:59:11 -07001138 * See if the method type implied by the invoke instruction matches the
1139 * access flags for the target method.
1140 */
1141 if (!isCorrectInvokeKind(methodType, resMethod)) {
1142 LOG_VFY("VFY: invoke type does not match method type of %s.%s\n",
1143 resMethod->clazz->descriptor, resMethod->name);
1144 goto fail;
1145 }
1146
1147 /*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001148 * If we're using invoke-super(method), make sure that the executing
1149 * method's class' superclass has a vtable entry for the target method.
1150 */
1151 if (isSuper) {
1152 assert(methodType == METHOD_VIRTUAL);
1153 ClassObject* super = meth->clazz->super;
1154 if (super == NULL || resMethod->methodIndex > super->vtableCount) {
1155 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1156 LOG_VFY("VFY: invalid invoke-super from %s.%s to super %s.%s %s\n",
1157 meth->clazz->descriptor, meth->name,
1158 (super == NULL) ? "-" : super->descriptor,
1159 resMethod->name, desc);
1160 free(desc);
Andy McFadden62a75162009-04-17 17:23:37 -07001161 *pFailure = VERIFY_ERROR_NO_METHOD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001162 goto fail;
1163 }
1164 }
1165
1166 /*
1167 * We use vAA as our expected arg count, rather than resMethod->insSize,
1168 * because we need to match the call to the signature. Also, we might
1169 * might be calling through an abstract method definition (which doesn't
1170 * have register count values).
1171 */
1172 sigOriginal = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1173 const char* sig = sigOriginal;
1174 int expectedArgs = pDecInsn->vA;
1175 int actualArgs = 0;
1176
Andy McFaddend3250112010-11-03 14:32:42 -07001177 /* caught by static verifier */
1178 assert(isRange || expectedArgs <= 5);
1179
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001180 if (expectedArgs > meth->outsSize) {
1181 LOG_VFY("VFY: invalid arg count (%d) exceeds outsSize (%d)\n",
1182 expectedArgs, meth->outsSize);
1183 goto fail;
1184 }
1185
1186 if (*sig++ != '(')
1187 goto bad_sig;
1188
1189 /*
1190 * Check the "this" argument, which must be an instance of the class
1191 * that declared the method. For an interface class, we don't do the
1192 * full interface merge, so we can't do a rigorous check here (which
1193 * is okay since we have to do it at runtime).
1194 */
1195 if (!dvmIsStaticMethod(resMethod)) {
1196 ClassObject* actualThisRef;
1197 RegType actualArgType;
1198
Andy McFaddend3250112010-11-03 14:32:42 -07001199 actualArgType = getInvocationThis(insnRegs, pDecInsn, pFailure);
Andy McFadden62a75162009-04-17 17:23:37 -07001200 if (!VERIFY_OK(*pFailure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001201 goto fail;
1202
1203 if (regTypeIsUninitReference(actualArgType) && resMethod->name[0] != '<')
1204 {
1205 LOG_VFY("VFY: 'this' arg must be initialized\n");
1206 goto fail;
1207 }
1208 if (methodType != METHOD_INTERFACE && actualArgType != kRegTypeZero) {
1209 actualThisRef = regTypeReferenceToClass(actualArgType, uninitMap);
1210 if (!dvmInstanceof(actualThisRef, resMethod->clazz)) {
1211 LOG_VFY("VFY: 'this' arg '%s' not instance of '%s'\n",
1212 actualThisRef->descriptor,
1213 resMethod->clazz->descriptor);
1214 goto fail;
1215 }
1216 }
1217 actualArgs++;
1218 }
1219
1220 /*
1221 * Process the target method's signature. This signature may or may not
1222 * have been verified, so we can't assume it's properly formed.
1223 */
1224 while (*sig != '\0' && *sig != ')') {
1225 if (actualArgs >= expectedArgs) {
1226 LOG_VFY("VFY: expected %d args, found more (%c)\n",
1227 expectedArgs, *sig);
1228 goto bad_sig;
1229 }
1230
1231 u4 getReg;
1232 if (isRange)
1233 getReg = pDecInsn->vC + actualArgs;
1234 else
1235 getReg = pDecInsn->arg[actualArgs];
1236
1237 switch (*sig) {
1238 case 'L':
1239 {
Andy McFadden62a75162009-04-17 17:23:37 -07001240 ClassObject* clazz = lookupSignatureClass(meth, &sig, pFailure);
1241 if (!VERIFY_OK(*pFailure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001242 goto bad_sig;
Andy McFaddend3250112010-11-03 14:32:42 -07001243 verifyRegisterType(insnRegs, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001244 regTypeFromClass(clazz), pFailure);
1245 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001246 LOG_VFY("VFY: bad arg %d (into %s)\n",
1247 actualArgs, clazz->descriptor);
1248 goto bad_sig;
1249 }
1250 }
1251 actualArgs++;
1252 break;
1253 case '[':
1254 {
1255 ClassObject* clazz =
Andy McFadden62a75162009-04-17 17:23:37 -07001256 lookupSignatureArrayClass(meth, &sig, pFailure);
1257 if (!VERIFY_OK(*pFailure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001258 goto bad_sig;
Andy McFaddend3250112010-11-03 14:32:42 -07001259 verifyRegisterType(insnRegs, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001260 regTypeFromClass(clazz), pFailure);
1261 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001262 LOG_VFY("VFY: bad arg %d (into %s)\n",
1263 actualArgs, clazz->descriptor);
1264 goto bad_sig;
1265 }
1266 }
1267 actualArgs++;
1268 break;
1269 case 'Z':
Andy McFaddend3250112010-11-03 14:32:42 -07001270 verifyRegisterType(insnRegs, getReg, kRegTypeBoolean, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001271 actualArgs++;
1272 break;
1273 case 'C':
Andy McFaddend3250112010-11-03 14:32:42 -07001274 verifyRegisterType(insnRegs, getReg, kRegTypeChar, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001275 actualArgs++;
1276 break;
1277 case 'B':
Andy McFaddend3250112010-11-03 14:32:42 -07001278 verifyRegisterType(insnRegs, getReg, kRegTypeByte, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001279 actualArgs++;
1280 break;
1281 case 'I':
Andy McFaddend3250112010-11-03 14:32:42 -07001282 verifyRegisterType(insnRegs, getReg, kRegTypeInteger, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001283 actualArgs++;
1284 break;
1285 case 'S':
Andy McFaddend3250112010-11-03 14:32:42 -07001286 verifyRegisterType(insnRegs, getReg, kRegTypeShort, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001287 actualArgs++;
1288 break;
1289 case 'F':
Andy McFaddend3250112010-11-03 14:32:42 -07001290 verifyRegisterType(insnRegs, getReg, kRegTypeFloat, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001291 actualArgs++;
1292 break;
1293 case 'D':
Andy McFaddend3250112010-11-03 14:32:42 -07001294 verifyRegisterType(insnRegs, getReg, kRegTypeDoubleLo, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001295 actualArgs += 2;
1296 break;
1297 case 'J':
Andy McFaddend3250112010-11-03 14:32:42 -07001298 verifyRegisterType(insnRegs, getReg, kRegTypeLongLo, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001299 actualArgs += 2;
1300 break;
1301 default:
1302 LOG_VFY("VFY: invocation target: bad signature type char '%c'\n",
1303 *sig);
1304 goto bad_sig;
1305 }
1306
1307 sig++;
1308 }
1309 if (*sig != ')') {
1310 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1311 LOG_VFY("VFY: invocation target: bad signature '%s'\n", desc);
1312 free(desc);
1313 goto bad_sig;
1314 }
1315
1316 if (actualArgs != expectedArgs) {
1317 LOG_VFY("VFY: expected %d args, found %d\n", expectedArgs, actualArgs);
1318 goto bad_sig;
1319 }
1320
1321 free(sigOriginal);
1322 return resMethod;
1323
1324bad_sig:
1325 if (resMethod != NULL) {
1326 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1327 LOG_VFY("VFY: rejecting call to %s.%s %s\n",
Andy McFadden62a75162009-04-17 17:23:37 -07001328 resMethod->clazz->descriptor, resMethod->name, desc);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001329 free(desc);
1330 }
1331
1332fail:
1333 free(sigOriginal);
Andy McFadden62a75162009-04-17 17:23:37 -07001334 if (*pFailure == VERIFY_ERROR_NONE)
1335 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001336 return NULL;
1337}
1338
1339/*
1340 * Get the class object for the type of data stored in a field. This isn't
1341 * stored in the Field struct, so we have to recover it from the signature.
1342 *
1343 * This only works for reference types. Don't call this for primitive types.
1344 *
1345 * If we can't find the class, we return java.lang.Object, so that
1346 * verification can continue if a field is only accessed in trivial ways.
1347 */
1348static ClassObject* getFieldClass(const Method* meth, const Field* field)
1349{
1350 ClassObject* fieldClass;
1351 const char* signature = field->signature;
1352
1353 if ((*signature == 'L') || (*signature == '[')) {
1354 fieldClass = dvmFindClassNoInit(signature,
1355 meth->clazz->classLoader);
1356 } else {
1357 return NULL;
1358 }
1359
1360 if (fieldClass == NULL) {
1361 dvmClearOptException(dvmThreadSelf());
1362 LOGV("VFY: unable to find class '%s' for field %s.%s, trying Object\n",
1363 field->signature, meth->clazz->descriptor, field->name);
1364 fieldClass = gDvm.classJavaLangObject;
1365 } else {
1366 assert(!dvmIsPrimitiveClass(fieldClass));
1367 }
1368 return fieldClass;
1369}
1370
1371
1372/*
1373 * ===========================================================================
1374 * Register operations
1375 * ===========================================================================
1376 */
1377
1378/*
Andy McFaddend3250112010-11-03 14:32:42 -07001379 * Get the type of register N.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001380 *
Andy McFaddend3250112010-11-03 14:32:42 -07001381 * The register index was validated during the static pass, so we don't
1382 * need to check it here.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001383 */
Andy McFaddend3250112010-11-03 14:32:42 -07001384static inline RegType getRegisterType(const RegType* insnRegs, u4 vsrc)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001385{
Andy McFaddend3250112010-11-03 14:32:42 -07001386 return insnRegs[vsrc];
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001387}
1388
1389/*
1390 * Get the value from a register, and cast it to a ClassObject. Sets
Andy McFadden62a75162009-04-17 17:23:37 -07001391 * "*pFailure" if something fails.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001392 *
1393 * This fails if the register holds an uninitialized class.
1394 *
1395 * If the register holds kRegTypeZero, this returns a NULL pointer.
1396 */
1397static ClassObject* getClassFromRegister(const RegType* insnRegs,
Andy McFaddend3250112010-11-03 14:32:42 -07001398 u4 vsrc, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001399{
1400 ClassObject* clazz = NULL;
1401 RegType type;
1402
1403 /* get the element type of the array held in vsrc */
Andy McFaddend3250112010-11-03 14:32:42 -07001404 type = getRegisterType(insnRegs, vsrc);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001405
1406 /* if "always zero", we allow it to fail at runtime */
1407 if (type == kRegTypeZero)
1408 goto bail;
1409
1410 if (!regTypeIsReference(type)) {
1411 LOG_VFY("VFY: tried to get class from non-ref register v%d (type=%d)\n",
1412 vsrc, type);
Andy McFadden62a75162009-04-17 17:23:37 -07001413 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001414 goto bail;
1415 }
1416 if (regTypeIsUninitReference(type)) {
1417 LOG_VFY("VFY: register %u holds uninitialized reference\n", vsrc);
Andy McFadden62a75162009-04-17 17:23:37 -07001418 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001419 goto bail;
1420 }
1421
1422 clazz = regTypeInitializedReferenceToClass(type);
1423
1424bail:
1425 return clazz;
1426}
1427
1428/*
1429 * Get the "this" pointer from a non-static method invocation. This
1430 * returns the RegType so the caller can decide whether it needs the
1431 * reference to be initialized or not. (Can also return kRegTypeZero
1432 * if the reference can only be zero at this point.)
1433 *
1434 * The argument count is in vA, and the first argument is in vC, for both
1435 * "simple" and "range" versions. We just need to make sure vA is >= 1
1436 * and then return vC.
1437 */
1438static RegType getInvocationThis(const RegType* insnRegs,
Andy McFaddend3250112010-11-03 14:32:42 -07001439 const DecodedInstruction* pDecInsn, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001440{
1441 RegType thisType = kRegTypeUnknown;
1442
1443 if (pDecInsn->vA < 1) {
1444 LOG_VFY("VFY: invoke lacks 'this'\n");
Andy McFadden62a75162009-04-17 17:23:37 -07001445 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001446 goto bail;
1447 }
1448
1449 /* get the element type of the array held in vsrc */
Andy McFaddend3250112010-11-03 14:32:42 -07001450 thisType = getRegisterType(insnRegs, pDecInsn->vC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001451 if (!regTypeIsReference(thisType)) {
1452 LOG_VFY("VFY: tried to get class from non-ref register v%d (type=%d)\n",
1453 pDecInsn->vC, thisType);
Andy McFadden62a75162009-04-17 17:23:37 -07001454 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001455 goto bail;
1456 }
1457
1458bail:
1459 return thisType;
1460}
1461
1462/*
1463 * Set the type of register N, verifying that the register is valid. If
1464 * "newType" is the "Lo" part of a 64-bit value, register N+1 will be
1465 * set to "newType+1".
1466 *
Andy McFaddend3250112010-11-03 14:32:42 -07001467 * The register index was validated during the static pass, so we don't
1468 * need to check it here.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001469 */
Andy McFaddend3250112010-11-03 14:32:42 -07001470static void setRegisterType(RegType* insnRegs, u4 vdst, RegType newType)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001471{
1472 //LOGD("set-reg v%u = %d\n", vdst, newType);
1473 switch (newType) {
1474 case kRegTypeUnknown:
1475 case kRegTypeBoolean:
1476 case kRegTypeOne:
1477 case kRegTypeByte:
1478 case kRegTypePosByte:
1479 case kRegTypeShort:
1480 case kRegTypePosShort:
1481 case kRegTypeChar:
1482 case kRegTypeInteger:
1483 case kRegTypeFloat:
1484 case kRegTypeZero:
Andy McFaddend3250112010-11-03 14:32:42 -07001485 case kRegTypeUninit:
1486 insnRegs[vdst] = newType;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001487 break;
1488 case kRegTypeLongLo:
1489 case kRegTypeDoubleLo:
Andy McFaddend3250112010-11-03 14:32:42 -07001490 insnRegs[vdst] = newType;
1491 insnRegs[vdst+1] = newType+1;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001492 break;
1493 case kRegTypeLongHi:
1494 case kRegTypeDoubleHi:
1495 /* should never set these explicitly */
Andy McFaddend3250112010-11-03 14:32:42 -07001496 LOGE("BUG: explicit set of high register type\n");
1497 dvmAbort();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001498 break;
1499
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001500 default:
Andy McFaddend3250112010-11-03 14:32:42 -07001501 /* can't switch for ref types, so we check explicitly */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001502 if (regTypeIsReference(newType)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001503 insnRegs[vdst] = newType;
1504
1505 /*
1506 * In most circumstances we won't see a reference to a primitive
1507 * class here (e.g. "D"), since that would mean the object in the
1508 * register is actually a primitive type. It can happen as the
1509 * result of an assumed-successful check-cast instruction in
1510 * which the second argument refers to a primitive class. (In
1511 * practice, such an instruction will always throw an exception.)
1512 *
1513 * This is not an issue for instructions like const-class, where
1514 * the object in the register is a java.lang.Class instance.
1515 */
1516 break;
1517 }
Andy McFaddend3250112010-11-03 14:32:42 -07001518 /* bad type - fall through */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001519
1520 case kRegTypeConflict: // should only be set during a merge
Andy McFaddend3250112010-11-03 14:32:42 -07001521 LOGE("BUG: set register to unknown type %d\n", newType);
1522 dvmAbort();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001523 break;
1524 }
1525}
1526
1527/*
1528 * Verify that the contents of the specified register have the specified
1529 * type (or can be converted to it through an implicit widening conversion).
1530 *
1531 * In theory we could use this to modify the type of the source register,
1532 * e.g. a generic 32-bit constant, once used as a float, would thereafter
1533 * remain a float. There is no compelling reason to require this though.
1534 *
1535 * If "vsrc" is a reference, both it and the "vsrc" register must be
1536 * initialized ("vsrc" may be Zero). This will verify that the value in
1537 * the register is an instance of checkType, or if checkType is an
1538 * interface, verify that the register implements checkType.
1539 */
Andy McFaddend3250112010-11-03 14:32:42 -07001540static void verifyRegisterType(const RegType* insnRegs, u4 vsrc,
1541 RegType checkType, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001542{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001543 RegType srcType = insnRegs[vsrc];
1544
1545 //LOGD("check-reg v%u = %d\n", vsrc, checkType);
1546 switch (checkType) {
1547 case kRegTypeFloat:
1548 case kRegTypeBoolean:
1549 case kRegTypePosByte:
1550 case kRegTypeByte:
1551 case kRegTypePosShort:
1552 case kRegTypeShort:
1553 case kRegTypeChar:
1554 case kRegTypeInteger:
1555 if (!canConvertTo1nr(srcType, checkType)) {
1556 LOG_VFY("VFY: register1 v%u type %d, wanted %d\n",
1557 vsrc, srcType, checkType);
Andy McFadden62a75162009-04-17 17:23:37 -07001558 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001559 }
1560 break;
1561 case kRegTypeLongLo:
1562 case kRegTypeDoubleLo:
Andy McFaddend3250112010-11-03 14:32:42 -07001563 if (insnRegs[vsrc+1] != srcType+1) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001564 LOG_VFY("VFY: register2 v%u-%u values %d,%d\n",
1565 vsrc, vsrc+1, insnRegs[vsrc], insnRegs[vsrc+1]);
Andy McFadden62a75162009-04-17 17:23:37 -07001566 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001567 } else if (!canConvertTo2(srcType, checkType)) {
1568 LOG_VFY("VFY: register2 v%u type %d, wanted %d\n",
1569 vsrc, srcType, checkType);
Andy McFadden62a75162009-04-17 17:23:37 -07001570 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001571 }
1572 break;
1573
1574 case kRegTypeLongHi:
1575 case kRegTypeDoubleHi:
1576 case kRegTypeZero:
1577 case kRegTypeOne:
1578 case kRegTypeUnknown:
1579 case kRegTypeConflict:
1580 /* should never be checking for these explicitly */
1581 assert(false);
Andy McFadden62a75162009-04-17 17:23:37 -07001582 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001583 return;
1584 case kRegTypeUninit:
1585 default:
1586 /* make sure checkType is initialized reference */
1587 if (!regTypeIsReference(checkType)) {
1588 LOG_VFY("VFY: unexpected check type %d\n", checkType);
1589 assert(false);
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(checkType)) {
1594 LOG_VFY("VFY: uninitialized ref not expected as reg check\n");
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 /* make sure srcType is initialized reference or always-NULL */
1599 if (!regTypeIsReference(srcType)) {
1600 LOG_VFY("VFY: register1 v%u type %d, wanted ref\n", vsrc, srcType);
Andy McFadden62a75162009-04-17 17:23:37 -07001601 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001602 break;
1603 }
1604 if (regTypeIsUninitReference(srcType)) {
1605 LOG_VFY("VFY: register1 v%u holds uninitialized ref\n", vsrc);
Andy McFadden62a75162009-04-17 17:23:37 -07001606 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001607 break;
1608 }
1609 /* if the register isn't Zero, make sure it's an instance of check */
1610 if (srcType != kRegTypeZero) {
1611 ClassObject* srcClass = regTypeInitializedReferenceToClass(srcType);
1612 ClassObject* checkClass = regTypeInitializedReferenceToClass(checkType);
1613 assert(srcClass != NULL);
1614 assert(checkClass != NULL);
1615
1616 if (dvmIsInterfaceClass(checkClass)) {
1617 /*
1618 * All objects implement all interfaces as far as the
1619 * verifier is concerned. The runtime has to sort it out.
1620 * See comments above findCommonSuperclass.
1621 */
1622 /*
1623 if (srcClass != checkClass &&
1624 !dvmImplements(srcClass, checkClass))
1625 {
1626 LOG_VFY("VFY: %s does not implement %s\n",
1627 srcClass->descriptor, checkClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07001628 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001629 }
1630 */
1631 } else {
1632 if (!dvmInstanceof(srcClass, checkClass)) {
1633 LOG_VFY("VFY: %s is not instance of %s\n",
1634 srcClass->descriptor, checkClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07001635 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001636 }
1637 }
1638 }
1639 break;
1640 }
1641}
1642
1643/*
Andy McFaddend3250112010-11-03 14:32:42 -07001644 * Set the type of the "result" register.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001645 */
1646static void setResultRegisterType(RegType* insnRegs, const int insnRegCount,
Andy McFaddend3250112010-11-03 14:32:42 -07001647 RegType newType)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001648{
Andy McFaddend3250112010-11-03 14:32:42 -07001649 setRegisterType(insnRegs, RESULT_REGISTER(insnRegCount), newType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001650}
1651
1652
1653/*
1654 * Update all registers holding "uninitType" to instead hold the
1655 * corresponding initialized reference type. This is called when an
1656 * appropriate <init> method is invoked -- all copies of the reference
1657 * must be marked as initialized.
1658 */
1659static void markRefsAsInitialized(RegType* insnRegs, int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001660 UninitInstanceMap* uninitMap, RegType uninitType, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001661{
1662 ClassObject* clazz;
1663 RegType initType;
1664 int i, changed;
1665
1666 clazz = dvmGetUninitInstance(uninitMap, regTypeToUninitIndex(uninitType));
1667 if (clazz == NULL) {
1668 LOGE("VFY: unable to find type=0x%x (idx=%d)\n",
1669 uninitType, regTypeToUninitIndex(uninitType));
Andy McFadden62a75162009-04-17 17:23:37 -07001670 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001671 return;
1672 }
1673 initType = regTypeFromClass(clazz);
1674
1675 changed = 0;
1676 for (i = 0; i < insnRegCount; i++) {
1677 if (insnRegs[i] == uninitType) {
1678 insnRegs[i] = initType;
1679 changed++;
1680 }
1681 }
1682 //LOGD("VFY: marked %d registers as initialized\n", changed);
1683 assert(changed > 0);
1684
1685 return;
1686}
1687
1688/*
1689 * We're creating a new instance of class C at address A. Any registers
1690 * holding instances previously created at address A must be initialized
1691 * by now. If not, we mark them as "conflict" to prevent them from being
1692 * used (otherwise, markRefsAsInitialized would mark the old ones and the
1693 * new ones at the same time).
1694 */
1695static void markUninitRefsAsInvalid(RegType* insnRegs, int insnRegCount,
1696 UninitInstanceMap* uninitMap, RegType uninitType)
1697{
1698 int i, changed;
1699
1700 changed = 0;
1701 for (i = 0; i < insnRegCount; i++) {
1702 if (insnRegs[i] == uninitType) {
1703 insnRegs[i] = kRegTypeConflict;
1704 changed++;
1705 }
1706 }
1707
1708 //if (changed)
1709 // LOGD("VFY: marked %d uninitialized registers as invalid\n", changed);
1710}
1711
1712/*
1713 * Find the start of the register set for the specified instruction in
1714 * the current method.
1715 */
1716static inline RegType* getRegisterLine(const RegisterTable* regTable,
1717 int insnIdx)
1718{
1719 return regTable->addrRegs[insnIdx];
1720}
1721
1722/*
1723 * Copy a bunch of registers.
1724 */
1725static inline void copyRegisters(RegType* dst, const RegType* src,
1726 int numRegs)
1727{
1728 memcpy(dst, src, numRegs * sizeof(RegType));
1729}
1730
1731/*
1732 * Compare a bunch of registers.
1733 *
1734 * Returns 0 if they match. Using this for a sort is unwise, since the
1735 * value can change based on machine endianness.
1736 */
1737static inline int compareRegisters(const RegType* src1, const RegType* src2,
1738 int numRegs)
1739{
1740 return memcmp(src1, src2, numRegs * sizeof(RegType));
1741}
1742
1743/*
1744 * Register type categories, for type checking.
1745 *
1746 * The spec says category 1 includes boolean, byte, char, short, int, float,
1747 * reference, and returnAddress. Category 2 includes long and double.
1748 *
1749 * We treat object references separately, so we have "category1nr". We
1750 * don't support jsr/ret, so there is no "returnAddress" type.
1751 */
1752typedef enum TypeCategory {
1753 kTypeCategoryUnknown = 0,
1754 kTypeCategory1nr, // byte, char, int, float, boolean
1755 kTypeCategory2, // long, double
1756 kTypeCategoryRef, // object reference
1757} TypeCategory;
1758
1759/*
1760 * See if "type" matches "cat". All we're really looking for here is that
1761 * we're not mixing and matching 32-bit and 64-bit quantities, and we're
1762 * not mixing references with numerics. (For example, the arguments to
1763 * "a < b" could be integers of different sizes, but they must both be
1764 * integers. Dalvik is less specific about int vs. float, so we treat them
1765 * as equivalent here.)
1766 *
1767 * For category 2 values, "type" must be the "low" half of the value.
1768 *
Andy McFadden62a75162009-04-17 17:23:37 -07001769 * Sets "*pFailure" if something looks wrong.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001770 */
Andy McFadden62a75162009-04-17 17:23:37 -07001771static void checkTypeCategory(RegType type, TypeCategory cat,
1772 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001773{
1774 switch (cat) {
1775 case kTypeCategory1nr:
1776 switch (type) {
1777 case kRegTypeFloat:
1778 case kRegTypeZero:
1779 case kRegTypeOne:
1780 case kRegTypeBoolean:
1781 case kRegTypePosByte:
1782 case kRegTypeByte:
1783 case kRegTypePosShort:
1784 case kRegTypeShort:
1785 case kRegTypeChar:
1786 case kRegTypeInteger:
1787 break;
1788 default:
Andy McFadden62a75162009-04-17 17:23:37 -07001789 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001790 break;
1791 }
1792 break;
1793
1794 case kTypeCategory2:
1795 switch (type) {
1796 case kRegTypeLongLo:
1797 case kRegTypeDoubleLo:
1798 break;
1799 default:
Andy McFadden62a75162009-04-17 17:23:37 -07001800 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001801 break;
1802 }
1803 break;
1804
1805 case kTypeCategoryRef:
1806 if (type != kRegTypeZero && !regTypeIsReference(type))
Andy McFadden62a75162009-04-17 17:23:37 -07001807 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001808 break;
1809
1810 default:
1811 assert(false);
Andy McFadden62a75162009-04-17 17:23:37 -07001812 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001813 break;
1814 }
1815}
1816
1817/*
1818 * For a category 2 register pair, verify that "typeh" is the appropriate
1819 * high part for "typel".
1820 *
1821 * Does not verify that "typel" is in fact the low part of a 64-bit
1822 * register pair.
1823 */
Andy McFadden62a75162009-04-17 17:23:37 -07001824static void checkWidePair(RegType typel, RegType typeh, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001825{
1826 if ((typeh != typel+1))
Andy McFadden62a75162009-04-17 17:23:37 -07001827 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001828}
1829
1830/*
1831 * Implement category-1 "move" instructions. Copy a 32-bit value from
1832 * "vsrc" to "vdst".
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001833 */
Andy McFaddend3250112010-11-03 14:32:42 -07001834static void copyRegister1(RegType* insnRegs, u4 vdst, u4 vsrc,
1835 TypeCategory cat, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001836{
Andy McFaddend3250112010-11-03 14:32:42 -07001837 RegType type = getRegisterType(insnRegs, vsrc);
1838 checkTypeCategory(type, cat, pFailure);
Andy McFadden62a75162009-04-17 17:23:37 -07001839 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001840 LOG_VFY("VFY: copy1 v%u<-v%u type=%d cat=%d\n", vdst, vsrc, type, cat);
Andy McFaddend3250112010-11-03 14:32:42 -07001841 } else {
1842 setRegisterType(insnRegs, vdst, type);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001843 }
Andy McFaddend3250112010-11-03 14:32:42 -07001844
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001845}
1846
1847/*
1848 * Implement category-2 "move" instructions. Copy a 64-bit value from
1849 * "vsrc" to "vdst". This copies both halves of the register.
1850 */
Andy McFaddend3250112010-11-03 14:32:42 -07001851static void copyRegister2(RegType* insnRegs, u4 vdst,
Andy McFadden62a75162009-04-17 17:23:37 -07001852 u4 vsrc, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001853{
Andy McFaddend3250112010-11-03 14:32:42 -07001854 RegType typel = getRegisterType(insnRegs, vsrc);
1855 RegType typeh = getRegisterType(insnRegs, vsrc+1);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001856
Andy McFaddend3250112010-11-03 14:32:42 -07001857 checkTypeCategory(typel, kTypeCategory2, pFailure);
1858 checkWidePair(typel, typeh, pFailure);
Andy McFadden62a75162009-04-17 17:23:37 -07001859 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001860 LOG_VFY("VFY: copy2 v%u<-v%u type=%d/%d\n", vdst, vsrc, typel, typeh);
Andy McFaddend3250112010-11-03 14:32:42 -07001861 } else {
1862 setRegisterType(insnRegs, vdst, typel);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001863 }
1864}
1865
1866/*
1867 * Implement "move-result". Copy the category-1 value from the result
1868 * register to another register, and reset the result register.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001869 */
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
Andy McFaddend3250112010-11-03 14:32:42 -07001876 assert(vdst < (u4) insnRegCount);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001877
Andy McFaddend3250112010-11-03 14:32:42 -07001878 vsrc = RESULT_REGISTER(insnRegCount);
1879 type = getRegisterType(insnRegs, vsrc);
1880 checkTypeCategory(type, cat, pFailure);
Andy McFadden62a75162009-04-17 17:23:37 -07001881 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001882 LOG_VFY("VFY: copyRes1 v%u<-v%u cat=%d type=%d\n",
1883 vdst, vsrc, cat, type);
Andy McFaddend3250112010-11-03 14:32:42 -07001884 } else {
1885 setRegisterType(insnRegs, vdst, type);
1886 insnRegs[vsrc] = kRegTypeUnknown;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001887 }
1888}
1889
1890/*
1891 * Implement "move-result-wide". Copy the category-2 value from the result
1892 * register to another register, and reset the result register.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001893 */
1894static void copyResultRegister2(RegType* insnRegs, const int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001895 u4 vdst, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001896{
1897 RegType typel, typeh;
1898 u4 vsrc;
1899
Andy McFaddend3250112010-11-03 14:32:42 -07001900 assert(vdst < (u4) insnRegCount);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001901
Andy McFaddend3250112010-11-03 14:32:42 -07001902 vsrc = RESULT_REGISTER(insnRegCount);
1903 typel = getRegisterType(insnRegs, vsrc);
1904 typeh = getRegisterType(insnRegs, vsrc+1);
1905 checkTypeCategory(typel, kTypeCategory2, pFailure);
1906 checkWidePair(typel, typeh, pFailure);
Andy McFadden62a75162009-04-17 17:23:37 -07001907 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001908 LOG_VFY("VFY: copyRes2 v%u<-v%u type=%d/%d\n",
1909 vdst, vsrc, typel, typeh);
Andy McFaddend3250112010-11-03 14:32:42 -07001910 } else {
1911 setRegisterType(insnRegs, vdst, typel);
1912 insnRegs[vsrc] = kRegTypeUnknown;
1913 insnRegs[vsrc+1] = kRegTypeUnknown;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001914 }
1915}
1916
1917/*
1918 * Verify types for a simple two-register instruction (e.g. "neg-int").
1919 * "dstType" is stored into vA, and "srcType" is verified against vB.
1920 */
Andy McFaddend3250112010-11-03 14:32:42 -07001921static void checkUnop(RegType* insnRegs, DecodedInstruction* pDecInsn,
1922 RegType dstType, RegType srcType, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001923{
Andy McFaddend3250112010-11-03 14:32:42 -07001924 verifyRegisterType(insnRegs, pDecInsn->vB, srcType, pFailure);
1925 setRegisterType(insnRegs, pDecInsn->vA, dstType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001926}
1927
1928/*
1929 * We're performing an operation like "and-int/2addr" that can be
1930 * performed on booleans as well as integers. We get no indication of
1931 * boolean-ness, but we can infer it from the types of the arguments.
1932 *
1933 * Assumes we've already validated reg1/reg2.
1934 *
Andy McFaddenb5f64bc2009-06-10 14:11:07 -07001935 * TODO: consider generalizing this. The key principle is that the
1936 * result of a bitwise operation can only be as wide as the widest of
1937 * the operands. You can safely AND/OR/XOR two chars together and know
1938 * you still have a char, so it's reasonable for the compiler or "dx"
1939 * to skip the int-to-char instruction. (We need to do this for boolean
1940 * because there is no int-to-boolean operation.)
1941 *
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001942 * Returns true if both args are Boolean, Zero, or One.
1943 */
Andy McFaddend3250112010-11-03 14:32:42 -07001944static bool upcastBooleanOp(RegType* insnRegs, u4 reg1, u4 reg2)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001945{
1946 RegType type1, type2;
1947
1948 type1 = insnRegs[reg1];
1949 type2 = insnRegs[reg2];
1950
1951 if ((type1 == kRegTypeBoolean || type1 == kRegTypeZero ||
1952 type1 == kRegTypeOne) &&
1953 (type2 == kRegTypeBoolean || type2 == kRegTypeZero ||
1954 type2 == kRegTypeOne))
1955 {
1956 return true;
1957 }
1958 return false;
1959}
1960
1961/*
1962 * Verify types for A two-register instruction with a literal constant
1963 * (e.g. "add-int/lit8"). "dstType" is stored into vA, and "srcType" is
1964 * verified against vB.
1965 *
1966 * If "checkBooleanOp" is set, we use the constant value in vC.
1967 */
Andy McFaddend3250112010-11-03 14:32:42 -07001968static void checkLitop(RegType* insnRegs, DecodedInstruction* pDecInsn,
1969 RegType dstType, RegType srcType, bool checkBooleanOp,
1970 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001971{
Andy McFaddend3250112010-11-03 14:32:42 -07001972 verifyRegisterType(insnRegs, pDecInsn->vB, srcType, pFailure);
Andy McFadden62a75162009-04-17 17:23:37 -07001973 if (VERIFY_OK(*pFailure) && checkBooleanOp) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001974 assert(dstType == kRegTypeInteger);
1975 /* check vB with the call, then check the constant manually */
Andy McFaddend3250112010-11-03 14:32:42 -07001976 if (upcastBooleanOp(insnRegs, pDecInsn->vB, pDecInsn->vB)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001977 && (pDecInsn->vC == 0 || pDecInsn->vC == 1))
1978 {
1979 dstType = kRegTypeBoolean;
1980 }
1981 }
Andy McFaddend3250112010-11-03 14:32:42 -07001982 setRegisterType(insnRegs, pDecInsn->vA, dstType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001983}
1984
1985/*
1986 * Verify types for a simple three-register instruction (e.g. "add-int").
1987 * "dstType" is stored into vA, and "srcType1"/"srcType2" are verified
1988 * against vB/vC.
1989 */
Andy McFaddend3250112010-11-03 14:32:42 -07001990static void checkBinop(RegType* insnRegs, DecodedInstruction* pDecInsn,
1991 RegType dstType, RegType srcType1, RegType srcType2, bool checkBooleanOp,
1992 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001993{
Andy McFaddend3250112010-11-03 14:32:42 -07001994 verifyRegisterType(insnRegs, pDecInsn->vB, srcType1, pFailure);
1995 verifyRegisterType(insnRegs, pDecInsn->vC, srcType2, pFailure);
Andy McFadden62a75162009-04-17 17:23:37 -07001996 if (VERIFY_OK(*pFailure) && checkBooleanOp) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001997 assert(dstType == kRegTypeInteger);
Andy McFaddend3250112010-11-03 14:32:42 -07001998 if (upcastBooleanOp(insnRegs, pDecInsn->vB, pDecInsn->vC))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001999 dstType = kRegTypeBoolean;
2000 }
Andy McFaddend3250112010-11-03 14:32:42 -07002001 setRegisterType(insnRegs, pDecInsn->vA, dstType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002002}
2003
2004/*
2005 * Verify types for a binary "2addr" operation. "srcType1"/"srcType2"
2006 * are verified against vA/vB, then "dstType" is stored into vA.
2007 */
Andy McFaddend3250112010-11-03 14:32:42 -07002008static void checkBinop2addr(RegType* insnRegs, DecodedInstruction* pDecInsn,
2009 RegType dstType, RegType srcType1, RegType srcType2, bool checkBooleanOp,
2010 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002011{
Andy McFaddend3250112010-11-03 14:32:42 -07002012 verifyRegisterType(insnRegs, pDecInsn->vA, srcType1, pFailure);
2013 verifyRegisterType(insnRegs, pDecInsn->vB, srcType2, pFailure);
Andy McFadden62a75162009-04-17 17:23:37 -07002014 if (VERIFY_OK(*pFailure) && checkBooleanOp) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002015 assert(dstType == kRegTypeInteger);
Andy McFaddend3250112010-11-03 14:32:42 -07002016 if (upcastBooleanOp(insnRegs, pDecInsn->vA, pDecInsn->vB))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002017 dstType = kRegTypeBoolean;
2018 }
Andy McFaddend3250112010-11-03 14:32:42 -07002019 setRegisterType(insnRegs, pDecInsn->vA, dstType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002020}
2021
Andy McFadden80d25ea2009-06-12 07:26:17 -07002022/*
2023 * Treat right-shifting as a narrowing conversion when possible.
2024 *
2025 * For example, right-shifting an int 24 times results in a value that can
2026 * be treated as a byte.
2027 *
2028 * Things get interesting when contemplating sign extension. Right-
2029 * shifting an integer by 16 yields a value that can be represented in a
2030 * "short" but not a "char", but an unsigned right shift by 16 yields a
2031 * value that belongs in a char rather than a short. (Consider what would
2032 * happen if the result of the shift were cast to a char or short and then
2033 * cast back to an int. If sign extension, or the lack thereof, causes
2034 * a change in the 32-bit representation, then the conversion was lossy.)
2035 *
2036 * A signed right shift by 17 on an integer results in a short. An unsigned
2037 * right shfit by 17 on an integer results in a posshort, which can be
2038 * assigned to a short or a char.
2039 *
2040 * An unsigned right shift on a short can actually expand the result into
2041 * a 32-bit integer. For example, 0xfffff123 >>> 8 becomes 0x00fffff1,
2042 * which can't be represented in anything smaller than an int.
2043 *
2044 * javac does not generate code that takes advantage of this, but some
2045 * of the code optimizers do. It's generally a peephole optimization
2046 * that replaces a particular sequence, e.g. (bipush 24, ishr, i2b) is
2047 * replaced by (bipush 24, ishr). Knowing that shifting a short 8 times
2048 * to the right yields a byte is really more than we need to handle the
2049 * code that's out there, but support is not much more complex than just
2050 * handling integer.
2051 *
2052 * Right-shifting never yields a boolean value.
2053 *
2054 * Returns the new register type.
2055 */
Andy McFaddend3250112010-11-03 14:32:42 -07002056static RegType adjustForRightShift(RegType* workRegs, int reg,
2057 unsigned int shiftCount, bool isUnsignedShift, VerifyError* pFailure)
Andy McFadden80d25ea2009-06-12 07:26:17 -07002058{
Andy McFaddend3250112010-11-03 14:32:42 -07002059 RegType srcType = getRegisterType(workRegs, reg);
Andy McFadden80d25ea2009-06-12 07:26:17 -07002060 RegType newType;
2061
2062 /* no-op */
2063 if (shiftCount == 0)
2064 return srcType;
2065
2066 /* safe defaults */
2067 if (isUnsignedShift)
2068 newType = kRegTypeInteger;
2069 else
2070 newType = srcType;
2071
2072 if (shiftCount >= 32) {
2073 LOG_VFY("Got unexpectedly large shift count %u\n", shiftCount);
2074 /* fail? */
2075 return newType;
2076 }
2077
2078 switch (srcType) {
2079 case kRegTypeInteger: /* 32-bit signed value */
2080 case kRegTypeFloat: /* (allowed; treat same as int) */
2081 if (isUnsignedShift) {
2082 if (shiftCount > 24)
2083 newType = kRegTypePosByte;
2084 else if (shiftCount >= 16)
2085 newType = kRegTypeChar;
2086 } else {
2087 if (shiftCount >= 24)
2088 newType = kRegTypeByte;
2089 else if (shiftCount >= 16)
2090 newType = kRegTypeShort;
2091 }
2092 break;
2093 case kRegTypeShort: /* 16-bit signed value */
2094 if (isUnsignedShift) {
2095 /* default (kRegTypeInteger) is correct */
2096 } else {
2097 if (shiftCount >= 8)
2098 newType = kRegTypeByte;
2099 }
2100 break;
2101 case kRegTypePosShort: /* 15-bit unsigned value */
2102 if (shiftCount >= 8)
2103 newType = kRegTypePosByte;
2104 break;
2105 case kRegTypeChar: /* 16-bit unsigned value */
2106 if (shiftCount > 8)
2107 newType = kRegTypePosByte;
2108 break;
2109 case kRegTypeByte: /* 8-bit signed value */
2110 /* defaults (u=kRegTypeInteger / s=srcType) are correct */
2111 break;
2112 case kRegTypePosByte: /* 7-bit unsigned value */
2113 /* always use newType=srcType */
2114 newType = srcType;
2115 break;
2116 case kRegTypeZero: /* 1-bit unsigned value */
2117 case kRegTypeOne:
2118 case kRegTypeBoolean:
2119 /* unnecessary? */
2120 newType = kRegTypeZero;
2121 break;
2122 default:
2123 /* long, double, references; shouldn't be here! */
2124 assert(false);
2125 break;
2126 }
2127
2128 if (newType != srcType) {
2129 LOGVV("narrowing: %d(%d) --> %d to %d\n",
2130 shiftCount, isUnsignedShift, srcType, newType);
2131 } else {
2132 LOGVV("not narrowed: %d(%d) --> %d\n",
2133 shiftCount, isUnsignedShift, srcType);
2134 }
2135 return newType;
2136}
2137
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002138
2139/*
2140 * ===========================================================================
2141 * Register merge
2142 * ===========================================================================
2143 */
2144
2145/*
2146 * Compute the "class depth" of a class. This is the distance from the
2147 * class to the top of the tree, chasing superclass links. java.lang.Object
2148 * has a class depth of 0.
2149 */
2150static int getClassDepth(ClassObject* clazz)
2151{
2152 int depth = 0;
2153
2154 while (clazz->super != NULL) {
2155 clazz = clazz->super;
2156 depth++;
2157 }
2158 return depth;
2159}
2160
2161/*
2162 * Given two classes, walk up the superclass tree to find a common
2163 * ancestor. (Called from findCommonSuperclass().)
2164 *
2165 * TODO: consider caching the class depth in the class object so we don't
2166 * have to search for it here.
2167 */
2168static ClassObject* digForSuperclass(ClassObject* c1, ClassObject* c2)
2169{
2170 int depth1, depth2;
2171
2172 depth1 = getClassDepth(c1);
2173 depth2 = getClassDepth(c2);
2174
2175 if (gDebugVerbose) {
2176 LOGVV("COMMON: %s(%d) + %s(%d)\n",
2177 c1->descriptor, depth1, c2->descriptor, depth2);
2178 }
2179
2180 /* pull the deepest one up */
2181 if (depth1 > depth2) {
2182 while (depth1 > depth2) {
2183 c1 = c1->super;
2184 depth1--;
2185 }
2186 } else {
2187 while (depth2 > depth1) {
2188 c2 = c2->super;
2189 depth2--;
2190 }
2191 }
2192
2193 /* walk up in lock-step */
2194 while (c1 != c2) {
2195 c1 = c1->super;
2196 c2 = c2->super;
2197
2198 assert(c1 != NULL && c2 != NULL);
2199 }
2200
2201 if (gDebugVerbose) {
2202 LOGVV(" : --> %s\n", c1->descriptor);
2203 }
2204 return c1;
2205}
2206
2207/*
2208 * Merge two array classes. We can't use the general "walk up to the
2209 * superclass" merge because the superclass of an array is always Object.
2210 * We want String[] + Integer[] = Object[]. This works for higher dimensions
2211 * as well, e.g. String[][] + Integer[][] = Object[][].
2212 *
2213 * If Foo1 and Foo2 are subclasses of Foo, Foo1[] + Foo2[] = Foo[].
2214 *
2215 * If Class implements Type, Class[] + Type[] = Type[].
2216 *
2217 * If the dimensions don't match, we want to convert to an array of Object
2218 * with the least dimension, e.g. String[][] + String[][][][] = Object[][].
2219 *
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002220 * Arrays of primitive types effectively have one less dimension when
2221 * merging. int[] + float[] = Object, int[] + String[] = Object,
2222 * int[][] + float[][] = Object[], int[][] + String[] = Object[]. (The
2223 * only time this function doesn't return an array class is when one of
2224 * the arguments is a 1-dimensional primitive array.)
2225 *
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002226 * This gets a little awkward because we may have to ask the VM to create
2227 * a new array type with the appropriate element and dimensions. However, we
2228 * shouldn't be doing this often.
2229 */
2230static ClassObject* findCommonArraySuperclass(ClassObject* c1, ClassObject* c2)
2231{
2232 ClassObject* arrayClass = NULL;
2233 ClassObject* commonElem;
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002234 int arrayDim1, arrayDim2;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002235 int i, numDims;
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002236 bool hasPrimitive = false;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002237
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002238 arrayDim1 = c1->arrayDim;
2239 arrayDim2 = c2->arrayDim;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002240 assert(c1->arrayDim > 0);
2241 assert(c2->arrayDim > 0);
2242
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002243 if (dvmIsPrimitiveClass(c1->elementClass)) {
2244 arrayDim1--;
2245 hasPrimitive = true;
2246 }
2247 if (dvmIsPrimitiveClass(c2->elementClass)) {
2248 arrayDim2--;
2249 hasPrimitive = true;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002250 }
2251
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002252 if (!hasPrimitive && arrayDim1 == arrayDim2) {
2253 /*
2254 * Two arrays of reference types with equal dimensions. Try to
2255 * find a good match.
2256 */
2257 commonElem = findCommonSuperclass(c1->elementClass, c2->elementClass);
2258 numDims = arrayDim1;
2259 } else {
2260 /*
2261 * Mismatched array depths and/or array(s) of primitives. We want
2262 * Object, or an Object array with appropriate dimensions.
2263 *
2264 * We initialize arrayClass to Object here, because it's possible
2265 * for us to set numDims=0.
2266 */
2267 if (arrayDim1 < arrayDim2)
2268 numDims = arrayDim1;
2269 else
2270 numDims = arrayDim2;
2271 arrayClass = commonElem = c1->super; // == java.lang.Object
2272 }
2273
2274 /*
2275 * Find an appropriately-dimensioned array class. This is easiest
2276 * to do iteratively, using the array class found by the current round
2277 * as the element type for the next round.
2278 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002279 for (i = 0; i < numDims; i++) {
2280 arrayClass = dvmFindArrayClassForElement(commonElem);
2281 commonElem = arrayClass;
2282 }
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002283 assert(arrayClass != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002284
2285 LOGVV("ArrayMerge '%s' + '%s' --> '%s'\n",
2286 c1->descriptor, c2->descriptor, arrayClass->descriptor);
2287 return arrayClass;
2288}
2289
2290/*
2291 * Find the first common superclass of the two classes. We're not
2292 * interested in common interfaces.
2293 *
2294 * The easiest way to do this for concrete classes is to compute the "class
2295 * depth" of each, move up toward the root of the deepest one until they're
2296 * at the same depth, then walk both up to the root until they match.
2297 *
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002298 * If both classes are arrays, we need to merge based on array depth and
2299 * element type.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002300 *
2301 * If one class is an interface, we check to see if the other class/interface
2302 * (or one of its predecessors) implements the interface. If so, we return
2303 * the interface; otherwise, we return Object.
2304 *
2305 * NOTE: we continue the tradition of "lazy interface handling". To wit,
2306 * suppose we have three classes:
2307 * One implements Fancy, Free
2308 * Two implements Fancy, Free
2309 * Three implements Free
2310 * where Fancy and Free are unrelated interfaces. The code requires us
2311 * to merge One into Two. Ideally we'd use a common interface, which
2312 * gives us a choice between Fancy and Free, and no guidance on which to
2313 * use. If we use Free, we'll be okay when Three gets merged in, but if
2314 * we choose Fancy, we're hosed. The "ideal" solution is to create a
2315 * set of common interfaces and carry that around, merging further references
2316 * into it. This is a pain. The easy solution is to simply boil them
2317 * down to Objects and let the runtime invokeinterface call fail, which
2318 * is what we do.
2319 */
2320static ClassObject* findCommonSuperclass(ClassObject* c1, ClassObject* c2)
2321{
2322 assert(!dvmIsPrimitiveClass(c1) && !dvmIsPrimitiveClass(c2));
2323
2324 if (c1 == c2)
2325 return c1;
2326
2327 if (dvmIsInterfaceClass(c1) && dvmImplements(c2, c1)) {
2328 if (gDebugVerbose)
2329 LOGVV("COMMON/I1: %s + %s --> %s\n",
2330 c1->descriptor, c2->descriptor, c1->descriptor);
2331 return c1;
2332 }
2333 if (dvmIsInterfaceClass(c2) && dvmImplements(c1, c2)) {
2334 if (gDebugVerbose)
2335 LOGVV("COMMON/I2: %s + %s --> %s\n",
2336 c1->descriptor, c2->descriptor, c2->descriptor);
2337 return c2;
2338 }
2339
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002340 if (dvmIsArrayClass(c1) && dvmIsArrayClass(c2)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002341 return findCommonArraySuperclass(c1, c2);
2342 }
2343
2344 return digForSuperclass(c1, c2);
2345}
2346
2347/*
2348 * Merge two RegType values.
2349 *
2350 * Sets "*pChanged" to "true" if the result doesn't match "type1".
2351 */
2352static RegType mergeTypes(RegType type1, RegType type2, bool* pChanged)
2353{
2354 RegType result;
2355
2356 /*
2357 * Check for trivial case so we don't have to hit memory.
2358 */
2359 if (type1 == type2)
2360 return type1;
2361
2362 /*
2363 * Use the table if we can, and reject any attempts to merge something
2364 * from the table with a reference type.
2365 *
Andy McFadden470cbbb2010-11-04 16:31:37 -07002366 * Uninitialized references are composed of the enum ORed with an
2367 * index value. The uninitialized table entry at index zero *will*
2368 * show up as a simple kRegTypeUninit value. Since this cannot be
2369 * merged with anything but itself, the rules do the right thing.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002370 */
2371 if (type1 < kRegTypeMAX) {
2372 if (type2 < kRegTypeMAX) {
2373 result = gDvmMergeTab[type1][type2];
2374 } else {
2375 /* simple + reference == conflict, usually */
2376 if (type1 == kRegTypeZero)
2377 result = type2;
2378 else
2379 result = kRegTypeConflict;
2380 }
2381 } else {
2382 if (type2 < kRegTypeMAX) {
2383 /* reference + simple == conflict, usually */
2384 if (type2 == kRegTypeZero)
2385 result = type1;
2386 else
2387 result = kRegTypeConflict;
2388 } else {
2389 /* merging two references */
2390 if (regTypeIsUninitReference(type1) ||
2391 regTypeIsUninitReference(type2))
2392 {
2393 /* can't merge uninit with anything but self */
2394 result = kRegTypeConflict;
2395 } else {
2396 ClassObject* clazz1 = regTypeInitializedReferenceToClass(type1);
2397 ClassObject* clazz2 = regTypeInitializedReferenceToClass(type2);
2398 ClassObject* mergedClass;
2399
2400 mergedClass = findCommonSuperclass(clazz1, clazz2);
2401 assert(mergedClass != NULL);
2402 result = regTypeFromClass(mergedClass);
2403 }
2404 }
2405 }
2406
2407 if (result != type1)
2408 *pChanged = true;
2409 return result;
2410}
2411
2412/*
2413 * Control can transfer to "nextInsn".
2414 *
2415 * Merge the registers from "workRegs" into "regTypes" at "nextInsn", and
2416 * set the "changed" flag on the target address if the registers have changed.
2417 */
2418static void updateRegisters(const Method* meth, InsnFlags* insnFlags,
2419 RegisterTable* regTable, int nextInsn, const RegType* workRegs)
2420{
2421 RegType* targetRegs = getRegisterLine(regTable, nextInsn);
2422 const int insnRegCount = meth->registersSize;
2423
Andy McFaddend3250112010-11-03 14:32:42 -07002424 assert(targetRegs != NULL);
2425
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002426#if 0
2427 if (!dvmInsnIsBranchTarget(insnFlags, nextInsn)) {
2428 LOGE("insnFlags[0x%x]=0x%08x\n", nextInsn, insnFlags[nextInsn]);
2429 LOGE(" In %s.%s %s\n",
2430 meth->clazz->descriptor, meth->name, meth->descriptor);
2431 assert(false);
2432 }
2433#endif
2434
2435 if (!dvmInsnIsVisitedOrChanged(insnFlags, nextInsn)) {
2436 /*
2437 * We haven't processed this instruction before, and we haven't
2438 * touched the registers here, so there's nothing to "merge". Copy
2439 * the registers over and mark it as changed. (This is the only
2440 * way a register can transition out of "unknown", so this is not
2441 * just an optimization.)
2442 */
2443 LOGVV("COPY into 0x%04x\n", nextInsn);
2444 copyRegisters(targetRegs, workRegs, insnRegCount + kExtraRegs);
2445 dvmInsnSetChanged(insnFlags, nextInsn, true);
Andy McFadden470cbbb2010-11-04 16:31:37 -07002446#ifdef VERIFIER_STATS
2447 gDvm.verifierStats.copyRegCount++;
2448#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002449 } else {
2450 if (gDebugVerbose) {
2451 LOGVV("MERGE into 0x%04x\n", nextInsn);
2452 //dumpRegTypes(meth, insnFlags, targetRegs, 0, "targ", NULL, 0);
2453 //dumpRegTypes(meth, insnFlags, workRegs, 0, "work", NULL, 0);
2454 }
2455 /* merge registers, set Changed only if different */
2456 bool changed = false;
2457 int i;
2458
Andy McFadden470cbbb2010-11-04 16:31:37 -07002459 assert(dvmInsnIsBranchTarget(insnFlags, nextInsn));
2460
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002461 for (i = 0; i < insnRegCount + kExtraRegs; i++) {
2462 targetRegs[i] = mergeTypes(targetRegs[i], workRegs[i], &changed);
2463 }
2464
2465 if (gDebugVerbose) {
2466 //LOGI(" RESULT (changed=%d)\n", changed);
2467 //dumpRegTypes(meth, insnFlags, targetRegs, 0, "rslt", NULL, 0);
2468 }
Andy McFadden470cbbb2010-11-04 16:31:37 -07002469#ifdef VERIFIER_STATS
2470 gDvm.verifierStats.mergeRegCount++;
2471 if (changed)
2472 gDvm.verifierStats.mergeRegChanged++;
2473#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002474
2475 if (changed)
2476 dvmInsnSetChanged(insnFlags, nextInsn, true);
2477 }
2478}
2479
2480
2481/*
2482 * ===========================================================================
2483 * Utility functions
2484 * ===========================================================================
2485 */
2486
2487/*
2488 * Look up an instance field, specified by "fieldIdx", that is going to be
2489 * accessed in object "objType". This resolves the field and then verifies
2490 * that the class containing the field is an instance of the reference in
2491 * "objType".
2492 *
2493 * It is possible for "objType" to be kRegTypeZero, meaning that we might
2494 * have a null reference. This is a runtime problem, so we allow it,
2495 * skipping some of the type checks.
2496 *
2497 * In general, "objType" must be an initialized reference. However, we
2498 * allow it to be uninitialized if this is an "<init>" method and the field
2499 * is declared within the "objType" class.
2500 *
Andy McFadden62a75162009-04-17 17:23:37 -07002501 * Returns an InstField on success, returns NULL and sets "*pFailure"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002502 * on failure.
2503 */
2504static InstField* getInstField(const Method* meth,
2505 const UninitInstanceMap* uninitMap, RegType objType, int fieldIdx,
Andy McFadden62a75162009-04-17 17:23:37 -07002506 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002507{
2508 InstField* instField = NULL;
2509 ClassObject* objClass;
2510 bool mustBeLocal = false;
2511
2512 if (!regTypeIsReference(objType)) {
Andy McFadden62a75162009-04-17 17:23:37 -07002513 LOG_VFY("VFY: attempt to access field in non-reference type %d\n",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002514 objType);
Andy McFadden62a75162009-04-17 17:23:37 -07002515 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002516 goto bail;
2517 }
2518
Andy McFadden62a75162009-04-17 17:23:37 -07002519 instField = dvmOptResolveInstField(meth->clazz, fieldIdx, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002520 if (instField == NULL) {
2521 LOG_VFY("VFY: unable to resolve instance field %u\n", fieldIdx);
Andy McFadden62a75162009-04-17 17:23:37 -07002522 assert(!VERIFY_OK(*pFailure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002523 goto bail;
2524 }
2525
2526 if (objType == kRegTypeZero)
2527 goto bail;
2528
2529 /*
2530 * Access to fields in uninitialized objects is allowed if this is
2531 * the <init> method for the object and the field in question is
2532 * declared by this class.
2533 */
2534 objClass = regTypeReferenceToClass(objType, uninitMap);
2535 assert(objClass != NULL);
2536 if (regTypeIsUninitReference(objType)) {
2537 if (!isInitMethod(meth) || meth->clazz != objClass) {
2538 LOG_VFY("VFY: attempt to access field via uninitialized ref\n");
Andy McFadden62a75162009-04-17 17:23:37 -07002539 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002540 goto bail;
2541 }
2542 mustBeLocal = true;
2543 }
2544
2545 if (!dvmInstanceof(objClass, instField->field.clazz)) {
2546 LOG_VFY("VFY: invalid field access (field %s.%s, through %s ref)\n",
2547 instField->field.clazz->descriptor, instField->field.name,
2548 objClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07002549 *pFailure = VERIFY_ERROR_NO_FIELD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002550 goto bail;
2551 }
2552
2553 if (mustBeLocal) {
2554 /* for uninit ref, make sure it's defined by this class, not super */
2555 if (instField < objClass->ifields ||
2556 instField >= objClass->ifields + objClass->ifieldCount)
2557 {
2558 LOG_VFY("VFY: invalid constructor field access (field %s in %s)\n",
2559 instField->field.name, objClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07002560 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002561 goto bail;
2562 }
2563 }
2564
2565bail:
2566 return instField;
2567}
2568
2569/*
2570 * Look up a static field.
2571 *
Andy McFadden62a75162009-04-17 17:23:37 -07002572 * Returns a StaticField on success, returns NULL and sets "*pFailure"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002573 * on failure.
2574 */
2575static StaticField* getStaticField(const Method* meth, int fieldIdx,
Andy McFadden62a75162009-04-17 17:23:37 -07002576 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002577{
2578 StaticField* staticField;
2579
Andy McFadden62a75162009-04-17 17:23:37 -07002580 staticField = dvmOptResolveStaticField(meth->clazz, fieldIdx, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002581 if (staticField == NULL) {
2582 DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
2583 const DexFieldId* pFieldId;
2584
2585 pFieldId = dexGetFieldId(pDexFile, fieldIdx);
2586
2587 LOG_VFY("VFY: unable to resolve static field %u (%s) in %s\n", fieldIdx,
2588 dexStringById(pDexFile, pFieldId->nameIdx),
2589 dexStringByTypeIdx(pDexFile, pFieldId->classIdx));
Andy McFadden62a75162009-04-17 17:23:37 -07002590 assert(!VERIFY_OK(*pFailure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002591 goto bail;
2592 }
2593
2594bail:
2595 return staticField;
2596}
2597
2598/*
2599 * If "field" is marked "final", make sure this is the either <clinit>
2600 * or <init> as appropriate.
2601 *
Andy McFadden62a75162009-04-17 17:23:37 -07002602 * Sets "*pFailure" on failure.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002603 */
2604static void checkFinalFieldAccess(const Method* meth, const Field* field,
Andy McFadden62a75162009-04-17 17:23:37 -07002605 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002606{
2607 if (!dvmIsFinalField(field))
2608 return;
2609
2610 /* make sure we're in the same class */
2611 if (meth->clazz != field->clazz) {
2612 LOG_VFY_METH(meth, "VFY: can't modify final field %s.%s\n",
2613 field->clazz->descriptor, field->name);
Andy McFaddenb51ea112009-05-08 16:50:17 -07002614 *pFailure = VERIFY_ERROR_ACCESS_FIELD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002615 return;
2616 }
2617
2618 /*
Andy McFadden62a75162009-04-17 17:23:37 -07002619 * The VM spec descriptions of putfield and putstatic say that
2620 * IllegalAccessError is only thrown when the instructions appear
2621 * outside the declaring class. Our earlier attempts to restrict
2622 * final field modification to constructors are, therefore, wrong.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002623 */
2624#if 0
2625 /* make sure we're in the right kind of constructor */
2626 if (dvmIsStaticField(field)) {
2627 if (!isClassInitMethod(meth)) {
2628 LOG_VFY_METH(meth,
2629 "VFY: can't modify final static field outside <clinit>\n");
Andy McFadden62a75162009-04-17 17:23:37 -07002630 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002631 }
2632 } else {
2633 if (!isInitMethod(meth)) {
2634 LOG_VFY_METH(meth,
2635 "VFY: can't modify final field outside <init>\n");
Andy McFadden62a75162009-04-17 17:23:37 -07002636 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002637 }
2638 }
2639#endif
2640}
2641
2642/*
2643 * Make sure that the register type is suitable for use as an array index.
2644 *
Andy McFadden62a75162009-04-17 17:23:37 -07002645 * Sets "*pFailure" if not.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002646 */
2647static void checkArrayIndexType(const Method* meth, RegType regType,
Andy McFadden62a75162009-04-17 17:23:37 -07002648 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002649{
Andy McFadden62a75162009-04-17 17:23:37 -07002650 if (VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002651 /*
2652 * The 1nr types are interchangeable at this level. We could
2653 * do something special if we can definitively identify it as a
2654 * float, but there's no real value in doing so.
2655 */
Andy McFadden62a75162009-04-17 17:23:37 -07002656 checkTypeCategory(regType, kTypeCategory1nr, pFailure);
2657 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002658 LOG_VFY_METH(meth, "Invalid reg type for array index (%d)\n",
2659 regType);
2660 }
2661 }
2662}
2663
2664/*
2665 * Check constraints on constructor return. Specifically, make sure that
2666 * the "this" argument got initialized.
2667 *
2668 * The "this" argument to <init> uses code offset kUninitThisArgAddr, which
2669 * puts it at the start of the list in slot 0. If we see a register with
2670 * an uninitialized slot 0 reference, we know it somehow didn't get
2671 * initialized.
2672 *
2673 * Returns "true" if all is well.
2674 */
2675static bool checkConstructorReturn(const Method* meth, const RegType* insnRegs,
2676 const int insnRegCount)
2677{
2678 int i;
2679
2680 if (!isInitMethod(meth))
2681 return true;
2682
2683 RegType uninitThis = regTypeFromUninitIndex(kUninitThisArgSlot);
2684
2685 for (i = 0; i < insnRegCount; i++) {
2686 if (insnRegs[i] == uninitThis) {
2687 LOG_VFY("VFY: <init> returning without calling superclass init\n");
2688 return false;
2689 }
2690 }
2691 return true;
2692}
2693
2694/*
2695 * Verify that the target instruction is not "move-exception". It's important
2696 * that the only way to execute a move-exception is as the first instruction
2697 * of an exception handler.
2698 *
2699 * Returns "true" if all is well, "false" if the target instruction is
2700 * move-exception.
2701 */
2702static bool checkMoveException(const Method* meth, int insnIdx,
2703 const char* logNote)
2704{
2705 assert(insnIdx >= 0 && insnIdx < (int)dvmGetMethodInsnsSize(meth));
2706
2707 if ((meth->insns[insnIdx] & 0xff) == OP_MOVE_EXCEPTION) {
2708 LOG_VFY("VFY: invalid use of move-exception\n");
2709 return false;
2710 }
2711 return true;
2712}
2713
2714/*
2715 * For the "move-exception" instruction at "insnIdx", which must be at an
2716 * exception handler address, determine the first common superclass of
2717 * all exceptions that can land here. (For javac output, we're probably
2718 * looking at multiple spans of bytecode covered by one "try" that lands
2719 * at an exception-specific "catch", but in general the handler could be
2720 * shared for multiple exceptions.)
2721 *
2722 * Returns NULL if no matching exception handler can be found, or if the
2723 * exception is not a subclass of Throwable.
2724 */
Andy McFadden62a75162009-04-17 17:23:37 -07002725static ClassObject* getCaughtExceptionType(const Method* meth, int insnIdx,
2726 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002727{
Andy McFadden62a75162009-04-17 17:23:37 -07002728 VerifyError localFailure;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002729 const DexCode* pCode;
2730 DexFile* pDexFile;
2731 ClassObject* commonSuper = NULL;
Andy McFadden62a75162009-04-17 17:23:37 -07002732 bool foundPossibleHandler = false;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002733 u4 handlersSize;
2734 u4 offset;
2735 u4 i;
2736
2737 pDexFile = meth->clazz->pDvmDex->pDexFile;
2738 pCode = dvmGetMethodCode(meth);
2739
2740 if (pCode->triesSize != 0) {
2741 handlersSize = dexGetHandlersSize(pCode);
2742 offset = dexGetFirstHandlerOffset(pCode);
2743 } else {
2744 handlersSize = 0;
2745 offset = 0;
2746 }
2747
2748 for (i = 0; i < handlersSize; i++) {
2749 DexCatchIterator iterator;
2750 dexCatchIteratorInit(&iterator, pCode, offset);
2751
2752 for (;;) {
2753 const DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
2754
2755 if (handler == NULL) {
2756 break;
2757 }
2758
2759 if (handler->address == (u4) insnIdx) {
2760 ClassObject* clazz;
Andy McFadden62a75162009-04-17 17:23:37 -07002761 foundPossibleHandler = true;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002762
2763 if (handler->typeIdx == kDexNoIndex)
2764 clazz = gDvm.classJavaLangThrowable;
2765 else
Andy McFadden62a75162009-04-17 17:23:37 -07002766 clazz = dvmOptResolveClass(meth->clazz, handler->typeIdx,
2767 &localFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002768
2769 if (clazz == NULL) {
2770 LOG_VFY("VFY: unable to resolve exception class %u (%s)\n",
2771 handler->typeIdx,
2772 dexStringByTypeIdx(pDexFile, handler->typeIdx));
Andy McFadden62a75162009-04-17 17:23:37 -07002773 /* TODO: do we want to keep going? If we don't fail
2774 * this we run the risk of having a non-Throwable
2775 * introduced at runtime. However, that won't pass
2776 * an instanceof test, so is essentially harmless. */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002777 } else {
2778 if (commonSuper == NULL)
2779 commonSuper = clazz;
2780 else
2781 commonSuper = findCommonSuperclass(clazz, commonSuper);
2782 }
2783 }
2784 }
2785
2786 offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
2787 }
2788
2789 if (commonSuper == NULL) {
Andy McFadden62a75162009-04-17 17:23:37 -07002790 /* no catch blocks, or no catches with classes we can find */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002791 LOG_VFY_METH(meth,
2792 "VFY: unable to find exception handler at addr 0x%x\n", insnIdx);
Andy McFadden62a75162009-04-17 17:23:37 -07002793 *pFailure = VERIFY_ERROR_GENERIC;
2794 } else {
2795 // TODO: verify the class is an instance of Throwable?
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002796 }
2797
2798 return commonSuper;
2799}
2800
2801/*
2802 * Initialize the RegisterTable.
2803 *
2804 * Every instruction address can have a different set of information about
2805 * what's in which register, but for verification purposes we only need to
2806 * store it at branch target addresses (because we merge into that).
2807 *
2808 * By zeroing out the storage we are effectively initializing the register
2809 * information to kRegTypeUnknown.
2810 */
2811static bool initRegisterTable(const Method* meth, const InsnFlags* insnFlags,
2812 RegisterTable* regTable, RegisterTrackingMode trackRegsFor)
2813{
2814 const int insnsSize = dvmGetMethodInsnsSize(meth);
2815 int i;
2816
2817 regTable->insnRegCountPlus = meth->registersSize + kExtraRegs;
2818 regTable->addrRegs = (RegType**) calloc(insnsSize, sizeof(RegType*));
2819 if (regTable->addrRegs == NULL)
2820 return false;
2821
2822 assert(insnsSize > 0);
2823
2824 /*
2825 * "All" means "every address that holds the start of an instruction".
2826 * "Branches" and "GcPoints" mean just those addresses.
2827 *
2828 * "GcPoints" fills about half the addresses, "Branches" about 15%.
2829 */
2830 int interestingCount = 0;
2831 //int insnCount = 0;
2832
2833 for (i = 0; i < insnsSize; i++) {
2834 bool interesting;
2835
2836 switch (trackRegsFor) {
2837 case kTrackRegsAll:
2838 interesting = dvmInsnIsOpcode(insnFlags, i);
2839 break;
2840 case kTrackRegsGcPoints:
2841 interesting = dvmInsnIsGcPoint(insnFlags, i) ||
2842 dvmInsnIsBranchTarget(insnFlags, i);
2843 break;
2844 case kTrackRegsBranches:
2845 interesting = dvmInsnIsBranchTarget(insnFlags, i);
2846 break;
2847 default:
2848 dvmAbort();
2849 return false;
2850 }
2851
2852 if (interesting)
2853 interestingCount++;
2854
2855 /* count instructions, for display only */
2856 //if (dvmInsnIsOpcode(insnFlags, i))
2857 // insnCount++;
2858 }
2859
2860 regTable->regAlloc = (RegType*)
2861 calloc(regTable->insnRegCountPlus * interestingCount, sizeof(RegType));
2862 if (regTable->regAlloc == NULL)
2863 return false;
2864
2865 RegType* regPtr = regTable->regAlloc;
2866 for (i = 0; i < insnsSize; i++) {
2867 bool interesting;
2868
2869 switch (trackRegsFor) {
2870 case kTrackRegsAll:
2871 interesting = dvmInsnIsOpcode(insnFlags, i);
2872 break;
2873 case kTrackRegsGcPoints:
2874 interesting = dvmInsnIsGcPoint(insnFlags, i) ||
2875 dvmInsnIsBranchTarget(insnFlags, i);
2876 break;
2877 case kTrackRegsBranches:
2878 interesting = dvmInsnIsBranchTarget(insnFlags, i);
2879 break;
2880 default:
2881 dvmAbort();
2882 return false;
2883 }
2884
2885 if (interesting) {
2886 regTable->addrRegs[i] = regPtr;
2887 regPtr += regTable->insnRegCountPlus;
2888 }
2889 }
2890
2891 //LOGD("Tracking registers for %d, total %d of %d(%d) (%d%%)\n",
2892 // TRACK_REGS_FOR, interestingCount, insnCount, insnsSize,
2893 // (interestingCount*100) / insnCount);
2894
2895 assert(regPtr - regTable->regAlloc ==
2896 regTable->insnRegCountPlus * interestingCount);
2897 assert(regTable->addrRegs[0] != NULL);
2898 return true;
2899}
2900
2901
2902/*
2903 * Verify that the arguments in a filled-new-array instruction are valid.
2904 *
2905 * "resClass" is the class refered to by pDecInsn->vB.
2906 */
2907static void verifyFilledNewArrayRegs(const Method* meth,
Andy McFaddend3250112010-11-03 14:32:42 -07002908 const RegType* insnRegs, const DecodedInstruction* pDecInsn,
2909 ClassObject* resClass, bool isRange, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002910{
2911 u4 argCount = pDecInsn->vA;
2912 RegType expectedType;
2913 PrimitiveType elemType;
2914 unsigned int ui;
2915
2916 assert(dvmIsArrayClass(resClass));
2917 elemType = resClass->elementClass->primitiveType;
2918 if (elemType == PRIM_NOT) {
2919 expectedType = regTypeFromClass(resClass->elementClass);
2920 } else {
2921 expectedType = primitiveTypeToRegType(elemType);
2922 }
2923 //LOGI("filled-new-array: %s -> %d\n", resClass->descriptor, expectedType);
2924
2925 /*
2926 * Verify each register. If "argCount" is bad, verifyRegisterType()
2927 * will run off the end of the list and fail. It's legal, if silly,
2928 * for argCount to be zero.
2929 */
2930 for (ui = 0; ui < argCount; ui++) {
2931 u4 getReg;
2932
2933 if (isRange)
2934 getReg = pDecInsn->vC + ui;
2935 else
2936 getReg = pDecInsn->arg[ui];
2937
Andy McFaddend3250112010-11-03 14:32:42 -07002938 verifyRegisterType(insnRegs, getReg, expectedType, pFailure);
Andy McFadden62a75162009-04-17 17:23:37 -07002939 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002940 LOG_VFY("VFY: filled-new-array arg %u(%u) not valid\n", ui, getReg);
2941 return;
2942 }
2943 }
2944}
2945
2946
2947/*
Andy McFaddenb51ea112009-05-08 16:50:17 -07002948 * Replace an instruction with "throw-verification-error". This allows us to
2949 * defer error reporting until the code path is first used.
2950 *
Andy McFadden861b3382010-03-05 15:58:31 -08002951 * This is expected to be called during "just in time" verification, not
2952 * from within dexopt. (Verification failures in dexopt will result in
2953 * postponement of verification to first use of the class.)
2954 *
Andy McFaddenb51ea112009-05-08 16:50:17 -07002955 * The throw-verification-error instruction requires two code units. Some
2956 * of the replaced instructions require three; the third code unit will
2957 * receive a "nop". The instruction's length will be left unchanged
2958 * in "insnFlags".
2959 *
Andy McFadden96516932009-10-28 17:39:02 -07002960 * The verifier explicitly locks out breakpoint activity, so there should
2961 * be no clashes with the debugger.
2962 *
Andy McFaddenb51ea112009-05-08 16:50:17 -07002963 * Returns "true" on success.
2964 */
Andy McFadden228a6b02010-05-04 15:02:32 -07002965static bool replaceFailingInstruction(const Method* meth, InsnFlags* insnFlags,
Andy McFaddenb51ea112009-05-08 16:50:17 -07002966 int insnIdx, VerifyError failure)
2967{
Andy McFaddenaf0e8382009-08-28 10:38:37 -07002968 VerifyErrorRefType refType;
Andy McFaddenb51ea112009-05-08 16:50:17 -07002969 const u2* oldInsns = meth->insns + insnIdx;
2970 u2 oldInsn = *oldInsns;
2971 bool result = false;
2972
Andy McFaddenfb119e62010-06-28 16:21:20 -07002973 if (gDvm.optimizing)
2974 LOGD("Weird: RFI during dexopt?");
2975
Andy McFaddenb51ea112009-05-08 16:50:17 -07002976 //LOGD(" was 0x%04x\n", oldInsn);
2977 u2* newInsns = (u2*) meth->insns + insnIdx;
2978
2979 /*
2980 * Generate the new instruction out of the old.
2981 *
2982 * First, make sure this is an instruction we're expecting to stomp on.
2983 */
2984 switch (oldInsn & 0xff) {
2985 case OP_CONST_CLASS: // insn[1] == class ref, 2 bytes
2986 case OP_CHECK_CAST:
2987 case OP_INSTANCE_OF:
2988 case OP_NEW_INSTANCE:
2989 case OP_NEW_ARRAY:
Andy McFaddenb51ea112009-05-08 16:50:17 -07002990 case OP_FILLED_NEW_ARRAY: // insn[1] == class ref, 3 bytes
2991 case OP_FILLED_NEW_ARRAY_RANGE:
Andy McFaddenaf0e8382009-08-28 10:38:37 -07002992 refType = VERIFY_ERROR_REF_CLASS;
2993 break;
Andy McFaddenb51ea112009-05-08 16:50:17 -07002994
2995 case OP_IGET: // insn[1] == field ref, 2 bytes
2996 case OP_IGET_BOOLEAN:
2997 case OP_IGET_BYTE:
2998 case OP_IGET_CHAR:
2999 case OP_IGET_SHORT:
3000 case OP_IGET_WIDE:
3001 case OP_IGET_OBJECT:
3002 case OP_IPUT:
3003 case OP_IPUT_BOOLEAN:
3004 case OP_IPUT_BYTE:
3005 case OP_IPUT_CHAR:
3006 case OP_IPUT_SHORT:
3007 case OP_IPUT_WIDE:
3008 case OP_IPUT_OBJECT:
3009 case OP_SGET:
3010 case OP_SGET_BOOLEAN:
3011 case OP_SGET_BYTE:
3012 case OP_SGET_CHAR:
3013 case OP_SGET_SHORT:
3014 case OP_SGET_WIDE:
3015 case OP_SGET_OBJECT:
3016 case OP_SPUT:
3017 case OP_SPUT_BOOLEAN:
3018 case OP_SPUT_BYTE:
3019 case OP_SPUT_CHAR:
3020 case OP_SPUT_SHORT:
3021 case OP_SPUT_WIDE:
3022 case OP_SPUT_OBJECT:
Andy McFaddenaf0e8382009-08-28 10:38:37 -07003023 refType = VERIFY_ERROR_REF_FIELD;
3024 break;
Andy McFaddenb51ea112009-05-08 16:50:17 -07003025
3026 case OP_INVOKE_VIRTUAL: // insn[1] == method ref, 3 bytes
3027 case OP_INVOKE_VIRTUAL_RANGE:
3028 case OP_INVOKE_SUPER:
3029 case OP_INVOKE_SUPER_RANGE:
3030 case OP_INVOKE_DIRECT:
3031 case OP_INVOKE_DIRECT_RANGE:
3032 case OP_INVOKE_STATIC:
3033 case OP_INVOKE_STATIC_RANGE:
3034 case OP_INVOKE_INTERFACE:
3035 case OP_INVOKE_INTERFACE_RANGE:
Andy McFaddenaf0e8382009-08-28 10:38:37 -07003036 refType = VERIFY_ERROR_REF_METHOD;
Andy McFaddenb51ea112009-05-08 16:50:17 -07003037 break;
Andy McFaddenaf0e8382009-08-28 10:38:37 -07003038
Andy McFaddenb51ea112009-05-08 16:50:17 -07003039 default:
3040 /* could handle this in a generic way, but this is probably safer */
3041 LOG_VFY("GLITCH: verifier asked to replace opcode 0x%02x\n",
3042 oldInsn & 0xff);
3043 goto bail;
3044 }
3045
3046 /* write a NOP over the third code unit, if necessary */
3047 int width = dvmInsnGetWidth(insnFlags, insnIdx);
3048 switch (width) {
3049 case 2:
3050 /* nothing to do */
3051 break;
3052 case 3:
Andy McFadden96516932009-10-28 17:39:02 -07003053 dvmDexChangeDex2(meth->clazz->pDvmDex, newInsns+2, OP_NOP);
3054 //newInsns[2] = OP_NOP;
Andy McFaddenb51ea112009-05-08 16:50:17 -07003055 break;
3056 default:
3057 /* whoops */
3058 LOGE("ERROR: stomped a %d-unit instruction with a verifier error\n",
3059 width);
3060 dvmAbort();
3061 }
3062
3063 /* encode the opcode, with the failure code in the high byte */
Andy McFadden96516932009-10-28 17:39:02 -07003064 u2 newVal = OP_THROW_VERIFICATION_ERROR |
Andy McFaddenaf0e8382009-08-28 10:38:37 -07003065 (failure << 8) | (refType << (8 + kVerifyErrorRefTypeShift));
Andy McFadden96516932009-10-28 17:39:02 -07003066 //newInsns[0] = newVal;
3067 dvmDexChangeDex2(meth->clazz->pDvmDex, newInsns, newVal);
Andy McFaddenb51ea112009-05-08 16:50:17 -07003068
3069 result = true;
3070
3071bail:
Andy McFaddenb51ea112009-05-08 16:50:17 -07003072 return result;
3073}
3074
3075
3076/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003077 * ===========================================================================
3078 * Entry point and driver loop
3079 * ===========================================================================
3080 */
3081
3082/*
Andy McFadden470cbbb2010-11-04 16:31:37 -07003083 * Entry point for the detailed code-flow analysis of a single method.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003084 */
Andy McFadden228a6b02010-05-04 15:02:32 -07003085bool dvmVerifyCodeFlow(VerifierData* vdata)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003086{
3087 bool result = false;
Andy McFadden228a6b02010-05-04 15:02:32 -07003088 const Method* meth = vdata->method;
3089 const int insnsSize = vdata->insnsSize;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003090 const bool generateRegisterMap = gDvm.generateRegisterMaps;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003091 RegisterTable regTable;
3092
3093 memset(&regTable, 0, sizeof(regTable));
3094
Andy McFadden470cbbb2010-11-04 16:31:37 -07003095#ifdef VERIFIER_STATS
3096 gDvm.verifierStats.methodsExamined++;
3097#endif
3098
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003099#ifndef NDEBUG
3100 checkMergeTab(); // only need to do this if table gets updated
3101#endif
3102
3103 /*
3104 * We rely on these for verification of const-class, const-string,
3105 * and throw instructions. Make sure we have them.
3106 */
3107 if (gDvm.classJavaLangClass == NULL)
3108 gDvm.classJavaLangClass =
3109 dvmFindSystemClassNoInit("Ljava/lang/Class;");
3110 if (gDvm.classJavaLangString == NULL)
3111 gDvm.classJavaLangString =
3112 dvmFindSystemClassNoInit("Ljava/lang/String;");
Andy McFadden686e1e22009-05-26 16:56:30 -07003113 if (gDvm.classJavaLangThrowable == NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003114 gDvm.classJavaLangThrowable =
3115 dvmFindSystemClassNoInit("Ljava/lang/Throwable;");
Andy McFadden686e1e22009-05-26 16:56:30 -07003116 gDvm.offJavaLangThrowable_cause =
3117 dvmFindFieldOffset(gDvm.classJavaLangThrowable,
3118 "cause", "Ljava/lang/Throwable;");
3119 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003120 if (gDvm.classJavaLangObject == NULL)
3121 gDvm.classJavaLangObject =
3122 dvmFindSystemClassNoInit("Ljava/lang/Object;");
3123
Andy McFadden6be954f2010-06-14 13:37:49 -07003124 if (meth->registersSize * insnsSize > 4*1024*1024) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003125 LOG_VFY_METH(meth,
Andy McFadden34e314a2010-09-28 13:58:16 -07003126 "VFY: warning: method is huge (regs=%d insnsSize=%d)\n",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003127 meth->registersSize, insnsSize);
Andy McFadden34e314a2010-09-28 13:58:16 -07003128 /* might be bogus data, might be some huge generated method */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003129 }
3130
3131 /*
3132 * Create register lists, and initialize them to "Unknown". If we're
3133 * also going to create the register map, we need to retain the
3134 * register lists for a larger set of addresses.
3135 */
Andy McFadden228a6b02010-05-04 15:02:32 -07003136 if (!initRegisterTable(meth, vdata->insnFlags, &regTable,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003137 generateRegisterMap ? kTrackRegsGcPoints : kTrackRegsBranches))
3138 goto bail;
3139
Andy McFadden228a6b02010-05-04 15:02:32 -07003140 vdata->addrRegs = NULL; /* don't set this until we need it */
3141
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003142 /*
3143 * Initialize the types of the registers that correspond to the
3144 * method arguments. We can determine this from the method signature.
3145 */
Andy McFadden228a6b02010-05-04 15:02:32 -07003146 if (!setTypesFromSignature(meth, regTable.addrRegs[0], vdata->uninitMap))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003147 goto bail;
3148
3149 /*
3150 * Run the verifier.
3151 */
Andy McFadden228a6b02010-05-04 15:02:32 -07003152 if (!doCodeVerification(meth, vdata->insnFlags, &regTable, vdata->uninitMap))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003153 goto bail;
3154
3155 /*
3156 * Generate a register map.
3157 */
3158 if (generateRegisterMap) {
Andy McFadden228a6b02010-05-04 15:02:32 -07003159 vdata->addrRegs = regTable.addrRegs;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003160
Andy McFadden228a6b02010-05-04 15:02:32 -07003161 RegisterMap* pMap = dvmGenerateRegisterMapV(vdata);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003162 if (pMap != NULL) {
3163 /*
3164 * Tuck it into the Method struct. It will either get used
3165 * directly or, if we're in dexopt, will be packed up and
3166 * appended to the DEX file.
3167 */
3168 dvmSetRegisterMap((Method*)meth, pMap);
3169 }
3170 }
3171
3172 /*
3173 * Success.
3174 */
3175 result = true;
3176
3177bail:
3178 free(regTable.addrRegs);
3179 free(regTable.regAlloc);
3180 return result;
3181}
3182
3183/*
3184 * Grind through the instructions.
3185 *
3186 * The basic strategy is as outlined in v3 4.11.1.2: set the "changed" bit
3187 * on the first instruction, process it (setting additional "changed" bits),
3188 * and repeat until there are no more.
3189 *
3190 * v3 4.11.1.1
3191 * - (N/A) operand stack is always the same size
3192 * - operand stack [registers] contain the correct types of values
3193 * - local variables [registers] contain the correct types of values
3194 * - methods are invoked with the appropriate arguments
3195 * - fields are assigned using values of appropriate types
3196 * - opcodes have the correct type values in operand registers
3197 * - there is never an uninitialized class instance in a local variable in
3198 * code protected by an exception handler (operand stack is okay, because
3199 * the operand stack is discarded when an exception is thrown) [can't
3200 * know what's a local var w/o the debug info -- should fall out of
3201 * register typing]
3202 *
3203 * v3 4.11.1.2
3204 * - execution cannot fall off the end of the code
3205 *
3206 * (We also do many of the items described in the "static checks" sections,
3207 * because it's easier to do them here.)
3208 *
3209 * We need an array of RegType values, one per register, for every
3210 * instruction. In theory this could become quite large -- up to several
3211 * megabytes for a monster function. For self-preservation we reject
3212 * anything that requires more than a certain amount of memory. (Typical
3213 * "large" should be on the order of 4K code units * 8 registers.) This
3214 * will likely have to be adjusted.
3215 *
3216 *
3217 * The spec forbids backward branches when there's an uninitialized reference
3218 * in a register. The idea is to prevent something like this:
3219 * loop:
3220 * move r1, r0
3221 * new-instance r0, MyClass
3222 * ...
3223 * if-eq rN, loop // once
3224 * initialize r0
3225 *
3226 * This leaves us with two different instances, both allocated by the
3227 * same instruction, but only one is initialized. The scheme outlined in
3228 * v3 4.11.1.4 wouldn't catch this, so they work around it by preventing
3229 * backward branches. We achieve identical results without restricting
3230 * code reordering by specifying that you can't execute the new-instance
3231 * instruction if a register contains an uninitialized instance created
3232 * by that same instrutcion.
3233 */
Andy McFadden228a6b02010-05-04 15:02:32 -07003234static bool doCodeVerification(const Method* meth, InsnFlags* insnFlags,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003235 RegisterTable* regTable, UninitInstanceMap* uninitMap)
3236{
3237 const int insnsSize = dvmGetMethodInsnsSize(meth);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003238 RegType workRegs[meth->registersSize + kExtraRegs];
3239 bool result = false;
3240 bool debugVerbose = false;
Carl Shapiroe3c01da2010-05-20 22:54:18 -07003241 int insnIdx, startGuess;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003242
3243 /*
3244 * Begin by marking the first instruction as "changed".
3245 */
3246 dvmInsnSetChanged(insnFlags, 0, true);
3247
3248 if (doVerboseLogging(meth)) {
3249 IF_LOGI() {
3250 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
3251 LOGI("Now verifying: %s.%s %s (ins=%d regs=%d)\n",
3252 meth->clazz->descriptor, meth->name, desc,
3253 meth->insSize, meth->registersSize);
3254 LOGI(" ------ [0 4 8 12 16 20 24 28 32 36\n");
3255 free(desc);
3256 }
3257 debugVerbose = true;
3258 gDebugVerbose = true;
3259 } else {
3260 gDebugVerbose = false;
3261 }
3262
3263 startGuess = 0;
3264
3265 /*
3266 * Continue until no instructions are marked "changed".
3267 */
3268 while (true) {
3269 /*
3270 * Find the first marked one. Use "startGuess" as a way to find
3271 * one quickly.
3272 */
3273 for (insnIdx = startGuess; insnIdx < insnsSize; insnIdx++) {
3274 if (dvmInsnIsChanged(insnFlags, insnIdx))
3275 break;
3276 }
3277
3278 if (insnIdx == insnsSize) {
3279 if (startGuess != 0) {
3280 /* try again, starting from the top */
3281 startGuess = 0;
3282 continue;
3283 } else {
3284 /* all flags are clear */
3285 break;
3286 }
3287 }
3288
3289 /*
3290 * We carry the working set of registers from instruction to
3291 * instruction. If this address can be the target of a branch
3292 * (or throw) instruction, or if we're skipping around chasing
3293 * "changed" flags, we need to load the set of registers from
3294 * the table.
3295 *
3296 * Because we always prefer to continue on to the next instruction,
3297 * we should never have a situation where we have a stray
3298 * "changed" flag set on an instruction that isn't a branch target.
3299 */
3300 if (dvmInsnIsBranchTarget(insnFlags, insnIdx)) {
3301 RegType* insnRegs = getRegisterLine(regTable, insnIdx);
3302 assert(insnRegs != NULL);
3303 copyRegisters(workRegs, insnRegs, meth->registersSize + kExtraRegs);
3304
3305 if (debugVerbose) {
3306 dumpRegTypes(meth, insnFlags, workRegs, insnIdx, NULL,uninitMap,
3307 SHOW_REG_DETAILS);
3308 }
3309
3310 } else {
3311 if (debugVerbose) {
3312 dumpRegTypes(meth, insnFlags, workRegs, insnIdx, NULL,uninitMap,
3313 SHOW_REG_DETAILS);
3314 }
3315
3316#ifndef NDEBUG
3317 /*
3318 * Sanity check: retrieve the stored register line (assuming
3319 * a full table) and make sure it actually matches.
3320 */
3321 RegType* insnRegs = getRegisterLine(regTable, insnIdx);
3322 if (insnRegs != NULL &&
3323 compareRegisters(workRegs, insnRegs,
3324 meth->registersSize + kExtraRegs) != 0)
3325 {
3326 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
3327 LOG_VFY("HUH? workRegs diverged in %s.%s %s\n",
3328 meth->clazz->descriptor, meth->name, desc);
3329 free(desc);
3330 dumpRegTypes(meth, insnFlags, workRegs, 0, "work",
3331 uninitMap, DRT_SHOW_REF_TYPES | DRT_SHOW_LOCALS);
3332 dumpRegTypes(meth, insnFlags, insnRegs, 0, "insn",
3333 uninitMap, DRT_SHOW_REF_TYPES | DRT_SHOW_LOCALS);
3334 }
3335#endif
3336 }
3337
3338 //LOGI("process %s.%s %s %d\n",
3339 // meth->clazz->descriptor, meth->name, meth->descriptor, insnIdx);
3340 if (!verifyInstruction(meth, insnFlags, regTable, workRegs, insnIdx,
3341 uninitMap, &startGuess))
3342 {
3343 //LOGD("+++ %s bailing at %d\n", meth->name, insnIdx);
3344 goto bail;
3345 }
3346
3347#if 0
3348 {
3349 static const int gcMask = kInstrCanBranch | kInstrCanSwitch |
3350 kInstrCanThrow | kInstrCanReturn;
3351 OpCode opCode = *(meth->insns + insnIdx) & 0xff;
3352 int flags = dexGetInstrFlags(gDvm.instrFlags, opCode);
3353
3354 /* 8, 16, 32, or 32*n -bit regs */
3355 int regWidth = (meth->registersSize + 7) / 8;
3356 if (regWidth == 3)
3357 regWidth = 4;
3358 if (regWidth > 4) {
3359 regWidth = ((regWidth + 3) / 4) * 4;
3360 if (false) {
3361 LOGW("WOW: %d regs -> %d %s.%s\n",
3362 meth->registersSize, regWidth,
3363 meth->clazz->descriptor, meth->name);
3364 //x = true;
3365 }
3366 }
3367
3368 if ((flags & gcMask) != 0) {
3369 /* this is a potential GC point */
3370 gDvm__gcInstr++;
3371
3372 if (insnsSize < 256)
3373 gDvm__gcData += 1;
3374 else
3375 gDvm__gcData += 2;
3376 gDvm__gcData += regWidth;
3377 }
3378 gDvm__gcSimpleData += regWidth;
3379
3380 gDvm__totalInstr++;
3381 }
3382#endif
3383
3384 /*
3385 * Clear "changed" and mark as visited.
3386 */
3387 dvmInsnSetVisited(insnFlags, insnIdx, true);
3388 dvmInsnSetChanged(insnFlags, insnIdx, false);
3389 }
3390
Andy McFaddenb51ea112009-05-08 16:50:17 -07003391 if (DEAD_CODE_SCAN && !IS_METHOD_FLAG_SET(meth, METHOD_ISWRITABLE)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003392 /*
Andy McFaddenb51ea112009-05-08 16:50:17 -07003393 * Scan for dead code. There's nothing "evil" about dead code
3394 * (besides the wasted space), but it indicates a flaw somewhere
3395 * down the line, possibly in the verifier.
3396 *
3397 * If we've rewritten "always throw" instructions into the stream,
3398 * we are almost certainly going to have some dead code.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003399 */
3400 int deadStart = -1;
3401 for (insnIdx = 0; insnIdx < insnsSize;
3402 insnIdx += dvmInsnGetWidth(insnFlags, insnIdx))
3403 {
3404 /*
3405 * Switch-statement data doesn't get "visited" by scanner. It
3406 * may or may not be preceded by a padding NOP.
3407 */
3408 int instr = meth->insns[insnIdx];
3409 if (instr == kPackedSwitchSignature ||
3410 instr == kSparseSwitchSignature ||
3411 instr == kArrayDataSignature ||
3412 (instr == OP_NOP &&
3413 (meth->insns[insnIdx+1] == kPackedSwitchSignature ||
3414 meth->insns[insnIdx+1] == kSparseSwitchSignature ||
3415 meth->insns[insnIdx+1] == kArrayDataSignature)))
3416 {
3417 dvmInsnSetVisited(insnFlags, insnIdx, true);
3418 }
3419
3420 if (!dvmInsnIsVisited(insnFlags, insnIdx)) {
3421 if (deadStart < 0)
3422 deadStart = insnIdx;
3423 } else if (deadStart >= 0) {
3424 IF_LOGD() {
3425 char* desc =
3426 dexProtoCopyMethodDescriptor(&meth->prototype);
3427 LOGD("VFY: dead code 0x%04x-%04x in %s.%s %s\n",
3428 deadStart, insnIdx-1,
3429 meth->clazz->descriptor, meth->name, desc);
3430 free(desc);
3431 }
3432
3433 deadStart = -1;
3434 }
3435 }
3436 if (deadStart >= 0) {
3437 IF_LOGD() {
3438 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
3439 LOGD("VFY: dead code 0x%04x-%04x in %s.%s %s\n",
3440 deadStart, insnIdx-1,
3441 meth->clazz->descriptor, meth->name, desc);
3442 free(desc);
3443 }
3444 }
3445 }
3446
3447 result = true;
3448
3449bail:
3450 return result;
3451}
3452
3453
3454/*
3455 * Perform verification for a single instruction.
3456 *
3457 * This requires fully decoding the instruction to determine the effect
3458 * it has on registers.
3459 *
3460 * Finds zero or more following instructions and sets the "changed" flag
3461 * if execution at that point needs to be (re-)evaluated. Register changes
3462 * are merged into "regTypes" at the target addresses. Does not set or
3463 * clear any other flags in "insnFlags".
Andy McFaddenb51ea112009-05-08 16:50:17 -07003464 *
3465 * This may alter meth->insns if we need to replace an instruction with
3466 * throw-verification-error.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003467 */
Andy McFadden228a6b02010-05-04 15:02:32 -07003468static bool verifyInstruction(const Method* meth, InsnFlags* insnFlags,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003469 RegisterTable* regTable, RegType* workRegs, int insnIdx,
3470 UninitInstanceMap* uninitMap, int* pStartGuess)
3471{
3472 const int insnsSize = dvmGetMethodInsnsSize(meth);
3473 const u2* insns = meth->insns + insnIdx;
3474 bool result = false;
3475
Andy McFadden470cbbb2010-11-04 16:31:37 -07003476#ifdef VERIFIER_STATS
3477 if (dvmInsnIsVisited(insnFlags, insnIdx)) {
3478 gDvm.verifierStats.instrsReexamined++;
3479 } else {
3480 gDvm.verifierStats.instrsExamined++;
3481 }
3482#endif
3483
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003484 /*
3485 * Once we finish decoding the instruction, we need to figure out where
3486 * we can go from here. There are three possible ways to transfer
3487 * control to another statement:
3488 *
3489 * (1) Continue to the next instruction. Applies to all but
3490 * unconditional branches, method returns, and exception throws.
3491 * (2) Branch to one or more possible locations. Applies to branches
3492 * and switch statements.
3493 * (3) Exception handlers. Applies to any instruction that can
3494 * throw an exception that is handled by an encompassing "try"
Andy McFadden228a6b02010-05-04 15:02:32 -07003495 * block.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003496 *
3497 * We can also return, in which case there is no successor instruction
3498 * from this point.
3499 *
Andy McFadden228a6b02010-05-04 15:02:32 -07003500 * The behavior can be determined from the InstructionFlags.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003501 */
3502
3503 const DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
3504 RegType entryRegs[meth->registersSize + kExtraRegs];
3505 ClassObject* resClass;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003506 int branchTarget = 0;
3507 const int insnRegCount = meth->registersSize;
3508 RegType tmpType;
3509 DecodedInstruction decInsn;
3510 bool justSetResult = false;
Andy McFadden62a75162009-04-17 17:23:37 -07003511 VerifyError failure = VERIFY_ERROR_NONE;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003512
3513#ifndef NDEBUG
3514 memset(&decInsn, 0x81, sizeof(decInsn));
3515#endif
Dan Bornstein44a38f42010-11-10 17:34:32 -08003516 dexDecodeInstruction(&gDvm.instrInfo, insns, &decInsn);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003517
Dan Bornstein44a38f42010-11-10 17:34:32 -08003518 int nextFlags = dexGetInstrFlags(gDvm.instrInfo.flags, decInsn.opCode);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003519
3520 /*
3521 * Make a copy of the previous register state. If the instruction
3522 * throws an exception, we merge *this* into the destination rather
3523 * than workRegs, because we don't want the result from the "successful"
3524 * code path (e.g. a check-cast that "improves" a type) to be visible
3525 * to the exception handler.
3526 */
3527 if ((nextFlags & kInstrCanThrow) != 0 && dvmInsnIsInTry(insnFlags, insnIdx))
3528 {
3529 copyRegisters(entryRegs, workRegs, meth->registersSize + kExtraRegs);
3530 } else {
3531#ifndef NDEBUG
3532 memset(entryRegs, 0xdd,
3533 (meth->registersSize + kExtraRegs) * sizeof(RegType));
3534#endif
3535 }
3536
3537 switch (decInsn.opCode) {
3538 case OP_NOP:
3539 /*
3540 * A "pure" NOP has no effect on anything. Data tables start with
3541 * a signature that looks like a NOP; if we see one of these in
3542 * the course of executing code then we have a problem.
3543 */
3544 if (decInsn.vA != 0) {
3545 LOG_VFY("VFY: encountered data table in instruction stream\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003546 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003547 }
3548 break;
3549
3550 case OP_MOVE:
3551 case OP_MOVE_FROM16:
3552 case OP_MOVE_16:
Andy McFaddend3250112010-11-03 14:32:42 -07003553 copyRegister1(workRegs, decInsn.vA, decInsn.vB, kTypeCategory1nr,
3554 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003555 break;
3556 case OP_MOVE_WIDE:
3557 case OP_MOVE_WIDE_FROM16:
3558 case OP_MOVE_WIDE_16:
Andy McFaddend3250112010-11-03 14:32:42 -07003559 copyRegister2(workRegs, decInsn.vA, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003560 break;
3561 case OP_MOVE_OBJECT:
3562 case OP_MOVE_OBJECT_FROM16:
3563 case OP_MOVE_OBJECT_16:
Andy McFaddend3250112010-11-03 14:32:42 -07003564 copyRegister1(workRegs, decInsn.vA, decInsn.vB, kTypeCategoryRef,
3565 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003566 break;
3567
3568 /*
3569 * The move-result instructions copy data out of a "pseudo-register"
3570 * with the results from the last method invocation. In practice we
3571 * might want to hold the result in an actual CPU register, so the
3572 * Dalvik spec requires that these only appear immediately after an
3573 * invoke or filled-new-array.
3574 *
3575 * These calls invalidate the "result" register. (This is now
3576 * redundant with the reset done below, but it can make the debug info
3577 * easier to read in some cases.)
3578 */
3579 case OP_MOVE_RESULT:
3580 copyResultRegister1(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003581 kTypeCategory1nr, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003582 break;
3583 case OP_MOVE_RESULT_WIDE:
Andy McFadden62a75162009-04-17 17:23:37 -07003584 copyResultRegister2(workRegs, insnRegCount, decInsn.vA, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003585 break;
3586 case OP_MOVE_RESULT_OBJECT:
3587 copyResultRegister1(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003588 kTypeCategoryRef, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003589 break;
3590
3591 case OP_MOVE_EXCEPTION:
3592 /*
3593 * This statement can only appear as the first instruction in an
3594 * exception handler (though not all exception handlers need to
3595 * have one of these). We verify that as part of extracting the
3596 * exception type from the catch block list.
3597 *
3598 * "resClass" will hold the closest common superclass of all
3599 * exceptions that can be handled here.
3600 */
Andy McFadden62a75162009-04-17 17:23:37 -07003601 resClass = getCaughtExceptionType(meth, insnIdx, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003602 if (resClass == NULL) {
Andy McFadden62a75162009-04-17 17:23:37 -07003603 assert(!VERIFY_OK(failure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003604 } else {
Andy McFaddend3250112010-11-03 14:32:42 -07003605 setRegisterType(workRegs, decInsn.vA, regTypeFromClass(resClass));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003606 }
3607 break;
3608
3609 case OP_RETURN_VOID:
Andy McFadden62a75162009-04-17 17:23:37 -07003610 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3611 failure = VERIFY_ERROR_GENERIC;
3612 } else if (getMethodReturnType(meth) != kRegTypeUnknown) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003613 LOG_VFY("VFY: return-void not expected\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003614 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003615 }
3616 break;
3617 case OP_RETURN:
Andy McFadden62a75162009-04-17 17:23:37 -07003618 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3619 failure = VERIFY_ERROR_GENERIC;
3620 } else {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003621 /* check the method signature */
3622 RegType returnType = getMethodReturnType(meth);
Andy McFadden62a75162009-04-17 17:23:37 -07003623 checkTypeCategory(returnType, kTypeCategory1nr, &failure);
3624 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003625 LOG_VFY("VFY: return-32 not expected\n");
3626
3627 /* check the register contents */
Andy McFaddend3250112010-11-03 14:32:42 -07003628 returnType = getRegisterType(workRegs, decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07003629 checkTypeCategory(returnType, kTypeCategory1nr, &failure);
3630 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003631 LOG_VFY("VFY: return-32 on invalid register v%d\n", decInsn.vA);
3632 }
3633 break;
3634 case OP_RETURN_WIDE:
Andy McFadden62a75162009-04-17 17:23:37 -07003635 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3636 failure = VERIFY_ERROR_GENERIC;
3637 } else {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003638 RegType returnType, returnTypeHi;
3639
3640 /* check the method signature */
3641 returnType = getMethodReturnType(meth);
Andy McFadden62a75162009-04-17 17:23:37 -07003642 checkTypeCategory(returnType, kTypeCategory2, &failure);
3643 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003644 LOG_VFY("VFY: return-wide not expected\n");
3645
3646 /* check the register contents */
Andy McFaddend3250112010-11-03 14:32:42 -07003647 returnType = getRegisterType(workRegs, decInsn.vA);
3648 returnTypeHi = getRegisterType(workRegs, decInsn.vA +1);
3649 checkTypeCategory(returnType, kTypeCategory2, &failure);
3650 checkWidePair(returnType, returnTypeHi, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07003651 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003652 LOG_VFY("VFY: return-wide on invalid register pair v%d\n",
3653 decInsn.vA);
3654 }
3655 }
3656 break;
3657 case OP_RETURN_OBJECT:
Andy McFadden62a75162009-04-17 17:23:37 -07003658 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3659 failure = VERIFY_ERROR_GENERIC;
3660 } else {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003661 RegType returnType = getMethodReturnType(meth);
Andy McFadden62a75162009-04-17 17:23:37 -07003662 checkTypeCategory(returnType, kTypeCategoryRef, &failure);
3663 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003664 LOG_VFY("VFY: return-object not expected\n");
3665 break;
3666 }
3667
3668 /* returnType is the *expected* return type, not register value */
3669 assert(returnType != kRegTypeZero);
3670 assert(!regTypeIsUninitReference(returnType));
3671
3672 /*
3673 * Verify that the reference in vAA is an instance of the type
3674 * in "returnType". The Zero type is allowed here. If the
3675 * method is declared to return an interface, then any
3676 * initialized reference is acceptable.
3677 *
3678 * Note getClassFromRegister fails if the register holds an
3679 * uninitialized reference, so we do not allow them to be
3680 * returned.
3681 */
3682 ClassObject* declClass;
3683
3684 declClass = regTypeInitializedReferenceToClass(returnType);
Andy McFaddend3250112010-11-03 14:32:42 -07003685 resClass = getClassFromRegister(workRegs, decInsn.vA, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07003686 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003687 break;
3688 if (resClass != NULL) {
3689 if (!dvmIsInterfaceClass(declClass) &&
3690 !dvmInstanceof(resClass, declClass))
3691 {
Andy McFadden86c86432009-05-27 14:40:12 -07003692 LOG_VFY("VFY: returning %s (cl=%p), declared %s (cl=%p)\n",
3693 resClass->descriptor, resClass->classLoader,
3694 declClass->descriptor, declClass->classLoader);
Andy McFadden62a75162009-04-17 17:23:37 -07003695 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003696 break;
3697 }
3698 }
3699 }
3700 break;
3701
3702 case OP_CONST_4:
3703 case OP_CONST_16:
3704 case OP_CONST:
3705 /* could be boolean, int, float, or a null reference */
Andy McFaddend3250112010-11-03 14:32:42 -07003706 setRegisterType(workRegs, decInsn.vA,
Andy McFadden470cbbb2010-11-04 16:31:37 -07003707 determineCat1Const((s4)decInsn.vB));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003708 break;
3709 case OP_CONST_HIGH16:
3710 /* could be boolean, int, float, or a null reference */
Andy McFaddend3250112010-11-03 14:32:42 -07003711 setRegisterType(workRegs, decInsn.vA,
Andy McFadden470cbbb2010-11-04 16:31:37 -07003712 determineCat1Const((s4) decInsn.vB << 16));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003713 break;
3714 case OP_CONST_WIDE_16:
3715 case OP_CONST_WIDE_32:
3716 case OP_CONST_WIDE:
3717 case OP_CONST_WIDE_HIGH16:
3718 /* could be long or double; default to long and allow conversion */
Andy McFaddend3250112010-11-03 14:32:42 -07003719 setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003720 break;
3721 case OP_CONST_STRING:
3722 case OP_CONST_STRING_JUMBO:
3723 assert(gDvm.classJavaLangString != NULL);
Andy McFaddend3250112010-11-03 14:32:42 -07003724 setRegisterType(workRegs, decInsn.vA,
3725 regTypeFromClass(gDvm.classJavaLangString));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003726 break;
3727 case OP_CONST_CLASS:
3728 assert(gDvm.classJavaLangClass != NULL);
3729 /* make sure we can resolve the class; access check is important */
Andy McFadden62a75162009-04-17 17:23:37 -07003730 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003731 if (resClass == NULL) {
3732 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3733 dvmLogUnableToResolveClass(badClassDesc, meth);
3734 LOG_VFY("VFY: unable to resolve const-class %d (%s) in %s\n",
3735 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003736 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003737 } else {
Andy McFaddend3250112010-11-03 14:32:42 -07003738 setRegisterType(workRegs, decInsn.vA,
3739 regTypeFromClass(gDvm.classJavaLangClass));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003740 }
3741 break;
3742
3743 case OP_MONITOR_ENTER:
3744 case OP_MONITOR_EXIT:
Andy McFaddend3250112010-11-03 14:32:42 -07003745 tmpType = getRegisterType(workRegs, decInsn.vA);
3746 if (!regTypeIsReference(tmpType)) {
3747 LOG_VFY("VFY: monitor op on non-object\n");
3748 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003749 }
3750 break;
3751
3752 case OP_CHECK_CAST:
3753 /*
3754 * If this instruction succeeds, we will promote register vA to
3755 * the type in vB. (This could be a demotion -- not expected, so
3756 * we don't try to address it.)
3757 *
3758 * If it fails, an exception is thrown, which we deal with later
3759 * by ignoring the update to decInsn.vA when branching to a handler.
3760 */
Andy McFadden62a75162009-04-17 17:23:37 -07003761 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003762 if (resClass == NULL) {
3763 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3764 dvmLogUnableToResolveClass(badClassDesc, meth);
3765 LOG_VFY("VFY: unable to resolve check-cast %d (%s) in %s\n",
3766 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003767 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003768 } else {
3769 RegType origType;
3770
Andy McFaddend3250112010-11-03 14:32:42 -07003771 origType = getRegisterType(workRegs, decInsn.vA);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003772 if (!regTypeIsReference(origType)) {
3773 LOG_VFY("VFY: check-cast on non-reference in v%u\n",decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07003774 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003775 break;
3776 }
Andy McFaddend3250112010-11-03 14:32:42 -07003777 setRegisterType(workRegs, decInsn.vA, regTypeFromClass(resClass));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003778 }
3779 break;
3780 case OP_INSTANCE_OF:
3781 /* make sure we're checking a reference type */
Andy McFaddend3250112010-11-03 14:32:42 -07003782 tmpType = getRegisterType(workRegs, decInsn.vB);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003783 if (!regTypeIsReference(tmpType)) {
3784 LOG_VFY("VFY: vB not a reference (%d)\n", tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07003785 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003786 break;
3787 }
3788
3789 /* make sure we can resolve the class; access check is important */
Andy McFadden62a75162009-04-17 17:23:37 -07003790 resClass = dvmOptResolveClass(meth->clazz, decInsn.vC, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003791 if (resClass == NULL) {
3792 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vC);
3793 dvmLogUnableToResolveClass(badClassDesc, meth);
3794 LOG_VFY("VFY: unable to resolve instanceof %d (%s) in %s\n",
3795 decInsn.vC, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003796 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003797 } else {
3798 /* result is boolean */
Andy McFaddend3250112010-11-03 14:32:42 -07003799 setRegisterType(workRegs, decInsn.vA, kRegTypeBoolean);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003800 }
3801 break;
3802
3803 case OP_ARRAY_LENGTH:
Andy McFaddend3250112010-11-03 14:32:42 -07003804 resClass = getClassFromRegister(workRegs, decInsn.vB, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07003805 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003806 break;
3807 if (resClass != NULL && !dvmIsArrayClass(resClass)) {
3808 LOG_VFY("VFY: array-length on non-array\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003809 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003810 break;
3811 }
Andy McFaddend3250112010-11-03 14:32:42 -07003812 setRegisterType(workRegs, decInsn.vA, kRegTypeInteger);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003813 break;
3814
3815 case OP_NEW_INSTANCE:
Andy McFadden62a75162009-04-17 17:23:37 -07003816 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003817 if (resClass == NULL) {
3818 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3819 dvmLogUnableToResolveClass(badClassDesc, meth);
3820 LOG_VFY("VFY: unable to resolve new-instance %d (%s) in %s\n",
3821 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003822 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003823 } else {
3824 RegType uninitType;
3825
Andy McFaddenb51ea112009-05-08 16:50:17 -07003826 /* can't create an instance of an interface or abstract class */
3827 if (dvmIsAbstractClass(resClass) || dvmIsInterfaceClass(resClass)) {
3828 LOG_VFY("VFY: new-instance on interface or abstract class %s\n",
3829 resClass->descriptor);
3830 failure = VERIFY_ERROR_INSTANTIATION;
3831 break;
3832 }
3833
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003834 /* add resolved class to uninit map if not already there */
3835 int uidx = dvmSetUninitInstance(uninitMap, insnIdx, resClass);
3836 assert(uidx >= 0);
3837 uninitType = regTypeFromUninitIndex(uidx);
3838
3839 /*
3840 * Any registers holding previous allocations from this address
3841 * that have not yet been initialized must be marked invalid.
3842 */
3843 markUninitRefsAsInvalid(workRegs, insnRegCount, uninitMap,
3844 uninitType);
3845
3846 /* add the new uninitialized reference to the register ste */
Andy McFaddend3250112010-11-03 14:32:42 -07003847 setRegisterType(workRegs, decInsn.vA, uninitType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003848 }
3849 break;
3850 case OP_NEW_ARRAY:
Andy McFadden62a75162009-04-17 17:23:37 -07003851 resClass = dvmOptResolveClass(meth->clazz, decInsn.vC, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003852 if (resClass == NULL) {
3853 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vC);
3854 dvmLogUnableToResolveClass(badClassDesc, meth);
3855 LOG_VFY("VFY: unable to resolve new-array %d (%s) in %s\n",
3856 decInsn.vC, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003857 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003858 } else if (!dvmIsArrayClass(resClass)) {
3859 LOG_VFY("VFY: new-array on non-array class\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003860 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003861 } else {
3862 /* make sure "size" register is valid type */
Andy McFaddend3250112010-11-03 14:32:42 -07003863 verifyRegisterType(workRegs, decInsn.vB, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003864 /* set register type to array class */
Andy McFaddend3250112010-11-03 14:32:42 -07003865 setRegisterType(workRegs, decInsn.vA, regTypeFromClass(resClass));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003866 }
3867 break;
3868 case OP_FILLED_NEW_ARRAY:
3869 case OP_FILLED_NEW_ARRAY_RANGE:
Andy McFadden62a75162009-04-17 17:23:37 -07003870 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003871 if (resClass == NULL) {
3872 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3873 dvmLogUnableToResolveClass(badClassDesc, meth);
3874 LOG_VFY("VFY: unable to resolve filled-array %d (%s) in %s\n",
3875 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003876 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003877 } else if (!dvmIsArrayClass(resClass)) {
3878 LOG_VFY("VFY: filled-new-array on non-array class\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003879 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003880 } else {
3881 bool isRange = (decInsn.opCode == OP_FILLED_NEW_ARRAY_RANGE);
3882
3883 /* check the arguments to the instruction */
Andy McFaddend3250112010-11-03 14:32:42 -07003884 verifyFilledNewArrayRegs(meth, workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07003885 resClass, isRange, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003886 /* filled-array result goes into "result" register */
3887 setResultRegisterType(workRegs, insnRegCount,
Andy McFaddend3250112010-11-03 14:32:42 -07003888 regTypeFromClass(resClass));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003889 justSetResult = true;
3890 }
3891 break;
3892
3893 case OP_CMPL_FLOAT:
3894 case OP_CMPG_FLOAT:
Andy McFaddend3250112010-11-03 14:32:42 -07003895 verifyRegisterType(workRegs, decInsn.vB, kRegTypeFloat, &failure);
3896 verifyRegisterType(workRegs, decInsn.vC, kRegTypeFloat, &failure);
3897 setRegisterType(workRegs, decInsn.vA, kRegTypeBoolean);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003898 break;
3899 case OP_CMPL_DOUBLE:
3900 case OP_CMPG_DOUBLE:
Andy McFaddend3250112010-11-03 14:32:42 -07003901 verifyRegisterType(workRegs, decInsn.vB, kRegTypeDoubleLo, &failure);
3902 verifyRegisterType(workRegs, decInsn.vC, kRegTypeDoubleLo, &failure);
3903 setRegisterType(workRegs, decInsn.vA, kRegTypeBoolean);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003904 break;
3905 case OP_CMP_LONG:
Andy McFaddend3250112010-11-03 14:32:42 -07003906 verifyRegisterType(workRegs, decInsn.vB, kRegTypeLongLo, &failure);
3907 verifyRegisterType(workRegs, decInsn.vC, kRegTypeLongLo, &failure);
3908 setRegisterType(workRegs, decInsn.vA, kRegTypeBoolean);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003909 break;
3910
3911 case OP_THROW:
Andy McFaddend3250112010-11-03 14:32:42 -07003912 resClass = getClassFromRegister(workRegs, decInsn.vA, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07003913 if (VERIFY_OK(failure) && resClass != NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003914 if (!dvmInstanceof(resClass, gDvm.classJavaLangThrowable)) {
3915 LOG_VFY("VFY: thrown class %s not instanceof Throwable\n",
3916 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003917 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003918 }
3919 }
3920 break;
3921
3922 case OP_GOTO:
3923 case OP_GOTO_16:
3924 case OP_GOTO_32:
3925 /* no effect on or use of registers */
3926 break;
3927
3928 case OP_PACKED_SWITCH:
3929 case OP_SPARSE_SWITCH:
3930 /* verify that vAA is an integer, or can be converted to one */
Andy McFaddend3250112010-11-03 14:32:42 -07003931 verifyRegisterType(workRegs, decInsn.vA, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003932 break;
3933
3934 case OP_FILL_ARRAY_DATA:
3935 {
3936 RegType valueType;
3937 const u2 *arrayData;
3938 u2 elemWidth;
3939
3940 /* Similar to the verification done for APUT */
Andy McFaddend3250112010-11-03 14:32:42 -07003941 resClass = getClassFromRegister(workRegs, decInsn.vA, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07003942 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003943 break;
3944
3945 /* resClass can be null if the reg type is Zero */
3946 if (resClass == NULL)
3947 break;
3948
3949 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
3950 resClass->elementClass->primitiveType == PRIM_NOT ||
3951 resClass->elementClass->primitiveType == PRIM_VOID)
3952 {
3953 LOG_VFY("VFY: invalid fill-array-data on %s\n",
3954 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003955 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003956 break;
3957 }
3958
3959 valueType = primitiveTypeToRegType(
3960 resClass->elementClass->primitiveType);
3961 assert(valueType != kRegTypeUnknown);
3962
3963 /*
3964 * Now verify if the element width in the table matches the element
3965 * width declared in the array
3966 */
3967 arrayData = insns + (insns[1] | (((s4)insns[2]) << 16));
3968 if (arrayData[0] != kArrayDataSignature) {
3969 LOG_VFY("VFY: invalid magic for array-data\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003970 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003971 break;
3972 }
3973
3974 switch (resClass->elementClass->primitiveType) {
3975 case PRIM_BOOLEAN:
3976 case PRIM_BYTE:
3977 elemWidth = 1;
3978 break;
3979 case PRIM_CHAR:
3980 case PRIM_SHORT:
3981 elemWidth = 2;
3982 break;
3983 case PRIM_FLOAT:
3984 case PRIM_INT:
3985 elemWidth = 4;
3986 break;
3987 case PRIM_DOUBLE:
3988 case PRIM_LONG:
3989 elemWidth = 8;
3990 break;
3991 default:
3992 elemWidth = 0;
3993 break;
3994 }
3995
3996 /*
3997 * Since we don't compress the data in Dex, expect to see equal
3998 * width of data stored in the table and expected from the array
3999 * class.
4000 */
4001 if (arrayData[1] != elemWidth) {
4002 LOG_VFY("VFY: array-data size mismatch (%d vs %d)\n",
4003 arrayData[1], elemWidth);
Andy McFadden62a75162009-04-17 17:23:37 -07004004 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004005 }
4006 }
4007 break;
4008
4009 case OP_IF_EQ:
4010 case OP_IF_NE:
4011 {
4012 RegType type1, type2;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004013
Andy McFaddend3250112010-11-03 14:32:42 -07004014 type1 = getRegisterType(workRegs, decInsn.vA);
4015 type2 = getRegisterType(workRegs, decInsn.vB);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004016
4017 /* both references? */
4018 if (regTypeIsReference(type1) && regTypeIsReference(type2))
4019 break;
4020
4021 /* both category-1nr? */
Andy McFadden62a75162009-04-17 17:23:37 -07004022 checkTypeCategory(type1, kTypeCategory1nr, &failure);
4023 checkTypeCategory(type2, kTypeCategory1nr, &failure);
4024 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004025 LOG_VFY("VFY: args to if-eq/if-ne must both be refs or cat1\n");
4026 break;
4027 }
4028 }
4029 break;
4030 case OP_IF_LT:
4031 case OP_IF_GE:
4032 case OP_IF_GT:
4033 case OP_IF_LE:
Andy McFaddend3250112010-11-03 14:32:42 -07004034 tmpType = getRegisterType(workRegs, decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07004035 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
4036 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004037 LOG_VFY("VFY: args to 'if' must be cat-1nr\n");
4038 break;
4039 }
Andy McFaddend3250112010-11-03 14:32:42 -07004040 tmpType = getRegisterType(workRegs, decInsn.vB);
Andy McFadden62a75162009-04-17 17:23:37 -07004041 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
4042 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004043 LOG_VFY("VFY: args to 'if' must be cat-1nr\n");
4044 break;
4045 }
4046 break;
4047 case OP_IF_EQZ:
4048 case OP_IF_NEZ:
Andy McFaddend3250112010-11-03 14:32:42 -07004049 tmpType = getRegisterType(workRegs, decInsn.vA);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004050 if (regTypeIsReference(tmpType))
4051 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004052 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
4053 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004054 LOG_VFY("VFY: expected cat-1 arg to if\n");
4055 break;
4056 case OP_IF_LTZ:
4057 case OP_IF_GEZ:
4058 case OP_IF_GTZ:
4059 case OP_IF_LEZ:
Andy McFaddend3250112010-11-03 14:32:42 -07004060 tmpType = getRegisterType(workRegs, decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07004061 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
4062 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004063 LOG_VFY("VFY: expected cat-1 arg to if\n");
4064 break;
4065
4066 case OP_AGET:
4067 tmpType = kRegTypeInteger;
4068 goto aget_1nr_common;
4069 case OP_AGET_BOOLEAN:
4070 tmpType = kRegTypeBoolean;
4071 goto aget_1nr_common;
4072 case OP_AGET_BYTE:
4073 tmpType = kRegTypeByte;
4074 goto aget_1nr_common;
4075 case OP_AGET_CHAR:
4076 tmpType = kRegTypeChar;
4077 goto aget_1nr_common;
4078 case OP_AGET_SHORT:
4079 tmpType = kRegTypeShort;
4080 goto aget_1nr_common;
4081aget_1nr_common:
4082 {
4083 RegType srcType, indexType;
4084
Andy McFaddend3250112010-11-03 14:32:42 -07004085 indexType = getRegisterType(workRegs, decInsn.vC);
Andy McFadden62a75162009-04-17 17:23:37 -07004086 checkArrayIndexType(meth, indexType, &failure);
4087 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004088 break;
4089
Andy McFaddend3250112010-11-03 14:32:42 -07004090 resClass = getClassFromRegister(workRegs, decInsn.vB, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07004091 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004092 break;
4093 if (resClass != NULL) {
4094 /* verify the class */
4095 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4096 resClass->elementClass->primitiveType == PRIM_NOT)
4097 {
4098 LOG_VFY("VFY: invalid aget-1nr target %s\n",
4099 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004100 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004101 break;
4102 }
4103
4104 /* make sure array type matches instruction */
4105 srcType = primitiveTypeToRegType(
4106 resClass->elementClass->primitiveType);
4107
4108 if (!checkFieldArrayStore1nr(tmpType, srcType)) {
4109 LOG_VFY("VFY: invalid aget-1nr, array type=%d with"
4110 " inst type=%d (on %s)\n",
4111 srcType, tmpType, resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004112 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004113 break;
4114 }
4115
4116 }
Andy McFaddend3250112010-11-03 14:32:42 -07004117 setRegisterType(workRegs, decInsn.vA, tmpType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004118 }
4119 break;
4120
4121 case OP_AGET_WIDE:
4122 {
4123 RegType dstType, indexType;
4124
Andy McFaddend3250112010-11-03 14:32:42 -07004125 indexType = getRegisterType(workRegs, decInsn.vC);
Andy McFadden62a75162009-04-17 17:23:37 -07004126 checkArrayIndexType(meth, indexType, &failure);
4127 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004128 break;
4129
Andy McFaddend3250112010-11-03 14:32:42 -07004130 resClass = getClassFromRegister(workRegs, decInsn.vB, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07004131 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004132 break;
4133 if (resClass != NULL) {
4134 /* verify the class */
4135 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4136 resClass->elementClass->primitiveType == PRIM_NOT)
4137 {
4138 LOG_VFY("VFY: invalid aget-wide target %s\n",
4139 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004140 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004141 break;
4142 }
4143
4144 /* try to refine "dstType" */
4145 switch (resClass->elementClass->primitiveType) {
4146 case PRIM_LONG:
4147 dstType = kRegTypeLongLo;
4148 break;
4149 case PRIM_DOUBLE:
4150 dstType = kRegTypeDoubleLo;
4151 break;
4152 default:
4153 LOG_VFY("VFY: invalid aget-wide on %s\n",
4154 resClass->descriptor);
4155 dstType = kRegTypeUnknown;
Andy McFadden62a75162009-04-17 17:23:37 -07004156 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004157 break;
4158 }
4159 } else {
4160 /*
4161 * Null array ref; this code path will fail at runtime. We
4162 * know this is either long or double, and we don't really
4163 * discriminate between those during verification, so we
4164 * call it a long.
4165 */
4166 dstType = kRegTypeLongLo;
4167 }
Andy McFaddend3250112010-11-03 14:32:42 -07004168 setRegisterType(workRegs, decInsn.vA, dstType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004169 }
4170 break;
4171
4172 case OP_AGET_OBJECT:
4173 {
4174 RegType dstType, indexType;
4175
Andy McFaddend3250112010-11-03 14:32:42 -07004176 indexType = getRegisterType(workRegs, decInsn.vC);
Andy McFadden62a75162009-04-17 17:23:37 -07004177 checkArrayIndexType(meth, indexType, &failure);
4178 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004179 break;
4180
4181 /* get the class of the array we're pulling an object from */
Andy McFaddend3250112010-11-03 14:32:42 -07004182 resClass = getClassFromRegister(workRegs, decInsn.vB, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07004183 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004184 break;
4185 if (resClass != NULL) {
4186 ClassObject* elementClass;
4187
4188 assert(resClass != NULL);
4189 if (!dvmIsArrayClass(resClass)) {
4190 LOG_VFY("VFY: aget-object on non-array class\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004191 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004192 break;
4193 }
4194 assert(resClass->elementClass != NULL);
4195
4196 /*
4197 * Find the element class. resClass->elementClass indicates
4198 * the basic type, which won't be what we want for a
4199 * multi-dimensional array.
4200 */
4201 if (resClass->descriptor[1] == '[') {
4202 assert(resClass->arrayDim > 1);
4203 elementClass = dvmFindArrayClass(&resClass->descriptor[1],
4204 resClass->classLoader);
4205 } else if (resClass->descriptor[1] == 'L') {
4206 assert(resClass->arrayDim == 1);
4207 elementClass = resClass->elementClass;
4208 } else {
4209 LOG_VFY("VFY: aget-object on non-ref array class (%s)\n",
4210 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004211 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004212 break;
4213 }
4214
4215 dstType = regTypeFromClass(elementClass);
4216 } else {
4217 /*
4218 * The array reference is NULL, so the current code path will
4219 * throw an exception. For proper merging with later code
4220 * paths, and correct handling of "if-eqz" tests on the
4221 * result of the array get, we want to treat this as a null
4222 * reference.
4223 */
4224 dstType = kRegTypeZero;
4225 }
Andy McFaddend3250112010-11-03 14:32:42 -07004226 setRegisterType(workRegs, decInsn.vA, dstType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004227 }
4228 break;
4229 case OP_APUT:
4230 tmpType = kRegTypeInteger;
4231 goto aput_1nr_common;
4232 case OP_APUT_BOOLEAN:
4233 tmpType = kRegTypeBoolean;
4234 goto aput_1nr_common;
4235 case OP_APUT_BYTE:
4236 tmpType = kRegTypeByte;
4237 goto aput_1nr_common;
4238 case OP_APUT_CHAR:
4239 tmpType = kRegTypeChar;
4240 goto aput_1nr_common;
4241 case OP_APUT_SHORT:
4242 tmpType = kRegTypeShort;
4243 goto aput_1nr_common;
4244aput_1nr_common:
4245 {
4246 RegType srcType, dstType, indexType;
4247
Andy McFaddend3250112010-11-03 14:32:42 -07004248 indexType = getRegisterType(workRegs, decInsn.vC);
Andy McFadden62a75162009-04-17 17:23:37 -07004249 checkArrayIndexType(meth, indexType, &failure);
4250 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004251 break;
4252
4253 /* make sure the source register has the correct type */
Andy McFaddend3250112010-11-03 14:32:42 -07004254 srcType = getRegisterType(workRegs, decInsn.vA);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004255 if (!canConvertTo1nr(srcType, tmpType)) {
4256 LOG_VFY("VFY: invalid reg type %d on aput instr (need %d)\n",
4257 srcType, tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07004258 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004259 break;
4260 }
4261
Andy McFaddend3250112010-11-03 14:32:42 -07004262 resClass = getClassFromRegister(workRegs, decInsn.vB, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07004263 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004264 break;
4265
4266 /* resClass can be null if the reg type is Zero */
4267 if (resClass == NULL)
4268 break;
4269
4270 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4271 resClass->elementClass->primitiveType == PRIM_NOT)
4272 {
4273 LOG_VFY("VFY: invalid aput-1nr on %s\n", resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004274 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004275 break;
4276 }
4277
4278 /* verify that instruction matches array */
4279 dstType = primitiveTypeToRegType(
4280 resClass->elementClass->primitiveType);
4281 assert(dstType != kRegTypeUnknown);
4282
4283 if (!checkFieldArrayStore1nr(tmpType, dstType)) {
4284 LOG_VFY("VFY: invalid aput-1nr on %s (inst=%d dst=%d)\n",
4285 resClass->descriptor, tmpType, dstType);
Andy McFadden62a75162009-04-17 17:23:37 -07004286 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004287 break;
4288 }
4289 }
4290 break;
4291 case OP_APUT_WIDE:
Andy McFaddend3250112010-11-03 14:32:42 -07004292 tmpType = getRegisterType(workRegs, decInsn.vC);
Andy McFadden62a75162009-04-17 17:23:37 -07004293 checkArrayIndexType(meth, tmpType, &failure);
4294 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004295 break;
4296
Andy McFaddend3250112010-11-03 14:32:42 -07004297 tmpType = getRegisterType(workRegs, decInsn.vA);
4298 {
4299 RegType typeHi = getRegisterType(workRegs, decInsn.vA+1);
Andy McFadden62a75162009-04-17 17:23:37 -07004300 checkTypeCategory(tmpType, kTypeCategory2, &failure);
4301 checkWidePair(tmpType, typeHi, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004302 }
Andy McFadden62a75162009-04-17 17:23:37 -07004303 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004304 break;
4305
Andy McFaddend3250112010-11-03 14:32:42 -07004306 resClass = getClassFromRegister(workRegs, decInsn.vB, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07004307 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004308 break;
4309 if (resClass != NULL) {
4310 /* verify the class and try to refine "dstType" */
4311 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4312 resClass->elementClass->primitiveType == PRIM_NOT)
4313 {
4314 LOG_VFY("VFY: invalid aput-wide on %s\n",
4315 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004316 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004317 break;
4318 }
4319
4320 switch (resClass->elementClass->primitiveType) {
4321 case PRIM_LONG:
4322 case PRIM_DOUBLE:
4323 /* these are okay */
4324 break;
4325 default:
4326 LOG_VFY("VFY: invalid aput-wide on %s\n",
4327 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004328 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004329 break;
4330 }
4331 }
4332 break;
4333 case OP_APUT_OBJECT:
Andy McFaddend3250112010-11-03 14:32:42 -07004334 tmpType = getRegisterType(workRegs, decInsn.vC);
Andy McFadden62a75162009-04-17 17:23:37 -07004335 checkArrayIndexType(meth, tmpType, &failure);
4336 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004337 break;
4338
4339 /* get the ref we're storing; Zero is okay, Uninit is not */
Andy McFaddend3250112010-11-03 14:32:42 -07004340 resClass = getClassFromRegister(workRegs, decInsn.vA, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07004341 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004342 break;
4343 if (resClass != NULL) {
4344 ClassObject* arrayClass;
4345 ClassObject* elementClass;
4346
4347 /*
4348 * Get the array class. If the array ref is null, we won't
4349 * have type information (and we'll crash at runtime with a
4350 * null pointer exception).
4351 */
Andy McFaddend3250112010-11-03 14:32:42 -07004352 arrayClass = getClassFromRegister(workRegs, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004353
4354 if (arrayClass != NULL) {
4355 /* see if the array holds a compatible type */
4356 if (!dvmIsArrayClass(arrayClass)) {
4357 LOG_VFY("VFY: invalid aput-object on %s\n",
4358 arrayClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004359 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004360 break;
4361 }
4362
4363 /*
4364 * Find the element class. resClass->elementClass indicates
4365 * the basic type, which won't be what we want for a
4366 * multi-dimensional array.
4367 *
4368 * All we want to check here is that the element type is a
4369 * reference class. We *don't* check instanceof here, because
4370 * you can still put a String into a String[] after the latter
4371 * has been cast to an Object[].
4372 */
4373 if (arrayClass->descriptor[1] == '[') {
4374 assert(arrayClass->arrayDim > 1);
4375 elementClass = dvmFindArrayClass(&arrayClass->descriptor[1],
4376 arrayClass->classLoader);
4377 } else {
4378 assert(arrayClass->arrayDim == 1);
4379 elementClass = arrayClass->elementClass;
4380 }
4381 if (elementClass->primitiveType != PRIM_NOT) {
4382 LOG_VFY("VFY: invalid aput-object of %s into %s\n",
4383 resClass->descriptor, arrayClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004384 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004385 break;
4386 }
4387 }
4388 }
4389 break;
4390
4391 case OP_IGET:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004392 case OP_IGET_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004393 tmpType = kRegTypeInteger;
4394 goto iget_1nr_common;
4395 case OP_IGET_BOOLEAN:
4396 tmpType = kRegTypeBoolean;
4397 goto iget_1nr_common;
4398 case OP_IGET_BYTE:
4399 tmpType = kRegTypeByte;
4400 goto iget_1nr_common;
4401 case OP_IGET_CHAR:
4402 tmpType = kRegTypeChar;
4403 goto iget_1nr_common;
4404 case OP_IGET_SHORT:
4405 tmpType = kRegTypeShort;
4406 goto iget_1nr_common;
4407iget_1nr_common:
4408 {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004409 InstField* instField;
4410 RegType objType, fieldType;
4411
Andy McFaddend3250112010-11-03 14:32:42 -07004412 objType = getRegisterType(workRegs, decInsn.vB);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004413 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004414 &failure);
4415 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004416 break;
4417
4418 /* make sure the field's type is compatible with expectation */
4419 fieldType = primSigCharToRegType(instField->field.signature[0]);
4420 if (fieldType == kRegTypeUnknown ||
4421 !checkFieldArrayStore1nr(tmpType, fieldType))
4422 {
4423 LOG_VFY("VFY: invalid iget-1nr of %s.%s (inst=%d field=%d)\n",
4424 instField->field.clazz->descriptor,
4425 instField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004426 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004427 break;
4428 }
4429
Andy McFaddend3250112010-11-03 14:32:42 -07004430 setRegisterType(workRegs, decInsn.vA, tmpType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004431 }
4432 break;
4433 case OP_IGET_WIDE:
Andy McFadden861b3382010-03-05 15:58:31 -08004434 case OP_IGET_WIDE_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004435 {
4436 RegType dstType;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004437 InstField* instField;
4438 RegType objType;
4439
Andy McFaddend3250112010-11-03 14:32:42 -07004440 objType = getRegisterType(workRegs, decInsn.vB);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004441 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004442 &failure);
4443 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004444 break;
4445 /* check the type, which should be prim */
4446 switch (instField->field.signature[0]) {
4447 case 'D':
4448 dstType = kRegTypeDoubleLo;
4449 break;
4450 case 'J':
4451 dstType = kRegTypeLongLo;
4452 break;
4453 default:
4454 LOG_VFY("VFY: invalid iget-wide of %s.%s\n",
4455 instField->field.clazz->descriptor,
4456 instField->field.name);
4457 dstType = kRegTypeUnknown;
Andy McFadden62a75162009-04-17 17:23:37 -07004458 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004459 break;
4460 }
Andy McFadden62a75162009-04-17 17:23:37 -07004461 if (VERIFY_OK(failure)) {
Andy McFaddend3250112010-11-03 14:32:42 -07004462 setRegisterType(workRegs, decInsn.vA, dstType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004463 }
4464 }
4465 break;
4466 case OP_IGET_OBJECT:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004467 case OP_IGET_OBJECT_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004468 {
4469 ClassObject* fieldClass;
4470 InstField* instField;
4471 RegType objType;
4472
Andy McFaddend3250112010-11-03 14:32:42 -07004473 objType = getRegisterType(workRegs, decInsn.vB);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004474 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004475 &failure);
4476 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004477 break;
4478 fieldClass = getFieldClass(meth, &instField->field);
4479 if (fieldClass == NULL) {
4480 /* class not found or primitive type */
4481 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4482 instField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004483 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004484 break;
4485 }
Andy McFadden62a75162009-04-17 17:23:37 -07004486 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004487 assert(!dvmIsPrimitiveClass(fieldClass));
Andy McFaddend3250112010-11-03 14:32:42 -07004488 setRegisterType(workRegs, decInsn.vA,
4489 regTypeFromClass(fieldClass));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004490 }
4491 }
4492 break;
4493 case OP_IPUT:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004494 case OP_IPUT_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004495 tmpType = kRegTypeInteger;
4496 goto iput_1nr_common;
4497 case OP_IPUT_BOOLEAN:
4498 tmpType = kRegTypeBoolean;
4499 goto iput_1nr_common;
4500 case OP_IPUT_BYTE:
4501 tmpType = kRegTypeByte;
4502 goto iput_1nr_common;
4503 case OP_IPUT_CHAR:
4504 tmpType = kRegTypeChar;
4505 goto iput_1nr_common;
4506 case OP_IPUT_SHORT:
4507 tmpType = kRegTypeShort;
4508 goto iput_1nr_common;
4509iput_1nr_common:
4510 {
4511 RegType srcType, fieldType, objType;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004512 InstField* instField;
4513
Andy McFaddend3250112010-11-03 14:32:42 -07004514 srcType = getRegisterType(workRegs, decInsn.vA);
Andy McFaddenb5f64bc2009-06-10 14:11:07 -07004515
4516 /*
4517 * javac generates synthetic functions that write byte values
4518 * into boolean fields.
4519 */
4520 if (tmpType == kRegTypeBoolean && srcType == kRegTypeByte)
4521 srcType = kRegTypeBoolean;
4522
4523 /* make sure the source register has the correct type */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004524 if (!canConvertTo1nr(srcType, tmpType)) {
4525 LOG_VFY("VFY: invalid reg type %d on iput instr (need %d)\n",
4526 srcType, tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07004527 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004528 break;
4529 }
4530
Andy McFaddend3250112010-11-03 14:32:42 -07004531 objType = getRegisterType(workRegs, decInsn.vB);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004532 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004533 &failure);
4534 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004535 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004536 checkFinalFieldAccess(meth, &instField->field, &failure);
4537 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004538 break;
4539
4540 /* get type of field we're storing into */
4541 fieldType = primSigCharToRegType(instField->field.signature[0]);
4542 if (fieldType == kRegTypeUnknown ||
4543 !checkFieldArrayStore1nr(tmpType, fieldType))
4544 {
4545 LOG_VFY("VFY: invalid iput-1nr of %s.%s (inst=%d field=%d)\n",
4546 instField->field.clazz->descriptor,
4547 instField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004548 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004549 break;
4550 }
4551 }
4552 break;
4553 case OP_IPUT_WIDE:
Andy McFadden861b3382010-03-05 15:58:31 -08004554 case OP_IPUT_WIDE_VOLATILE:
Andy McFaddend3250112010-11-03 14:32:42 -07004555 tmpType = getRegisterType(workRegs, decInsn.vA);
4556 {
4557 RegType typeHi = getRegisterType(workRegs, decInsn.vA+1);
Andy McFadden62a75162009-04-17 17:23:37 -07004558 checkTypeCategory(tmpType, kTypeCategory2, &failure);
4559 checkWidePair(tmpType, typeHi, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004560 }
Andy McFadden62a75162009-04-17 17:23:37 -07004561 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004562 InstField* instField;
4563 RegType objType;
4564
Andy McFaddend3250112010-11-03 14:32:42 -07004565 objType = getRegisterType(workRegs, decInsn.vB);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004566 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004567 &failure);
4568 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004569 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004570 checkFinalFieldAccess(meth, &instField->field, &failure);
4571 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004572 break;
4573
4574 /* check the type, which should be prim */
4575 switch (instField->field.signature[0]) {
4576 case 'D':
4577 case 'J':
4578 /* these are okay (and interchangeable) */
4579 break;
4580 default:
4581 LOG_VFY("VFY: invalid iput-wide of %s.%s\n",
4582 instField->field.clazz->descriptor,
4583 instField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07004584 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004585 break;
4586 }
4587 }
4588 break;
4589 case OP_IPUT_OBJECT:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004590 case OP_IPUT_OBJECT_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004591 {
4592 ClassObject* fieldClass;
4593 ClassObject* valueClass;
4594 InstField* instField;
4595 RegType objType, valueType;
4596
Andy McFaddend3250112010-11-03 14:32:42 -07004597 objType = getRegisterType(workRegs, decInsn.vB);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004598 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004599 &failure);
4600 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004601 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004602 checkFinalFieldAccess(meth, &instField->field, &failure);
4603 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004604 break;
4605
4606 fieldClass = getFieldClass(meth, &instField->field);
4607 if (fieldClass == NULL) {
4608 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4609 instField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004610 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004611 break;
4612 }
4613
Andy McFaddend3250112010-11-03 14:32:42 -07004614 valueType = getRegisterType(workRegs, decInsn.vA);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004615 if (!regTypeIsReference(valueType)) {
4616 LOG_VFY("VFY: storing non-ref v%d into ref field '%s' (%s)\n",
4617 decInsn.vA, instField->field.name,
4618 fieldClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004619 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004620 break;
4621 }
4622 if (valueType != kRegTypeZero) {
4623 valueClass = regTypeInitializedReferenceToClass(valueType);
4624 if (valueClass == NULL) {
4625 LOG_VFY("VFY: storing uninit ref v%d into ref field\n",
4626 decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07004627 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004628 break;
4629 }
4630 /* allow if field is any interface or field is base class */
4631 if (!dvmIsInterfaceClass(fieldClass) &&
4632 !dvmInstanceof(valueClass, fieldClass))
4633 {
4634 LOG_VFY("VFY: storing type '%s' into field type '%s' (%s.%s)\n",
4635 valueClass->descriptor, fieldClass->descriptor,
4636 instField->field.clazz->descriptor,
4637 instField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07004638 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004639 break;
4640 }
4641 }
4642 }
4643 break;
4644
4645 case OP_SGET:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004646 case OP_SGET_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004647 tmpType = kRegTypeInteger;
4648 goto sget_1nr_common;
4649 case OP_SGET_BOOLEAN:
4650 tmpType = kRegTypeBoolean;
4651 goto sget_1nr_common;
4652 case OP_SGET_BYTE:
4653 tmpType = kRegTypeByte;
4654 goto sget_1nr_common;
4655 case OP_SGET_CHAR:
4656 tmpType = kRegTypeChar;
4657 goto sget_1nr_common;
4658 case OP_SGET_SHORT:
4659 tmpType = kRegTypeShort;
4660 goto sget_1nr_common;
4661sget_1nr_common:
4662 {
4663 StaticField* staticField;
4664 RegType fieldType;
4665
Andy McFadden62a75162009-04-17 17:23:37 -07004666 staticField = getStaticField(meth, decInsn.vB, &failure);
4667 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004668 break;
4669
4670 /*
4671 * Make sure the field's type is compatible with expectation.
4672 * We can get ourselves into trouble if we mix & match loads
4673 * and stores with different widths, so rather than just checking
4674 * "canConvertTo1nr" we require that the field types have equal
4675 * widths. (We can't generally require an exact type match,
4676 * because e.g. "int" and "float" are interchangeable.)
4677 */
4678 fieldType = primSigCharToRegType(staticField->field.signature[0]);
4679 if (!checkFieldArrayStore1nr(tmpType, fieldType)) {
4680 LOG_VFY("VFY: invalid sget-1nr of %s.%s (inst=%d actual=%d)\n",
4681 staticField->field.clazz->descriptor,
4682 staticField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004683 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004684 break;
4685 }
4686
Andy McFaddend3250112010-11-03 14:32:42 -07004687 setRegisterType(workRegs, decInsn.vA, tmpType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004688 }
4689 break;
4690 case OP_SGET_WIDE:
Andy McFadden861b3382010-03-05 15:58:31 -08004691 case OP_SGET_WIDE_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004692 {
4693 StaticField* staticField;
4694 RegType dstType;
4695
Andy McFadden62a75162009-04-17 17:23:37 -07004696 staticField = getStaticField(meth, decInsn.vB, &failure);
4697 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004698 break;
4699 /* check the type, which should be prim */
4700 switch (staticField->field.signature[0]) {
4701 case 'D':
4702 dstType = kRegTypeDoubleLo;
4703 break;
4704 case 'J':
4705 dstType = kRegTypeLongLo;
4706 break;
4707 default:
4708 LOG_VFY("VFY: invalid sget-wide of %s.%s\n",
4709 staticField->field.clazz->descriptor,
4710 staticField->field.name);
4711 dstType = kRegTypeUnknown;
Andy McFadden62a75162009-04-17 17:23:37 -07004712 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004713 break;
4714 }
Andy McFadden62a75162009-04-17 17:23:37 -07004715 if (VERIFY_OK(failure)) {
Andy McFaddend3250112010-11-03 14:32:42 -07004716 setRegisterType(workRegs, decInsn.vA, dstType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004717 }
4718 }
4719 break;
4720 case OP_SGET_OBJECT:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004721 case OP_SGET_OBJECT_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004722 {
4723 StaticField* staticField;
4724 ClassObject* fieldClass;
4725
Andy McFadden62a75162009-04-17 17:23:37 -07004726 staticField = getStaticField(meth, decInsn.vB, &failure);
4727 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004728 break;
4729 fieldClass = getFieldClass(meth, &staticField->field);
4730 if (fieldClass == NULL) {
4731 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4732 staticField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004733 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004734 break;
4735 }
4736 if (dvmIsPrimitiveClass(fieldClass)) {
4737 LOG_VFY("VFY: attempt to get prim field with sget-object\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004738 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004739 break;
4740 }
Andy McFaddend3250112010-11-03 14:32:42 -07004741 setRegisterType(workRegs, decInsn.vA, regTypeFromClass(fieldClass));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004742 }
4743 break;
4744 case OP_SPUT:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004745 case OP_SPUT_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004746 tmpType = kRegTypeInteger;
4747 goto sput_1nr_common;
4748 case OP_SPUT_BOOLEAN:
4749 tmpType = kRegTypeBoolean;
4750 goto sput_1nr_common;
4751 case OP_SPUT_BYTE:
4752 tmpType = kRegTypeByte;
4753 goto sput_1nr_common;
4754 case OP_SPUT_CHAR:
4755 tmpType = kRegTypeChar;
4756 goto sput_1nr_common;
4757 case OP_SPUT_SHORT:
4758 tmpType = kRegTypeShort;
4759 goto sput_1nr_common;
4760sput_1nr_common:
4761 {
4762 RegType srcType, fieldType;
4763 StaticField* staticField;
4764
Andy McFaddend3250112010-11-03 14:32:42 -07004765 srcType = getRegisterType(workRegs, decInsn.vA);
Andy McFaddenb5f64bc2009-06-10 14:11:07 -07004766
4767 /*
4768 * javac generates synthetic functions that write byte values
4769 * into boolean fields.
4770 */
4771 if (tmpType == kRegTypeBoolean && srcType == kRegTypeByte)
4772 srcType = kRegTypeBoolean;
4773
4774 /* make sure the source register has the correct type */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004775 if (!canConvertTo1nr(srcType, tmpType)) {
Andy McFaddenb5f64bc2009-06-10 14:11:07 -07004776 LOG_VFY("VFY: invalid reg type %d on sput instr (need %d)\n",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004777 srcType, tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07004778 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004779 break;
4780 }
4781
Andy McFadden62a75162009-04-17 17:23:37 -07004782 staticField = getStaticField(meth, decInsn.vB, &failure);
4783 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004784 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004785 checkFinalFieldAccess(meth, &staticField->field, &failure);
4786 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004787 break;
4788
4789 /*
4790 * Get type of field we're storing into. We know that the
4791 * contents of the register match the instruction, but we also
4792 * need to ensure that the instruction matches the field type.
4793 * Using e.g. sput-short to write into a 32-bit integer field
4794 * can lead to trouble if we do 16-bit writes.
4795 */
4796 fieldType = primSigCharToRegType(staticField->field.signature[0]);
4797 if (!checkFieldArrayStore1nr(tmpType, fieldType)) {
4798 LOG_VFY("VFY: invalid sput-1nr of %s.%s (inst=%d actual=%d)\n",
4799 staticField->field.clazz->descriptor,
4800 staticField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004801 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004802 break;
4803 }
4804 }
4805 break;
4806 case OP_SPUT_WIDE:
Andy McFadden861b3382010-03-05 15:58:31 -08004807 case OP_SPUT_WIDE_VOLATILE:
Andy McFaddend3250112010-11-03 14:32:42 -07004808 tmpType = getRegisterType(workRegs, decInsn.vA);
4809 {
4810 RegType typeHi = getRegisterType(workRegs, decInsn.vA+1);
Andy McFadden62a75162009-04-17 17:23:37 -07004811 checkTypeCategory(tmpType, kTypeCategory2, &failure);
4812 checkWidePair(tmpType, typeHi, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004813 }
Andy McFadden62a75162009-04-17 17:23:37 -07004814 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004815 StaticField* staticField;
4816
Andy McFadden62a75162009-04-17 17:23:37 -07004817 staticField = getStaticField(meth, decInsn.vB, &failure);
4818 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004819 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004820 checkFinalFieldAccess(meth, &staticField->field, &failure);
4821 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004822 break;
4823
4824 /* check the type, which should be prim */
4825 switch (staticField->field.signature[0]) {
4826 case 'D':
4827 case 'J':
4828 /* these are okay */
4829 break;
4830 default:
4831 LOG_VFY("VFY: invalid sput-wide of %s.%s\n",
4832 staticField->field.clazz->descriptor,
4833 staticField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07004834 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004835 break;
4836 }
4837 }
4838 break;
4839 case OP_SPUT_OBJECT:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004840 case OP_SPUT_OBJECT_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004841 {
4842 ClassObject* fieldClass;
4843 ClassObject* valueClass;
4844 StaticField* staticField;
4845 RegType valueType;
4846
Andy McFadden62a75162009-04-17 17:23:37 -07004847 staticField = getStaticField(meth, decInsn.vB, &failure);
4848 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004849 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004850 checkFinalFieldAccess(meth, &staticField->field, &failure);
4851 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004852 break;
4853
4854 fieldClass = getFieldClass(meth, &staticField->field);
4855 if (fieldClass == NULL) {
4856 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4857 staticField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004858 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004859 break;
4860 }
4861
Andy McFaddend3250112010-11-03 14:32:42 -07004862 valueType = getRegisterType(workRegs, decInsn.vA);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004863 if (!regTypeIsReference(valueType)) {
4864 LOG_VFY("VFY: storing non-ref v%d into ref field '%s' (%s)\n",
4865 decInsn.vA, staticField->field.name,
4866 fieldClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004867 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004868 break;
4869 }
4870 if (valueType != kRegTypeZero) {
4871 valueClass = regTypeInitializedReferenceToClass(valueType);
4872 if (valueClass == NULL) {
4873 LOG_VFY("VFY: storing uninit ref v%d into ref field\n",
4874 decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07004875 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004876 break;
4877 }
4878 /* allow if field is any interface or field is base class */
4879 if (!dvmIsInterfaceClass(fieldClass) &&
4880 !dvmInstanceof(valueClass, fieldClass))
4881 {
4882 LOG_VFY("VFY: storing type '%s' into field type '%s' (%s.%s)\n",
4883 valueClass->descriptor, fieldClass->descriptor,
4884 staticField->field.clazz->descriptor,
4885 staticField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07004886 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004887 break;
4888 }
4889 }
4890 }
4891 break;
4892
4893 case OP_INVOKE_VIRTUAL:
4894 case OP_INVOKE_VIRTUAL_RANGE:
4895 case OP_INVOKE_SUPER:
4896 case OP_INVOKE_SUPER_RANGE:
4897 {
4898 Method* calledMethod;
4899 RegType returnType;
4900 bool isRange;
4901 bool isSuper;
4902
4903 isRange = (decInsn.opCode == OP_INVOKE_VIRTUAL_RANGE ||
4904 decInsn.opCode == OP_INVOKE_SUPER_RANGE);
4905 isSuper = (decInsn.opCode == OP_INVOKE_SUPER ||
4906 decInsn.opCode == OP_INVOKE_SUPER_RANGE);
4907
4908 calledMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
4909 &decInsn, uninitMap, METHOD_VIRTUAL, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07004910 isSuper, &failure);
4911 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004912 break;
4913 returnType = getMethodReturnType(calledMethod);
Andy McFaddend3250112010-11-03 14:32:42 -07004914 setResultRegisterType(workRegs, insnRegCount, returnType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004915 justSetResult = true;
4916 }
4917 break;
4918 case OP_INVOKE_DIRECT:
4919 case OP_INVOKE_DIRECT_RANGE:
4920 {
4921 RegType returnType;
4922 Method* calledMethod;
4923 bool isRange;
4924
4925 isRange = (decInsn.opCode == OP_INVOKE_DIRECT_RANGE);
4926 calledMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
4927 &decInsn, uninitMap, METHOD_DIRECT, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07004928 false, &failure);
4929 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004930 break;
4931
4932 /*
4933 * Some additional checks when calling <init>. We know from
4934 * the invocation arg check that the "this" argument is an
4935 * instance of calledMethod->clazz. Now we further restrict
4936 * that to require that calledMethod->clazz is the same as
4937 * this->clazz or this->super, allowing the latter only if
4938 * the "this" argument is the same as the "this" argument to
4939 * this method (which implies that we're in <init> ourselves).
4940 */
4941 if (isInitMethod(calledMethod)) {
4942 RegType thisType;
Andy McFaddend3250112010-11-03 14:32:42 -07004943 thisType = getInvocationThis(workRegs, &decInsn, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07004944 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004945 break;
4946
4947 /* no null refs allowed (?) */
4948 if (thisType == kRegTypeZero) {
4949 LOG_VFY("VFY: unable to initialize null ref\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004950 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004951 break;
4952 }
4953
4954 ClassObject* thisClass;
4955
4956 thisClass = regTypeReferenceToClass(thisType, uninitMap);
4957 assert(thisClass != NULL);
4958
4959 /* must be in same class or in superclass */
4960 if (calledMethod->clazz == thisClass->super) {
4961 if (thisClass != meth->clazz) {
4962 LOG_VFY("VFY: invoke-direct <init> on super only "
4963 "allowed for 'this' in <init>");
Andy McFadden62a75162009-04-17 17:23:37 -07004964 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004965 break;
4966 }
4967 } else if (calledMethod->clazz != thisClass) {
4968 LOG_VFY("VFY: invoke-direct <init> must be on current "
4969 "class or super\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004970 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004971 break;
4972 }
4973
4974 /* arg must be an uninitialized reference */
4975 if (!regTypeIsUninitReference(thisType)) {
4976 LOG_VFY("VFY: can only initialize the uninitialized\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004977 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004978 break;
4979 }
4980
4981 /*
4982 * Replace the uninitialized reference with an initialized
4983 * one, and clear the entry in the uninit map. We need to
4984 * do this for all registers that have the same object
4985 * instance in them, not just the "this" register.
4986 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004987 markRefsAsInitialized(workRegs, insnRegCount, uninitMap,
Andy McFadden62a75162009-04-17 17:23:37 -07004988 thisType, &failure);
4989 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004990 break;
4991 }
4992 returnType = getMethodReturnType(calledMethod);
Andy McFaddend3250112010-11-03 14:32:42 -07004993 setResultRegisterType(workRegs, insnRegCount, returnType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004994 justSetResult = true;
4995 }
4996 break;
4997 case OP_INVOKE_STATIC:
4998 case OP_INVOKE_STATIC_RANGE:
4999 {
5000 RegType returnType;
5001 Method* calledMethod;
5002 bool isRange;
5003
5004 isRange = (decInsn.opCode == OP_INVOKE_STATIC_RANGE);
5005 calledMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
5006 &decInsn, uninitMap, METHOD_STATIC, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07005007 false, &failure);
5008 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005009 break;
5010
5011 returnType = getMethodReturnType(calledMethod);
Andy McFaddend3250112010-11-03 14:32:42 -07005012 setResultRegisterType(workRegs, insnRegCount, returnType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005013 justSetResult = true;
5014 }
5015 break;
5016 case OP_INVOKE_INTERFACE:
5017 case OP_INVOKE_INTERFACE_RANGE:
5018 {
5019 RegType /*thisType,*/ returnType;
5020 Method* absMethod;
5021 bool isRange;
5022
5023 isRange = (decInsn.opCode == OP_INVOKE_INTERFACE_RANGE);
5024 absMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
5025 &decInsn, uninitMap, METHOD_INTERFACE, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07005026 false, &failure);
5027 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005028 break;
5029
5030#if 0 /* can't do this here, fails on dalvik test 052-verifier-fun */
5031 /*
5032 * Get the type of the "this" arg, which should always be an
5033 * interface class. Because we don't do a full merge on
5034 * interface classes, this might have reduced to Object.
5035 */
Andy McFaddend3250112010-11-03 14:32:42 -07005036 thisType = getInvocationThis(workRegs, &decInsn, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07005037 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005038 break;
5039
5040 if (thisType == kRegTypeZero) {
5041 /* null pointer always passes (and always fails at runtime) */
5042 } else {
5043 ClassObject* thisClass;
5044
5045 thisClass = regTypeInitializedReferenceToClass(thisType);
5046 if (thisClass == NULL) {
5047 LOG_VFY("VFY: interface call on uninitialized\n");
Andy McFadden62a75162009-04-17 17:23:37 -07005048 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005049 break;
5050 }
5051
5052 /*
5053 * Either "thisClass" needs to be the interface class that
5054 * defined absMethod, or absMethod's class needs to be one
5055 * of the interfaces implemented by "thisClass". (Or, if
5056 * we couldn't complete the merge, this will be Object.)
5057 */
5058 if (thisClass != absMethod->clazz &&
5059 thisClass != gDvm.classJavaLangObject &&
5060 !dvmImplements(thisClass, absMethod->clazz))
5061 {
5062 LOG_VFY("VFY: unable to match absMethod '%s' with %s interfaces\n",
5063 absMethod->name, thisClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07005064 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005065 break;
5066 }
5067 }
5068#endif
5069
5070 /*
5071 * We don't have an object instance, so we can't find the
5072 * concrete method. However, all of the type information is
5073 * in the abstract method, so we're good.
5074 */
5075 returnType = getMethodReturnType(absMethod);
Andy McFaddend3250112010-11-03 14:32:42 -07005076 setResultRegisterType(workRegs, insnRegCount, returnType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005077 justSetResult = true;
5078 }
5079 break;
5080
5081 case OP_NEG_INT:
5082 case OP_NOT_INT:
Andy McFaddend3250112010-11-03 14:32:42 -07005083 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005084 kRegTypeInteger, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005085 break;
5086 case OP_NEG_LONG:
5087 case OP_NOT_LONG:
Andy McFaddend3250112010-11-03 14:32:42 -07005088 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005089 kRegTypeLongLo, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005090 break;
5091 case OP_NEG_FLOAT:
Andy McFaddend3250112010-11-03 14:32:42 -07005092 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005093 kRegTypeFloat, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005094 break;
5095 case OP_NEG_DOUBLE:
Andy McFaddend3250112010-11-03 14:32:42 -07005096 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005097 kRegTypeDoubleLo, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005098 break;
5099 case OP_INT_TO_LONG:
Andy McFaddend3250112010-11-03 14:32:42 -07005100 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005101 kRegTypeLongLo, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005102 break;
5103 case OP_INT_TO_FLOAT:
Andy McFaddend3250112010-11-03 14:32:42 -07005104 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005105 kRegTypeFloat, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005106 break;
5107 case OP_INT_TO_DOUBLE:
Andy McFaddend3250112010-11-03 14:32:42 -07005108 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005109 kRegTypeDoubleLo, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005110 break;
5111 case OP_LONG_TO_INT:
Andy McFaddend3250112010-11-03 14:32:42 -07005112 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005113 kRegTypeInteger, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005114 break;
5115 case OP_LONG_TO_FLOAT:
Andy McFaddend3250112010-11-03 14:32:42 -07005116 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005117 kRegTypeFloat, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005118 break;
5119 case OP_LONG_TO_DOUBLE:
Andy McFaddend3250112010-11-03 14:32:42 -07005120 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005121 kRegTypeDoubleLo, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005122 break;
5123 case OP_FLOAT_TO_INT:
Andy McFaddend3250112010-11-03 14:32:42 -07005124 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005125 kRegTypeInteger, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005126 break;
5127 case OP_FLOAT_TO_LONG:
Andy McFaddend3250112010-11-03 14:32:42 -07005128 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005129 kRegTypeLongLo, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005130 break;
5131 case OP_FLOAT_TO_DOUBLE:
Andy McFaddend3250112010-11-03 14:32:42 -07005132 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005133 kRegTypeDoubleLo, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005134 break;
5135 case OP_DOUBLE_TO_INT:
Andy McFaddend3250112010-11-03 14:32:42 -07005136 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005137 kRegTypeInteger, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005138 break;
5139 case OP_DOUBLE_TO_LONG:
Andy McFaddend3250112010-11-03 14:32:42 -07005140 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005141 kRegTypeLongLo, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005142 break;
5143 case OP_DOUBLE_TO_FLOAT:
Andy McFaddend3250112010-11-03 14:32:42 -07005144 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005145 kRegTypeFloat, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005146 break;
5147 case OP_INT_TO_BYTE:
Andy McFaddend3250112010-11-03 14:32:42 -07005148 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005149 kRegTypeByte, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005150 break;
5151 case OP_INT_TO_CHAR:
Andy McFaddend3250112010-11-03 14:32:42 -07005152 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005153 kRegTypeChar, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005154 break;
5155 case OP_INT_TO_SHORT:
Andy McFaddend3250112010-11-03 14:32:42 -07005156 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005157 kRegTypeShort, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005158 break;
5159
5160 case OP_ADD_INT:
5161 case OP_SUB_INT:
5162 case OP_MUL_INT:
5163 case OP_REM_INT:
5164 case OP_DIV_INT:
5165 case OP_SHL_INT:
5166 case OP_SHR_INT:
5167 case OP_USHR_INT:
Andy McFaddend3250112010-11-03 14:32:42 -07005168 checkBinop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005169 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005170 break;
5171 case OP_AND_INT:
5172 case OP_OR_INT:
5173 case OP_XOR_INT:
Andy McFaddend3250112010-11-03 14:32:42 -07005174 checkBinop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005175 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005176 break;
5177 case OP_ADD_LONG:
5178 case OP_SUB_LONG:
5179 case OP_MUL_LONG:
5180 case OP_DIV_LONG:
5181 case OP_REM_LONG:
5182 case OP_AND_LONG:
5183 case OP_OR_LONG:
5184 case OP_XOR_LONG:
Andy McFaddend3250112010-11-03 14:32:42 -07005185 checkBinop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005186 kRegTypeLongLo, kRegTypeLongLo, kRegTypeLongLo, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005187 break;
5188 case OP_SHL_LONG:
5189 case OP_SHR_LONG:
5190 case OP_USHR_LONG:
5191 /* shift distance is Int, making these different from other binops */
Andy McFaddend3250112010-11-03 14:32:42 -07005192 checkBinop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005193 kRegTypeLongLo, kRegTypeLongLo, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005194 break;
5195 case OP_ADD_FLOAT:
5196 case OP_SUB_FLOAT:
5197 case OP_MUL_FLOAT:
5198 case OP_DIV_FLOAT:
5199 case OP_REM_FLOAT:
Andy McFaddend3250112010-11-03 14:32:42 -07005200 checkBinop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005201 kRegTypeFloat, kRegTypeFloat, kRegTypeFloat, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005202 break;
5203 case OP_ADD_DOUBLE:
5204 case OP_SUB_DOUBLE:
5205 case OP_MUL_DOUBLE:
5206 case OP_DIV_DOUBLE:
5207 case OP_REM_DOUBLE:
Andy McFaddend3250112010-11-03 14:32:42 -07005208 checkBinop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005209 kRegTypeDoubleLo, kRegTypeDoubleLo, kRegTypeDoubleLo, false,
5210 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005211 break;
5212 case OP_ADD_INT_2ADDR:
5213 case OP_SUB_INT_2ADDR:
5214 case OP_MUL_INT_2ADDR:
5215 case OP_REM_INT_2ADDR:
5216 case OP_SHL_INT_2ADDR:
5217 case OP_SHR_INT_2ADDR:
5218 case OP_USHR_INT_2ADDR:
Andy McFaddend3250112010-11-03 14:32:42 -07005219 checkBinop2addr(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005220 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005221 break;
5222 case OP_AND_INT_2ADDR:
5223 case OP_OR_INT_2ADDR:
5224 case OP_XOR_INT_2ADDR:
Andy McFaddend3250112010-11-03 14:32:42 -07005225 checkBinop2addr(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005226 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005227 break;
5228 case OP_DIV_INT_2ADDR:
Andy McFaddend3250112010-11-03 14:32:42 -07005229 checkBinop2addr(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005230 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005231 break;
5232 case OP_ADD_LONG_2ADDR:
5233 case OP_SUB_LONG_2ADDR:
5234 case OP_MUL_LONG_2ADDR:
5235 case OP_DIV_LONG_2ADDR:
5236 case OP_REM_LONG_2ADDR:
5237 case OP_AND_LONG_2ADDR:
5238 case OP_OR_LONG_2ADDR:
5239 case OP_XOR_LONG_2ADDR:
Andy McFaddend3250112010-11-03 14:32:42 -07005240 checkBinop2addr(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005241 kRegTypeLongLo, kRegTypeLongLo, kRegTypeLongLo, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005242 break;
5243 case OP_SHL_LONG_2ADDR:
5244 case OP_SHR_LONG_2ADDR:
5245 case OP_USHR_LONG_2ADDR:
Andy McFaddend3250112010-11-03 14:32:42 -07005246 checkBinop2addr(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005247 kRegTypeLongLo, kRegTypeLongLo, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005248 break;
5249 case OP_ADD_FLOAT_2ADDR:
5250 case OP_SUB_FLOAT_2ADDR:
5251 case OP_MUL_FLOAT_2ADDR:
5252 case OP_DIV_FLOAT_2ADDR:
5253 case OP_REM_FLOAT_2ADDR:
Andy McFaddend3250112010-11-03 14:32:42 -07005254 checkBinop2addr(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005255 kRegTypeFloat, kRegTypeFloat, kRegTypeFloat, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005256 break;
5257 case OP_ADD_DOUBLE_2ADDR:
5258 case OP_SUB_DOUBLE_2ADDR:
5259 case OP_MUL_DOUBLE_2ADDR:
5260 case OP_DIV_DOUBLE_2ADDR:
5261 case OP_REM_DOUBLE_2ADDR:
Andy McFaddend3250112010-11-03 14:32:42 -07005262 checkBinop2addr(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005263 kRegTypeDoubleLo, kRegTypeDoubleLo, kRegTypeDoubleLo, false,
5264 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005265 break;
5266 case OP_ADD_INT_LIT16:
5267 case OP_RSUB_INT:
5268 case OP_MUL_INT_LIT16:
5269 case OP_DIV_INT_LIT16:
5270 case OP_REM_INT_LIT16:
Andy McFaddend3250112010-11-03 14:32:42 -07005271 checkLitop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005272 kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005273 break;
5274 case OP_AND_INT_LIT16:
5275 case OP_OR_INT_LIT16:
5276 case OP_XOR_INT_LIT16:
Andy McFaddend3250112010-11-03 14:32:42 -07005277 checkLitop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005278 kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005279 break;
5280 case OP_ADD_INT_LIT8:
5281 case OP_RSUB_INT_LIT8:
5282 case OP_MUL_INT_LIT8:
5283 case OP_DIV_INT_LIT8:
5284 case OP_REM_INT_LIT8:
5285 case OP_SHL_INT_LIT8:
Andy McFaddend3250112010-11-03 14:32:42 -07005286 checkLitop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005287 kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005288 break;
Andy McFadden80d25ea2009-06-12 07:26:17 -07005289 case OP_SHR_INT_LIT8:
Andy McFaddend3250112010-11-03 14:32:42 -07005290 tmpType = adjustForRightShift(workRegs,
Andy McFadden80d25ea2009-06-12 07:26:17 -07005291 decInsn.vB, decInsn.vC, false, &failure);
Andy McFaddend3250112010-11-03 14:32:42 -07005292 checkLitop(workRegs, &decInsn,
Andy McFadden80d25ea2009-06-12 07:26:17 -07005293 tmpType, kRegTypeInteger, false, &failure);
5294 break;
5295 case OP_USHR_INT_LIT8:
Andy McFaddend3250112010-11-03 14:32:42 -07005296 tmpType = adjustForRightShift(workRegs,
Andy McFadden80d25ea2009-06-12 07:26:17 -07005297 decInsn.vB, decInsn.vC, true, &failure);
Andy McFaddend3250112010-11-03 14:32:42 -07005298 checkLitop(workRegs, &decInsn,
Andy McFadden80d25ea2009-06-12 07:26:17 -07005299 tmpType, kRegTypeInteger, false, &failure);
5300 break;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005301 case OP_AND_INT_LIT8:
5302 case OP_OR_INT_LIT8:
5303 case OP_XOR_INT_LIT8:
Andy McFaddend3250112010-11-03 14:32:42 -07005304 checkLitop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005305 kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005306 break;
5307
Andy McFaddenb51ea112009-05-08 16:50:17 -07005308 /*
5309 * This falls into the general category of "optimized" instructions,
5310 * which don't generally appear during verification. Because it's
5311 * inserted in the course of verification, we can expect to see it here.
5312 */
5313 case OP_THROW_VERIFICATION_ERROR:
5314 break;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005315
5316 /*
5317 * Verifying "quickened" instructions is tricky, because we have
5318 * discarded the original field/method information. The byte offsets
5319 * and vtable indices only have meaning in the context of an object
5320 * instance.
5321 *
5322 * If a piece of code declares a local reference variable, assigns
5323 * null to it, and then issues a virtual method call on it, we
5324 * cannot evaluate the method call during verification. This situation
5325 * isn't hard to handle, since we know the call will always result in an
5326 * NPE, and the arguments and return value don't matter. Any code that
5327 * depends on the result of the method call is inaccessible, so the
5328 * fact that we can't fully verify anything that comes after the bad
5329 * call is not a problem.
5330 *
5331 * We must also consider the case of multiple code paths, only some of
5332 * which involve a null reference. We can completely verify the method
5333 * if we sidestep the results of executing with a null reference.
5334 * For example, if on the first pass through the code we try to do a
5335 * virtual method invocation through a null ref, we have to skip the
5336 * method checks and have the method return a "wildcard" type (which
5337 * merges with anything to become that other thing). The move-result
5338 * will tell us if it's a reference, single-word numeric, or double-word
5339 * value. We continue to perform the verification, and at the end of
5340 * the function any invocations that were never fully exercised are
5341 * marked as null-only.
5342 *
5343 * We would do something similar for the field accesses. The field's
5344 * type, once known, can be used to recover the width of short integers.
5345 * If the object reference was null, the field-get returns the "wildcard"
5346 * type, which is acceptable for any operation.
5347 */
5348 case OP_EXECUTE_INLINE:
Andy McFaddenb0a05412009-11-19 10:23:41 -08005349 case OP_EXECUTE_INLINE_RANGE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005350 case OP_INVOKE_DIRECT_EMPTY:
5351 case OP_IGET_QUICK:
5352 case OP_IGET_WIDE_QUICK:
5353 case OP_IGET_OBJECT_QUICK:
5354 case OP_IPUT_QUICK:
5355 case OP_IPUT_WIDE_QUICK:
5356 case OP_IPUT_OBJECT_QUICK:
5357 case OP_INVOKE_VIRTUAL_QUICK:
5358 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
5359 case OP_INVOKE_SUPER_QUICK:
5360 case OP_INVOKE_SUPER_QUICK_RANGE:
Andy McFadden291758c2010-09-10 08:04:52 -07005361 case OP_RETURN_VOID_BARRIER:
Andy McFadden62a75162009-04-17 17:23:37 -07005362 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005363 break;
5364
Andy McFadden96516932009-10-28 17:39:02 -07005365 /* these should never appear during verification */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005366 case OP_UNUSED_3E:
5367 case OP_UNUSED_3F:
5368 case OP_UNUSED_40:
5369 case OP_UNUSED_41:
5370 case OP_UNUSED_42:
5371 case OP_UNUSED_43:
5372 case OP_UNUSED_73:
5373 case OP_UNUSED_79:
5374 case OP_UNUSED_7A:
Andy McFadden96516932009-10-28 17:39:02 -07005375 case OP_BREAKPOINT:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005376 case OP_UNUSED_FF:
Andy McFadden62a75162009-04-17 17:23:37 -07005377 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005378 break;
5379
5380 /*
5381 * DO NOT add a "default" clause here. Without it the compiler will
5382 * complain if an instruction is missing (which is desirable).
5383 */
5384 }
5385
Andy McFadden62a75162009-04-17 17:23:37 -07005386 if (!VERIFY_OK(failure)) {
Andy McFaddenb51ea112009-05-08 16:50:17 -07005387 if (failure == VERIFY_ERROR_GENERIC || gDvm.optimizing) {
5388 /* immediate failure, reject class */
5389 LOG_VFY_METH(meth, "VFY: rejecting opcode 0x%02x at 0x%04x\n",
5390 decInsn.opCode, insnIdx);
5391 goto bail;
5392 } else {
5393 /* replace opcode and continue on */
5394 LOGD("VFY: replacing opcode 0x%02x at 0x%04x\n",
5395 decInsn.opCode, insnIdx);
5396 if (!replaceFailingInstruction(meth, insnFlags, insnIdx, failure)) {
5397 LOG_VFY_METH(meth, "VFY: rejecting opcode 0x%02x at 0x%04x\n",
5398 decInsn.opCode, insnIdx);
5399 goto bail;
5400 }
5401 /* IMPORTANT: meth->insns may have been changed */
5402 insns = meth->insns + insnIdx;
5403
5404 /* continue on as if we just handled a throw-verification-error */
5405 failure = VERIFY_ERROR_NONE;
5406 nextFlags = kInstrCanThrow;
5407 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005408 }
5409
5410 /*
5411 * If we didn't just set the result register, clear it out. This
5412 * ensures that you can only use "move-result" immediately after the
Andy McFadden2e1ee502010-03-24 13:25:53 -07005413 * result is set. (We could check this statically, but it's not
5414 * expensive and it makes our debugging output cleaner.)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005415 */
5416 if (!justSetResult) {
5417 int reg = RESULT_REGISTER(insnRegCount);
5418 workRegs[reg] = workRegs[reg+1] = kRegTypeUnknown;
5419 }
5420
5421 /*
5422 * Handle "continue". Tag the next consecutive instruction.
5423 */
5424 if ((nextFlags & kInstrCanContinue) != 0) {
5425 int insnWidth = dvmInsnGetWidth(insnFlags, insnIdx);
5426 if (insnIdx+insnWidth >= insnsSize) {
5427 LOG_VFY_METH(meth,
5428 "VFY: execution can walk off end of code area (from 0x%x)\n",
5429 insnIdx);
5430 goto bail;
5431 }
5432
5433 /*
5434 * The only way to get to a move-exception instruction is to get
5435 * thrown there. Make sure the next instruction isn't one.
5436 */
5437 if (!checkMoveException(meth, insnIdx+insnWidth, "next"))
5438 goto bail;
5439
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005440 if (getRegisterLine(regTable, insnIdx+insnWidth) != NULL) {
Andy McFadden06b7a282009-05-11 10:44:52 -07005441 /*
5442 * Merge registers into what we have for the next instruction,
5443 * and set the "changed" flag if needed.
5444 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005445 updateRegisters(meth, insnFlags, regTable, insnIdx+insnWidth,
5446 workRegs);
5447 } else {
The Android Open Source Project99409882009-03-18 22:20:24 -07005448 /*
Andy McFadden06b7a282009-05-11 10:44:52 -07005449 * We're not recording register data for the next instruction,
5450 * so we don't know what the prior state was. We have to
5451 * assume that something has changed and re-evaluate it.
The Android Open Source Project99409882009-03-18 22:20:24 -07005452 */
5453 dvmInsnSetChanged(insnFlags, insnIdx+insnWidth, true);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005454 }
5455 }
5456
5457 /*
5458 * Handle "branch". Tag the branch target.
5459 *
5460 * NOTE: instructions like OP_EQZ provide information about the state
5461 * of the register when the branch is taken or not taken. For example,
5462 * somebody could get a reference field, check it for zero, and if the
5463 * branch is taken immediately store that register in a boolean field
5464 * since the value is known to be zero. We do not currently account for
5465 * that, and will reject the code.
5466 */
5467 if ((nextFlags & kInstrCanBranch) != 0) {
5468 bool isConditional;
5469
5470 if (!dvmGetBranchTarget(meth, insnFlags, insnIdx, &branchTarget,
5471 &isConditional))
5472 {
5473 /* should never happen after static verification */
5474 LOG_VFY_METH(meth, "VFY: bad branch at %d\n", insnIdx);
5475 goto bail;
5476 }
5477 assert(isConditional || (nextFlags & kInstrCanContinue) == 0);
5478 assert(!isConditional || (nextFlags & kInstrCanContinue) != 0);
5479
5480 if (!checkMoveException(meth, insnIdx+branchTarget, "branch"))
5481 goto bail;
5482
The Android Open Source Project99409882009-03-18 22:20:24 -07005483 /* update branch target, set "changed" if appropriate */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005484 updateRegisters(meth, insnFlags, regTable, insnIdx+branchTarget,
5485 workRegs);
5486 }
5487
5488 /*
5489 * Handle "switch". Tag all possible branch targets.
5490 *
5491 * We've already verified that the table is structurally sound, so we
5492 * just need to walk through and tag the targets.
5493 */
5494 if ((nextFlags & kInstrCanSwitch) != 0) {
5495 int offsetToSwitch = insns[1] | (((s4)insns[2]) << 16);
5496 const u2* switchInsns = insns + offsetToSwitch;
5497 int switchCount = switchInsns[1];
5498 int offsetToTargets, targ;
5499
5500 if ((*insns & 0xff) == OP_PACKED_SWITCH) {
5501 /* 0=sig, 1=count, 2/3=firstKey */
5502 offsetToTargets = 4;
5503 } else {
5504 /* 0=sig, 1=count, 2..count*2 = keys */
5505 assert((*insns & 0xff) == OP_SPARSE_SWITCH);
5506 offsetToTargets = 2 + 2*switchCount;
5507 }
5508
5509 /* verify each switch target */
5510 for (targ = 0; targ < switchCount; targ++) {
5511 int offset, absOffset;
5512
5513 /* offsets are 32-bit, and only partly endian-swapped */
5514 offset = switchInsns[offsetToTargets + targ*2] |
5515 (((s4) switchInsns[offsetToTargets + targ*2 +1]) << 16);
5516 absOffset = insnIdx + offset;
5517
5518 assert(absOffset >= 0 && absOffset < insnsSize);
5519
5520 if (!checkMoveException(meth, absOffset, "switch"))
5521 goto bail;
5522
5523 updateRegisters(meth, insnFlags, regTable, absOffset, workRegs);
5524 }
5525 }
5526
5527 /*
5528 * Handle instructions that can throw and that are sitting in a
5529 * "try" block. (If they're not in a "try" block when they throw,
5530 * control transfers out of the method.)
5531 */
5532 if ((nextFlags & kInstrCanThrow) != 0 && dvmInsnIsInTry(insnFlags, insnIdx))
5533 {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005534 const DexCode* pCode = dvmGetMethodCode(meth);
5535 DexCatchIterator iterator;
5536
5537 if (dexFindCatchHandler(&iterator, pCode, insnIdx)) {
5538 for (;;) {
5539 DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
5540
5541 if (handler == NULL) {
5542 break;
5543 }
5544
5545 /* note we use entryRegs, not workRegs */
5546 updateRegisters(meth, insnFlags, regTable, handler->address,
5547 entryRegs);
5548 }
5549 }
5550 }
5551
5552 /*
5553 * Update startGuess. Advance to the next instruction of that's
5554 * possible, otherwise use the branch target if one was found. If
5555 * neither of those exists we're in a return or throw; leave startGuess
5556 * alone and let the caller sort it out.
5557 */
5558 if ((nextFlags & kInstrCanContinue) != 0) {
5559 *pStartGuess = insnIdx + dvmInsnGetWidth(insnFlags, insnIdx);
5560 } else if ((nextFlags & kInstrCanBranch) != 0) {
5561 /* we're still okay if branchTarget is zero */
5562 *pStartGuess = insnIdx + branchTarget;
5563 }
5564
5565 assert(*pStartGuess >= 0 && *pStartGuess < insnsSize &&
5566 dvmInsnGetWidth(insnFlags, *pStartGuess) != 0);
5567
5568 result = true;
5569
5570bail:
5571 return result;
5572}
5573
Andy McFaddenb51ea112009-05-08 16:50:17 -07005574
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005575/*
5576 * callback function used in dumpRegTypes to print local vars
5577 * valid at a given address.
5578 */
5579static void logLocalsCb(void *cnxt, u2 reg, u4 startAddress, u4 endAddress,
5580 const char *name, const char *descriptor,
5581 const char *signature)
5582{
5583 int addr = *((int *)cnxt);
5584
5585 if (addr >= (int) startAddress && addr < (int) endAddress)
5586 {
5587 LOGI(" %2d: '%s' %s\n", reg, name, descriptor);
5588 }
5589}
5590
5591/*
5592 * Dump the register types for the specifed address to the log file.
5593 */
5594static void dumpRegTypes(const Method* meth, const InsnFlags* insnFlags,
5595 const RegType* addrRegs, int addr, const char* addrName,
5596 const UninitInstanceMap* uninitMap, int displayFlags)
5597{
5598 int regCount = meth->registersSize;
5599 int fullRegCount = regCount + kExtraRegs;
5600 bool branchTarget = dvmInsnIsBranchTarget(insnFlags, addr);
5601 int i;
5602
5603 assert(addr >= 0 && addr < (int) dvmGetMethodInsnsSize(meth));
5604
5605 int regCharSize = fullRegCount + (fullRegCount-1)/4 + 2 +1;
5606 char regChars[regCharSize +1];
5607 memset(regChars, ' ', regCharSize);
5608 regChars[0] = '[';
5609 if (regCount == 0)
5610 regChars[1] = ']';
5611 else
5612 regChars[1 + (regCount-1) + (regCount-1)/4 +1] = ']';
5613 regChars[regCharSize] = '\0';
5614
5615 //const RegType* addrRegs = getRegisterLine(regTable, addr);
5616
5617 for (i = 0; i < regCount + kExtraRegs; i++) {
5618 char tch;
5619
5620 switch (addrRegs[i]) {
5621 case kRegTypeUnknown: tch = '.'; break;
5622 case kRegTypeConflict: tch = 'X'; break;
5623 case kRegTypeFloat: tch = 'F'; break;
5624 case kRegTypeZero: tch = '0'; break;
5625 case kRegTypeOne: tch = '1'; break;
5626 case kRegTypeBoolean: tch = 'Z'; break;
5627 case kRegTypePosByte: tch = 'b'; break;
5628 case kRegTypeByte: tch = 'B'; break;
5629 case kRegTypePosShort: tch = 's'; break;
5630 case kRegTypeShort: tch = 'S'; break;
5631 case kRegTypeChar: tch = 'C'; break;
5632 case kRegTypeInteger: tch = 'I'; break;
5633 case kRegTypeLongLo: tch = 'J'; break;
5634 case kRegTypeLongHi: tch = 'j'; break;
5635 case kRegTypeDoubleLo: tch = 'D'; break;
5636 case kRegTypeDoubleHi: tch = 'd'; break;
5637 default:
5638 if (regTypeIsReference(addrRegs[i])) {
5639 if (regTypeIsUninitReference(addrRegs[i]))
5640 tch = 'U';
5641 else
5642 tch = 'L';
5643 } else {
5644 tch = '*';
5645 assert(false);
5646 }
5647 break;
5648 }
5649
5650 if (i < regCount)
5651 regChars[1 + i + (i/4)] = tch;
5652 else
5653 regChars[1 + i + (i/4) + 2] = tch;
5654 }
5655
5656 if (addr == 0 && addrName != NULL)
5657 LOGI("%c%s %s\n", branchTarget ? '>' : ' ', addrName, regChars);
5658 else
5659 LOGI("%c0x%04x %s\n", branchTarget ? '>' : ' ', addr, regChars);
5660
5661 if (displayFlags & DRT_SHOW_REF_TYPES) {
5662 for (i = 0; i < regCount + kExtraRegs; i++) {
5663 if (regTypeIsReference(addrRegs[i]) && addrRegs[i] != kRegTypeZero)
5664 {
5665 ClassObject* clazz;
5666
5667 clazz = regTypeReferenceToClass(addrRegs[i], uninitMap);
5668 assert(dvmValidateObject((Object*)clazz));
5669 if (i < regCount) {
5670 LOGI(" %2d: 0x%08x %s%s\n",
5671 i, addrRegs[i],
5672 regTypeIsUninitReference(addrRegs[i]) ? "[U]" : "",
5673 clazz->descriptor);
5674 } else {
5675 LOGI(" RS: 0x%08x %s%s\n",
5676 addrRegs[i],
5677 regTypeIsUninitReference(addrRegs[i]) ? "[U]" : "",
5678 clazz->descriptor);
5679 }
5680 }
5681 }
5682 }
5683 if (displayFlags & DRT_SHOW_LOCALS) {
5684 dexDecodeDebugInfo(meth->clazz->pDvmDex->pDexFile,
5685 dvmGetMethodCode(meth),
5686 meth->clazz->descriptor,
5687 meth->prototype.protoIdx,
5688 meth->accessFlags,
5689 NULL, logLocalsCb, &addr);
5690 }
5691}