blob: b76ce75af2ef2e433eb03063588938e4e1f7f302 [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/*
360 * Create a new uninitialized instance map.
361 *
362 * The map is allocated and populated with address entries. The addresses
363 * appear in ascending order to allow binary searching.
364 *
365 * Very few methods have 10 or more new-instance instructions; the
366 * majority have 0 or 1. Occasionally a static initializer will have 200+.
367 */
368UninitInstanceMap* dvmCreateUninitInstanceMap(const Method* meth,
369 const InsnFlags* insnFlags, int newInstanceCount)
370{
371 const int insnsSize = dvmGetMethodInsnsSize(meth);
372 const u2* insns = meth->insns;
373 UninitInstanceMap* uninitMap;
374 bool isInit = false;
375 int idx, addr;
376
377 if (isInitMethod(meth)) {
378 newInstanceCount++;
379 isInit = true;
380 }
381
382 /*
383 * Allocate the header and map as a single unit.
384 *
385 * TODO: consider having a static instance so we can avoid allocations.
386 * I don't think the verifier is guaranteed to be single-threaded when
387 * running in the VM (rather than dexopt), so that must be taken into
388 * account.
389 */
390 int size = offsetof(UninitInstanceMap, map) +
391 newInstanceCount * sizeof(uninitMap->map[0]);
392 uninitMap = calloc(1, size);
393 if (uninitMap == NULL)
394 return NULL;
395 uninitMap->numEntries = newInstanceCount;
396
397 idx = 0;
398 if (isInit) {
399 uninitMap->map[idx++].addr = kUninitThisArgAddr;
400 }
401
402 /*
403 * Run through and find the new-instance instructions.
404 */
405 for (addr = 0; addr < insnsSize; /**/) {
406 int width = dvmInsnGetWidth(insnFlags, addr);
407
408 if ((*insns & 0xff) == OP_NEW_INSTANCE)
409 uninitMap->map[idx++].addr = addr;
410
411 addr += width;
412 insns += width;
413 }
414
415 assert(idx == newInstanceCount);
416 return uninitMap;
417}
418
419/*
420 * Free the map.
421 */
422void dvmFreeUninitInstanceMap(UninitInstanceMap* uninitMap)
423{
424 free(uninitMap);
425}
426
427/*
428 * Set the class object associated with the instruction at "addr".
429 *
430 * Returns the map slot index, or -1 if the address isn't listed in the map
431 * (shouldn't happen) or if a class is already associated with the address
432 * (bad bytecode).
433 *
434 * Entries, once set, do not change -- a given address can only allocate
435 * one type of object.
436 */
437int dvmSetUninitInstance(UninitInstanceMap* uninitMap, int addr,
438 ClassObject* clazz)
439{
440 int idx;
441
442 assert(clazz != NULL);
443
444 /* TODO: binary search when numEntries > 8 */
445 for (idx = uninitMap->numEntries - 1; idx >= 0; idx--) {
446 if (uninitMap->map[idx].addr == addr) {
447 if (uninitMap->map[idx].clazz != NULL &&
448 uninitMap->map[idx].clazz != clazz)
449 {
450 LOG_VFY("VFY: addr %d already set to %p, not setting to %p\n",
451 addr, uninitMap->map[idx].clazz, clazz);
452 return -1; // already set to something else??
453 }
454 uninitMap->map[idx].clazz = clazz;
455 return idx;
456 }
457 }
458
459 LOG_VFY("VFY: addr %d not found in uninit map\n", addr);
460 assert(false); // shouldn't happen
461 return -1;
462}
463
464/*
465 * Get the class object at the specified index.
466 */
467ClassObject* dvmGetUninitInstance(const UninitInstanceMap* uninitMap, int idx)
468{
469 assert(idx >= 0 && idx < uninitMap->numEntries);
470 return uninitMap->map[idx].clazz;
471}
472
473/* determine if "type" is actually an object reference (init/uninit/zero) */
474static inline bool regTypeIsReference(RegType type) {
475 return (type > kRegTypeMAX || type == kRegTypeUninit ||
476 type == kRegTypeZero);
477}
478
479/* determine if "type" is an uninitialized object reference */
480static inline bool regTypeIsUninitReference(RegType type) {
481 return ((type & kRegTypeUninitMask) == kRegTypeUninit);
482}
483
484/* convert the initialized reference "type" to a ClassObject pointer */
485/* (does not expect uninit ref types or "zero") */
486static ClassObject* regTypeInitializedReferenceToClass(RegType type)
487{
488 assert(regTypeIsReference(type) && type != kRegTypeZero);
489 if ((type & 0x01) == 0) {
490 return (ClassObject*) type;
491 } else {
492 //LOG_VFY("VFY: attempted to use uninitialized reference\n");
493 return NULL;
494 }
495}
496
497/* extract the index into the uninitialized instance map table */
498static inline int regTypeToUninitIndex(RegType type) {
499 assert(regTypeIsUninitReference(type));
500 return (type & ~kRegTypeUninitMask) >> kRegTypeUninitShift;
501}
502
503/* convert the reference "type" to a ClassObject pointer */
504static ClassObject* regTypeReferenceToClass(RegType type,
505 const UninitInstanceMap* uninitMap)
506{
507 assert(regTypeIsReference(type) && type != kRegTypeZero);
508 if (regTypeIsUninitReference(type)) {
509 assert(uninitMap != NULL);
510 return dvmGetUninitInstance(uninitMap, regTypeToUninitIndex(type));
511 } else {
512 return (ClassObject*) type;
513 }
514}
515
516/* convert the ClassObject pointer to an (initialized) register type */
517static inline RegType regTypeFromClass(ClassObject* clazz) {
518 return (u4) clazz;
519}
520
521/* return the RegType for the uninitialized reference in slot "uidx" */
522static RegType regTypeFromUninitIndex(int uidx) {
523 return (u4) (kRegTypeUninit | (uidx << kRegTypeUninitShift));
524}
525
526
527/*
528 * ===========================================================================
529 * Signature operations
530 * ===========================================================================
531 */
532
533/*
534 * Is this method a constructor?
535 */
536static bool isInitMethod(const Method* meth)
537{
538 return (*meth->name == '<' && strcmp(meth->name+1, "init>") == 0);
539}
540
541/*
542 * Is this method a class initializer?
543 */
Carl Shapiroe3c01da2010-05-20 22:54:18 -0700544#if 0
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800545static bool isClassInitMethod(const Method* meth)
546{
547 return (*meth->name == '<' && strcmp(meth->name+1, "clinit>") == 0);
548}
Carl Shapiroe3c01da2010-05-20 22:54:18 -0700549#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800550
551/*
552 * Look up a class reference given as a simple string descriptor.
Andy McFadden62a75162009-04-17 17:23:37 -0700553 *
554 * If we can't find it, return a generic substitute when possible.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800555 */
556static ClassObject* lookupClassByDescriptor(const Method* meth,
Andy McFadden62a75162009-04-17 17:23:37 -0700557 const char* pDescriptor, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800558{
559 /*
560 * The javac compiler occasionally puts references to nonexistent
561 * classes in signatures. For example, if you have a non-static
562 * inner class with no constructor, the compiler provides
563 * a private <init> for you. Constructing the class
564 * requires <init>(parent), but the outer class can't call
565 * that because the method is private. So the compiler
566 * generates a package-scope <init>(parent,bogus) method that
567 * just calls the regular <init> (the "bogus" part being necessary
568 * to distinguish the signature of the synthetic method).
569 * Treating the bogus class as an instance of java.lang.Object
570 * allows the verifier to process the class successfully.
571 */
572
573 //LOGI("Looking up '%s'\n", typeStr);
574 ClassObject* clazz;
575 clazz = dvmFindClassNoInit(pDescriptor, meth->clazz->classLoader);
576 if (clazz == NULL) {
577 dvmClearOptException(dvmThreadSelf());
578 if (strchr(pDescriptor, '$') != NULL) {
579 LOGV("VFY: unable to find class referenced in signature (%s)\n",
580 pDescriptor);
581 } else {
582 LOG_VFY("VFY: unable to find class referenced in signature (%s)\n",
583 pDescriptor);
584 }
585
586 if (pDescriptor[0] == '[') {
587 /* We are looking at an array descriptor. */
588
589 /*
590 * There should never be a problem loading primitive arrays.
591 */
592 if (pDescriptor[1] != 'L' && pDescriptor[1] != '[') {
593 LOG_VFY("VFY: invalid char in signature in '%s'\n",
594 pDescriptor);
Andy McFadden62a75162009-04-17 17:23:37 -0700595 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800596 }
597
598 /*
599 * Try to continue with base array type. This will let
600 * us pass basic stuff (e.g. get array len) that wouldn't
601 * fly with an Object. This is NOT correct if the
602 * missing type is a primitive array, but we should never
603 * have a problem loading those. (I'm not convinced this
604 * is correct or even useful. Just use Object here?)
605 */
606 clazz = dvmFindClassNoInit("[Ljava/lang/Object;",
607 meth->clazz->classLoader);
608 } else if (pDescriptor[0] == 'L') {
609 /*
610 * We are looking at a non-array reference descriptor;
611 * try to continue with base reference type.
612 */
613 clazz = gDvm.classJavaLangObject;
614 } else {
615 /* We are looking at a primitive type. */
616 LOG_VFY("VFY: invalid char in signature in '%s'\n", pDescriptor);
Andy McFadden62a75162009-04-17 17:23:37 -0700617 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800618 }
619
620 if (clazz == NULL) {
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 if (dvmIsPrimitiveClass(clazz)) {
626 LOG_VFY("VFY: invalid use of primitive type '%s'\n", pDescriptor);
Andy McFadden62a75162009-04-17 17:23:37 -0700627 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800628 clazz = NULL;
629 }
630
631 return clazz;
632}
633
634/*
635 * Look up a class reference in a signature. Could be an arg or the
636 * return value.
637 *
638 * Advances "*pSig" to the last character in the signature (that is, to
639 * the ';').
640 *
641 * NOTE: this is also expected to verify the signature.
642 */
643static ClassObject* lookupSignatureClass(const Method* meth, const char** pSig,
Andy McFadden62a75162009-04-17 17:23:37 -0700644 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800645{
646 const char* sig = *pSig;
647 const char* endp = sig;
648
649 assert(sig != NULL && *sig == 'L');
650
651 while (*++endp != ';' && *endp != '\0')
652 ;
653 if (*endp != ';') {
654 LOG_VFY("VFY: bad signature component '%s' (missing ';')\n", sig);
Andy McFadden62a75162009-04-17 17:23:37 -0700655 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800656 return NULL;
657 }
658
659 endp++; /* Advance past the ';'. */
660 int typeLen = endp - sig;
661 char typeStr[typeLen+1]; /* +1 for the '\0' */
662 memcpy(typeStr, sig, typeLen);
663 typeStr[typeLen] = '\0';
664
665 *pSig = endp - 1; /* - 1 so that *pSig points at, not past, the ';' */
666
Andy McFadden62a75162009-04-17 17:23:37 -0700667 return lookupClassByDescriptor(meth, typeStr, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800668}
669
670/*
671 * Look up an array class reference in a signature. Could be an arg or the
672 * return value.
673 *
674 * Advances "*pSig" to the last character in the signature.
675 *
676 * NOTE: this is also expected to verify the signature.
677 */
678static ClassObject* lookupSignatureArrayClass(const Method* meth,
Andy McFadden62a75162009-04-17 17:23:37 -0700679 const char** pSig, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800680{
681 const char* sig = *pSig;
682 const char* endp = sig;
683
684 assert(sig != NULL && *sig == '[');
685
686 /* find the end */
687 while (*++endp == '[' && *endp != '\0')
688 ;
689
690 if (*endp == 'L') {
691 while (*++endp != ';' && *endp != '\0')
692 ;
693 if (*endp != ';') {
694 LOG_VFY("VFY: bad signature component '%s' (missing ';')\n", sig);
Andy McFadden62a75162009-04-17 17:23:37 -0700695 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800696 return NULL;
697 }
698 }
699
700 int typeLen = endp - sig +1;
701 char typeStr[typeLen+1];
702 memcpy(typeStr, sig, typeLen);
703 typeStr[typeLen] = '\0';
704
705 *pSig = endp;
706
Andy McFadden62a75162009-04-17 17:23:37 -0700707 return lookupClassByDescriptor(meth, typeStr, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800708}
709
710/*
711 * Set the register types for the first instruction in the method based on
712 * the method signature.
713 *
714 * This has the side-effect of validating the signature.
715 *
716 * Returns "true" on success.
717 */
718static bool setTypesFromSignature(const Method* meth, RegType* regTypes,
719 UninitInstanceMap* uninitMap)
720{
721 DexParameterIterator iterator;
722 int actualArgs, expectedArgs, argStart;
Andy McFadden62a75162009-04-17 17:23:37 -0700723 VerifyError failure = VERIFY_ERROR_NONE;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800724
725 dexParameterIteratorInit(&iterator, &meth->prototype);
726 argStart = meth->registersSize - meth->insSize;
727 expectedArgs = meth->insSize; /* long/double count as two */
728 actualArgs = 0;
729
730 assert(argStart >= 0); /* should have been verified earlier */
731
732 /*
733 * Include the "this" pointer.
734 */
735 if (!dvmIsStaticMethod(meth)) {
736 /*
737 * If this is a constructor for a class other than java.lang.Object,
738 * mark the first ("this") argument as uninitialized. This restricts
739 * field access until the superclass constructor is called.
740 */
741 if (isInitMethod(meth) && meth->clazz != gDvm.classJavaLangObject) {
742 int uidx = dvmSetUninitInstance(uninitMap, kUninitThisArgAddr,
743 meth->clazz);
744 assert(uidx == 0);
745 regTypes[argStart + actualArgs] = regTypeFromUninitIndex(uidx);
746 } else {
747 regTypes[argStart + actualArgs] = regTypeFromClass(meth->clazz);
748 }
749 actualArgs++;
750 }
751
752 for (;;) {
753 const char* descriptor = dexParameterIteratorNextDescriptor(&iterator);
754
755 if (descriptor == NULL) {
756 break;
757 }
758
759 if (actualArgs >= expectedArgs) {
760 LOG_VFY("VFY: expected %d args, found more (%s)\n",
761 expectedArgs, descriptor);
762 goto bad_sig;
763 }
764
765 switch (*descriptor) {
766 case 'L':
767 case '[':
768 /*
769 * We assume that reference arguments are initialized. The
770 * only way it could be otherwise (assuming the caller was
771 * verified) is if the current method is <init>, but in that
772 * case it's effectively considered initialized the instant
773 * we reach here (in the sense that we can return without
774 * doing anything or call virtual methods).
775 */
776 {
777 ClassObject* clazz =
Andy McFadden62a75162009-04-17 17:23:37 -0700778 lookupClassByDescriptor(meth, descriptor, &failure);
779 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800780 goto bad_sig;
781 regTypes[argStart + actualArgs] = regTypeFromClass(clazz);
782 }
783 actualArgs++;
784 break;
785 case 'Z':
786 regTypes[argStart + actualArgs] = kRegTypeBoolean;
787 actualArgs++;
788 break;
789 case 'C':
790 regTypes[argStart + actualArgs] = kRegTypeChar;
791 actualArgs++;
792 break;
793 case 'B':
794 regTypes[argStart + actualArgs] = kRegTypeByte;
795 actualArgs++;
796 break;
797 case 'I':
798 regTypes[argStart + actualArgs] = kRegTypeInteger;
799 actualArgs++;
800 break;
801 case 'S':
802 regTypes[argStart + actualArgs] = kRegTypeShort;
803 actualArgs++;
804 break;
805 case 'F':
806 regTypes[argStart + actualArgs] = kRegTypeFloat;
807 actualArgs++;
808 break;
809 case 'D':
810 regTypes[argStart + actualArgs] = kRegTypeDoubleLo;
811 regTypes[argStart + actualArgs +1] = kRegTypeDoubleHi;
812 actualArgs += 2;
813 break;
814 case 'J':
815 regTypes[argStart + actualArgs] = kRegTypeLongLo;
816 regTypes[argStart + actualArgs +1] = kRegTypeLongHi;
817 actualArgs += 2;
818 break;
819 default:
820 LOG_VFY("VFY: unexpected signature type char '%c'\n", *descriptor);
821 goto bad_sig;
822 }
823 }
824
825 if (actualArgs != expectedArgs) {
826 LOG_VFY("VFY: expected %d args, found %d\n", expectedArgs, actualArgs);
827 goto bad_sig;
828 }
829
830 const char* descriptor = dexProtoGetReturnType(&meth->prototype);
831
832 /*
833 * Validate return type. We don't do the type lookup; just want to make
834 * sure that it has the right format. Only major difference from the
835 * method argument format is that 'V' is supported.
836 */
837 switch (*descriptor) {
838 case 'I':
839 case 'C':
840 case 'S':
841 case 'B':
842 case 'Z':
843 case 'V':
844 case 'F':
845 case 'D':
846 case 'J':
847 if (*(descriptor+1) != '\0')
848 goto bad_sig;
849 break;
850 case '[':
851 /* single/multi, object/primitive */
852 while (*++descriptor == '[')
853 ;
854 if (*descriptor == 'L') {
855 while (*++descriptor != ';' && *descriptor != '\0')
856 ;
857 if (*descriptor != ';')
858 goto bad_sig;
859 } else {
860 if (*(descriptor+1) != '\0')
861 goto bad_sig;
862 }
863 break;
864 case 'L':
865 /* could be more thorough here, but shouldn't be required */
866 while (*++descriptor != ';' && *descriptor != '\0')
867 ;
868 if (*descriptor != ';')
869 goto bad_sig;
870 break;
871 default:
872 goto bad_sig;
873 }
874
875 return true;
876
877//fail:
878// LOG_VFY_METH(meth, "VFY: bad sig\n");
879// return false;
880
881bad_sig:
882 {
883 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
884 LOG_VFY("VFY: bad signature '%s' for %s.%s\n",
885 desc, meth->clazz->descriptor, meth->name);
886 free(desc);
887 }
888 return false;
889}
890
891/*
892 * Return the register type for the method. We can't just use the
893 * already-computed DalvikJniReturnType, because if it's a reference type
894 * we need to do the class lookup.
895 *
896 * Returned references are assumed to be initialized.
897 *
898 * Returns kRegTypeUnknown for "void".
899 */
900static RegType getMethodReturnType(const Method* meth)
901{
902 RegType type;
903 const char* descriptor = dexProtoGetReturnType(&meth->prototype);
904
905 switch (*descriptor) {
906 case 'I':
907 type = kRegTypeInteger;
908 break;
909 case 'C':
910 type = kRegTypeChar;
911 break;
912 case 'S':
913 type = kRegTypeShort;
914 break;
915 case 'B':
916 type = kRegTypeByte;
917 break;
918 case 'Z':
919 type = kRegTypeBoolean;
920 break;
921 case 'V':
922 type = kRegTypeUnknown;
923 break;
924 case 'F':
925 type = kRegTypeFloat;
926 break;
927 case 'D':
928 type = kRegTypeDoubleLo;
929 break;
930 case 'J':
931 type = kRegTypeLongLo;
932 break;
933 case 'L':
934 case '[':
935 {
Andy McFadden62a75162009-04-17 17:23:37 -0700936 VerifyError failure = VERIFY_ERROR_NONE;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800937 ClassObject* clazz =
Andy McFadden62a75162009-04-17 17:23:37 -0700938 lookupClassByDescriptor(meth, descriptor, &failure);
939 assert(VERIFY_OK(failure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800940 type = regTypeFromClass(clazz);
941 }
942 break;
943 default:
944 /* we verified signature return type earlier, so this is impossible */
945 assert(false);
946 type = kRegTypeConflict;
947 break;
948 }
949
950 return type;
951}
952
953/*
954 * Convert a single-character signature value (i.e. a primitive type) to
955 * the corresponding RegType. This is intended for access to object fields
956 * holding primitive types.
957 *
958 * Returns kRegTypeUnknown for objects, arrays, and void.
959 */
960static RegType primSigCharToRegType(char sigChar)
961{
962 RegType type;
963
964 switch (sigChar) {
965 case 'I':
966 type = kRegTypeInteger;
967 break;
968 case 'C':
969 type = kRegTypeChar;
970 break;
971 case 'S':
972 type = kRegTypeShort;
973 break;
974 case 'B':
975 type = kRegTypeByte;
976 break;
977 case 'Z':
978 type = kRegTypeBoolean;
979 break;
980 case 'F':
981 type = kRegTypeFloat;
982 break;
983 case 'D':
984 type = kRegTypeDoubleLo;
985 break;
986 case 'J':
987 type = kRegTypeLongLo;
988 break;
989 case 'V':
990 case 'L':
991 case '[':
992 type = kRegTypeUnknown;
993 break;
994 default:
995 assert(false);
996 type = kRegTypeUnknown;
997 break;
998 }
999
1000 return type;
1001}
1002
1003/*
Andy McFadden99a33e72010-10-10 12:59:11 -07001004 * See if the method matches the MethodType.
1005 */
1006static bool isCorrectInvokeKind(MethodType methodType, Method* resMethod)
1007{
1008 switch (methodType) {
1009 case METHOD_DIRECT:
1010 return dvmIsDirectMethod(resMethod);
1011 case METHOD_STATIC:
1012 return dvmIsStaticMethod(resMethod);
1013 case METHOD_VIRTUAL:
1014 case METHOD_INTERFACE:
1015 return !dvmIsDirectMethod(resMethod);
1016 default:
1017 return false;
1018 }
1019}
1020
1021/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001022 * Verify the arguments to a method. We're executing in "method", making
1023 * a call to the method reference in vB.
1024 *
1025 * If this is a "direct" invoke, we allow calls to <init>. For calls to
1026 * <init>, the first argument may be an uninitialized reference. Otherwise,
1027 * calls to anything starting with '<' will be rejected, as will any
1028 * uninitialized reference arguments.
1029 *
1030 * For non-static method calls, this will verify that the method call is
1031 * appropriate for the "this" argument.
1032 *
1033 * The method reference is in vBBBB. The "isRange" parameter determines
1034 * whether we use 0-4 "args" values or a range of registers defined by
1035 * vAA and vCCCC.
1036 *
1037 * Widening conversions on integers and references are allowed, but
1038 * narrowing conversions are not.
1039 *
Andy McFadden62a75162009-04-17 17:23:37 -07001040 * Returns the resolved method on success, NULL on failure (with *pFailure
1041 * set appropriately).
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001042 */
1043static Method* verifyInvocationArgs(const Method* meth, const RegType* insnRegs,
1044 const int insnRegCount, const DecodedInstruction* pDecInsn,
1045 UninitInstanceMap* uninitMap, MethodType methodType, bool isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07001046 bool isSuper, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001047{
1048 Method* resMethod;
1049 char* sigOriginal = NULL;
1050
1051 /*
1052 * Resolve the method. This could be an abstract or concrete method
1053 * depending on what sort of call we're making.
1054 */
1055 if (methodType == METHOD_INTERFACE) {
1056 resMethod = dvmOptResolveInterfaceMethod(meth->clazz, pDecInsn->vB);
1057 } else {
Andy McFadden62a75162009-04-17 17:23:37 -07001058 resMethod = dvmOptResolveMethod(meth->clazz, pDecInsn->vB, methodType,
1059 pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001060 }
1061 if (resMethod == NULL) {
1062 /* failed; print a meaningful failure message */
1063 DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
1064 const DexMethodId* pMethodId;
1065 const char* methodName;
1066 char* methodDesc;
1067 const char* classDescriptor;
1068
1069 pMethodId = dexGetMethodId(pDexFile, pDecInsn->vB);
1070 methodName = dexStringById(pDexFile, pMethodId->nameIdx);
1071 methodDesc = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
1072 classDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
1073
1074 if (!gDvm.optimizing) {
1075 char* dotMissingClass = dvmDescriptorToDot(classDescriptor);
1076 char* dotMethClass = dvmDescriptorToDot(meth->clazz->descriptor);
1077 //char* curMethodDesc =
1078 // dexProtoCopyMethodDescriptor(&meth->prototype);
1079
Andy McFadden99a33e72010-10-10 12:59:11 -07001080 LOGI("Could not find method %s.%s, referenced from method %s.%s\n",
1081 dotMissingClass, methodName/*, methodDesc*/,
1082 dotMethClass, meth->name/*, curMethodDesc*/);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001083
1084 free(dotMissingClass);
1085 free(dotMethClass);
1086 //free(curMethodDesc);
1087 }
1088
1089 LOG_VFY("VFY: unable to resolve %s method %u: %s.%s %s\n",
1090 dvmMethodTypeStr(methodType), pDecInsn->vB,
1091 classDescriptor, methodName, methodDesc);
1092 free(methodDesc);
Andy McFaddenb51ea112009-05-08 16:50:17 -07001093 if (VERIFY_OK(*pFailure)) /* not set for interface resolve */
1094 *pFailure = VERIFY_ERROR_NO_METHOD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001095 goto fail;
1096 }
1097
1098 /*
1099 * Only time you can explicitly call a method starting with '<' is when
1100 * making a "direct" invocation on "<init>". There are additional
1101 * restrictions but we don't enforce them here.
1102 */
1103 if (resMethod->name[0] == '<') {
1104 if (methodType != METHOD_DIRECT || !isInitMethod(resMethod)) {
1105 LOG_VFY("VFY: invalid call to %s.%s\n",
1106 resMethod->clazz->descriptor, resMethod->name);
1107 goto bad_sig;
1108 }
1109 }
1110
1111 /*
Andy McFadden99a33e72010-10-10 12:59:11 -07001112 * See if the method type implied by the invoke instruction matches the
1113 * access flags for the target method.
1114 */
1115 if (!isCorrectInvokeKind(methodType, resMethod)) {
1116 LOG_VFY("VFY: invoke type does not match method type of %s.%s\n",
1117 resMethod->clazz->descriptor, resMethod->name);
1118 goto fail;
1119 }
1120
1121 /*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001122 * If we're using invoke-super(method), make sure that the executing
1123 * method's class' superclass has a vtable entry for the target method.
1124 */
1125 if (isSuper) {
1126 assert(methodType == METHOD_VIRTUAL);
1127 ClassObject* super = meth->clazz->super;
1128 if (super == NULL || resMethod->methodIndex > super->vtableCount) {
1129 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1130 LOG_VFY("VFY: invalid invoke-super from %s.%s to super %s.%s %s\n",
1131 meth->clazz->descriptor, meth->name,
1132 (super == NULL) ? "-" : super->descriptor,
1133 resMethod->name, desc);
1134 free(desc);
Andy McFadden62a75162009-04-17 17:23:37 -07001135 *pFailure = VERIFY_ERROR_NO_METHOD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001136 goto fail;
1137 }
1138 }
1139
1140 /*
1141 * We use vAA as our expected arg count, rather than resMethod->insSize,
1142 * because we need to match the call to the signature. Also, we might
1143 * might be calling through an abstract method definition (which doesn't
1144 * have register count values).
1145 */
1146 sigOriginal = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1147 const char* sig = sigOriginal;
1148 int expectedArgs = pDecInsn->vA;
1149 int actualArgs = 0;
1150
Andy McFaddend3250112010-11-03 14:32:42 -07001151 /* caught by static verifier */
1152 assert(isRange || expectedArgs <= 5);
1153
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001154 if (expectedArgs > meth->outsSize) {
1155 LOG_VFY("VFY: invalid arg count (%d) exceeds outsSize (%d)\n",
1156 expectedArgs, meth->outsSize);
1157 goto fail;
1158 }
1159
1160 if (*sig++ != '(')
1161 goto bad_sig;
1162
1163 /*
1164 * Check the "this" argument, which must be an instance of the class
1165 * that declared the method. For an interface class, we don't do the
1166 * full interface merge, so we can't do a rigorous check here (which
1167 * is okay since we have to do it at runtime).
1168 */
1169 if (!dvmIsStaticMethod(resMethod)) {
1170 ClassObject* actualThisRef;
1171 RegType actualArgType;
1172
Andy McFaddend3250112010-11-03 14:32:42 -07001173 actualArgType = getInvocationThis(insnRegs, pDecInsn, pFailure);
Andy McFadden62a75162009-04-17 17:23:37 -07001174 if (!VERIFY_OK(*pFailure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001175 goto fail;
1176
1177 if (regTypeIsUninitReference(actualArgType) && resMethod->name[0] != '<')
1178 {
1179 LOG_VFY("VFY: 'this' arg must be initialized\n");
1180 goto fail;
1181 }
1182 if (methodType != METHOD_INTERFACE && actualArgType != kRegTypeZero) {
1183 actualThisRef = regTypeReferenceToClass(actualArgType, uninitMap);
1184 if (!dvmInstanceof(actualThisRef, resMethod->clazz)) {
1185 LOG_VFY("VFY: 'this' arg '%s' not instance of '%s'\n",
1186 actualThisRef->descriptor,
1187 resMethod->clazz->descriptor);
1188 goto fail;
1189 }
1190 }
1191 actualArgs++;
1192 }
1193
1194 /*
1195 * Process the target method's signature. This signature may or may not
1196 * have been verified, so we can't assume it's properly formed.
1197 */
1198 while (*sig != '\0' && *sig != ')') {
1199 if (actualArgs >= expectedArgs) {
1200 LOG_VFY("VFY: expected %d args, found more (%c)\n",
1201 expectedArgs, *sig);
1202 goto bad_sig;
1203 }
1204
1205 u4 getReg;
1206 if (isRange)
1207 getReg = pDecInsn->vC + actualArgs;
1208 else
1209 getReg = pDecInsn->arg[actualArgs];
1210
1211 switch (*sig) {
1212 case 'L':
1213 {
Andy McFadden62a75162009-04-17 17:23:37 -07001214 ClassObject* clazz = lookupSignatureClass(meth, &sig, pFailure);
1215 if (!VERIFY_OK(*pFailure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001216 goto bad_sig;
Andy McFaddend3250112010-11-03 14:32:42 -07001217 verifyRegisterType(insnRegs, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001218 regTypeFromClass(clazz), pFailure);
1219 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001220 LOG_VFY("VFY: bad arg %d (into %s)\n",
1221 actualArgs, clazz->descriptor);
1222 goto bad_sig;
1223 }
1224 }
1225 actualArgs++;
1226 break;
1227 case '[':
1228 {
1229 ClassObject* clazz =
Andy McFadden62a75162009-04-17 17:23:37 -07001230 lookupSignatureArrayClass(meth, &sig, pFailure);
1231 if (!VERIFY_OK(*pFailure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001232 goto bad_sig;
Andy McFaddend3250112010-11-03 14:32:42 -07001233 verifyRegisterType(insnRegs, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001234 regTypeFromClass(clazz), pFailure);
1235 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001236 LOG_VFY("VFY: bad arg %d (into %s)\n",
1237 actualArgs, clazz->descriptor);
1238 goto bad_sig;
1239 }
1240 }
1241 actualArgs++;
1242 break;
1243 case 'Z':
Andy McFaddend3250112010-11-03 14:32:42 -07001244 verifyRegisterType(insnRegs, getReg, kRegTypeBoolean, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001245 actualArgs++;
1246 break;
1247 case 'C':
Andy McFaddend3250112010-11-03 14:32:42 -07001248 verifyRegisterType(insnRegs, getReg, kRegTypeChar, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001249 actualArgs++;
1250 break;
1251 case 'B':
Andy McFaddend3250112010-11-03 14:32:42 -07001252 verifyRegisterType(insnRegs, getReg, kRegTypeByte, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001253 actualArgs++;
1254 break;
1255 case 'I':
Andy McFaddend3250112010-11-03 14:32:42 -07001256 verifyRegisterType(insnRegs, getReg, kRegTypeInteger, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001257 actualArgs++;
1258 break;
1259 case 'S':
Andy McFaddend3250112010-11-03 14:32:42 -07001260 verifyRegisterType(insnRegs, getReg, kRegTypeShort, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001261 actualArgs++;
1262 break;
1263 case 'F':
Andy McFaddend3250112010-11-03 14:32:42 -07001264 verifyRegisterType(insnRegs, getReg, kRegTypeFloat, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001265 actualArgs++;
1266 break;
1267 case 'D':
Andy McFaddend3250112010-11-03 14:32:42 -07001268 verifyRegisterType(insnRegs, getReg, kRegTypeDoubleLo, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001269 actualArgs += 2;
1270 break;
1271 case 'J':
Andy McFaddend3250112010-11-03 14:32:42 -07001272 verifyRegisterType(insnRegs, getReg, kRegTypeLongLo, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001273 actualArgs += 2;
1274 break;
1275 default:
1276 LOG_VFY("VFY: invocation target: bad signature type char '%c'\n",
1277 *sig);
1278 goto bad_sig;
1279 }
1280
1281 sig++;
1282 }
1283 if (*sig != ')') {
1284 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1285 LOG_VFY("VFY: invocation target: bad signature '%s'\n", desc);
1286 free(desc);
1287 goto bad_sig;
1288 }
1289
1290 if (actualArgs != expectedArgs) {
1291 LOG_VFY("VFY: expected %d args, found %d\n", expectedArgs, actualArgs);
1292 goto bad_sig;
1293 }
1294
1295 free(sigOriginal);
1296 return resMethod;
1297
1298bad_sig:
1299 if (resMethod != NULL) {
1300 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1301 LOG_VFY("VFY: rejecting call to %s.%s %s\n",
Andy McFadden62a75162009-04-17 17:23:37 -07001302 resMethod->clazz->descriptor, resMethod->name, desc);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001303 free(desc);
1304 }
1305
1306fail:
1307 free(sigOriginal);
Andy McFadden62a75162009-04-17 17:23:37 -07001308 if (*pFailure == VERIFY_ERROR_NONE)
1309 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001310 return NULL;
1311}
1312
1313/*
1314 * Get the class object for the type of data stored in a field. This isn't
1315 * stored in the Field struct, so we have to recover it from the signature.
1316 *
1317 * This only works for reference types. Don't call this for primitive types.
1318 *
1319 * If we can't find the class, we return java.lang.Object, so that
1320 * verification can continue if a field is only accessed in trivial ways.
1321 */
1322static ClassObject* getFieldClass(const Method* meth, const Field* field)
1323{
1324 ClassObject* fieldClass;
1325 const char* signature = field->signature;
1326
1327 if ((*signature == 'L') || (*signature == '[')) {
1328 fieldClass = dvmFindClassNoInit(signature,
1329 meth->clazz->classLoader);
1330 } else {
1331 return NULL;
1332 }
1333
1334 if (fieldClass == NULL) {
1335 dvmClearOptException(dvmThreadSelf());
1336 LOGV("VFY: unable to find class '%s' for field %s.%s, trying Object\n",
1337 field->signature, meth->clazz->descriptor, field->name);
1338 fieldClass = gDvm.classJavaLangObject;
1339 } else {
1340 assert(!dvmIsPrimitiveClass(fieldClass));
1341 }
1342 return fieldClass;
1343}
1344
1345
1346/*
1347 * ===========================================================================
1348 * Register operations
1349 * ===========================================================================
1350 */
1351
1352/*
Andy McFaddend3250112010-11-03 14:32:42 -07001353 * Get the type of register N.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001354 *
Andy McFaddend3250112010-11-03 14:32:42 -07001355 * The register index was validated during the static pass, so we don't
1356 * need to check it here.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001357 */
Andy McFaddend3250112010-11-03 14:32:42 -07001358static inline RegType getRegisterType(const RegType* insnRegs, u4 vsrc)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001359{
Andy McFaddend3250112010-11-03 14:32:42 -07001360 return insnRegs[vsrc];
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001361}
1362
1363/*
1364 * Get the value from a register, and cast it to a ClassObject. Sets
Andy McFadden62a75162009-04-17 17:23:37 -07001365 * "*pFailure" if something fails.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001366 *
1367 * This fails if the register holds an uninitialized class.
1368 *
1369 * If the register holds kRegTypeZero, this returns a NULL pointer.
1370 */
1371static ClassObject* getClassFromRegister(const RegType* insnRegs,
Andy McFaddend3250112010-11-03 14:32:42 -07001372 u4 vsrc, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001373{
1374 ClassObject* clazz = NULL;
1375 RegType type;
1376
1377 /* get the element type of the array held in vsrc */
Andy McFaddend3250112010-11-03 14:32:42 -07001378 type = getRegisterType(insnRegs, vsrc);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001379
1380 /* if "always zero", we allow it to fail at runtime */
1381 if (type == kRegTypeZero)
1382 goto bail;
1383
1384 if (!regTypeIsReference(type)) {
1385 LOG_VFY("VFY: tried to get class from non-ref register v%d (type=%d)\n",
1386 vsrc, type);
Andy McFadden62a75162009-04-17 17:23:37 -07001387 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001388 goto bail;
1389 }
1390 if (regTypeIsUninitReference(type)) {
1391 LOG_VFY("VFY: register %u holds uninitialized reference\n", vsrc);
Andy McFadden62a75162009-04-17 17:23:37 -07001392 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001393 goto bail;
1394 }
1395
1396 clazz = regTypeInitializedReferenceToClass(type);
1397
1398bail:
1399 return clazz;
1400}
1401
1402/*
1403 * Get the "this" pointer from a non-static method invocation. This
1404 * returns the RegType so the caller can decide whether it needs the
1405 * reference to be initialized or not. (Can also return kRegTypeZero
1406 * if the reference can only be zero at this point.)
1407 *
1408 * The argument count is in vA, and the first argument is in vC, for both
1409 * "simple" and "range" versions. We just need to make sure vA is >= 1
1410 * and then return vC.
1411 */
1412static RegType getInvocationThis(const RegType* insnRegs,
Andy McFaddend3250112010-11-03 14:32:42 -07001413 const DecodedInstruction* pDecInsn, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001414{
1415 RegType thisType = kRegTypeUnknown;
1416
1417 if (pDecInsn->vA < 1) {
1418 LOG_VFY("VFY: invoke lacks 'this'\n");
Andy McFadden62a75162009-04-17 17:23:37 -07001419 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001420 goto bail;
1421 }
1422
1423 /* get the element type of the array held in vsrc */
Andy McFaddend3250112010-11-03 14:32:42 -07001424 thisType = getRegisterType(insnRegs, pDecInsn->vC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001425 if (!regTypeIsReference(thisType)) {
1426 LOG_VFY("VFY: tried to get class from non-ref register v%d (type=%d)\n",
1427 pDecInsn->vC, thisType);
Andy McFadden62a75162009-04-17 17:23:37 -07001428 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001429 goto bail;
1430 }
1431
1432bail:
1433 return thisType;
1434}
1435
1436/*
1437 * Set the type of register N, verifying that the register is valid. If
1438 * "newType" is the "Lo" part of a 64-bit value, register N+1 will be
1439 * set to "newType+1".
1440 *
Andy McFaddend3250112010-11-03 14:32:42 -07001441 * The register index was validated during the static pass, so we don't
1442 * need to check it here.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001443 */
Andy McFaddend3250112010-11-03 14:32:42 -07001444static void setRegisterType(RegType* insnRegs, u4 vdst, RegType newType)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001445{
1446 //LOGD("set-reg v%u = %d\n", vdst, newType);
1447 switch (newType) {
1448 case kRegTypeUnknown:
1449 case kRegTypeBoolean:
1450 case kRegTypeOne:
1451 case kRegTypeByte:
1452 case kRegTypePosByte:
1453 case kRegTypeShort:
1454 case kRegTypePosShort:
1455 case kRegTypeChar:
1456 case kRegTypeInteger:
1457 case kRegTypeFloat:
1458 case kRegTypeZero:
Andy McFaddend3250112010-11-03 14:32:42 -07001459 case kRegTypeUninit:
1460 insnRegs[vdst] = newType;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001461 break;
1462 case kRegTypeLongLo:
1463 case kRegTypeDoubleLo:
Andy McFaddend3250112010-11-03 14:32:42 -07001464 insnRegs[vdst] = newType;
1465 insnRegs[vdst+1] = newType+1;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001466 break;
1467 case kRegTypeLongHi:
1468 case kRegTypeDoubleHi:
1469 /* should never set these explicitly */
Andy McFaddend3250112010-11-03 14:32:42 -07001470 LOGE("BUG: explicit set of high register type\n");
1471 dvmAbort();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001472 break;
1473
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001474 default:
Andy McFaddend3250112010-11-03 14:32:42 -07001475 /* can't switch for ref types, so we check explicitly */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001476 if (regTypeIsReference(newType)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001477 insnRegs[vdst] = newType;
1478
1479 /*
1480 * In most circumstances we won't see a reference to a primitive
1481 * class here (e.g. "D"), since that would mean the object in the
1482 * register is actually a primitive type. It can happen as the
1483 * result of an assumed-successful check-cast instruction in
1484 * which the second argument refers to a primitive class. (In
1485 * practice, such an instruction will always throw an exception.)
1486 *
1487 * This is not an issue for instructions like const-class, where
1488 * the object in the register is a java.lang.Class instance.
1489 */
1490 break;
1491 }
Andy McFaddend3250112010-11-03 14:32:42 -07001492 /* bad type - fall through */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001493
1494 case kRegTypeConflict: // should only be set during a merge
Andy McFaddend3250112010-11-03 14:32:42 -07001495 LOGE("BUG: set register to unknown type %d\n", newType);
1496 dvmAbort();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001497 break;
1498 }
1499}
1500
1501/*
1502 * Verify that the contents of the specified register have the specified
1503 * type (or can be converted to it through an implicit widening conversion).
1504 *
1505 * In theory we could use this to modify the type of the source register,
1506 * e.g. a generic 32-bit constant, once used as a float, would thereafter
1507 * remain a float. There is no compelling reason to require this though.
1508 *
1509 * If "vsrc" is a reference, both it and the "vsrc" register must be
1510 * initialized ("vsrc" may be Zero). This will verify that the value in
1511 * the register is an instance of checkType, or if checkType is an
1512 * interface, verify that the register implements checkType.
1513 */
Andy McFaddend3250112010-11-03 14:32:42 -07001514static void verifyRegisterType(const RegType* insnRegs, u4 vsrc,
1515 RegType checkType, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001516{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001517 RegType srcType = insnRegs[vsrc];
1518
1519 //LOGD("check-reg v%u = %d\n", vsrc, checkType);
1520 switch (checkType) {
1521 case kRegTypeFloat:
1522 case kRegTypeBoolean:
1523 case kRegTypePosByte:
1524 case kRegTypeByte:
1525 case kRegTypePosShort:
1526 case kRegTypeShort:
1527 case kRegTypeChar:
1528 case kRegTypeInteger:
1529 if (!canConvertTo1nr(srcType, checkType)) {
1530 LOG_VFY("VFY: register1 v%u type %d, wanted %d\n",
1531 vsrc, srcType, checkType);
Andy McFadden62a75162009-04-17 17:23:37 -07001532 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001533 }
1534 break;
1535 case kRegTypeLongLo:
1536 case kRegTypeDoubleLo:
Andy McFaddend3250112010-11-03 14:32:42 -07001537 if (insnRegs[vsrc+1] != srcType+1) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001538 LOG_VFY("VFY: register2 v%u-%u values %d,%d\n",
1539 vsrc, vsrc+1, insnRegs[vsrc], insnRegs[vsrc+1]);
Andy McFadden62a75162009-04-17 17:23:37 -07001540 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001541 } else if (!canConvertTo2(srcType, checkType)) {
1542 LOG_VFY("VFY: register2 v%u type %d, wanted %d\n",
1543 vsrc, srcType, checkType);
Andy McFadden62a75162009-04-17 17:23:37 -07001544 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001545 }
1546 break;
1547
1548 case kRegTypeLongHi:
1549 case kRegTypeDoubleHi:
1550 case kRegTypeZero:
1551 case kRegTypeOne:
1552 case kRegTypeUnknown:
1553 case kRegTypeConflict:
1554 /* should never be checking for these explicitly */
1555 assert(false);
Andy McFadden62a75162009-04-17 17:23:37 -07001556 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001557 return;
1558 case kRegTypeUninit:
1559 default:
1560 /* make sure checkType is initialized reference */
1561 if (!regTypeIsReference(checkType)) {
1562 LOG_VFY("VFY: unexpected check type %d\n", checkType);
1563 assert(false);
Andy McFadden62a75162009-04-17 17:23:37 -07001564 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001565 break;
1566 }
1567 if (regTypeIsUninitReference(checkType)) {
1568 LOG_VFY("VFY: uninitialized ref not expected as reg check\n");
Andy McFadden62a75162009-04-17 17:23:37 -07001569 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001570 break;
1571 }
1572 /* make sure srcType is initialized reference or always-NULL */
1573 if (!regTypeIsReference(srcType)) {
1574 LOG_VFY("VFY: register1 v%u type %d, wanted ref\n", vsrc, srcType);
Andy McFadden62a75162009-04-17 17:23:37 -07001575 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001576 break;
1577 }
1578 if (regTypeIsUninitReference(srcType)) {
1579 LOG_VFY("VFY: register1 v%u holds uninitialized ref\n", vsrc);
Andy McFadden62a75162009-04-17 17:23:37 -07001580 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001581 break;
1582 }
1583 /* if the register isn't Zero, make sure it's an instance of check */
1584 if (srcType != kRegTypeZero) {
1585 ClassObject* srcClass = regTypeInitializedReferenceToClass(srcType);
1586 ClassObject* checkClass = regTypeInitializedReferenceToClass(checkType);
1587 assert(srcClass != NULL);
1588 assert(checkClass != NULL);
1589
1590 if (dvmIsInterfaceClass(checkClass)) {
1591 /*
1592 * All objects implement all interfaces as far as the
1593 * verifier is concerned. The runtime has to sort it out.
1594 * See comments above findCommonSuperclass.
1595 */
1596 /*
1597 if (srcClass != checkClass &&
1598 !dvmImplements(srcClass, checkClass))
1599 {
1600 LOG_VFY("VFY: %s does not implement %s\n",
1601 srcClass->descriptor, checkClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07001602 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001603 }
1604 */
1605 } else {
1606 if (!dvmInstanceof(srcClass, checkClass)) {
1607 LOG_VFY("VFY: %s is not instance of %s\n",
1608 srcClass->descriptor, checkClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07001609 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001610 }
1611 }
1612 }
1613 break;
1614 }
1615}
1616
1617/*
Andy McFaddend3250112010-11-03 14:32:42 -07001618 * Set the type of the "result" register.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001619 */
1620static void setResultRegisterType(RegType* insnRegs, const int insnRegCount,
Andy McFaddend3250112010-11-03 14:32:42 -07001621 RegType newType)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001622{
Andy McFaddend3250112010-11-03 14:32:42 -07001623 setRegisterType(insnRegs, RESULT_REGISTER(insnRegCount), newType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001624}
1625
1626
1627/*
1628 * Update all registers holding "uninitType" to instead hold the
1629 * corresponding initialized reference type. This is called when an
1630 * appropriate <init> method is invoked -- all copies of the reference
1631 * must be marked as initialized.
1632 */
1633static void markRefsAsInitialized(RegType* insnRegs, int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001634 UninitInstanceMap* uninitMap, RegType uninitType, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001635{
1636 ClassObject* clazz;
1637 RegType initType;
1638 int i, changed;
1639
1640 clazz = dvmGetUninitInstance(uninitMap, regTypeToUninitIndex(uninitType));
1641 if (clazz == NULL) {
1642 LOGE("VFY: unable to find type=0x%x (idx=%d)\n",
1643 uninitType, regTypeToUninitIndex(uninitType));
Andy McFadden62a75162009-04-17 17:23:37 -07001644 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001645 return;
1646 }
1647 initType = regTypeFromClass(clazz);
1648
1649 changed = 0;
1650 for (i = 0; i < insnRegCount; i++) {
1651 if (insnRegs[i] == uninitType) {
1652 insnRegs[i] = initType;
1653 changed++;
1654 }
1655 }
1656 //LOGD("VFY: marked %d registers as initialized\n", changed);
1657 assert(changed > 0);
1658
1659 return;
1660}
1661
1662/*
1663 * We're creating a new instance of class C at address A. Any registers
1664 * holding instances previously created at address A must be initialized
1665 * by now. If not, we mark them as "conflict" to prevent them from being
1666 * used (otherwise, markRefsAsInitialized would mark the old ones and the
1667 * new ones at the same time).
1668 */
1669static void markUninitRefsAsInvalid(RegType* insnRegs, int insnRegCount,
1670 UninitInstanceMap* uninitMap, RegType uninitType)
1671{
1672 int i, changed;
1673
1674 changed = 0;
1675 for (i = 0; i < insnRegCount; i++) {
1676 if (insnRegs[i] == uninitType) {
1677 insnRegs[i] = kRegTypeConflict;
1678 changed++;
1679 }
1680 }
1681
1682 //if (changed)
1683 // LOGD("VFY: marked %d uninitialized registers as invalid\n", changed);
1684}
1685
1686/*
1687 * Find the start of the register set for the specified instruction in
1688 * the current method.
1689 */
1690static inline RegType* getRegisterLine(const RegisterTable* regTable,
1691 int insnIdx)
1692{
1693 return regTable->addrRegs[insnIdx];
1694}
1695
1696/*
1697 * Copy a bunch of registers.
1698 */
1699static inline void copyRegisters(RegType* dst, const RegType* src,
1700 int numRegs)
1701{
1702 memcpy(dst, src, numRegs * sizeof(RegType));
1703}
1704
1705/*
1706 * Compare a bunch of registers.
1707 *
1708 * Returns 0 if they match. Using this for a sort is unwise, since the
1709 * value can change based on machine endianness.
1710 */
1711static inline int compareRegisters(const RegType* src1, const RegType* src2,
1712 int numRegs)
1713{
1714 return memcmp(src1, src2, numRegs * sizeof(RegType));
1715}
1716
1717/*
1718 * Register type categories, for type checking.
1719 *
1720 * The spec says category 1 includes boolean, byte, char, short, int, float,
1721 * reference, and returnAddress. Category 2 includes long and double.
1722 *
1723 * We treat object references separately, so we have "category1nr". We
1724 * don't support jsr/ret, so there is no "returnAddress" type.
1725 */
1726typedef enum TypeCategory {
1727 kTypeCategoryUnknown = 0,
1728 kTypeCategory1nr, // byte, char, int, float, boolean
1729 kTypeCategory2, // long, double
1730 kTypeCategoryRef, // object reference
1731} TypeCategory;
1732
1733/*
1734 * See if "type" matches "cat". All we're really looking for here is that
1735 * we're not mixing and matching 32-bit and 64-bit quantities, and we're
1736 * not mixing references with numerics. (For example, the arguments to
1737 * "a < b" could be integers of different sizes, but they must both be
1738 * integers. Dalvik is less specific about int vs. float, so we treat them
1739 * as equivalent here.)
1740 *
1741 * For category 2 values, "type" must be the "low" half of the value.
1742 *
Andy McFadden62a75162009-04-17 17:23:37 -07001743 * Sets "*pFailure" if something looks wrong.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001744 */
Andy McFadden62a75162009-04-17 17:23:37 -07001745static void checkTypeCategory(RegType type, TypeCategory cat,
1746 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001747{
1748 switch (cat) {
1749 case kTypeCategory1nr:
1750 switch (type) {
1751 case kRegTypeFloat:
1752 case kRegTypeZero:
1753 case kRegTypeOne:
1754 case kRegTypeBoolean:
1755 case kRegTypePosByte:
1756 case kRegTypeByte:
1757 case kRegTypePosShort:
1758 case kRegTypeShort:
1759 case kRegTypeChar:
1760 case kRegTypeInteger:
1761 break;
1762 default:
Andy McFadden62a75162009-04-17 17:23:37 -07001763 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001764 break;
1765 }
1766 break;
1767
1768 case kTypeCategory2:
1769 switch (type) {
1770 case kRegTypeLongLo:
1771 case kRegTypeDoubleLo:
1772 break;
1773 default:
Andy McFadden62a75162009-04-17 17:23:37 -07001774 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001775 break;
1776 }
1777 break;
1778
1779 case kTypeCategoryRef:
1780 if (type != kRegTypeZero && !regTypeIsReference(type))
Andy McFadden62a75162009-04-17 17:23:37 -07001781 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001782 break;
1783
1784 default:
1785 assert(false);
Andy McFadden62a75162009-04-17 17:23:37 -07001786 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001787 break;
1788 }
1789}
1790
1791/*
1792 * For a category 2 register pair, verify that "typeh" is the appropriate
1793 * high part for "typel".
1794 *
1795 * Does not verify that "typel" is in fact the low part of a 64-bit
1796 * register pair.
1797 */
Andy McFadden62a75162009-04-17 17:23:37 -07001798static void checkWidePair(RegType typel, RegType typeh, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001799{
1800 if ((typeh != typel+1))
Andy McFadden62a75162009-04-17 17:23:37 -07001801 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001802}
1803
1804/*
1805 * Implement category-1 "move" instructions. Copy a 32-bit value from
1806 * "vsrc" to "vdst".
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001807 */
Andy McFaddend3250112010-11-03 14:32:42 -07001808static void copyRegister1(RegType* insnRegs, u4 vdst, u4 vsrc,
1809 TypeCategory cat, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001810{
Andy McFaddend3250112010-11-03 14:32:42 -07001811 RegType type = getRegisterType(insnRegs, vsrc);
1812 checkTypeCategory(type, cat, pFailure);
Andy McFadden62a75162009-04-17 17:23:37 -07001813 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001814 LOG_VFY("VFY: copy1 v%u<-v%u type=%d cat=%d\n", vdst, vsrc, type, cat);
Andy McFaddend3250112010-11-03 14:32:42 -07001815 } else {
1816 setRegisterType(insnRegs, vdst, type);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001817 }
Andy McFaddend3250112010-11-03 14:32:42 -07001818
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001819}
1820
1821/*
1822 * Implement category-2 "move" instructions. Copy a 64-bit value from
1823 * "vsrc" to "vdst". This copies both halves of the register.
1824 */
Andy McFaddend3250112010-11-03 14:32:42 -07001825static void copyRegister2(RegType* insnRegs, u4 vdst,
Andy McFadden62a75162009-04-17 17:23:37 -07001826 u4 vsrc, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001827{
Andy McFaddend3250112010-11-03 14:32:42 -07001828 RegType typel = getRegisterType(insnRegs, vsrc);
1829 RegType typeh = getRegisterType(insnRegs, vsrc+1);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001830
Andy McFaddend3250112010-11-03 14:32:42 -07001831 checkTypeCategory(typel, kTypeCategory2, pFailure);
1832 checkWidePair(typel, typeh, pFailure);
Andy McFadden62a75162009-04-17 17:23:37 -07001833 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001834 LOG_VFY("VFY: copy2 v%u<-v%u type=%d/%d\n", vdst, vsrc, typel, typeh);
Andy McFaddend3250112010-11-03 14:32:42 -07001835 } else {
1836 setRegisterType(insnRegs, vdst, typel);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001837 }
1838}
1839
1840/*
1841 * Implement "move-result". Copy the category-1 value from the result
1842 * register to another register, and reset the result register.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001843 */
1844static void copyResultRegister1(RegType* insnRegs, const int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001845 u4 vdst, TypeCategory cat, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001846{
1847 RegType type;
1848 u4 vsrc;
1849
Andy McFaddend3250112010-11-03 14:32:42 -07001850 assert(vdst < (u4) insnRegCount);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001851
Andy McFaddend3250112010-11-03 14:32:42 -07001852 vsrc = RESULT_REGISTER(insnRegCount);
1853 type = getRegisterType(insnRegs, vsrc);
1854 checkTypeCategory(type, cat, pFailure);
Andy McFadden62a75162009-04-17 17:23:37 -07001855 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001856 LOG_VFY("VFY: copyRes1 v%u<-v%u cat=%d type=%d\n",
1857 vdst, vsrc, cat, type);
Andy McFaddend3250112010-11-03 14:32:42 -07001858 } else {
1859 setRegisterType(insnRegs, vdst, type);
1860 insnRegs[vsrc] = kRegTypeUnknown;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001861 }
1862}
1863
1864/*
1865 * Implement "move-result-wide". Copy the category-2 value from the result
1866 * register to another register, and reset the result register.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001867 */
1868static void copyResultRegister2(RegType* insnRegs, const int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001869 u4 vdst, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001870{
1871 RegType typel, typeh;
1872 u4 vsrc;
1873
Andy McFaddend3250112010-11-03 14:32:42 -07001874 assert(vdst < (u4) insnRegCount);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001875
Andy McFaddend3250112010-11-03 14:32:42 -07001876 vsrc = RESULT_REGISTER(insnRegCount);
1877 typel = getRegisterType(insnRegs, vsrc);
1878 typeh = getRegisterType(insnRegs, vsrc+1);
1879 checkTypeCategory(typel, kTypeCategory2, pFailure);
1880 checkWidePair(typel, typeh, 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: copyRes2 v%u<-v%u type=%d/%d\n",
1883 vdst, vsrc, typel, typeh);
Andy McFaddend3250112010-11-03 14:32:42 -07001884 } else {
1885 setRegisterType(insnRegs, vdst, typel);
1886 insnRegs[vsrc] = kRegTypeUnknown;
1887 insnRegs[vsrc+1] = kRegTypeUnknown;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001888 }
1889}
1890
1891/*
1892 * Verify types for a simple two-register instruction (e.g. "neg-int").
1893 * "dstType" is stored into vA, and "srcType" is verified against vB.
1894 */
Andy McFaddend3250112010-11-03 14:32:42 -07001895static void checkUnop(RegType* insnRegs, DecodedInstruction* pDecInsn,
1896 RegType dstType, RegType srcType, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001897{
Andy McFaddend3250112010-11-03 14:32:42 -07001898 verifyRegisterType(insnRegs, pDecInsn->vB, srcType, pFailure);
1899 setRegisterType(insnRegs, pDecInsn->vA, dstType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001900}
1901
1902/*
1903 * We're performing an operation like "and-int/2addr" that can be
1904 * performed on booleans as well as integers. We get no indication of
1905 * boolean-ness, but we can infer it from the types of the arguments.
1906 *
1907 * Assumes we've already validated reg1/reg2.
1908 *
Andy McFaddenb5f64bc2009-06-10 14:11:07 -07001909 * TODO: consider generalizing this. The key principle is that the
1910 * result of a bitwise operation can only be as wide as the widest of
1911 * the operands. You can safely AND/OR/XOR two chars together and know
1912 * you still have a char, so it's reasonable for the compiler or "dx"
1913 * to skip the int-to-char instruction. (We need to do this for boolean
1914 * because there is no int-to-boolean operation.)
1915 *
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001916 * Returns true if both args are Boolean, Zero, or One.
1917 */
Andy McFaddend3250112010-11-03 14:32:42 -07001918static bool upcastBooleanOp(RegType* insnRegs, u4 reg1, u4 reg2)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001919{
1920 RegType type1, type2;
1921
1922 type1 = insnRegs[reg1];
1923 type2 = insnRegs[reg2];
1924
1925 if ((type1 == kRegTypeBoolean || type1 == kRegTypeZero ||
1926 type1 == kRegTypeOne) &&
1927 (type2 == kRegTypeBoolean || type2 == kRegTypeZero ||
1928 type2 == kRegTypeOne))
1929 {
1930 return true;
1931 }
1932 return false;
1933}
1934
1935/*
1936 * Verify types for A two-register instruction with a literal constant
1937 * (e.g. "add-int/lit8"). "dstType" is stored into vA, and "srcType" is
1938 * verified against vB.
1939 *
1940 * If "checkBooleanOp" is set, we use the constant value in vC.
1941 */
Andy McFaddend3250112010-11-03 14:32:42 -07001942static void checkLitop(RegType* insnRegs, DecodedInstruction* pDecInsn,
1943 RegType dstType, RegType srcType, bool checkBooleanOp,
1944 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001945{
Andy McFaddend3250112010-11-03 14:32:42 -07001946 verifyRegisterType(insnRegs, pDecInsn->vB, srcType, pFailure);
Andy McFadden62a75162009-04-17 17:23:37 -07001947 if (VERIFY_OK(*pFailure) && checkBooleanOp) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001948 assert(dstType == kRegTypeInteger);
1949 /* check vB with the call, then check the constant manually */
Andy McFaddend3250112010-11-03 14:32:42 -07001950 if (upcastBooleanOp(insnRegs, pDecInsn->vB, pDecInsn->vB)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001951 && (pDecInsn->vC == 0 || pDecInsn->vC == 1))
1952 {
1953 dstType = kRegTypeBoolean;
1954 }
1955 }
Andy McFaddend3250112010-11-03 14:32:42 -07001956 setRegisterType(insnRegs, pDecInsn->vA, dstType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001957}
1958
1959/*
1960 * Verify types for a simple three-register instruction (e.g. "add-int").
1961 * "dstType" is stored into vA, and "srcType1"/"srcType2" are verified
1962 * against vB/vC.
1963 */
Andy McFaddend3250112010-11-03 14:32:42 -07001964static void checkBinop(RegType* insnRegs, DecodedInstruction* pDecInsn,
1965 RegType dstType, RegType srcType1, RegType srcType2, bool checkBooleanOp,
1966 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001967{
Andy McFaddend3250112010-11-03 14:32:42 -07001968 verifyRegisterType(insnRegs, pDecInsn->vB, srcType1, pFailure);
1969 verifyRegisterType(insnRegs, pDecInsn->vC, srcType2, pFailure);
Andy McFadden62a75162009-04-17 17:23:37 -07001970 if (VERIFY_OK(*pFailure) && checkBooleanOp) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001971 assert(dstType == kRegTypeInteger);
Andy McFaddend3250112010-11-03 14:32:42 -07001972 if (upcastBooleanOp(insnRegs, pDecInsn->vB, pDecInsn->vC))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001973 dstType = kRegTypeBoolean;
1974 }
Andy McFaddend3250112010-11-03 14:32:42 -07001975 setRegisterType(insnRegs, pDecInsn->vA, dstType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001976}
1977
1978/*
1979 * Verify types for a binary "2addr" operation. "srcType1"/"srcType2"
1980 * are verified against vA/vB, then "dstType" is stored into vA.
1981 */
Andy McFaddend3250112010-11-03 14:32:42 -07001982static void checkBinop2addr(RegType* insnRegs, DecodedInstruction* pDecInsn,
1983 RegType dstType, RegType srcType1, RegType srcType2, bool checkBooleanOp,
1984 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001985{
Andy McFaddend3250112010-11-03 14:32:42 -07001986 verifyRegisterType(insnRegs, pDecInsn->vA, srcType1, pFailure);
1987 verifyRegisterType(insnRegs, pDecInsn->vB, srcType2, pFailure);
Andy McFadden62a75162009-04-17 17:23:37 -07001988 if (VERIFY_OK(*pFailure) && checkBooleanOp) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001989 assert(dstType == kRegTypeInteger);
Andy McFaddend3250112010-11-03 14:32:42 -07001990 if (upcastBooleanOp(insnRegs, pDecInsn->vA, pDecInsn->vB))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001991 dstType = kRegTypeBoolean;
1992 }
Andy McFaddend3250112010-11-03 14:32:42 -07001993 setRegisterType(insnRegs, pDecInsn->vA, dstType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001994}
1995
Andy McFadden80d25ea2009-06-12 07:26:17 -07001996/*
1997 * Treat right-shifting as a narrowing conversion when possible.
1998 *
1999 * For example, right-shifting an int 24 times results in a value that can
2000 * be treated as a byte.
2001 *
2002 * Things get interesting when contemplating sign extension. Right-
2003 * shifting an integer by 16 yields a value that can be represented in a
2004 * "short" but not a "char", but an unsigned right shift by 16 yields a
2005 * value that belongs in a char rather than a short. (Consider what would
2006 * happen if the result of the shift were cast to a char or short and then
2007 * cast back to an int. If sign extension, or the lack thereof, causes
2008 * a change in the 32-bit representation, then the conversion was lossy.)
2009 *
2010 * A signed right shift by 17 on an integer results in a short. An unsigned
2011 * right shfit by 17 on an integer results in a posshort, which can be
2012 * assigned to a short or a char.
2013 *
2014 * An unsigned right shift on a short can actually expand the result into
2015 * a 32-bit integer. For example, 0xfffff123 >>> 8 becomes 0x00fffff1,
2016 * which can't be represented in anything smaller than an int.
2017 *
2018 * javac does not generate code that takes advantage of this, but some
2019 * of the code optimizers do. It's generally a peephole optimization
2020 * that replaces a particular sequence, e.g. (bipush 24, ishr, i2b) is
2021 * replaced by (bipush 24, ishr). Knowing that shifting a short 8 times
2022 * to the right yields a byte is really more than we need to handle the
2023 * code that's out there, but support is not much more complex than just
2024 * handling integer.
2025 *
2026 * Right-shifting never yields a boolean value.
2027 *
2028 * Returns the new register type.
2029 */
Andy McFaddend3250112010-11-03 14:32:42 -07002030static RegType adjustForRightShift(RegType* workRegs, int reg,
2031 unsigned int shiftCount, bool isUnsignedShift, VerifyError* pFailure)
Andy McFadden80d25ea2009-06-12 07:26:17 -07002032{
Andy McFaddend3250112010-11-03 14:32:42 -07002033 RegType srcType = getRegisterType(workRegs, reg);
Andy McFadden80d25ea2009-06-12 07:26:17 -07002034 RegType newType;
2035
2036 /* no-op */
2037 if (shiftCount == 0)
2038 return srcType;
2039
2040 /* safe defaults */
2041 if (isUnsignedShift)
2042 newType = kRegTypeInteger;
2043 else
2044 newType = srcType;
2045
2046 if (shiftCount >= 32) {
2047 LOG_VFY("Got unexpectedly large shift count %u\n", shiftCount);
2048 /* fail? */
2049 return newType;
2050 }
2051
2052 switch (srcType) {
2053 case kRegTypeInteger: /* 32-bit signed value */
2054 case kRegTypeFloat: /* (allowed; treat same as int) */
2055 if (isUnsignedShift) {
2056 if (shiftCount > 24)
2057 newType = kRegTypePosByte;
2058 else if (shiftCount >= 16)
2059 newType = kRegTypeChar;
2060 } else {
2061 if (shiftCount >= 24)
2062 newType = kRegTypeByte;
2063 else if (shiftCount >= 16)
2064 newType = kRegTypeShort;
2065 }
2066 break;
2067 case kRegTypeShort: /* 16-bit signed value */
2068 if (isUnsignedShift) {
2069 /* default (kRegTypeInteger) is correct */
2070 } else {
2071 if (shiftCount >= 8)
2072 newType = kRegTypeByte;
2073 }
2074 break;
2075 case kRegTypePosShort: /* 15-bit unsigned value */
2076 if (shiftCount >= 8)
2077 newType = kRegTypePosByte;
2078 break;
2079 case kRegTypeChar: /* 16-bit unsigned value */
2080 if (shiftCount > 8)
2081 newType = kRegTypePosByte;
2082 break;
2083 case kRegTypeByte: /* 8-bit signed value */
2084 /* defaults (u=kRegTypeInteger / s=srcType) are correct */
2085 break;
2086 case kRegTypePosByte: /* 7-bit unsigned value */
2087 /* always use newType=srcType */
2088 newType = srcType;
2089 break;
2090 case kRegTypeZero: /* 1-bit unsigned value */
2091 case kRegTypeOne:
2092 case kRegTypeBoolean:
2093 /* unnecessary? */
2094 newType = kRegTypeZero;
2095 break;
2096 default:
2097 /* long, double, references; shouldn't be here! */
2098 assert(false);
2099 break;
2100 }
2101
2102 if (newType != srcType) {
2103 LOGVV("narrowing: %d(%d) --> %d to %d\n",
2104 shiftCount, isUnsignedShift, srcType, newType);
2105 } else {
2106 LOGVV("not narrowed: %d(%d) --> %d\n",
2107 shiftCount, isUnsignedShift, srcType);
2108 }
2109 return newType;
2110}
2111
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002112
2113/*
2114 * ===========================================================================
2115 * Register merge
2116 * ===========================================================================
2117 */
2118
2119/*
2120 * Compute the "class depth" of a class. This is the distance from the
2121 * class to the top of the tree, chasing superclass links. java.lang.Object
2122 * has a class depth of 0.
2123 */
2124static int getClassDepth(ClassObject* clazz)
2125{
2126 int depth = 0;
2127
2128 while (clazz->super != NULL) {
2129 clazz = clazz->super;
2130 depth++;
2131 }
2132 return depth;
2133}
2134
2135/*
2136 * Given two classes, walk up the superclass tree to find a common
2137 * ancestor. (Called from findCommonSuperclass().)
2138 *
2139 * TODO: consider caching the class depth in the class object so we don't
2140 * have to search for it here.
2141 */
2142static ClassObject* digForSuperclass(ClassObject* c1, ClassObject* c2)
2143{
2144 int depth1, depth2;
2145
2146 depth1 = getClassDepth(c1);
2147 depth2 = getClassDepth(c2);
2148
2149 if (gDebugVerbose) {
2150 LOGVV("COMMON: %s(%d) + %s(%d)\n",
2151 c1->descriptor, depth1, c2->descriptor, depth2);
2152 }
2153
2154 /* pull the deepest one up */
2155 if (depth1 > depth2) {
2156 while (depth1 > depth2) {
2157 c1 = c1->super;
2158 depth1--;
2159 }
2160 } else {
2161 while (depth2 > depth1) {
2162 c2 = c2->super;
2163 depth2--;
2164 }
2165 }
2166
2167 /* walk up in lock-step */
2168 while (c1 != c2) {
2169 c1 = c1->super;
2170 c2 = c2->super;
2171
2172 assert(c1 != NULL && c2 != NULL);
2173 }
2174
2175 if (gDebugVerbose) {
2176 LOGVV(" : --> %s\n", c1->descriptor);
2177 }
2178 return c1;
2179}
2180
2181/*
2182 * Merge two array classes. We can't use the general "walk up to the
2183 * superclass" merge because the superclass of an array is always Object.
2184 * We want String[] + Integer[] = Object[]. This works for higher dimensions
2185 * as well, e.g. String[][] + Integer[][] = Object[][].
2186 *
2187 * If Foo1 and Foo2 are subclasses of Foo, Foo1[] + Foo2[] = Foo[].
2188 *
2189 * If Class implements Type, Class[] + Type[] = Type[].
2190 *
2191 * If the dimensions don't match, we want to convert to an array of Object
2192 * with the least dimension, e.g. String[][] + String[][][][] = Object[][].
2193 *
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002194 * Arrays of primitive types effectively have one less dimension when
2195 * merging. int[] + float[] = Object, int[] + String[] = Object,
2196 * int[][] + float[][] = Object[], int[][] + String[] = Object[]. (The
2197 * only time this function doesn't return an array class is when one of
2198 * the arguments is a 1-dimensional primitive array.)
2199 *
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002200 * This gets a little awkward because we may have to ask the VM to create
2201 * a new array type with the appropriate element and dimensions. However, we
2202 * shouldn't be doing this often.
2203 */
2204static ClassObject* findCommonArraySuperclass(ClassObject* c1, ClassObject* c2)
2205{
2206 ClassObject* arrayClass = NULL;
2207 ClassObject* commonElem;
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002208 int arrayDim1, arrayDim2;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002209 int i, numDims;
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002210 bool hasPrimitive = false;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002211
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002212 arrayDim1 = c1->arrayDim;
2213 arrayDim2 = c2->arrayDim;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002214 assert(c1->arrayDim > 0);
2215 assert(c2->arrayDim > 0);
2216
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002217 if (dvmIsPrimitiveClass(c1->elementClass)) {
2218 arrayDim1--;
2219 hasPrimitive = true;
2220 }
2221 if (dvmIsPrimitiveClass(c2->elementClass)) {
2222 arrayDim2--;
2223 hasPrimitive = true;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002224 }
2225
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002226 if (!hasPrimitive && arrayDim1 == arrayDim2) {
2227 /*
2228 * Two arrays of reference types with equal dimensions. Try to
2229 * find a good match.
2230 */
2231 commonElem = findCommonSuperclass(c1->elementClass, c2->elementClass);
2232 numDims = arrayDim1;
2233 } else {
2234 /*
2235 * Mismatched array depths and/or array(s) of primitives. We want
2236 * Object, or an Object array with appropriate dimensions.
2237 *
2238 * We initialize arrayClass to Object here, because it's possible
2239 * for us to set numDims=0.
2240 */
2241 if (arrayDim1 < arrayDim2)
2242 numDims = arrayDim1;
2243 else
2244 numDims = arrayDim2;
2245 arrayClass = commonElem = c1->super; // == java.lang.Object
2246 }
2247
2248 /*
2249 * Find an appropriately-dimensioned array class. This is easiest
2250 * to do iteratively, using the array class found by the current round
2251 * as the element type for the next round.
2252 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002253 for (i = 0; i < numDims; i++) {
2254 arrayClass = dvmFindArrayClassForElement(commonElem);
2255 commonElem = arrayClass;
2256 }
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002257 assert(arrayClass != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002258
2259 LOGVV("ArrayMerge '%s' + '%s' --> '%s'\n",
2260 c1->descriptor, c2->descriptor, arrayClass->descriptor);
2261 return arrayClass;
2262}
2263
2264/*
2265 * Find the first common superclass of the two classes. We're not
2266 * interested in common interfaces.
2267 *
2268 * The easiest way to do this for concrete classes is to compute the "class
2269 * depth" of each, move up toward the root of the deepest one until they're
2270 * at the same depth, then walk both up to the root until they match.
2271 *
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002272 * If both classes are arrays, we need to merge based on array depth and
2273 * element type.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002274 *
2275 * If one class is an interface, we check to see if the other class/interface
2276 * (or one of its predecessors) implements the interface. If so, we return
2277 * the interface; otherwise, we return Object.
2278 *
2279 * NOTE: we continue the tradition of "lazy interface handling". To wit,
2280 * suppose we have three classes:
2281 * One implements Fancy, Free
2282 * Two implements Fancy, Free
2283 * Three implements Free
2284 * where Fancy and Free are unrelated interfaces. The code requires us
2285 * to merge One into Two. Ideally we'd use a common interface, which
2286 * gives us a choice between Fancy and Free, and no guidance on which to
2287 * use. If we use Free, we'll be okay when Three gets merged in, but if
2288 * we choose Fancy, we're hosed. The "ideal" solution is to create a
2289 * set of common interfaces and carry that around, merging further references
2290 * into it. This is a pain. The easy solution is to simply boil them
2291 * down to Objects and let the runtime invokeinterface call fail, which
2292 * is what we do.
2293 */
2294static ClassObject* findCommonSuperclass(ClassObject* c1, ClassObject* c2)
2295{
2296 assert(!dvmIsPrimitiveClass(c1) && !dvmIsPrimitiveClass(c2));
2297
2298 if (c1 == c2)
2299 return c1;
2300
2301 if (dvmIsInterfaceClass(c1) && dvmImplements(c2, c1)) {
2302 if (gDebugVerbose)
2303 LOGVV("COMMON/I1: %s + %s --> %s\n",
2304 c1->descriptor, c2->descriptor, c1->descriptor);
2305 return c1;
2306 }
2307 if (dvmIsInterfaceClass(c2) && dvmImplements(c1, c2)) {
2308 if (gDebugVerbose)
2309 LOGVV("COMMON/I2: %s + %s --> %s\n",
2310 c1->descriptor, c2->descriptor, c2->descriptor);
2311 return c2;
2312 }
2313
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002314 if (dvmIsArrayClass(c1) && dvmIsArrayClass(c2)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002315 return findCommonArraySuperclass(c1, c2);
2316 }
2317
2318 return digForSuperclass(c1, c2);
2319}
2320
2321/*
2322 * Merge two RegType values.
2323 *
2324 * Sets "*pChanged" to "true" if the result doesn't match "type1".
2325 */
2326static RegType mergeTypes(RegType type1, RegType type2, bool* pChanged)
2327{
2328 RegType result;
2329
2330 /*
2331 * Check for trivial case so we don't have to hit memory.
2332 */
2333 if (type1 == type2)
2334 return type1;
2335
2336 /*
2337 * Use the table if we can, and reject any attempts to merge something
2338 * from the table with a reference type.
2339 *
2340 * The uninitialized table entry at index zero *will* show up as a
2341 * simple kRegTypeUninit value. Since this cannot be merged with
2342 * anything but itself, the rules do the right thing.
2343 */
2344 if (type1 < kRegTypeMAX) {
2345 if (type2 < kRegTypeMAX) {
2346 result = gDvmMergeTab[type1][type2];
2347 } else {
2348 /* simple + reference == conflict, usually */
2349 if (type1 == kRegTypeZero)
2350 result = type2;
2351 else
2352 result = kRegTypeConflict;
2353 }
2354 } else {
2355 if (type2 < kRegTypeMAX) {
2356 /* reference + simple == conflict, usually */
2357 if (type2 == kRegTypeZero)
2358 result = type1;
2359 else
2360 result = kRegTypeConflict;
2361 } else {
2362 /* merging two references */
2363 if (regTypeIsUninitReference(type1) ||
2364 regTypeIsUninitReference(type2))
2365 {
2366 /* can't merge uninit with anything but self */
2367 result = kRegTypeConflict;
2368 } else {
2369 ClassObject* clazz1 = regTypeInitializedReferenceToClass(type1);
2370 ClassObject* clazz2 = regTypeInitializedReferenceToClass(type2);
2371 ClassObject* mergedClass;
2372
2373 mergedClass = findCommonSuperclass(clazz1, clazz2);
2374 assert(mergedClass != NULL);
2375 result = regTypeFromClass(mergedClass);
2376 }
2377 }
2378 }
2379
2380 if (result != type1)
2381 *pChanged = true;
2382 return result;
2383}
2384
2385/*
2386 * Control can transfer to "nextInsn".
2387 *
2388 * Merge the registers from "workRegs" into "regTypes" at "nextInsn", and
2389 * set the "changed" flag on the target address if the registers have changed.
2390 */
2391static void updateRegisters(const Method* meth, InsnFlags* insnFlags,
2392 RegisterTable* regTable, int nextInsn, const RegType* workRegs)
2393{
2394 RegType* targetRegs = getRegisterLine(regTable, nextInsn);
2395 const int insnRegCount = meth->registersSize;
2396
Andy McFaddend3250112010-11-03 14:32:42 -07002397 assert(targetRegs != NULL);
2398
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002399#if 0
2400 if (!dvmInsnIsBranchTarget(insnFlags, nextInsn)) {
2401 LOGE("insnFlags[0x%x]=0x%08x\n", nextInsn, insnFlags[nextInsn]);
2402 LOGE(" In %s.%s %s\n",
2403 meth->clazz->descriptor, meth->name, meth->descriptor);
2404 assert(false);
2405 }
2406#endif
2407
2408 if (!dvmInsnIsVisitedOrChanged(insnFlags, nextInsn)) {
2409 /*
2410 * We haven't processed this instruction before, and we haven't
2411 * touched the registers here, so there's nothing to "merge". Copy
2412 * the registers over and mark it as changed. (This is the only
2413 * way a register can transition out of "unknown", so this is not
2414 * just an optimization.)
2415 */
2416 LOGVV("COPY into 0x%04x\n", nextInsn);
2417 copyRegisters(targetRegs, workRegs, insnRegCount + kExtraRegs);
2418 dvmInsnSetChanged(insnFlags, nextInsn, true);
2419 } else {
2420 if (gDebugVerbose) {
2421 LOGVV("MERGE into 0x%04x\n", nextInsn);
2422 //dumpRegTypes(meth, insnFlags, targetRegs, 0, "targ", NULL, 0);
2423 //dumpRegTypes(meth, insnFlags, workRegs, 0, "work", NULL, 0);
2424 }
2425 /* merge registers, set Changed only if different */
2426 bool changed = false;
2427 int i;
2428
2429 for (i = 0; i < insnRegCount + kExtraRegs; i++) {
2430 targetRegs[i] = mergeTypes(targetRegs[i], workRegs[i], &changed);
2431 }
2432
2433 if (gDebugVerbose) {
2434 //LOGI(" RESULT (changed=%d)\n", changed);
2435 //dumpRegTypes(meth, insnFlags, targetRegs, 0, "rslt", NULL, 0);
2436 }
2437
2438 if (changed)
2439 dvmInsnSetChanged(insnFlags, nextInsn, true);
2440 }
2441}
2442
2443
2444/*
2445 * ===========================================================================
2446 * Utility functions
2447 * ===========================================================================
2448 */
2449
2450/*
2451 * Look up an instance field, specified by "fieldIdx", that is going to be
2452 * accessed in object "objType". This resolves the field and then verifies
2453 * that the class containing the field is an instance of the reference in
2454 * "objType".
2455 *
2456 * It is possible for "objType" to be kRegTypeZero, meaning that we might
2457 * have a null reference. This is a runtime problem, so we allow it,
2458 * skipping some of the type checks.
2459 *
2460 * In general, "objType" must be an initialized reference. However, we
2461 * allow it to be uninitialized if this is an "<init>" method and the field
2462 * is declared within the "objType" class.
2463 *
Andy McFadden62a75162009-04-17 17:23:37 -07002464 * Returns an InstField on success, returns NULL and sets "*pFailure"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002465 * on failure.
2466 */
2467static InstField* getInstField(const Method* meth,
2468 const UninitInstanceMap* uninitMap, RegType objType, int fieldIdx,
Andy McFadden62a75162009-04-17 17:23:37 -07002469 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002470{
2471 InstField* instField = NULL;
2472 ClassObject* objClass;
2473 bool mustBeLocal = false;
2474
2475 if (!regTypeIsReference(objType)) {
Andy McFadden62a75162009-04-17 17:23:37 -07002476 LOG_VFY("VFY: attempt to access field in non-reference type %d\n",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002477 objType);
Andy McFadden62a75162009-04-17 17:23:37 -07002478 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002479 goto bail;
2480 }
2481
Andy McFadden62a75162009-04-17 17:23:37 -07002482 instField = dvmOptResolveInstField(meth->clazz, fieldIdx, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002483 if (instField == NULL) {
2484 LOG_VFY("VFY: unable to resolve instance field %u\n", fieldIdx);
Andy McFadden62a75162009-04-17 17:23:37 -07002485 assert(!VERIFY_OK(*pFailure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002486 goto bail;
2487 }
2488
2489 if (objType == kRegTypeZero)
2490 goto bail;
2491
2492 /*
2493 * Access to fields in uninitialized objects is allowed if this is
2494 * the <init> method for the object and the field in question is
2495 * declared by this class.
2496 */
2497 objClass = regTypeReferenceToClass(objType, uninitMap);
2498 assert(objClass != NULL);
2499 if (regTypeIsUninitReference(objType)) {
2500 if (!isInitMethod(meth) || meth->clazz != objClass) {
2501 LOG_VFY("VFY: attempt to access field via uninitialized ref\n");
Andy McFadden62a75162009-04-17 17:23:37 -07002502 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002503 goto bail;
2504 }
2505 mustBeLocal = true;
2506 }
2507
2508 if (!dvmInstanceof(objClass, instField->field.clazz)) {
2509 LOG_VFY("VFY: invalid field access (field %s.%s, through %s ref)\n",
2510 instField->field.clazz->descriptor, instField->field.name,
2511 objClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07002512 *pFailure = VERIFY_ERROR_NO_FIELD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002513 goto bail;
2514 }
2515
2516 if (mustBeLocal) {
2517 /* for uninit ref, make sure it's defined by this class, not super */
2518 if (instField < objClass->ifields ||
2519 instField >= objClass->ifields + objClass->ifieldCount)
2520 {
2521 LOG_VFY("VFY: invalid constructor field access (field %s in %s)\n",
2522 instField->field.name, objClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07002523 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002524 goto bail;
2525 }
2526 }
2527
2528bail:
2529 return instField;
2530}
2531
2532/*
2533 * Look up a static field.
2534 *
Andy McFadden62a75162009-04-17 17:23:37 -07002535 * Returns a StaticField on success, returns NULL and sets "*pFailure"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002536 * on failure.
2537 */
2538static StaticField* getStaticField(const Method* meth, int fieldIdx,
Andy McFadden62a75162009-04-17 17:23:37 -07002539 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002540{
2541 StaticField* staticField;
2542
Andy McFadden62a75162009-04-17 17:23:37 -07002543 staticField = dvmOptResolveStaticField(meth->clazz, fieldIdx, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002544 if (staticField == NULL) {
2545 DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
2546 const DexFieldId* pFieldId;
2547
2548 pFieldId = dexGetFieldId(pDexFile, fieldIdx);
2549
2550 LOG_VFY("VFY: unable to resolve static field %u (%s) in %s\n", fieldIdx,
2551 dexStringById(pDexFile, pFieldId->nameIdx),
2552 dexStringByTypeIdx(pDexFile, pFieldId->classIdx));
Andy McFadden62a75162009-04-17 17:23:37 -07002553 assert(!VERIFY_OK(*pFailure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002554 goto bail;
2555 }
2556
2557bail:
2558 return staticField;
2559}
2560
2561/*
2562 * If "field" is marked "final", make sure this is the either <clinit>
2563 * or <init> as appropriate.
2564 *
Andy McFadden62a75162009-04-17 17:23:37 -07002565 * Sets "*pFailure" on failure.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002566 */
2567static void checkFinalFieldAccess(const Method* meth, const Field* field,
Andy McFadden62a75162009-04-17 17:23:37 -07002568 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002569{
2570 if (!dvmIsFinalField(field))
2571 return;
2572
2573 /* make sure we're in the same class */
2574 if (meth->clazz != field->clazz) {
2575 LOG_VFY_METH(meth, "VFY: can't modify final field %s.%s\n",
2576 field->clazz->descriptor, field->name);
Andy McFaddenb51ea112009-05-08 16:50:17 -07002577 *pFailure = VERIFY_ERROR_ACCESS_FIELD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002578 return;
2579 }
2580
2581 /*
Andy McFadden62a75162009-04-17 17:23:37 -07002582 * The VM spec descriptions of putfield and putstatic say that
2583 * IllegalAccessError is only thrown when the instructions appear
2584 * outside the declaring class. Our earlier attempts to restrict
2585 * final field modification to constructors are, therefore, wrong.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002586 */
2587#if 0
2588 /* make sure we're in the right kind of constructor */
2589 if (dvmIsStaticField(field)) {
2590 if (!isClassInitMethod(meth)) {
2591 LOG_VFY_METH(meth,
2592 "VFY: can't modify final static field outside <clinit>\n");
Andy McFadden62a75162009-04-17 17:23:37 -07002593 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002594 }
2595 } else {
2596 if (!isInitMethod(meth)) {
2597 LOG_VFY_METH(meth,
2598 "VFY: can't modify final field outside <init>\n");
Andy McFadden62a75162009-04-17 17:23:37 -07002599 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002600 }
2601 }
2602#endif
2603}
2604
2605/*
2606 * Make sure that the register type is suitable for use as an array index.
2607 *
Andy McFadden62a75162009-04-17 17:23:37 -07002608 * Sets "*pFailure" if not.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002609 */
2610static void checkArrayIndexType(const Method* meth, RegType regType,
Andy McFadden62a75162009-04-17 17:23:37 -07002611 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002612{
Andy McFadden62a75162009-04-17 17:23:37 -07002613 if (VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002614 /*
2615 * The 1nr types are interchangeable at this level. We could
2616 * do something special if we can definitively identify it as a
2617 * float, but there's no real value in doing so.
2618 */
Andy McFadden62a75162009-04-17 17:23:37 -07002619 checkTypeCategory(regType, kTypeCategory1nr, pFailure);
2620 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002621 LOG_VFY_METH(meth, "Invalid reg type for array index (%d)\n",
2622 regType);
2623 }
2624 }
2625}
2626
2627/*
2628 * Check constraints on constructor return. Specifically, make sure that
2629 * the "this" argument got initialized.
2630 *
2631 * The "this" argument to <init> uses code offset kUninitThisArgAddr, which
2632 * puts it at the start of the list in slot 0. If we see a register with
2633 * an uninitialized slot 0 reference, we know it somehow didn't get
2634 * initialized.
2635 *
2636 * Returns "true" if all is well.
2637 */
2638static bool checkConstructorReturn(const Method* meth, const RegType* insnRegs,
2639 const int insnRegCount)
2640{
2641 int i;
2642
2643 if (!isInitMethod(meth))
2644 return true;
2645
2646 RegType uninitThis = regTypeFromUninitIndex(kUninitThisArgSlot);
2647
2648 for (i = 0; i < insnRegCount; i++) {
2649 if (insnRegs[i] == uninitThis) {
2650 LOG_VFY("VFY: <init> returning without calling superclass init\n");
2651 return false;
2652 }
2653 }
2654 return true;
2655}
2656
2657/*
2658 * Verify that the target instruction is not "move-exception". It's important
2659 * that the only way to execute a move-exception is as the first instruction
2660 * of an exception handler.
2661 *
2662 * Returns "true" if all is well, "false" if the target instruction is
2663 * move-exception.
2664 */
2665static bool checkMoveException(const Method* meth, int insnIdx,
2666 const char* logNote)
2667{
2668 assert(insnIdx >= 0 && insnIdx < (int)dvmGetMethodInsnsSize(meth));
2669
2670 if ((meth->insns[insnIdx] & 0xff) == OP_MOVE_EXCEPTION) {
2671 LOG_VFY("VFY: invalid use of move-exception\n");
2672 return false;
2673 }
2674 return true;
2675}
2676
2677/*
2678 * For the "move-exception" instruction at "insnIdx", which must be at an
2679 * exception handler address, determine the first common superclass of
2680 * all exceptions that can land here. (For javac output, we're probably
2681 * looking at multiple spans of bytecode covered by one "try" that lands
2682 * at an exception-specific "catch", but in general the handler could be
2683 * shared for multiple exceptions.)
2684 *
2685 * Returns NULL if no matching exception handler can be found, or if the
2686 * exception is not a subclass of Throwable.
2687 */
Andy McFadden62a75162009-04-17 17:23:37 -07002688static ClassObject* getCaughtExceptionType(const Method* meth, int insnIdx,
2689 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002690{
Andy McFadden62a75162009-04-17 17:23:37 -07002691 VerifyError localFailure;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002692 const DexCode* pCode;
2693 DexFile* pDexFile;
2694 ClassObject* commonSuper = NULL;
Andy McFadden62a75162009-04-17 17:23:37 -07002695 bool foundPossibleHandler = false;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002696 u4 handlersSize;
2697 u4 offset;
2698 u4 i;
2699
2700 pDexFile = meth->clazz->pDvmDex->pDexFile;
2701 pCode = dvmGetMethodCode(meth);
2702
2703 if (pCode->triesSize != 0) {
2704 handlersSize = dexGetHandlersSize(pCode);
2705 offset = dexGetFirstHandlerOffset(pCode);
2706 } else {
2707 handlersSize = 0;
2708 offset = 0;
2709 }
2710
2711 for (i = 0; i < handlersSize; i++) {
2712 DexCatchIterator iterator;
2713 dexCatchIteratorInit(&iterator, pCode, offset);
2714
2715 for (;;) {
2716 const DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
2717
2718 if (handler == NULL) {
2719 break;
2720 }
2721
2722 if (handler->address == (u4) insnIdx) {
2723 ClassObject* clazz;
Andy McFadden62a75162009-04-17 17:23:37 -07002724 foundPossibleHandler = true;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002725
2726 if (handler->typeIdx == kDexNoIndex)
2727 clazz = gDvm.classJavaLangThrowable;
2728 else
Andy McFadden62a75162009-04-17 17:23:37 -07002729 clazz = dvmOptResolveClass(meth->clazz, handler->typeIdx,
2730 &localFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002731
2732 if (clazz == NULL) {
2733 LOG_VFY("VFY: unable to resolve exception class %u (%s)\n",
2734 handler->typeIdx,
2735 dexStringByTypeIdx(pDexFile, handler->typeIdx));
Andy McFadden62a75162009-04-17 17:23:37 -07002736 /* TODO: do we want to keep going? If we don't fail
2737 * this we run the risk of having a non-Throwable
2738 * introduced at runtime. However, that won't pass
2739 * an instanceof test, so is essentially harmless. */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002740 } else {
2741 if (commonSuper == NULL)
2742 commonSuper = clazz;
2743 else
2744 commonSuper = findCommonSuperclass(clazz, commonSuper);
2745 }
2746 }
2747 }
2748
2749 offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
2750 }
2751
2752 if (commonSuper == NULL) {
Andy McFadden62a75162009-04-17 17:23:37 -07002753 /* no catch blocks, or no catches with classes we can find */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002754 LOG_VFY_METH(meth,
2755 "VFY: unable to find exception handler at addr 0x%x\n", insnIdx);
Andy McFadden62a75162009-04-17 17:23:37 -07002756 *pFailure = VERIFY_ERROR_GENERIC;
2757 } else {
2758 // TODO: verify the class is an instance of Throwable?
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002759 }
2760
2761 return commonSuper;
2762}
2763
2764/*
2765 * Initialize the RegisterTable.
2766 *
2767 * Every instruction address can have a different set of information about
2768 * what's in which register, but for verification purposes we only need to
2769 * store it at branch target addresses (because we merge into that).
2770 *
2771 * By zeroing out the storage we are effectively initializing the register
2772 * information to kRegTypeUnknown.
2773 */
2774static bool initRegisterTable(const Method* meth, const InsnFlags* insnFlags,
2775 RegisterTable* regTable, RegisterTrackingMode trackRegsFor)
2776{
2777 const int insnsSize = dvmGetMethodInsnsSize(meth);
2778 int i;
2779
2780 regTable->insnRegCountPlus = meth->registersSize + kExtraRegs;
2781 regTable->addrRegs = (RegType**) calloc(insnsSize, sizeof(RegType*));
2782 if (regTable->addrRegs == NULL)
2783 return false;
2784
2785 assert(insnsSize > 0);
2786
2787 /*
2788 * "All" means "every address that holds the start of an instruction".
2789 * "Branches" and "GcPoints" mean just those addresses.
2790 *
2791 * "GcPoints" fills about half the addresses, "Branches" about 15%.
2792 */
2793 int interestingCount = 0;
2794 //int insnCount = 0;
2795
2796 for (i = 0; i < insnsSize; i++) {
2797 bool interesting;
2798
2799 switch (trackRegsFor) {
2800 case kTrackRegsAll:
2801 interesting = dvmInsnIsOpcode(insnFlags, i);
2802 break;
2803 case kTrackRegsGcPoints:
2804 interesting = dvmInsnIsGcPoint(insnFlags, i) ||
2805 dvmInsnIsBranchTarget(insnFlags, i);
2806 break;
2807 case kTrackRegsBranches:
2808 interesting = dvmInsnIsBranchTarget(insnFlags, i);
2809 break;
2810 default:
2811 dvmAbort();
2812 return false;
2813 }
2814
2815 if (interesting)
2816 interestingCount++;
2817
2818 /* count instructions, for display only */
2819 //if (dvmInsnIsOpcode(insnFlags, i))
2820 // insnCount++;
2821 }
2822
2823 regTable->regAlloc = (RegType*)
2824 calloc(regTable->insnRegCountPlus * interestingCount, sizeof(RegType));
2825 if (regTable->regAlloc == NULL)
2826 return false;
2827
2828 RegType* regPtr = regTable->regAlloc;
2829 for (i = 0; i < insnsSize; i++) {
2830 bool interesting;
2831
2832 switch (trackRegsFor) {
2833 case kTrackRegsAll:
2834 interesting = dvmInsnIsOpcode(insnFlags, i);
2835 break;
2836 case kTrackRegsGcPoints:
2837 interesting = dvmInsnIsGcPoint(insnFlags, i) ||
2838 dvmInsnIsBranchTarget(insnFlags, i);
2839 break;
2840 case kTrackRegsBranches:
2841 interesting = dvmInsnIsBranchTarget(insnFlags, i);
2842 break;
2843 default:
2844 dvmAbort();
2845 return false;
2846 }
2847
2848 if (interesting) {
2849 regTable->addrRegs[i] = regPtr;
2850 regPtr += regTable->insnRegCountPlus;
2851 }
2852 }
2853
2854 //LOGD("Tracking registers for %d, total %d of %d(%d) (%d%%)\n",
2855 // TRACK_REGS_FOR, interestingCount, insnCount, insnsSize,
2856 // (interestingCount*100) / insnCount);
2857
2858 assert(regPtr - regTable->regAlloc ==
2859 regTable->insnRegCountPlus * interestingCount);
2860 assert(regTable->addrRegs[0] != NULL);
2861 return true;
2862}
2863
2864
2865/*
2866 * Verify that the arguments in a filled-new-array instruction are valid.
2867 *
2868 * "resClass" is the class refered to by pDecInsn->vB.
2869 */
2870static void verifyFilledNewArrayRegs(const Method* meth,
Andy McFaddend3250112010-11-03 14:32:42 -07002871 const RegType* insnRegs, const DecodedInstruction* pDecInsn,
2872 ClassObject* resClass, bool isRange, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002873{
2874 u4 argCount = pDecInsn->vA;
2875 RegType expectedType;
2876 PrimitiveType elemType;
2877 unsigned int ui;
2878
2879 assert(dvmIsArrayClass(resClass));
2880 elemType = resClass->elementClass->primitiveType;
2881 if (elemType == PRIM_NOT) {
2882 expectedType = regTypeFromClass(resClass->elementClass);
2883 } else {
2884 expectedType = primitiveTypeToRegType(elemType);
2885 }
2886 //LOGI("filled-new-array: %s -> %d\n", resClass->descriptor, expectedType);
2887
2888 /*
2889 * Verify each register. If "argCount" is bad, verifyRegisterType()
2890 * will run off the end of the list and fail. It's legal, if silly,
2891 * for argCount to be zero.
2892 */
2893 for (ui = 0; ui < argCount; ui++) {
2894 u4 getReg;
2895
2896 if (isRange)
2897 getReg = pDecInsn->vC + ui;
2898 else
2899 getReg = pDecInsn->arg[ui];
2900
Andy McFaddend3250112010-11-03 14:32:42 -07002901 verifyRegisterType(insnRegs, getReg, expectedType, pFailure);
Andy McFadden62a75162009-04-17 17:23:37 -07002902 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002903 LOG_VFY("VFY: filled-new-array arg %u(%u) not valid\n", ui, getReg);
2904 return;
2905 }
2906 }
2907}
2908
2909
2910/*
Andy McFaddenb51ea112009-05-08 16:50:17 -07002911 * Replace an instruction with "throw-verification-error". This allows us to
2912 * defer error reporting until the code path is first used.
2913 *
Andy McFadden861b3382010-03-05 15:58:31 -08002914 * This is expected to be called during "just in time" verification, not
2915 * from within dexopt. (Verification failures in dexopt will result in
2916 * postponement of verification to first use of the class.)
2917 *
Andy McFaddenb51ea112009-05-08 16:50:17 -07002918 * The throw-verification-error instruction requires two code units. Some
2919 * of the replaced instructions require three; the third code unit will
2920 * receive a "nop". The instruction's length will be left unchanged
2921 * in "insnFlags".
2922 *
Andy McFadden96516932009-10-28 17:39:02 -07002923 * The verifier explicitly locks out breakpoint activity, so there should
2924 * be no clashes with the debugger.
2925 *
Andy McFaddenb51ea112009-05-08 16:50:17 -07002926 * Returns "true" on success.
2927 */
Andy McFadden228a6b02010-05-04 15:02:32 -07002928static bool replaceFailingInstruction(const Method* meth, InsnFlags* insnFlags,
Andy McFaddenb51ea112009-05-08 16:50:17 -07002929 int insnIdx, VerifyError failure)
2930{
Andy McFaddenaf0e8382009-08-28 10:38:37 -07002931 VerifyErrorRefType refType;
Andy McFaddenb51ea112009-05-08 16:50:17 -07002932 const u2* oldInsns = meth->insns + insnIdx;
2933 u2 oldInsn = *oldInsns;
2934 bool result = false;
2935
Andy McFaddenfb119e62010-06-28 16:21:20 -07002936 if (gDvm.optimizing)
2937 LOGD("Weird: RFI during dexopt?");
2938
Andy McFaddenb51ea112009-05-08 16:50:17 -07002939 //LOGD(" was 0x%04x\n", oldInsn);
2940 u2* newInsns = (u2*) meth->insns + insnIdx;
2941
2942 /*
2943 * Generate the new instruction out of the old.
2944 *
2945 * First, make sure this is an instruction we're expecting to stomp on.
2946 */
2947 switch (oldInsn & 0xff) {
2948 case OP_CONST_CLASS: // insn[1] == class ref, 2 bytes
2949 case OP_CHECK_CAST:
2950 case OP_INSTANCE_OF:
2951 case OP_NEW_INSTANCE:
2952 case OP_NEW_ARRAY:
Andy McFaddenb51ea112009-05-08 16:50:17 -07002953 case OP_FILLED_NEW_ARRAY: // insn[1] == class ref, 3 bytes
2954 case OP_FILLED_NEW_ARRAY_RANGE:
Andy McFaddenaf0e8382009-08-28 10:38:37 -07002955 refType = VERIFY_ERROR_REF_CLASS;
2956 break;
Andy McFaddenb51ea112009-05-08 16:50:17 -07002957
2958 case OP_IGET: // insn[1] == field ref, 2 bytes
2959 case OP_IGET_BOOLEAN:
2960 case OP_IGET_BYTE:
2961 case OP_IGET_CHAR:
2962 case OP_IGET_SHORT:
2963 case OP_IGET_WIDE:
2964 case OP_IGET_OBJECT:
2965 case OP_IPUT:
2966 case OP_IPUT_BOOLEAN:
2967 case OP_IPUT_BYTE:
2968 case OP_IPUT_CHAR:
2969 case OP_IPUT_SHORT:
2970 case OP_IPUT_WIDE:
2971 case OP_IPUT_OBJECT:
2972 case OP_SGET:
2973 case OP_SGET_BOOLEAN:
2974 case OP_SGET_BYTE:
2975 case OP_SGET_CHAR:
2976 case OP_SGET_SHORT:
2977 case OP_SGET_WIDE:
2978 case OP_SGET_OBJECT:
2979 case OP_SPUT:
2980 case OP_SPUT_BOOLEAN:
2981 case OP_SPUT_BYTE:
2982 case OP_SPUT_CHAR:
2983 case OP_SPUT_SHORT:
2984 case OP_SPUT_WIDE:
2985 case OP_SPUT_OBJECT:
Andy McFaddenaf0e8382009-08-28 10:38:37 -07002986 refType = VERIFY_ERROR_REF_FIELD;
2987 break;
Andy McFaddenb51ea112009-05-08 16:50:17 -07002988
2989 case OP_INVOKE_VIRTUAL: // insn[1] == method ref, 3 bytes
2990 case OP_INVOKE_VIRTUAL_RANGE:
2991 case OP_INVOKE_SUPER:
2992 case OP_INVOKE_SUPER_RANGE:
2993 case OP_INVOKE_DIRECT:
2994 case OP_INVOKE_DIRECT_RANGE:
2995 case OP_INVOKE_STATIC:
2996 case OP_INVOKE_STATIC_RANGE:
2997 case OP_INVOKE_INTERFACE:
2998 case OP_INVOKE_INTERFACE_RANGE:
Andy McFaddenaf0e8382009-08-28 10:38:37 -07002999 refType = VERIFY_ERROR_REF_METHOD;
Andy McFaddenb51ea112009-05-08 16:50:17 -07003000 break;
Andy McFaddenaf0e8382009-08-28 10:38:37 -07003001
Andy McFaddenb51ea112009-05-08 16:50:17 -07003002 default:
3003 /* could handle this in a generic way, but this is probably safer */
3004 LOG_VFY("GLITCH: verifier asked to replace opcode 0x%02x\n",
3005 oldInsn & 0xff);
3006 goto bail;
3007 }
3008
3009 /* write a NOP over the third code unit, if necessary */
3010 int width = dvmInsnGetWidth(insnFlags, insnIdx);
3011 switch (width) {
3012 case 2:
3013 /* nothing to do */
3014 break;
3015 case 3:
Andy McFadden96516932009-10-28 17:39:02 -07003016 dvmDexChangeDex2(meth->clazz->pDvmDex, newInsns+2, OP_NOP);
3017 //newInsns[2] = OP_NOP;
Andy McFaddenb51ea112009-05-08 16:50:17 -07003018 break;
3019 default:
3020 /* whoops */
3021 LOGE("ERROR: stomped a %d-unit instruction with a verifier error\n",
3022 width);
3023 dvmAbort();
3024 }
3025
3026 /* encode the opcode, with the failure code in the high byte */
Andy McFadden96516932009-10-28 17:39:02 -07003027 u2 newVal = OP_THROW_VERIFICATION_ERROR |
Andy McFaddenaf0e8382009-08-28 10:38:37 -07003028 (failure << 8) | (refType << (8 + kVerifyErrorRefTypeShift));
Andy McFadden96516932009-10-28 17:39:02 -07003029 //newInsns[0] = newVal;
3030 dvmDexChangeDex2(meth->clazz->pDvmDex, newInsns, newVal);
Andy McFaddenb51ea112009-05-08 16:50:17 -07003031
3032 result = true;
3033
3034bail:
Andy McFaddenb51ea112009-05-08 16:50:17 -07003035 return result;
3036}
3037
3038
3039/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003040 * ===========================================================================
3041 * Entry point and driver loop
3042 * ===========================================================================
3043 */
3044
3045/*
3046 * Entry point for the detailed code-flow analysis.
3047 */
Andy McFadden228a6b02010-05-04 15:02:32 -07003048bool dvmVerifyCodeFlow(VerifierData* vdata)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003049{
3050 bool result = false;
Andy McFadden228a6b02010-05-04 15:02:32 -07003051 const Method* meth = vdata->method;
3052 const int insnsSize = vdata->insnsSize;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003053 const bool generateRegisterMap = gDvm.generateRegisterMaps;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003054 RegisterTable regTable;
3055
3056 memset(&regTable, 0, sizeof(regTable));
3057
3058#ifndef NDEBUG
3059 checkMergeTab(); // only need to do this if table gets updated
3060#endif
3061
3062 /*
3063 * We rely on these for verification of const-class, const-string,
3064 * and throw instructions. Make sure we have them.
3065 */
3066 if (gDvm.classJavaLangClass == NULL)
3067 gDvm.classJavaLangClass =
3068 dvmFindSystemClassNoInit("Ljava/lang/Class;");
3069 if (gDvm.classJavaLangString == NULL)
3070 gDvm.classJavaLangString =
3071 dvmFindSystemClassNoInit("Ljava/lang/String;");
Andy McFadden686e1e22009-05-26 16:56:30 -07003072 if (gDvm.classJavaLangThrowable == NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003073 gDvm.classJavaLangThrowable =
3074 dvmFindSystemClassNoInit("Ljava/lang/Throwable;");
Andy McFadden686e1e22009-05-26 16:56:30 -07003075 gDvm.offJavaLangThrowable_cause =
3076 dvmFindFieldOffset(gDvm.classJavaLangThrowable,
3077 "cause", "Ljava/lang/Throwable;");
3078 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003079 if (gDvm.classJavaLangObject == NULL)
3080 gDvm.classJavaLangObject =
3081 dvmFindSystemClassNoInit("Ljava/lang/Object;");
3082
Andy McFadden6be954f2010-06-14 13:37:49 -07003083 if (meth->registersSize * insnsSize > 4*1024*1024) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003084 LOG_VFY_METH(meth,
Andy McFadden34e314a2010-09-28 13:58:16 -07003085 "VFY: warning: method is huge (regs=%d insnsSize=%d)\n",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003086 meth->registersSize, insnsSize);
Andy McFadden34e314a2010-09-28 13:58:16 -07003087 /* might be bogus data, might be some huge generated method */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003088 }
3089
3090 /*
3091 * Create register lists, and initialize them to "Unknown". If we're
3092 * also going to create the register map, we need to retain the
3093 * register lists for a larger set of addresses.
3094 */
Andy McFadden228a6b02010-05-04 15:02:32 -07003095 if (!initRegisterTable(meth, vdata->insnFlags, &regTable,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003096 generateRegisterMap ? kTrackRegsGcPoints : kTrackRegsBranches))
3097 goto bail;
3098
Andy McFadden228a6b02010-05-04 15:02:32 -07003099 vdata->addrRegs = NULL; /* don't set this until we need it */
3100
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003101 /*
3102 * Initialize the types of the registers that correspond to the
3103 * method arguments. We can determine this from the method signature.
3104 */
Andy McFadden228a6b02010-05-04 15:02:32 -07003105 if (!setTypesFromSignature(meth, regTable.addrRegs[0], vdata->uninitMap))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003106 goto bail;
3107
3108 /*
3109 * Run the verifier.
3110 */
Andy McFadden228a6b02010-05-04 15:02:32 -07003111 if (!doCodeVerification(meth, vdata->insnFlags, &regTable, vdata->uninitMap))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003112 goto bail;
3113
3114 /*
3115 * Generate a register map.
3116 */
3117 if (generateRegisterMap) {
Andy McFadden228a6b02010-05-04 15:02:32 -07003118 vdata->addrRegs = regTable.addrRegs;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003119
Andy McFadden228a6b02010-05-04 15:02:32 -07003120 RegisterMap* pMap = dvmGenerateRegisterMapV(vdata);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003121 if (pMap != NULL) {
3122 /*
3123 * Tuck it into the Method struct. It will either get used
3124 * directly or, if we're in dexopt, will be packed up and
3125 * appended to the DEX file.
3126 */
3127 dvmSetRegisterMap((Method*)meth, pMap);
3128 }
3129 }
3130
3131 /*
3132 * Success.
3133 */
3134 result = true;
3135
3136bail:
3137 free(regTable.addrRegs);
3138 free(regTable.regAlloc);
3139 return result;
3140}
3141
3142/*
3143 * Grind through the instructions.
3144 *
3145 * The basic strategy is as outlined in v3 4.11.1.2: set the "changed" bit
3146 * on the first instruction, process it (setting additional "changed" bits),
3147 * and repeat until there are no more.
3148 *
3149 * v3 4.11.1.1
3150 * - (N/A) operand stack is always the same size
3151 * - operand stack [registers] contain the correct types of values
3152 * - local variables [registers] contain the correct types of values
3153 * - methods are invoked with the appropriate arguments
3154 * - fields are assigned using values of appropriate types
3155 * - opcodes have the correct type values in operand registers
3156 * - there is never an uninitialized class instance in a local variable in
3157 * code protected by an exception handler (operand stack is okay, because
3158 * the operand stack is discarded when an exception is thrown) [can't
3159 * know what's a local var w/o the debug info -- should fall out of
3160 * register typing]
3161 *
3162 * v3 4.11.1.2
3163 * - execution cannot fall off the end of the code
3164 *
3165 * (We also do many of the items described in the "static checks" sections,
3166 * because it's easier to do them here.)
3167 *
3168 * We need an array of RegType values, one per register, for every
3169 * instruction. In theory this could become quite large -- up to several
3170 * megabytes for a monster function. For self-preservation we reject
3171 * anything that requires more than a certain amount of memory. (Typical
3172 * "large" should be on the order of 4K code units * 8 registers.) This
3173 * will likely have to be adjusted.
3174 *
3175 *
3176 * The spec forbids backward branches when there's an uninitialized reference
3177 * in a register. The idea is to prevent something like this:
3178 * loop:
3179 * move r1, r0
3180 * new-instance r0, MyClass
3181 * ...
3182 * if-eq rN, loop // once
3183 * initialize r0
3184 *
3185 * This leaves us with two different instances, both allocated by the
3186 * same instruction, but only one is initialized. The scheme outlined in
3187 * v3 4.11.1.4 wouldn't catch this, so they work around it by preventing
3188 * backward branches. We achieve identical results without restricting
3189 * code reordering by specifying that you can't execute the new-instance
3190 * instruction if a register contains an uninitialized instance created
3191 * by that same instrutcion.
3192 */
Andy McFadden228a6b02010-05-04 15:02:32 -07003193static bool doCodeVerification(const Method* meth, InsnFlags* insnFlags,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003194 RegisterTable* regTable, UninitInstanceMap* uninitMap)
3195{
3196 const int insnsSize = dvmGetMethodInsnsSize(meth);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003197 RegType workRegs[meth->registersSize + kExtraRegs];
3198 bool result = false;
3199 bool debugVerbose = false;
Carl Shapiroe3c01da2010-05-20 22:54:18 -07003200 int insnIdx, startGuess;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003201
3202 /*
3203 * Begin by marking the first instruction as "changed".
3204 */
3205 dvmInsnSetChanged(insnFlags, 0, true);
3206
3207 if (doVerboseLogging(meth)) {
3208 IF_LOGI() {
3209 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
3210 LOGI("Now verifying: %s.%s %s (ins=%d regs=%d)\n",
3211 meth->clazz->descriptor, meth->name, desc,
3212 meth->insSize, meth->registersSize);
3213 LOGI(" ------ [0 4 8 12 16 20 24 28 32 36\n");
3214 free(desc);
3215 }
3216 debugVerbose = true;
3217 gDebugVerbose = true;
3218 } else {
3219 gDebugVerbose = false;
3220 }
3221
3222 startGuess = 0;
3223
3224 /*
3225 * Continue until no instructions are marked "changed".
3226 */
3227 while (true) {
3228 /*
3229 * Find the first marked one. Use "startGuess" as a way to find
3230 * one quickly.
3231 */
3232 for (insnIdx = startGuess; insnIdx < insnsSize; insnIdx++) {
3233 if (dvmInsnIsChanged(insnFlags, insnIdx))
3234 break;
3235 }
3236
3237 if (insnIdx == insnsSize) {
3238 if (startGuess != 0) {
3239 /* try again, starting from the top */
3240 startGuess = 0;
3241 continue;
3242 } else {
3243 /* all flags are clear */
3244 break;
3245 }
3246 }
3247
3248 /*
3249 * We carry the working set of registers from instruction to
3250 * instruction. If this address can be the target of a branch
3251 * (or throw) instruction, or if we're skipping around chasing
3252 * "changed" flags, we need to load the set of registers from
3253 * the table.
3254 *
3255 * Because we always prefer to continue on to the next instruction,
3256 * we should never have a situation where we have a stray
3257 * "changed" flag set on an instruction that isn't a branch target.
3258 */
3259 if (dvmInsnIsBranchTarget(insnFlags, insnIdx)) {
3260 RegType* insnRegs = getRegisterLine(regTable, insnIdx);
3261 assert(insnRegs != NULL);
3262 copyRegisters(workRegs, insnRegs, meth->registersSize + kExtraRegs);
3263
3264 if (debugVerbose) {
3265 dumpRegTypes(meth, insnFlags, workRegs, insnIdx, NULL,uninitMap,
3266 SHOW_REG_DETAILS);
3267 }
3268
3269 } else {
3270 if (debugVerbose) {
3271 dumpRegTypes(meth, insnFlags, workRegs, insnIdx, NULL,uninitMap,
3272 SHOW_REG_DETAILS);
3273 }
3274
3275#ifndef NDEBUG
3276 /*
3277 * Sanity check: retrieve the stored register line (assuming
3278 * a full table) and make sure it actually matches.
3279 */
3280 RegType* insnRegs = getRegisterLine(regTable, insnIdx);
3281 if (insnRegs != NULL &&
3282 compareRegisters(workRegs, insnRegs,
3283 meth->registersSize + kExtraRegs) != 0)
3284 {
3285 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
3286 LOG_VFY("HUH? workRegs diverged in %s.%s %s\n",
3287 meth->clazz->descriptor, meth->name, desc);
3288 free(desc);
3289 dumpRegTypes(meth, insnFlags, workRegs, 0, "work",
3290 uninitMap, DRT_SHOW_REF_TYPES | DRT_SHOW_LOCALS);
3291 dumpRegTypes(meth, insnFlags, insnRegs, 0, "insn",
3292 uninitMap, DRT_SHOW_REF_TYPES | DRT_SHOW_LOCALS);
3293 }
3294#endif
3295 }
3296
3297 //LOGI("process %s.%s %s %d\n",
3298 // meth->clazz->descriptor, meth->name, meth->descriptor, insnIdx);
3299 if (!verifyInstruction(meth, insnFlags, regTable, workRegs, insnIdx,
3300 uninitMap, &startGuess))
3301 {
3302 //LOGD("+++ %s bailing at %d\n", meth->name, insnIdx);
3303 goto bail;
3304 }
3305
3306#if 0
3307 {
3308 static const int gcMask = kInstrCanBranch | kInstrCanSwitch |
3309 kInstrCanThrow | kInstrCanReturn;
3310 OpCode opCode = *(meth->insns + insnIdx) & 0xff;
3311 int flags = dexGetInstrFlags(gDvm.instrFlags, opCode);
3312
3313 /* 8, 16, 32, or 32*n -bit regs */
3314 int regWidth = (meth->registersSize + 7) / 8;
3315 if (regWidth == 3)
3316 regWidth = 4;
3317 if (regWidth > 4) {
3318 regWidth = ((regWidth + 3) / 4) * 4;
3319 if (false) {
3320 LOGW("WOW: %d regs -> %d %s.%s\n",
3321 meth->registersSize, regWidth,
3322 meth->clazz->descriptor, meth->name);
3323 //x = true;
3324 }
3325 }
3326
3327 if ((flags & gcMask) != 0) {
3328 /* this is a potential GC point */
3329 gDvm__gcInstr++;
3330
3331 if (insnsSize < 256)
3332 gDvm__gcData += 1;
3333 else
3334 gDvm__gcData += 2;
3335 gDvm__gcData += regWidth;
3336 }
3337 gDvm__gcSimpleData += regWidth;
3338
3339 gDvm__totalInstr++;
3340 }
3341#endif
3342
3343 /*
3344 * Clear "changed" and mark as visited.
3345 */
3346 dvmInsnSetVisited(insnFlags, insnIdx, true);
3347 dvmInsnSetChanged(insnFlags, insnIdx, false);
3348 }
3349
Andy McFaddenb51ea112009-05-08 16:50:17 -07003350 if (DEAD_CODE_SCAN && !IS_METHOD_FLAG_SET(meth, METHOD_ISWRITABLE)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003351 /*
Andy McFaddenb51ea112009-05-08 16:50:17 -07003352 * Scan for dead code. There's nothing "evil" about dead code
3353 * (besides the wasted space), but it indicates a flaw somewhere
3354 * down the line, possibly in the verifier.
3355 *
3356 * If we've rewritten "always throw" instructions into the stream,
3357 * we are almost certainly going to have some dead code.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003358 */
3359 int deadStart = -1;
3360 for (insnIdx = 0; insnIdx < insnsSize;
3361 insnIdx += dvmInsnGetWidth(insnFlags, insnIdx))
3362 {
3363 /*
3364 * Switch-statement data doesn't get "visited" by scanner. It
3365 * may or may not be preceded by a padding NOP.
3366 */
3367 int instr = meth->insns[insnIdx];
3368 if (instr == kPackedSwitchSignature ||
3369 instr == kSparseSwitchSignature ||
3370 instr == kArrayDataSignature ||
3371 (instr == OP_NOP &&
3372 (meth->insns[insnIdx+1] == kPackedSwitchSignature ||
3373 meth->insns[insnIdx+1] == kSparseSwitchSignature ||
3374 meth->insns[insnIdx+1] == kArrayDataSignature)))
3375 {
3376 dvmInsnSetVisited(insnFlags, insnIdx, true);
3377 }
3378
3379 if (!dvmInsnIsVisited(insnFlags, insnIdx)) {
3380 if (deadStart < 0)
3381 deadStart = insnIdx;
3382 } else if (deadStart >= 0) {
3383 IF_LOGD() {
3384 char* desc =
3385 dexProtoCopyMethodDescriptor(&meth->prototype);
3386 LOGD("VFY: dead code 0x%04x-%04x in %s.%s %s\n",
3387 deadStart, insnIdx-1,
3388 meth->clazz->descriptor, meth->name, desc);
3389 free(desc);
3390 }
3391
3392 deadStart = -1;
3393 }
3394 }
3395 if (deadStart >= 0) {
3396 IF_LOGD() {
3397 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
3398 LOGD("VFY: dead code 0x%04x-%04x in %s.%s %s\n",
3399 deadStart, insnIdx-1,
3400 meth->clazz->descriptor, meth->name, desc);
3401 free(desc);
3402 }
3403 }
3404 }
3405
3406 result = true;
3407
3408bail:
3409 return result;
3410}
3411
3412
3413/*
3414 * Perform verification for a single instruction.
3415 *
3416 * This requires fully decoding the instruction to determine the effect
3417 * it has on registers.
3418 *
3419 * Finds zero or more following instructions and sets the "changed" flag
3420 * if execution at that point needs to be (re-)evaluated. Register changes
3421 * are merged into "regTypes" at the target addresses. Does not set or
3422 * clear any other flags in "insnFlags".
Andy McFaddenb51ea112009-05-08 16:50:17 -07003423 *
3424 * This may alter meth->insns if we need to replace an instruction with
3425 * throw-verification-error.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003426 */
Andy McFadden228a6b02010-05-04 15:02:32 -07003427static bool verifyInstruction(const Method* meth, InsnFlags* insnFlags,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003428 RegisterTable* regTable, RegType* workRegs, int insnIdx,
3429 UninitInstanceMap* uninitMap, int* pStartGuess)
3430{
3431 const int insnsSize = dvmGetMethodInsnsSize(meth);
3432 const u2* insns = meth->insns + insnIdx;
3433 bool result = false;
3434
3435 /*
3436 * Once we finish decoding the instruction, we need to figure out where
3437 * we can go from here. There are three possible ways to transfer
3438 * control to another statement:
3439 *
3440 * (1) Continue to the next instruction. Applies to all but
3441 * unconditional branches, method returns, and exception throws.
3442 * (2) Branch to one or more possible locations. Applies to branches
3443 * and switch statements.
3444 * (3) Exception handlers. Applies to any instruction that can
3445 * throw an exception that is handled by an encompassing "try"
Andy McFadden228a6b02010-05-04 15:02:32 -07003446 * block.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003447 *
3448 * We can also return, in which case there is no successor instruction
3449 * from this point.
3450 *
Andy McFadden228a6b02010-05-04 15:02:32 -07003451 * The behavior can be determined from the InstructionFlags.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003452 */
3453
3454 const DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
3455 RegType entryRegs[meth->registersSize + kExtraRegs];
3456 ClassObject* resClass;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003457 int branchTarget = 0;
3458 const int insnRegCount = meth->registersSize;
3459 RegType tmpType;
3460 DecodedInstruction decInsn;
3461 bool justSetResult = false;
Andy McFadden62a75162009-04-17 17:23:37 -07003462 VerifyError failure = VERIFY_ERROR_NONE;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003463
3464#ifndef NDEBUG
3465 memset(&decInsn, 0x81, sizeof(decInsn));
3466#endif
3467 dexDecodeInstruction(gDvm.instrFormat, insns, &decInsn);
3468
Andy McFaddenb51ea112009-05-08 16:50:17 -07003469 int nextFlags = dexGetInstrFlags(gDvm.instrFlags, decInsn.opCode);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003470
3471 /*
3472 * Make a copy of the previous register state. If the instruction
3473 * throws an exception, we merge *this* into the destination rather
3474 * than workRegs, because we don't want the result from the "successful"
3475 * code path (e.g. a check-cast that "improves" a type) to be visible
3476 * to the exception handler.
3477 */
3478 if ((nextFlags & kInstrCanThrow) != 0 && dvmInsnIsInTry(insnFlags, insnIdx))
3479 {
3480 copyRegisters(entryRegs, workRegs, meth->registersSize + kExtraRegs);
3481 } else {
3482#ifndef NDEBUG
3483 memset(entryRegs, 0xdd,
3484 (meth->registersSize + kExtraRegs) * sizeof(RegType));
3485#endif
3486 }
3487
3488 switch (decInsn.opCode) {
3489 case OP_NOP:
3490 /*
3491 * A "pure" NOP has no effect on anything. Data tables start with
3492 * a signature that looks like a NOP; if we see one of these in
3493 * the course of executing code then we have a problem.
3494 */
3495 if (decInsn.vA != 0) {
3496 LOG_VFY("VFY: encountered data table in instruction stream\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003497 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003498 }
3499 break;
3500
3501 case OP_MOVE:
3502 case OP_MOVE_FROM16:
3503 case OP_MOVE_16:
Andy McFaddend3250112010-11-03 14:32:42 -07003504 copyRegister1(workRegs, decInsn.vA, decInsn.vB, kTypeCategory1nr,
3505 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003506 break;
3507 case OP_MOVE_WIDE:
3508 case OP_MOVE_WIDE_FROM16:
3509 case OP_MOVE_WIDE_16:
Andy McFaddend3250112010-11-03 14:32:42 -07003510 copyRegister2(workRegs, decInsn.vA, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003511 break;
3512 case OP_MOVE_OBJECT:
3513 case OP_MOVE_OBJECT_FROM16:
3514 case OP_MOVE_OBJECT_16:
Andy McFaddend3250112010-11-03 14:32:42 -07003515 copyRegister1(workRegs, decInsn.vA, decInsn.vB, kTypeCategoryRef,
3516 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003517 break;
3518
3519 /*
3520 * The move-result instructions copy data out of a "pseudo-register"
3521 * with the results from the last method invocation. In practice we
3522 * might want to hold the result in an actual CPU register, so the
3523 * Dalvik spec requires that these only appear immediately after an
3524 * invoke or filled-new-array.
3525 *
3526 * These calls invalidate the "result" register. (This is now
3527 * redundant with the reset done below, but it can make the debug info
3528 * easier to read in some cases.)
3529 */
3530 case OP_MOVE_RESULT:
3531 copyResultRegister1(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003532 kTypeCategory1nr, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003533 break;
3534 case OP_MOVE_RESULT_WIDE:
Andy McFadden62a75162009-04-17 17:23:37 -07003535 copyResultRegister2(workRegs, insnRegCount, decInsn.vA, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003536 break;
3537 case OP_MOVE_RESULT_OBJECT:
3538 copyResultRegister1(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003539 kTypeCategoryRef, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003540 break;
3541
3542 case OP_MOVE_EXCEPTION:
3543 /*
3544 * This statement can only appear as the first instruction in an
3545 * exception handler (though not all exception handlers need to
3546 * have one of these). We verify that as part of extracting the
3547 * exception type from the catch block list.
3548 *
3549 * "resClass" will hold the closest common superclass of all
3550 * exceptions that can be handled here.
3551 */
Andy McFadden62a75162009-04-17 17:23:37 -07003552 resClass = getCaughtExceptionType(meth, insnIdx, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003553 if (resClass == NULL) {
Andy McFadden62a75162009-04-17 17:23:37 -07003554 assert(!VERIFY_OK(failure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003555 } else {
Andy McFaddend3250112010-11-03 14:32:42 -07003556 setRegisterType(workRegs, decInsn.vA, regTypeFromClass(resClass));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003557 }
3558 break;
3559
3560 case OP_RETURN_VOID:
Andy McFadden62a75162009-04-17 17:23:37 -07003561 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3562 failure = VERIFY_ERROR_GENERIC;
3563 } else if (getMethodReturnType(meth) != kRegTypeUnknown) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003564 LOG_VFY("VFY: return-void not expected\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003565 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003566 }
3567 break;
3568 case OP_RETURN:
Andy McFadden62a75162009-04-17 17:23:37 -07003569 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3570 failure = VERIFY_ERROR_GENERIC;
3571 } else {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003572 /* check the method signature */
3573 RegType returnType = getMethodReturnType(meth);
Andy McFadden62a75162009-04-17 17:23:37 -07003574 checkTypeCategory(returnType, kTypeCategory1nr, &failure);
3575 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003576 LOG_VFY("VFY: return-32 not expected\n");
3577
3578 /* check the register contents */
Andy McFaddend3250112010-11-03 14:32:42 -07003579 returnType = getRegisterType(workRegs, decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07003580 checkTypeCategory(returnType, kTypeCategory1nr, &failure);
3581 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003582 LOG_VFY("VFY: return-32 on invalid register v%d\n", decInsn.vA);
3583 }
3584 break;
3585 case OP_RETURN_WIDE:
Andy McFadden62a75162009-04-17 17:23:37 -07003586 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3587 failure = VERIFY_ERROR_GENERIC;
3588 } else {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003589 RegType returnType, returnTypeHi;
3590
3591 /* check the method signature */
3592 returnType = getMethodReturnType(meth);
Andy McFadden62a75162009-04-17 17:23:37 -07003593 checkTypeCategory(returnType, kTypeCategory2, &failure);
3594 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003595 LOG_VFY("VFY: return-wide not expected\n");
3596
3597 /* check the register contents */
Andy McFaddend3250112010-11-03 14:32:42 -07003598 returnType = getRegisterType(workRegs, decInsn.vA);
3599 returnTypeHi = getRegisterType(workRegs, decInsn.vA +1);
3600 checkTypeCategory(returnType, kTypeCategory2, &failure);
3601 checkWidePair(returnType, returnTypeHi, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07003602 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003603 LOG_VFY("VFY: return-wide on invalid register pair v%d\n",
3604 decInsn.vA);
3605 }
3606 }
3607 break;
3608 case OP_RETURN_OBJECT:
Andy McFadden62a75162009-04-17 17:23:37 -07003609 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3610 failure = VERIFY_ERROR_GENERIC;
3611 } else {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003612 RegType returnType = getMethodReturnType(meth);
Andy McFadden62a75162009-04-17 17:23:37 -07003613 checkTypeCategory(returnType, kTypeCategoryRef, &failure);
3614 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003615 LOG_VFY("VFY: return-object not expected\n");
3616 break;
3617 }
3618
3619 /* returnType is the *expected* return type, not register value */
3620 assert(returnType != kRegTypeZero);
3621 assert(!regTypeIsUninitReference(returnType));
3622
3623 /*
3624 * Verify that the reference in vAA is an instance of the type
3625 * in "returnType". The Zero type is allowed here. If the
3626 * method is declared to return an interface, then any
3627 * initialized reference is acceptable.
3628 *
3629 * Note getClassFromRegister fails if the register holds an
3630 * uninitialized reference, so we do not allow them to be
3631 * returned.
3632 */
3633 ClassObject* declClass;
3634
3635 declClass = regTypeInitializedReferenceToClass(returnType);
Andy McFaddend3250112010-11-03 14:32:42 -07003636 resClass = getClassFromRegister(workRegs, decInsn.vA, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07003637 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003638 break;
3639 if (resClass != NULL) {
3640 if (!dvmIsInterfaceClass(declClass) &&
3641 !dvmInstanceof(resClass, declClass))
3642 {
Andy McFadden86c86432009-05-27 14:40:12 -07003643 LOG_VFY("VFY: returning %s (cl=%p), declared %s (cl=%p)\n",
3644 resClass->descriptor, resClass->classLoader,
3645 declClass->descriptor, declClass->classLoader);
Andy McFadden62a75162009-04-17 17:23:37 -07003646 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003647 break;
3648 }
3649 }
3650 }
3651 break;
3652
3653 case OP_CONST_4:
3654 case OP_CONST_16:
3655 case OP_CONST:
3656 /* could be boolean, int, float, or a null reference */
Andy McFaddend3250112010-11-03 14:32:42 -07003657 setRegisterType(workRegs, decInsn.vA,
3658 dvmDetermineCat1Const((s4)decInsn.vB));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003659 break;
3660 case OP_CONST_HIGH16:
3661 /* could be boolean, int, float, or a null reference */
Andy McFaddend3250112010-11-03 14:32:42 -07003662 setRegisterType(workRegs, decInsn.vA,
3663 dvmDetermineCat1Const((s4) decInsn.vB << 16));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003664 break;
3665 case OP_CONST_WIDE_16:
3666 case OP_CONST_WIDE_32:
3667 case OP_CONST_WIDE:
3668 case OP_CONST_WIDE_HIGH16:
3669 /* could be long or double; default to long and allow conversion */
Andy McFaddend3250112010-11-03 14:32:42 -07003670 setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003671 break;
3672 case OP_CONST_STRING:
3673 case OP_CONST_STRING_JUMBO:
3674 assert(gDvm.classJavaLangString != NULL);
Andy McFaddend3250112010-11-03 14:32:42 -07003675 setRegisterType(workRegs, decInsn.vA,
3676 regTypeFromClass(gDvm.classJavaLangString));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003677 break;
3678 case OP_CONST_CLASS:
3679 assert(gDvm.classJavaLangClass != NULL);
3680 /* make sure we can resolve the class; access check is important */
Andy McFadden62a75162009-04-17 17:23:37 -07003681 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003682 if (resClass == NULL) {
3683 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3684 dvmLogUnableToResolveClass(badClassDesc, meth);
3685 LOG_VFY("VFY: unable to resolve const-class %d (%s) in %s\n",
3686 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003687 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003688 } else {
Andy McFaddend3250112010-11-03 14:32:42 -07003689 setRegisterType(workRegs, decInsn.vA,
3690 regTypeFromClass(gDvm.classJavaLangClass));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003691 }
3692 break;
3693
3694 case OP_MONITOR_ENTER:
3695 case OP_MONITOR_EXIT:
Andy McFaddend3250112010-11-03 14:32:42 -07003696 tmpType = getRegisterType(workRegs, decInsn.vA);
3697 if (!regTypeIsReference(tmpType)) {
3698 LOG_VFY("VFY: monitor op on non-object\n");
3699 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003700 }
3701 break;
3702
3703 case OP_CHECK_CAST:
3704 /*
3705 * If this instruction succeeds, we will promote register vA to
3706 * the type in vB. (This could be a demotion -- not expected, so
3707 * we don't try to address it.)
3708 *
3709 * If it fails, an exception is thrown, which we deal with later
3710 * by ignoring the update to decInsn.vA when branching to a handler.
3711 */
Andy McFadden62a75162009-04-17 17:23:37 -07003712 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003713 if (resClass == NULL) {
3714 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3715 dvmLogUnableToResolveClass(badClassDesc, meth);
3716 LOG_VFY("VFY: unable to resolve check-cast %d (%s) in %s\n",
3717 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003718 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003719 } else {
3720 RegType origType;
3721
Andy McFaddend3250112010-11-03 14:32:42 -07003722 origType = getRegisterType(workRegs, decInsn.vA);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003723 if (!regTypeIsReference(origType)) {
3724 LOG_VFY("VFY: check-cast on non-reference in v%u\n",decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07003725 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003726 break;
3727 }
Andy McFaddend3250112010-11-03 14:32:42 -07003728 setRegisterType(workRegs, decInsn.vA, regTypeFromClass(resClass));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003729 }
3730 break;
3731 case OP_INSTANCE_OF:
3732 /* make sure we're checking a reference type */
Andy McFaddend3250112010-11-03 14:32:42 -07003733 tmpType = getRegisterType(workRegs, decInsn.vB);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003734 if (!regTypeIsReference(tmpType)) {
3735 LOG_VFY("VFY: vB not a reference (%d)\n", tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07003736 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003737 break;
3738 }
3739
3740 /* make sure we can resolve the class; access check is important */
Andy McFadden62a75162009-04-17 17:23:37 -07003741 resClass = dvmOptResolveClass(meth->clazz, decInsn.vC, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003742 if (resClass == NULL) {
3743 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vC);
3744 dvmLogUnableToResolveClass(badClassDesc, meth);
3745 LOG_VFY("VFY: unable to resolve instanceof %d (%s) in %s\n",
3746 decInsn.vC, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003747 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003748 } else {
3749 /* result is boolean */
Andy McFaddend3250112010-11-03 14:32:42 -07003750 setRegisterType(workRegs, decInsn.vA, kRegTypeBoolean);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003751 }
3752 break;
3753
3754 case OP_ARRAY_LENGTH:
Andy McFaddend3250112010-11-03 14:32:42 -07003755 resClass = getClassFromRegister(workRegs, decInsn.vB, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07003756 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003757 break;
3758 if (resClass != NULL && !dvmIsArrayClass(resClass)) {
3759 LOG_VFY("VFY: array-length on non-array\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003760 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003761 break;
3762 }
Andy McFaddend3250112010-11-03 14:32:42 -07003763 setRegisterType(workRegs, decInsn.vA, kRegTypeInteger);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003764 break;
3765
3766 case OP_NEW_INSTANCE:
Andy McFadden62a75162009-04-17 17:23:37 -07003767 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003768 if (resClass == NULL) {
3769 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3770 dvmLogUnableToResolveClass(badClassDesc, meth);
3771 LOG_VFY("VFY: unable to resolve new-instance %d (%s) in %s\n",
3772 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003773 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003774 } else {
3775 RegType uninitType;
3776
Andy McFaddenb51ea112009-05-08 16:50:17 -07003777 /* can't create an instance of an interface or abstract class */
3778 if (dvmIsAbstractClass(resClass) || dvmIsInterfaceClass(resClass)) {
3779 LOG_VFY("VFY: new-instance on interface or abstract class %s\n",
3780 resClass->descriptor);
3781 failure = VERIFY_ERROR_INSTANTIATION;
3782 break;
3783 }
3784
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003785 /* add resolved class to uninit map if not already there */
3786 int uidx = dvmSetUninitInstance(uninitMap, insnIdx, resClass);
3787 assert(uidx >= 0);
3788 uninitType = regTypeFromUninitIndex(uidx);
3789
3790 /*
3791 * Any registers holding previous allocations from this address
3792 * that have not yet been initialized must be marked invalid.
3793 */
3794 markUninitRefsAsInvalid(workRegs, insnRegCount, uninitMap,
3795 uninitType);
3796
3797 /* add the new uninitialized reference to the register ste */
Andy McFaddend3250112010-11-03 14:32:42 -07003798 setRegisterType(workRegs, decInsn.vA, uninitType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003799 }
3800 break;
3801 case OP_NEW_ARRAY:
Andy McFadden62a75162009-04-17 17:23:37 -07003802 resClass = dvmOptResolveClass(meth->clazz, decInsn.vC, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003803 if (resClass == NULL) {
3804 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vC);
3805 dvmLogUnableToResolveClass(badClassDesc, meth);
3806 LOG_VFY("VFY: unable to resolve new-array %d (%s) in %s\n",
3807 decInsn.vC, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003808 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003809 } else if (!dvmIsArrayClass(resClass)) {
3810 LOG_VFY("VFY: new-array on non-array class\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003811 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003812 } else {
3813 /* make sure "size" register is valid type */
Andy McFaddend3250112010-11-03 14:32:42 -07003814 verifyRegisterType(workRegs, decInsn.vB, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003815 /* set register type to array class */
Andy McFaddend3250112010-11-03 14:32:42 -07003816 setRegisterType(workRegs, decInsn.vA, regTypeFromClass(resClass));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003817 }
3818 break;
3819 case OP_FILLED_NEW_ARRAY:
3820 case OP_FILLED_NEW_ARRAY_RANGE:
Andy McFadden62a75162009-04-17 17:23:37 -07003821 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003822 if (resClass == NULL) {
3823 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3824 dvmLogUnableToResolveClass(badClassDesc, meth);
3825 LOG_VFY("VFY: unable to resolve filled-array %d (%s) in %s\n",
3826 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003827 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003828 } else if (!dvmIsArrayClass(resClass)) {
3829 LOG_VFY("VFY: filled-new-array on non-array class\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003830 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003831 } else {
3832 bool isRange = (decInsn.opCode == OP_FILLED_NEW_ARRAY_RANGE);
3833
3834 /* check the arguments to the instruction */
Andy McFaddend3250112010-11-03 14:32:42 -07003835 verifyFilledNewArrayRegs(meth, workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07003836 resClass, isRange, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003837 /* filled-array result goes into "result" register */
3838 setResultRegisterType(workRegs, insnRegCount,
Andy McFaddend3250112010-11-03 14:32:42 -07003839 regTypeFromClass(resClass));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003840 justSetResult = true;
3841 }
3842 break;
3843
3844 case OP_CMPL_FLOAT:
3845 case OP_CMPG_FLOAT:
Andy McFaddend3250112010-11-03 14:32:42 -07003846 verifyRegisterType(workRegs, decInsn.vB, kRegTypeFloat, &failure);
3847 verifyRegisterType(workRegs, decInsn.vC, kRegTypeFloat, &failure);
3848 setRegisterType(workRegs, decInsn.vA, kRegTypeBoolean);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003849 break;
3850 case OP_CMPL_DOUBLE:
3851 case OP_CMPG_DOUBLE:
Andy McFaddend3250112010-11-03 14:32:42 -07003852 verifyRegisterType(workRegs, decInsn.vB, kRegTypeDoubleLo, &failure);
3853 verifyRegisterType(workRegs, decInsn.vC, kRegTypeDoubleLo, &failure);
3854 setRegisterType(workRegs, decInsn.vA, kRegTypeBoolean);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003855 break;
3856 case OP_CMP_LONG:
Andy McFaddend3250112010-11-03 14:32:42 -07003857 verifyRegisterType(workRegs, decInsn.vB, kRegTypeLongLo, &failure);
3858 verifyRegisterType(workRegs, decInsn.vC, kRegTypeLongLo, &failure);
3859 setRegisterType(workRegs, decInsn.vA, kRegTypeBoolean);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003860 break;
3861
3862 case OP_THROW:
Andy McFaddend3250112010-11-03 14:32:42 -07003863 resClass = getClassFromRegister(workRegs, decInsn.vA, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07003864 if (VERIFY_OK(failure) && resClass != NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003865 if (!dvmInstanceof(resClass, gDvm.classJavaLangThrowable)) {
3866 LOG_VFY("VFY: thrown class %s not instanceof Throwable\n",
3867 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003868 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003869 }
3870 }
3871 break;
3872
3873 case OP_GOTO:
3874 case OP_GOTO_16:
3875 case OP_GOTO_32:
3876 /* no effect on or use of registers */
3877 break;
3878
3879 case OP_PACKED_SWITCH:
3880 case OP_SPARSE_SWITCH:
3881 /* verify that vAA is an integer, or can be converted to one */
Andy McFaddend3250112010-11-03 14:32:42 -07003882 verifyRegisterType(workRegs, decInsn.vA, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003883 break;
3884
3885 case OP_FILL_ARRAY_DATA:
3886 {
3887 RegType valueType;
3888 const u2 *arrayData;
3889 u2 elemWidth;
3890
3891 /* Similar to the verification done for APUT */
Andy McFaddend3250112010-11-03 14:32:42 -07003892 resClass = getClassFromRegister(workRegs, decInsn.vA, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07003893 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003894 break;
3895
3896 /* resClass can be null if the reg type is Zero */
3897 if (resClass == NULL)
3898 break;
3899
3900 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
3901 resClass->elementClass->primitiveType == PRIM_NOT ||
3902 resClass->elementClass->primitiveType == PRIM_VOID)
3903 {
3904 LOG_VFY("VFY: invalid fill-array-data on %s\n",
3905 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003906 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003907 break;
3908 }
3909
3910 valueType = primitiveTypeToRegType(
3911 resClass->elementClass->primitiveType);
3912 assert(valueType != kRegTypeUnknown);
3913
3914 /*
3915 * Now verify if the element width in the table matches the element
3916 * width declared in the array
3917 */
3918 arrayData = insns + (insns[1] | (((s4)insns[2]) << 16));
3919 if (arrayData[0] != kArrayDataSignature) {
3920 LOG_VFY("VFY: invalid magic for array-data\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003921 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003922 break;
3923 }
3924
3925 switch (resClass->elementClass->primitiveType) {
3926 case PRIM_BOOLEAN:
3927 case PRIM_BYTE:
3928 elemWidth = 1;
3929 break;
3930 case PRIM_CHAR:
3931 case PRIM_SHORT:
3932 elemWidth = 2;
3933 break;
3934 case PRIM_FLOAT:
3935 case PRIM_INT:
3936 elemWidth = 4;
3937 break;
3938 case PRIM_DOUBLE:
3939 case PRIM_LONG:
3940 elemWidth = 8;
3941 break;
3942 default:
3943 elemWidth = 0;
3944 break;
3945 }
3946
3947 /*
3948 * Since we don't compress the data in Dex, expect to see equal
3949 * width of data stored in the table and expected from the array
3950 * class.
3951 */
3952 if (arrayData[1] != elemWidth) {
3953 LOG_VFY("VFY: array-data size mismatch (%d vs %d)\n",
3954 arrayData[1], elemWidth);
Andy McFadden62a75162009-04-17 17:23:37 -07003955 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003956 }
3957 }
3958 break;
3959
3960 case OP_IF_EQ:
3961 case OP_IF_NE:
3962 {
3963 RegType type1, type2;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003964
Andy McFaddend3250112010-11-03 14:32:42 -07003965 type1 = getRegisterType(workRegs, decInsn.vA);
3966 type2 = getRegisterType(workRegs, decInsn.vB);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003967
3968 /* both references? */
3969 if (regTypeIsReference(type1) && regTypeIsReference(type2))
3970 break;
3971
3972 /* both category-1nr? */
Andy McFadden62a75162009-04-17 17:23:37 -07003973 checkTypeCategory(type1, kTypeCategory1nr, &failure);
3974 checkTypeCategory(type2, kTypeCategory1nr, &failure);
3975 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003976 LOG_VFY("VFY: args to if-eq/if-ne must both be refs or cat1\n");
3977 break;
3978 }
3979 }
3980 break;
3981 case OP_IF_LT:
3982 case OP_IF_GE:
3983 case OP_IF_GT:
3984 case OP_IF_LE:
Andy McFaddend3250112010-11-03 14:32:42 -07003985 tmpType = getRegisterType(workRegs, decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07003986 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
3987 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003988 LOG_VFY("VFY: args to 'if' must be cat-1nr\n");
3989 break;
3990 }
Andy McFaddend3250112010-11-03 14:32:42 -07003991 tmpType = getRegisterType(workRegs, decInsn.vB);
Andy McFadden62a75162009-04-17 17:23:37 -07003992 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
3993 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003994 LOG_VFY("VFY: args to 'if' must be cat-1nr\n");
3995 break;
3996 }
3997 break;
3998 case OP_IF_EQZ:
3999 case OP_IF_NEZ:
Andy McFaddend3250112010-11-03 14:32:42 -07004000 tmpType = getRegisterType(workRegs, decInsn.vA);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004001 if (regTypeIsReference(tmpType))
4002 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004003 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
4004 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004005 LOG_VFY("VFY: expected cat-1 arg to if\n");
4006 break;
4007 case OP_IF_LTZ:
4008 case OP_IF_GEZ:
4009 case OP_IF_GTZ:
4010 case OP_IF_LEZ:
Andy McFaddend3250112010-11-03 14:32:42 -07004011 tmpType = getRegisterType(workRegs, decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07004012 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
4013 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004014 LOG_VFY("VFY: expected cat-1 arg to if\n");
4015 break;
4016
4017 case OP_AGET:
4018 tmpType = kRegTypeInteger;
4019 goto aget_1nr_common;
4020 case OP_AGET_BOOLEAN:
4021 tmpType = kRegTypeBoolean;
4022 goto aget_1nr_common;
4023 case OP_AGET_BYTE:
4024 tmpType = kRegTypeByte;
4025 goto aget_1nr_common;
4026 case OP_AGET_CHAR:
4027 tmpType = kRegTypeChar;
4028 goto aget_1nr_common;
4029 case OP_AGET_SHORT:
4030 tmpType = kRegTypeShort;
4031 goto aget_1nr_common;
4032aget_1nr_common:
4033 {
4034 RegType srcType, indexType;
4035
Andy McFaddend3250112010-11-03 14:32:42 -07004036 indexType = getRegisterType(workRegs, decInsn.vC);
Andy McFadden62a75162009-04-17 17:23:37 -07004037 checkArrayIndexType(meth, indexType, &failure);
4038 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004039 break;
4040
Andy McFaddend3250112010-11-03 14:32:42 -07004041 resClass = getClassFromRegister(workRegs, decInsn.vB, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07004042 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004043 break;
4044 if (resClass != NULL) {
4045 /* verify the class */
4046 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4047 resClass->elementClass->primitiveType == PRIM_NOT)
4048 {
4049 LOG_VFY("VFY: invalid aget-1nr target %s\n",
4050 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004051 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004052 break;
4053 }
4054
4055 /* make sure array type matches instruction */
4056 srcType = primitiveTypeToRegType(
4057 resClass->elementClass->primitiveType);
4058
4059 if (!checkFieldArrayStore1nr(tmpType, srcType)) {
4060 LOG_VFY("VFY: invalid aget-1nr, array type=%d with"
4061 " inst type=%d (on %s)\n",
4062 srcType, tmpType, resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004063 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004064 break;
4065 }
4066
4067 }
Andy McFaddend3250112010-11-03 14:32:42 -07004068 setRegisterType(workRegs, decInsn.vA, tmpType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004069 }
4070 break;
4071
4072 case OP_AGET_WIDE:
4073 {
4074 RegType dstType, indexType;
4075
Andy McFaddend3250112010-11-03 14:32:42 -07004076 indexType = getRegisterType(workRegs, decInsn.vC);
Andy McFadden62a75162009-04-17 17:23:37 -07004077 checkArrayIndexType(meth, indexType, &failure);
4078 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004079 break;
4080
Andy McFaddend3250112010-11-03 14:32:42 -07004081 resClass = getClassFromRegister(workRegs, decInsn.vB, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07004082 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004083 break;
4084 if (resClass != NULL) {
4085 /* verify the class */
4086 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4087 resClass->elementClass->primitiveType == PRIM_NOT)
4088 {
4089 LOG_VFY("VFY: invalid aget-wide target %s\n",
4090 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004091 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004092 break;
4093 }
4094
4095 /* try to refine "dstType" */
4096 switch (resClass->elementClass->primitiveType) {
4097 case PRIM_LONG:
4098 dstType = kRegTypeLongLo;
4099 break;
4100 case PRIM_DOUBLE:
4101 dstType = kRegTypeDoubleLo;
4102 break;
4103 default:
4104 LOG_VFY("VFY: invalid aget-wide on %s\n",
4105 resClass->descriptor);
4106 dstType = kRegTypeUnknown;
Andy McFadden62a75162009-04-17 17:23:37 -07004107 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004108 break;
4109 }
4110 } else {
4111 /*
4112 * Null array ref; this code path will fail at runtime. We
4113 * know this is either long or double, and we don't really
4114 * discriminate between those during verification, so we
4115 * call it a long.
4116 */
4117 dstType = kRegTypeLongLo;
4118 }
Andy McFaddend3250112010-11-03 14:32:42 -07004119 setRegisterType(workRegs, decInsn.vA, dstType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004120 }
4121 break;
4122
4123 case OP_AGET_OBJECT:
4124 {
4125 RegType dstType, indexType;
4126
Andy McFaddend3250112010-11-03 14:32:42 -07004127 indexType = getRegisterType(workRegs, decInsn.vC);
Andy McFadden62a75162009-04-17 17:23:37 -07004128 checkArrayIndexType(meth, indexType, &failure);
4129 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004130 break;
4131
4132 /* get the class of the array we're pulling an object from */
Andy McFaddend3250112010-11-03 14:32:42 -07004133 resClass = getClassFromRegister(workRegs, decInsn.vB, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07004134 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004135 break;
4136 if (resClass != NULL) {
4137 ClassObject* elementClass;
4138
4139 assert(resClass != NULL);
4140 if (!dvmIsArrayClass(resClass)) {
4141 LOG_VFY("VFY: aget-object on non-array class\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004142 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004143 break;
4144 }
4145 assert(resClass->elementClass != NULL);
4146
4147 /*
4148 * Find the element class. resClass->elementClass indicates
4149 * the basic type, which won't be what we want for a
4150 * multi-dimensional array.
4151 */
4152 if (resClass->descriptor[1] == '[') {
4153 assert(resClass->arrayDim > 1);
4154 elementClass = dvmFindArrayClass(&resClass->descriptor[1],
4155 resClass->classLoader);
4156 } else if (resClass->descriptor[1] == 'L') {
4157 assert(resClass->arrayDim == 1);
4158 elementClass = resClass->elementClass;
4159 } else {
4160 LOG_VFY("VFY: aget-object on non-ref array class (%s)\n",
4161 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004162 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004163 break;
4164 }
4165
4166 dstType = regTypeFromClass(elementClass);
4167 } else {
4168 /*
4169 * The array reference is NULL, so the current code path will
4170 * throw an exception. For proper merging with later code
4171 * paths, and correct handling of "if-eqz" tests on the
4172 * result of the array get, we want to treat this as a null
4173 * reference.
4174 */
4175 dstType = kRegTypeZero;
4176 }
Andy McFaddend3250112010-11-03 14:32:42 -07004177 setRegisterType(workRegs, decInsn.vA, dstType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004178 }
4179 break;
4180 case OP_APUT:
4181 tmpType = kRegTypeInteger;
4182 goto aput_1nr_common;
4183 case OP_APUT_BOOLEAN:
4184 tmpType = kRegTypeBoolean;
4185 goto aput_1nr_common;
4186 case OP_APUT_BYTE:
4187 tmpType = kRegTypeByte;
4188 goto aput_1nr_common;
4189 case OP_APUT_CHAR:
4190 tmpType = kRegTypeChar;
4191 goto aput_1nr_common;
4192 case OP_APUT_SHORT:
4193 tmpType = kRegTypeShort;
4194 goto aput_1nr_common;
4195aput_1nr_common:
4196 {
4197 RegType srcType, dstType, indexType;
4198
Andy McFaddend3250112010-11-03 14:32:42 -07004199 indexType = getRegisterType(workRegs, decInsn.vC);
Andy McFadden62a75162009-04-17 17:23:37 -07004200 checkArrayIndexType(meth, indexType, &failure);
4201 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004202 break;
4203
4204 /* make sure the source register has the correct type */
Andy McFaddend3250112010-11-03 14:32:42 -07004205 srcType = getRegisterType(workRegs, decInsn.vA);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004206 if (!canConvertTo1nr(srcType, tmpType)) {
4207 LOG_VFY("VFY: invalid reg type %d on aput instr (need %d)\n",
4208 srcType, tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07004209 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004210 break;
4211 }
4212
Andy McFaddend3250112010-11-03 14:32:42 -07004213 resClass = getClassFromRegister(workRegs, decInsn.vB, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07004214 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004215 break;
4216
4217 /* resClass can be null if the reg type is Zero */
4218 if (resClass == NULL)
4219 break;
4220
4221 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4222 resClass->elementClass->primitiveType == PRIM_NOT)
4223 {
4224 LOG_VFY("VFY: invalid aput-1nr on %s\n", resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004225 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004226 break;
4227 }
4228
4229 /* verify that instruction matches array */
4230 dstType = primitiveTypeToRegType(
4231 resClass->elementClass->primitiveType);
4232 assert(dstType != kRegTypeUnknown);
4233
4234 if (!checkFieldArrayStore1nr(tmpType, dstType)) {
4235 LOG_VFY("VFY: invalid aput-1nr on %s (inst=%d dst=%d)\n",
4236 resClass->descriptor, tmpType, dstType);
Andy McFadden62a75162009-04-17 17:23:37 -07004237 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004238 break;
4239 }
4240 }
4241 break;
4242 case OP_APUT_WIDE:
Andy McFaddend3250112010-11-03 14:32:42 -07004243 tmpType = getRegisterType(workRegs, decInsn.vC);
Andy McFadden62a75162009-04-17 17:23:37 -07004244 checkArrayIndexType(meth, tmpType, &failure);
4245 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004246 break;
4247
Andy McFaddend3250112010-11-03 14:32:42 -07004248 tmpType = getRegisterType(workRegs, decInsn.vA);
4249 {
4250 RegType typeHi = getRegisterType(workRegs, decInsn.vA+1);
Andy McFadden62a75162009-04-17 17:23:37 -07004251 checkTypeCategory(tmpType, kTypeCategory2, &failure);
4252 checkWidePair(tmpType, typeHi, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004253 }
Andy McFadden62a75162009-04-17 17:23:37 -07004254 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004255 break;
4256
Andy McFaddend3250112010-11-03 14:32:42 -07004257 resClass = getClassFromRegister(workRegs, decInsn.vB, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07004258 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004259 break;
4260 if (resClass != NULL) {
4261 /* verify the class and try to refine "dstType" */
4262 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4263 resClass->elementClass->primitiveType == PRIM_NOT)
4264 {
4265 LOG_VFY("VFY: invalid aput-wide on %s\n",
4266 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004267 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004268 break;
4269 }
4270
4271 switch (resClass->elementClass->primitiveType) {
4272 case PRIM_LONG:
4273 case PRIM_DOUBLE:
4274 /* these are okay */
4275 break;
4276 default:
4277 LOG_VFY("VFY: invalid aput-wide on %s\n",
4278 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004279 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004280 break;
4281 }
4282 }
4283 break;
4284 case OP_APUT_OBJECT:
Andy McFaddend3250112010-11-03 14:32:42 -07004285 tmpType = getRegisterType(workRegs, decInsn.vC);
Andy McFadden62a75162009-04-17 17:23:37 -07004286 checkArrayIndexType(meth, tmpType, &failure);
4287 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004288 break;
4289
4290 /* get the ref we're storing; Zero is okay, Uninit is not */
Andy McFaddend3250112010-11-03 14:32:42 -07004291 resClass = getClassFromRegister(workRegs, decInsn.vA, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07004292 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004293 break;
4294 if (resClass != NULL) {
4295 ClassObject* arrayClass;
4296 ClassObject* elementClass;
4297
4298 /*
4299 * Get the array class. If the array ref is null, we won't
4300 * have type information (and we'll crash at runtime with a
4301 * null pointer exception).
4302 */
Andy McFaddend3250112010-11-03 14:32:42 -07004303 arrayClass = getClassFromRegister(workRegs, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004304
4305 if (arrayClass != NULL) {
4306 /* see if the array holds a compatible type */
4307 if (!dvmIsArrayClass(arrayClass)) {
4308 LOG_VFY("VFY: invalid aput-object on %s\n",
4309 arrayClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004310 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004311 break;
4312 }
4313
4314 /*
4315 * Find the element class. resClass->elementClass indicates
4316 * the basic type, which won't be what we want for a
4317 * multi-dimensional array.
4318 *
4319 * All we want to check here is that the element type is a
4320 * reference class. We *don't* check instanceof here, because
4321 * you can still put a String into a String[] after the latter
4322 * has been cast to an Object[].
4323 */
4324 if (arrayClass->descriptor[1] == '[') {
4325 assert(arrayClass->arrayDim > 1);
4326 elementClass = dvmFindArrayClass(&arrayClass->descriptor[1],
4327 arrayClass->classLoader);
4328 } else {
4329 assert(arrayClass->arrayDim == 1);
4330 elementClass = arrayClass->elementClass;
4331 }
4332 if (elementClass->primitiveType != PRIM_NOT) {
4333 LOG_VFY("VFY: invalid aput-object of %s into %s\n",
4334 resClass->descriptor, arrayClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004335 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004336 break;
4337 }
4338 }
4339 }
4340 break;
4341
4342 case OP_IGET:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004343 case OP_IGET_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004344 tmpType = kRegTypeInteger;
4345 goto iget_1nr_common;
4346 case OP_IGET_BOOLEAN:
4347 tmpType = kRegTypeBoolean;
4348 goto iget_1nr_common;
4349 case OP_IGET_BYTE:
4350 tmpType = kRegTypeByte;
4351 goto iget_1nr_common;
4352 case OP_IGET_CHAR:
4353 tmpType = kRegTypeChar;
4354 goto iget_1nr_common;
4355 case OP_IGET_SHORT:
4356 tmpType = kRegTypeShort;
4357 goto iget_1nr_common;
4358iget_1nr_common:
4359 {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004360 InstField* instField;
4361 RegType objType, fieldType;
4362
Andy McFaddend3250112010-11-03 14:32:42 -07004363 objType = getRegisterType(workRegs, decInsn.vB);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004364 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004365 &failure);
4366 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004367 break;
4368
4369 /* make sure the field's type is compatible with expectation */
4370 fieldType = primSigCharToRegType(instField->field.signature[0]);
4371 if (fieldType == kRegTypeUnknown ||
4372 !checkFieldArrayStore1nr(tmpType, fieldType))
4373 {
4374 LOG_VFY("VFY: invalid iget-1nr of %s.%s (inst=%d field=%d)\n",
4375 instField->field.clazz->descriptor,
4376 instField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004377 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004378 break;
4379 }
4380
Andy McFaddend3250112010-11-03 14:32:42 -07004381 setRegisterType(workRegs, decInsn.vA, tmpType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004382 }
4383 break;
4384 case OP_IGET_WIDE:
Andy McFadden861b3382010-03-05 15:58:31 -08004385 case OP_IGET_WIDE_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004386 {
4387 RegType dstType;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004388 InstField* instField;
4389 RegType objType;
4390
Andy McFaddend3250112010-11-03 14:32:42 -07004391 objType = getRegisterType(workRegs, decInsn.vB);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004392 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004393 &failure);
4394 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004395 break;
4396 /* check the type, which should be prim */
4397 switch (instField->field.signature[0]) {
4398 case 'D':
4399 dstType = kRegTypeDoubleLo;
4400 break;
4401 case 'J':
4402 dstType = kRegTypeLongLo;
4403 break;
4404 default:
4405 LOG_VFY("VFY: invalid iget-wide of %s.%s\n",
4406 instField->field.clazz->descriptor,
4407 instField->field.name);
4408 dstType = kRegTypeUnknown;
Andy McFadden62a75162009-04-17 17:23:37 -07004409 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004410 break;
4411 }
Andy McFadden62a75162009-04-17 17:23:37 -07004412 if (VERIFY_OK(failure)) {
Andy McFaddend3250112010-11-03 14:32:42 -07004413 setRegisterType(workRegs, decInsn.vA, dstType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004414 }
4415 }
4416 break;
4417 case OP_IGET_OBJECT:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004418 case OP_IGET_OBJECT_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004419 {
4420 ClassObject* fieldClass;
4421 InstField* instField;
4422 RegType objType;
4423
Andy McFaddend3250112010-11-03 14:32:42 -07004424 objType = getRegisterType(workRegs, decInsn.vB);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004425 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004426 &failure);
4427 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004428 break;
4429 fieldClass = getFieldClass(meth, &instField->field);
4430 if (fieldClass == NULL) {
4431 /* class not found or primitive type */
4432 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4433 instField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004434 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004435 break;
4436 }
Andy McFadden62a75162009-04-17 17:23:37 -07004437 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004438 assert(!dvmIsPrimitiveClass(fieldClass));
Andy McFaddend3250112010-11-03 14:32:42 -07004439 setRegisterType(workRegs, decInsn.vA,
4440 regTypeFromClass(fieldClass));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004441 }
4442 }
4443 break;
4444 case OP_IPUT:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004445 case OP_IPUT_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004446 tmpType = kRegTypeInteger;
4447 goto iput_1nr_common;
4448 case OP_IPUT_BOOLEAN:
4449 tmpType = kRegTypeBoolean;
4450 goto iput_1nr_common;
4451 case OP_IPUT_BYTE:
4452 tmpType = kRegTypeByte;
4453 goto iput_1nr_common;
4454 case OP_IPUT_CHAR:
4455 tmpType = kRegTypeChar;
4456 goto iput_1nr_common;
4457 case OP_IPUT_SHORT:
4458 tmpType = kRegTypeShort;
4459 goto iput_1nr_common;
4460iput_1nr_common:
4461 {
4462 RegType srcType, fieldType, objType;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004463 InstField* instField;
4464
Andy McFaddend3250112010-11-03 14:32:42 -07004465 srcType = getRegisterType(workRegs, decInsn.vA);
Andy McFaddenb5f64bc2009-06-10 14:11:07 -07004466
4467 /*
4468 * javac generates synthetic functions that write byte values
4469 * into boolean fields.
4470 */
4471 if (tmpType == kRegTypeBoolean && srcType == kRegTypeByte)
4472 srcType = kRegTypeBoolean;
4473
4474 /* make sure the source register has the correct type */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004475 if (!canConvertTo1nr(srcType, tmpType)) {
4476 LOG_VFY("VFY: invalid reg type %d on iput instr (need %d)\n",
4477 srcType, tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07004478 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004479 break;
4480 }
4481
Andy McFaddend3250112010-11-03 14:32:42 -07004482 objType = getRegisterType(workRegs, decInsn.vB);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004483 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004484 &failure);
4485 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004486 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004487 checkFinalFieldAccess(meth, &instField->field, &failure);
4488 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004489 break;
4490
4491 /* get type of field we're storing into */
4492 fieldType = primSigCharToRegType(instField->field.signature[0]);
4493 if (fieldType == kRegTypeUnknown ||
4494 !checkFieldArrayStore1nr(tmpType, fieldType))
4495 {
4496 LOG_VFY("VFY: invalid iput-1nr of %s.%s (inst=%d field=%d)\n",
4497 instField->field.clazz->descriptor,
4498 instField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004499 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004500 break;
4501 }
4502 }
4503 break;
4504 case OP_IPUT_WIDE:
Andy McFadden861b3382010-03-05 15:58:31 -08004505 case OP_IPUT_WIDE_VOLATILE:
Andy McFaddend3250112010-11-03 14:32:42 -07004506 tmpType = getRegisterType(workRegs, decInsn.vA);
4507 {
4508 RegType typeHi = getRegisterType(workRegs, decInsn.vA+1);
Andy McFadden62a75162009-04-17 17:23:37 -07004509 checkTypeCategory(tmpType, kTypeCategory2, &failure);
4510 checkWidePair(tmpType, typeHi, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004511 }
Andy McFadden62a75162009-04-17 17:23:37 -07004512 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004513 InstField* instField;
4514 RegType objType;
4515
Andy McFaddend3250112010-11-03 14:32:42 -07004516 objType = getRegisterType(workRegs, decInsn.vB);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004517 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004518 &failure);
4519 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004520 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004521 checkFinalFieldAccess(meth, &instField->field, &failure);
4522 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004523 break;
4524
4525 /* check the type, which should be prim */
4526 switch (instField->field.signature[0]) {
4527 case 'D':
4528 case 'J':
4529 /* these are okay (and interchangeable) */
4530 break;
4531 default:
4532 LOG_VFY("VFY: invalid iput-wide of %s.%s\n",
4533 instField->field.clazz->descriptor,
4534 instField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07004535 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004536 break;
4537 }
4538 }
4539 break;
4540 case OP_IPUT_OBJECT:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004541 case OP_IPUT_OBJECT_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004542 {
4543 ClassObject* fieldClass;
4544 ClassObject* valueClass;
4545 InstField* instField;
4546 RegType objType, valueType;
4547
Andy McFaddend3250112010-11-03 14:32:42 -07004548 objType = getRegisterType(workRegs, decInsn.vB);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004549 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004550 &failure);
4551 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004552 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004553 checkFinalFieldAccess(meth, &instField->field, &failure);
4554 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004555 break;
4556
4557 fieldClass = getFieldClass(meth, &instField->field);
4558 if (fieldClass == NULL) {
4559 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4560 instField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004561 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004562 break;
4563 }
4564
Andy McFaddend3250112010-11-03 14:32:42 -07004565 valueType = getRegisterType(workRegs, decInsn.vA);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004566 if (!regTypeIsReference(valueType)) {
4567 LOG_VFY("VFY: storing non-ref v%d into ref field '%s' (%s)\n",
4568 decInsn.vA, instField->field.name,
4569 fieldClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004570 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004571 break;
4572 }
4573 if (valueType != kRegTypeZero) {
4574 valueClass = regTypeInitializedReferenceToClass(valueType);
4575 if (valueClass == NULL) {
4576 LOG_VFY("VFY: storing uninit ref v%d into ref field\n",
4577 decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07004578 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004579 break;
4580 }
4581 /* allow if field is any interface or field is base class */
4582 if (!dvmIsInterfaceClass(fieldClass) &&
4583 !dvmInstanceof(valueClass, fieldClass))
4584 {
4585 LOG_VFY("VFY: storing type '%s' into field type '%s' (%s.%s)\n",
4586 valueClass->descriptor, fieldClass->descriptor,
4587 instField->field.clazz->descriptor,
4588 instField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07004589 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004590 break;
4591 }
4592 }
4593 }
4594 break;
4595
4596 case OP_SGET:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004597 case OP_SGET_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004598 tmpType = kRegTypeInteger;
4599 goto sget_1nr_common;
4600 case OP_SGET_BOOLEAN:
4601 tmpType = kRegTypeBoolean;
4602 goto sget_1nr_common;
4603 case OP_SGET_BYTE:
4604 tmpType = kRegTypeByte;
4605 goto sget_1nr_common;
4606 case OP_SGET_CHAR:
4607 tmpType = kRegTypeChar;
4608 goto sget_1nr_common;
4609 case OP_SGET_SHORT:
4610 tmpType = kRegTypeShort;
4611 goto sget_1nr_common;
4612sget_1nr_common:
4613 {
4614 StaticField* staticField;
4615 RegType fieldType;
4616
Andy McFadden62a75162009-04-17 17:23:37 -07004617 staticField = getStaticField(meth, decInsn.vB, &failure);
4618 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004619 break;
4620
4621 /*
4622 * Make sure the field's type is compatible with expectation.
4623 * We can get ourselves into trouble if we mix & match loads
4624 * and stores with different widths, so rather than just checking
4625 * "canConvertTo1nr" we require that the field types have equal
4626 * widths. (We can't generally require an exact type match,
4627 * because e.g. "int" and "float" are interchangeable.)
4628 */
4629 fieldType = primSigCharToRegType(staticField->field.signature[0]);
4630 if (!checkFieldArrayStore1nr(tmpType, fieldType)) {
4631 LOG_VFY("VFY: invalid sget-1nr of %s.%s (inst=%d actual=%d)\n",
4632 staticField->field.clazz->descriptor,
4633 staticField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004634 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004635 break;
4636 }
4637
Andy McFaddend3250112010-11-03 14:32:42 -07004638 setRegisterType(workRegs, decInsn.vA, tmpType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004639 }
4640 break;
4641 case OP_SGET_WIDE:
Andy McFadden861b3382010-03-05 15:58:31 -08004642 case OP_SGET_WIDE_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004643 {
4644 StaticField* staticField;
4645 RegType dstType;
4646
Andy McFadden62a75162009-04-17 17:23:37 -07004647 staticField = getStaticField(meth, decInsn.vB, &failure);
4648 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004649 break;
4650 /* check the type, which should be prim */
4651 switch (staticField->field.signature[0]) {
4652 case 'D':
4653 dstType = kRegTypeDoubleLo;
4654 break;
4655 case 'J':
4656 dstType = kRegTypeLongLo;
4657 break;
4658 default:
4659 LOG_VFY("VFY: invalid sget-wide of %s.%s\n",
4660 staticField->field.clazz->descriptor,
4661 staticField->field.name);
4662 dstType = kRegTypeUnknown;
Andy McFadden62a75162009-04-17 17:23:37 -07004663 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004664 break;
4665 }
Andy McFadden62a75162009-04-17 17:23:37 -07004666 if (VERIFY_OK(failure)) {
Andy McFaddend3250112010-11-03 14:32:42 -07004667 setRegisterType(workRegs, decInsn.vA, dstType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004668 }
4669 }
4670 break;
4671 case OP_SGET_OBJECT:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004672 case OP_SGET_OBJECT_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004673 {
4674 StaticField* staticField;
4675 ClassObject* fieldClass;
4676
Andy McFadden62a75162009-04-17 17:23:37 -07004677 staticField = getStaticField(meth, decInsn.vB, &failure);
4678 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004679 break;
4680 fieldClass = getFieldClass(meth, &staticField->field);
4681 if (fieldClass == NULL) {
4682 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4683 staticField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004684 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004685 break;
4686 }
4687 if (dvmIsPrimitiveClass(fieldClass)) {
4688 LOG_VFY("VFY: attempt to get prim field with sget-object\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004689 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004690 break;
4691 }
Andy McFaddend3250112010-11-03 14:32:42 -07004692 setRegisterType(workRegs, decInsn.vA, regTypeFromClass(fieldClass));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004693 }
4694 break;
4695 case OP_SPUT:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004696 case OP_SPUT_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004697 tmpType = kRegTypeInteger;
4698 goto sput_1nr_common;
4699 case OP_SPUT_BOOLEAN:
4700 tmpType = kRegTypeBoolean;
4701 goto sput_1nr_common;
4702 case OP_SPUT_BYTE:
4703 tmpType = kRegTypeByte;
4704 goto sput_1nr_common;
4705 case OP_SPUT_CHAR:
4706 tmpType = kRegTypeChar;
4707 goto sput_1nr_common;
4708 case OP_SPUT_SHORT:
4709 tmpType = kRegTypeShort;
4710 goto sput_1nr_common;
4711sput_1nr_common:
4712 {
4713 RegType srcType, fieldType;
4714 StaticField* staticField;
4715
Andy McFaddend3250112010-11-03 14:32:42 -07004716 srcType = getRegisterType(workRegs, decInsn.vA);
Andy McFaddenb5f64bc2009-06-10 14:11:07 -07004717
4718 /*
4719 * javac generates synthetic functions that write byte values
4720 * into boolean fields.
4721 */
4722 if (tmpType == kRegTypeBoolean && srcType == kRegTypeByte)
4723 srcType = kRegTypeBoolean;
4724
4725 /* make sure the source register has the correct type */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004726 if (!canConvertTo1nr(srcType, tmpType)) {
Andy McFaddenb5f64bc2009-06-10 14:11:07 -07004727 LOG_VFY("VFY: invalid reg type %d on sput instr (need %d)\n",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004728 srcType, tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07004729 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004730 break;
4731 }
4732
Andy McFadden62a75162009-04-17 17:23:37 -07004733 staticField = getStaticField(meth, decInsn.vB, &failure);
4734 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004735 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004736 checkFinalFieldAccess(meth, &staticField->field, &failure);
4737 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004738 break;
4739
4740 /*
4741 * Get type of field we're storing into. We know that the
4742 * contents of the register match the instruction, but we also
4743 * need to ensure that the instruction matches the field type.
4744 * Using e.g. sput-short to write into a 32-bit integer field
4745 * can lead to trouble if we do 16-bit writes.
4746 */
4747 fieldType = primSigCharToRegType(staticField->field.signature[0]);
4748 if (!checkFieldArrayStore1nr(tmpType, fieldType)) {
4749 LOG_VFY("VFY: invalid sput-1nr of %s.%s (inst=%d actual=%d)\n",
4750 staticField->field.clazz->descriptor,
4751 staticField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004752 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004753 break;
4754 }
4755 }
4756 break;
4757 case OP_SPUT_WIDE:
Andy McFadden861b3382010-03-05 15:58:31 -08004758 case OP_SPUT_WIDE_VOLATILE:
Andy McFaddend3250112010-11-03 14:32:42 -07004759 tmpType = getRegisterType(workRegs, decInsn.vA);
4760 {
4761 RegType typeHi = getRegisterType(workRegs, decInsn.vA+1);
Andy McFadden62a75162009-04-17 17:23:37 -07004762 checkTypeCategory(tmpType, kTypeCategory2, &failure);
4763 checkWidePair(tmpType, typeHi, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004764 }
Andy McFadden62a75162009-04-17 17:23:37 -07004765 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004766 StaticField* staticField;
4767
Andy McFadden62a75162009-04-17 17:23:37 -07004768 staticField = getStaticField(meth, decInsn.vB, &failure);
4769 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004770 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004771 checkFinalFieldAccess(meth, &staticField->field, &failure);
4772 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004773 break;
4774
4775 /* check the type, which should be prim */
4776 switch (staticField->field.signature[0]) {
4777 case 'D':
4778 case 'J':
4779 /* these are okay */
4780 break;
4781 default:
4782 LOG_VFY("VFY: invalid sput-wide of %s.%s\n",
4783 staticField->field.clazz->descriptor,
4784 staticField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07004785 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004786 break;
4787 }
4788 }
4789 break;
4790 case OP_SPUT_OBJECT:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004791 case OP_SPUT_OBJECT_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004792 {
4793 ClassObject* fieldClass;
4794 ClassObject* valueClass;
4795 StaticField* staticField;
4796 RegType valueType;
4797
Andy McFadden62a75162009-04-17 17:23:37 -07004798 staticField = getStaticField(meth, decInsn.vB, &failure);
4799 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004800 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004801 checkFinalFieldAccess(meth, &staticField->field, &failure);
4802 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004803 break;
4804
4805 fieldClass = getFieldClass(meth, &staticField->field);
4806 if (fieldClass == NULL) {
4807 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4808 staticField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004809 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004810 break;
4811 }
4812
Andy McFaddend3250112010-11-03 14:32:42 -07004813 valueType = getRegisterType(workRegs, decInsn.vA);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004814 if (!regTypeIsReference(valueType)) {
4815 LOG_VFY("VFY: storing non-ref v%d into ref field '%s' (%s)\n",
4816 decInsn.vA, staticField->field.name,
4817 fieldClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004818 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004819 break;
4820 }
4821 if (valueType != kRegTypeZero) {
4822 valueClass = regTypeInitializedReferenceToClass(valueType);
4823 if (valueClass == NULL) {
4824 LOG_VFY("VFY: storing uninit ref v%d into ref field\n",
4825 decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07004826 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004827 break;
4828 }
4829 /* allow if field is any interface or field is base class */
4830 if (!dvmIsInterfaceClass(fieldClass) &&
4831 !dvmInstanceof(valueClass, fieldClass))
4832 {
4833 LOG_VFY("VFY: storing type '%s' into field type '%s' (%s.%s)\n",
4834 valueClass->descriptor, fieldClass->descriptor,
4835 staticField->field.clazz->descriptor,
4836 staticField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07004837 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004838 break;
4839 }
4840 }
4841 }
4842 break;
4843
4844 case OP_INVOKE_VIRTUAL:
4845 case OP_INVOKE_VIRTUAL_RANGE:
4846 case OP_INVOKE_SUPER:
4847 case OP_INVOKE_SUPER_RANGE:
4848 {
4849 Method* calledMethod;
4850 RegType returnType;
4851 bool isRange;
4852 bool isSuper;
4853
4854 isRange = (decInsn.opCode == OP_INVOKE_VIRTUAL_RANGE ||
4855 decInsn.opCode == OP_INVOKE_SUPER_RANGE);
4856 isSuper = (decInsn.opCode == OP_INVOKE_SUPER ||
4857 decInsn.opCode == OP_INVOKE_SUPER_RANGE);
4858
4859 calledMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
4860 &decInsn, uninitMap, METHOD_VIRTUAL, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07004861 isSuper, &failure);
4862 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004863 break;
4864 returnType = getMethodReturnType(calledMethod);
Andy McFaddend3250112010-11-03 14:32:42 -07004865 setResultRegisterType(workRegs, insnRegCount, returnType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004866 justSetResult = true;
4867 }
4868 break;
4869 case OP_INVOKE_DIRECT:
4870 case OP_INVOKE_DIRECT_RANGE:
4871 {
4872 RegType returnType;
4873 Method* calledMethod;
4874 bool isRange;
4875
4876 isRange = (decInsn.opCode == OP_INVOKE_DIRECT_RANGE);
4877 calledMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
4878 &decInsn, uninitMap, METHOD_DIRECT, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07004879 false, &failure);
4880 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004881 break;
4882
4883 /*
4884 * Some additional checks when calling <init>. We know from
4885 * the invocation arg check that the "this" argument is an
4886 * instance of calledMethod->clazz. Now we further restrict
4887 * that to require that calledMethod->clazz is the same as
4888 * this->clazz or this->super, allowing the latter only if
4889 * the "this" argument is the same as the "this" argument to
4890 * this method (which implies that we're in <init> ourselves).
4891 */
4892 if (isInitMethod(calledMethod)) {
4893 RegType thisType;
Andy McFaddend3250112010-11-03 14:32:42 -07004894 thisType = getInvocationThis(workRegs, &decInsn, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07004895 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004896 break;
4897
4898 /* no null refs allowed (?) */
4899 if (thisType == kRegTypeZero) {
4900 LOG_VFY("VFY: unable to initialize null ref\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004901 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004902 break;
4903 }
4904
4905 ClassObject* thisClass;
4906
4907 thisClass = regTypeReferenceToClass(thisType, uninitMap);
4908 assert(thisClass != NULL);
4909
4910 /* must be in same class or in superclass */
4911 if (calledMethod->clazz == thisClass->super) {
4912 if (thisClass != meth->clazz) {
4913 LOG_VFY("VFY: invoke-direct <init> on super only "
4914 "allowed for 'this' in <init>");
Andy McFadden62a75162009-04-17 17:23:37 -07004915 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004916 break;
4917 }
4918 } else if (calledMethod->clazz != thisClass) {
4919 LOG_VFY("VFY: invoke-direct <init> must be on current "
4920 "class or super\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004921 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004922 break;
4923 }
4924
4925 /* arg must be an uninitialized reference */
4926 if (!regTypeIsUninitReference(thisType)) {
4927 LOG_VFY("VFY: can only initialize the uninitialized\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004928 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004929 break;
4930 }
4931
4932 /*
4933 * Replace the uninitialized reference with an initialized
4934 * one, and clear the entry in the uninit map. We need to
4935 * do this for all registers that have the same object
4936 * instance in them, not just the "this" register.
4937 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004938 markRefsAsInitialized(workRegs, insnRegCount, uninitMap,
Andy McFadden62a75162009-04-17 17:23:37 -07004939 thisType, &failure);
4940 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004941 break;
4942 }
4943 returnType = getMethodReturnType(calledMethod);
Andy McFaddend3250112010-11-03 14:32:42 -07004944 setResultRegisterType(workRegs, insnRegCount, returnType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004945 justSetResult = true;
4946 }
4947 break;
4948 case OP_INVOKE_STATIC:
4949 case OP_INVOKE_STATIC_RANGE:
4950 {
4951 RegType returnType;
4952 Method* calledMethod;
4953 bool isRange;
4954
4955 isRange = (decInsn.opCode == OP_INVOKE_STATIC_RANGE);
4956 calledMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
4957 &decInsn, uninitMap, METHOD_STATIC, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07004958 false, &failure);
4959 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004960 break;
4961
4962 returnType = getMethodReturnType(calledMethod);
Andy McFaddend3250112010-11-03 14:32:42 -07004963 setResultRegisterType(workRegs, insnRegCount, returnType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004964 justSetResult = true;
4965 }
4966 break;
4967 case OP_INVOKE_INTERFACE:
4968 case OP_INVOKE_INTERFACE_RANGE:
4969 {
4970 RegType /*thisType,*/ returnType;
4971 Method* absMethod;
4972 bool isRange;
4973
4974 isRange = (decInsn.opCode == OP_INVOKE_INTERFACE_RANGE);
4975 absMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
4976 &decInsn, uninitMap, METHOD_INTERFACE, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07004977 false, &failure);
4978 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004979 break;
4980
4981#if 0 /* can't do this here, fails on dalvik test 052-verifier-fun */
4982 /*
4983 * Get the type of the "this" arg, which should always be an
4984 * interface class. Because we don't do a full merge on
4985 * interface classes, this might have reduced to Object.
4986 */
Andy McFaddend3250112010-11-03 14:32:42 -07004987 thisType = getInvocationThis(workRegs, &decInsn, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07004988 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004989 break;
4990
4991 if (thisType == kRegTypeZero) {
4992 /* null pointer always passes (and always fails at runtime) */
4993 } else {
4994 ClassObject* thisClass;
4995
4996 thisClass = regTypeInitializedReferenceToClass(thisType);
4997 if (thisClass == NULL) {
4998 LOG_VFY("VFY: interface call on uninitialized\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004999 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005000 break;
5001 }
5002
5003 /*
5004 * Either "thisClass" needs to be the interface class that
5005 * defined absMethod, or absMethod's class needs to be one
5006 * of the interfaces implemented by "thisClass". (Or, if
5007 * we couldn't complete the merge, this will be Object.)
5008 */
5009 if (thisClass != absMethod->clazz &&
5010 thisClass != gDvm.classJavaLangObject &&
5011 !dvmImplements(thisClass, absMethod->clazz))
5012 {
5013 LOG_VFY("VFY: unable to match absMethod '%s' with %s interfaces\n",
5014 absMethod->name, thisClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07005015 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005016 break;
5017 }
5018 }
5019#endif
5020
5021 /*
5022 * We don't have an object instance, so we can't find the
5023 * concrete method. However, all of the type information is
5024 * in the abstract method, so we're good.
5025 */
5026 returnType = getMethodReturnType(absMethod);
Andy McFaddend3250112010-11-03 14:32:42 -07005027 setResultRegisterType(workRegs, insnRegCount, returnType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005028 justSetResult = true;
5029 }
5030 break;
5031
5032 case OP_NEG_INT:
5033 case OP_NOT_INT:
Andy McFaddend3250112010-11-03 14:32:42 -07005034 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005035 kRegTypeInteger, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005036 break;
5037 case OP_NEG_LONG:
5038 case OP_NOT_LONG:
Andy McFaddend3250112010-11-03 14:32:42 -07005039 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005040 kRegTypeLongLo, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005041 break;
5042 case OP_NEG_FLOAT:
Andy McFaddend3250112010-11-03 14:32:42 -07005043 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005044 kRegTypeFloat, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005045 break;
5046 case OP_NEG_DOUBLE:
Andy McFaddend3250112010-11-03 14:32:42 -07005047 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005048 kRegTypeDoubleLo, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005049 break;
5050 case OP_INT_TO_LONG:
Andy McFaddend3250112010-11-03 14:32:42 -07005051 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005052 kRegTypeLongLo, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005053 break;
5054 case OP_INT_TO_FLOAT:
Andy McFaddend3250112010-11-03 14:32:42 -07005055 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005056 kRegTypeFloat, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005057 break;
5058 case OP_INT_TO_DOUBLE:
Andy McFaddend3250112010-11-03 14:32:42 -07005059 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005060 kRegTypeDoubleLo, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005061 break;
5062 case OP_LONG_TO_INT:
Andy McFaddend3250112010-11-03 14:32:42 -07005063 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005064 kRegTypeInteger, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005065 break;
5066 case OP_LONG_TO_FLOAT:
Andy McFaddend3250112010-11-03 14:32:42 -07005067 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005068 kRegTypeFloat, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005069 break;
5070 case OP_LONG_TO_DOUBLE:
Andy McFaddend3250112010-11-03 14:32:42 -07005071 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005072 kRegTypeDoubleLo, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005073 break;
5074 case OP_FLOAT_TO_INT:
Andy McFaddend3250112010-11-03 14:32:42 -07005075 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005076 kRegTypeInteger, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005077 break;
5078 case OP_FLOAT_TO_LONG:
Andy McFaddend3250112010-11-03 14:32:42 -07005079 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005080 kRegTypeLongLo, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005081 break;
5082 case OP_FLOAT_TO_DOUBLE:
Andy McFaddend3250112010-11-03 14:32:42 -07005083 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005084 kRegTypeDoubleLo, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005085 break;
5086 case OP_DOUBLE_TO_INT:
Andy McFaddend3250112010-11-03 14:32:42 -07005087 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005088 kRegTypeInteger, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005089 break;
5090 case OP_DOUBLE_TO_LONG:
Andy McFaddend3250112010-11-03 14:32:42 -07005091 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005092 kRegTypeLongLo, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005093 break;
5094 case OP_DOUBLE_TO_FLOAT:
Andy McFaddend3250112010-11-03 14:32:42 -07005095 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005096 kRegTypeFloat, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005097 break;
5098 case OP_INT_TO_BYTE:
Andy McFaddend3250112010-11-03 14:32:42 -07005099 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005100 kRegTypeByte, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005101 break;
5102 case OP_INT_TO_CHAR:
Andy McFaddend3250112010-11-03 14:32:42 -07005103 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005104 kRegTypeChar, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005105 break;
5106 case OP_INT_TO_SHORT:
Andy McFaddend3250112010-11-03 14:32:42 -07005107 checkUnop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005108 kRegTypeShort, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005109 break;
5110
5111 case OP_ADD_INT:
5112 case OP_SUB_INT:
5113 case OP_MUL_INT:
5114 case OP_REM_INT:
5115 case OP_DIV_INT:
5116 case OP_SHL_INT:
5117 case OP_SHR_INT:
5118 case OP_USHR_INT:
Andy McFaddend3250112010-11-03 14:32:42 -07005119 checkBinop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005120 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005121 break;
5122 case OP_AND_INT:
5123 case OP_OR_INT:
5124 case OP_XOR_INT:
Andy McFaddend3250112010-11-03 14:32:42 -07005125 checkBinop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005126 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005127 break;
5128 case OP_ADD_LONG:
5129 case OP_SUB_LONG:
5130 case OP_MUL_LONG:
5131 case OP_DIV_LONG:
5132 case OP_REM_LONG:
5133 case OP_AND_LONG:
5134 case OP_OR_LONG:
5135 case OP_XOR_LONG:
Andy McFaddend3250112010-11-03 14:32:42 -07005136 checkBinop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005137 kRegTypeLongLo, kRegTypeLongLo, kRegTypeLongLo, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005138 break;
5139 case OP_SHL_LONG:
5140 case OP_SHR_LONG:
5141 case OP_USHR_LONG:
5142 /* shift distance is Int, making these different from other binops */
Andy McFaddend3250112010-11-03 14:32:42 -07005143 checkBinop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005144 kRegTypeLongLo, kRegTypeLongLo, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005145 break;
5146 case OP_ADD_FLOAT:
5147 case OP_SUB_FLOAT:
5148 case OP_MUL_FLOAT:
5149 case OP_DIV_FLOAT:
5150 case OP_REM_FLOAT:
Andy McFaddend3250112010-11-03 14:32:42 -07005151 checkBinop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005152 kRegTypeFloat, kRegTypeFloat, kRegTypeFloat, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005153 break;
5154 case OP_ADD_DOUBLE:
5155 case OP_SUB_DOUBLE:
5156 case OP_MUL_DOUBLE:
5157 case OP_DIV_DOUBLE:
5158 case OP_REM_DOUBLE:
Andy McFaddend3250112010-11-03 14:32:42 -07005159 checkBinop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005160 kRegTypeDoubleLo, kRegTypeDoubleLo, kRegTypeDoubleLo, false,
5161 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005162 break;
5163 case OP_ADD_INT_2ADDR:
5164 case OP_SUB_INT_2ADDR:
5165 case OP_MUL_INT_2ADDR:
5166 case OP_REM_INT_2ADDR:
5167 case OP_SHL_INT_2ADDR:
5168 case OP_SHR_INT_2ADDR:
5169 case OP_USHR_INT_2ADDR:
Andy McFaddend3250112010-11-03 14:32:42 -07005170 checkBinop2addr(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005171 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005172 break;
5173 case OP_AND_INT_2ADDR:
5174 case OP_OR_INT_2ADDR:
5175 case OP_XOR_INT_2ADDR:
Andy McFaddend3250112010-11-03 14:32:42 -07005176 checkBinop2addr(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005177 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005178 break;
5179 case OP_DIV_INT_2ADDR:
Andy McFaddend3250112010-11-03 14:32:42 -07005180 checkBinop2addr(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005181 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005182 break;
5183 case OP_ADD_LONG_2ADDR:
5184 case OP_SUB_LONG_2ADDR:
5185 case OP_MUL_LONG_2ADDR:
5186 case OP_DIV_LONG_2ADDR:
5187 case OP_REM_LONG_2ADDR:
5188 case OP_AND_LONG_2ADDR:
5189 case OP_OR_LONG_2ADDR:
5190 case OP_XOR_LONG_2ADDR:
Andy McFaddend3250112010-11-03 14:32:42 -07005191 checkBinop2addr(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005192 kRegTypeLongLo, kRegTypeLongLo, kRegTypeLongLo, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005193 break;
5194 case OP_SHL_LONG_2ADDR:
5195 case OP_SHR_LONG_2ADDR:
5196 case OP_USHR_LONG_2ADDR:
Andy McFaddend3250112010-11-03 14:32:42 -07005197 checkBinop2addr(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005198 kRegTypeLongLo, kRegTypeLongLo, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005199 break;
5200 case OP_ADD_FLOAT_2ADDR:
5201 case OP_SUB_FLOAT_2ADDR:
5202 case OP_MUL_FLOAT_2ADDR:
5203 case OP_DIV_FLOAT_2ADDR:
5204 case OP_REM_FLOAT_2ADDR:
Andy McFaddend3250112010-11-03 14:32:42 -07005205 checkBinop2addr(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005206 kRegTypeFloat, kRegTypeFloat, kRegTypeFloat, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005207 break;
5208 case OP_ADD_DOUBLE_2ADDR:
5209 case OP_SUB_DOUBLE_2ADDR:
5210 case OP_MUL_DOUBLE_2ADDR:
5211 case OP_DIV_DOUBLE_2ADDR:
5212 case OP_REM_DOUBLE_2ADDR:
Andy McFaddend3250112010-11-03 14:32:42 -07005213 checkBinop2addr(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005214 kRegTypeDoubleLo, kRegTypeDoubleLo, kRegTypeDoubleLo, false,
5215 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005216 break;
5217 case OP_ADD_INT_LIT16:
5218 case OP_RSUB_INT:
5219 case OP_MUL_INT_LIT16:
5220 case OP_DIV_INT_LIT16:
5221 case OP_REM_INT_LIT16:
Andy McFaddend3250112010-11-03 14:32:42 -07005222 checkLitop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005223 kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005224 break;
5225 case OP_AND_INT_LIT16:
5226 case OP_OR_INT_LIT16:
5227 case OP_XOR_INT_LIT16:
Andy McFaddend3250112010-11-03 14:32:42 -07005228 checkLitop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005229 kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005230 break;
5231 case OP_ADD_INT_LIT8:
5232 case OP_RSUB_INT_LIT8:
5233 case OP_MUL_INT_LIT8:
5234 case OP_DIV_INT_LIT8:
5235 case OP_REM_INT_LIT8:
5236 case OP_SHL_INT_LIT8:
Andy McFaddend3250112010-11-03 14:32:42 -07005237 checkLitop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005238 kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005239 break;
Andy McFadden80d25ea2009-06-12 07:26:17 -07005240 case OP_SHR_INT_LIT8:
Andy McFaddend3250112010-11-03 14:32:42 -07005241 tmpType = adjustForRightShift(workRegs,
Andy McFadden80d25ea2009-06-12 07:26:17 -07005242 decInsn.vB, decInsn.vC, false, &failure);
Andy McFaddend3250112010-11-03 14:32:42 -07005243 checkLitop(workRegs, &decInsn,
Andy McFadden80d25ea2009-06-12 07:26:17 -07005244 tmpType, kRegTypeInteger, false, &failure);
5245 break;
5246 case OP_USHR_INT_LIT8:
Andy McFaddend3250112010-11-03 14:32:42 -07005247 tmpType = adjustForRightShift(workRegs,
Andy McFadden80d25ea2009-06-12 07:26:17 -07005248 decInsn.vB, decInsn.vC, true, &failure);
Andy McFaddend3250112010-11-03 14:32:42 -07005249 checkLitop(workRegs, &decInsn,
Andy McFadden80d25ea2009-06-12 07:26:17 -07005250 tmpType, kRegTypeInteger, false, &failure);
5251 break;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005252 case OP_AND_INT_LIT8:
5253 case OP_OR_INT_LIT8:
5254 case OP_XOR_INT_LIT8:
Andy McFaddend3250112010-11-03 14:32:42 -07005255 checkLitop(workRegs, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005256 kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005257 break;
5258
Andy McFaddenb51ea112009-05-08 16:50:17 -07005259 /*
5260 * This falls into the general category of "optimized" instructions,
5261 * which don't generally appear during verification. Because it's
5262 * inserted in the course of verification, we can expect to see it here.
5263 */
5264 case OP_THROW_VERIFICATION_ERROR:
5265 break;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005266
5267 /*
5268 * Verifying "quickened" instructions is tricky, because we have
5269 * discarded the original field/method information. The byte offsets
5270 * and vtable indices only have meaning in the context of an object
5271 * instance.
5272 *
5273 * If a piece of code declares a local reference variable, assigns
5274 * null to it, and then issues a virtual method call on it, we
5275 * cannot evaluate the method call during verification. This situation
5276 * isn't hard to handle, since we know the call will always result in an
5277 * NPE, and the arguments and return value don't matter. Any code that
5278 * depends on the result of the method call is inaccessible, so the
5279 * fact that we can't fully verify anything that comes after the bad
5280 * call is not a problem.
5281 *
5282 * We must also consider the case of multiple code paths, only some of
5283 * which involve a null reference. We can completely verify the method
5284 * if we sidestep the results of executing with a null reference.
5285 * For example, if on the first pass through the code we try to do a
5286 * virtual method invocation through a null ref, we have to skip the
5287 * method checks and have the method return a "wildcard" type (which
5288 * merges with anything to become that other thing). The move-result
5289 * will tell us if it's a reference, single-word numeric, or double-word
5290 * value. We continue to perform the verification, and at the end of
5291 * the function any invocations that were never fully exercised are
5292 * marked as null-only.
5293 *
5294 * We would do something similar for the field accesses. The field's
5295 * type, once known, can be used to recover the width of short integers.
5296 * If the object reference was null, the field-get returns the "wildcard"
5297 * type, which is acceptable for any operation.
5298 */
5299 case OP_EXECUTE_INLINE:
Andy McFaddenb0a05412009-11-19 10:23:41 -08005300 case OP_EXECUTE_INLINE_RANGE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005301 case OP_INVOKE_DIRECT_EMPTY:
5302 case OP_IGET_QUICK:
5303 case OP_IGET_WIDE_QUICK:
5304 case OP_IGET_OBJECT_QUICK:
5305 case OP_IPUT_QUICK:
5306 case OP_IPUT_WIDE_QUICK:
5307 case OP_IPUT_OBJECT_QUICK:
5308 case OP_INVOKE_VIRTUAL_QUICK:
5309 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
5310 case OP_INVOKE_SUPER_QUICK:
5311 case OP_INVOKE_SUPER_QUICK_RANGE:
Andy McFadden291758c2010-09-10 08:04:52 -07005312 case OP_RETURN_VOID_BARRIER:
Andy McFadden62a75162009-04-17 17:23:37 -07005313 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005314 break;
5315
Andy McFadden96516932009-10-28 17:39:02 -07005316 /* these should never appear during verification */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005317 case OP_UNUSED_3E:
5318 case OP_UNUSED_3F:
5319 case OP_UNUSED_40:
5320 case OP_UNUSED_41:
5321 case OP_UNUSED_42:
5322 case OP_UNUSED_43:
5323 case OP_UNUSED_73:
5324 case OP_UNUSED_79:
5325 case OP_UNUSED_7A:
Andy McFadden96516932009-10-28 17:39:02 -07005326 case OP_BREAKPOINT:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005327 case OP_UNUSED_FF:
Andy McFadden62a75162009-04-17 17:23:37 -07005328 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005329 break;
5330
5331 /*
5332 * DO NOT add a "default" clause here. Without it the compiler will
5333 * complain if an instruction is missing (which is desirable).
5334 */
5335 }
5336
Andy McFadden62a75162009-04-17 17:23:37 -07005337 if (!VERIFY_OK(failure)) {
Andy McFaddenb51ea112009-05-08 16:50:17 -07005338 if (failure == VERIFY_ERROR_GENERIC || gDvm.optimizing) {
5339 /* immediate failure, reject class */
5340 LOG_VFY_METH(meth, "VFY: rejecting opcode 0x%02x at 0x%04x\n",
5341 decInsn.opCode, insnIdx);
5342 goto bail;
5343 } else {
5344 /* replace opcode and continue on */
5345 LOGD("VFY: replacing opcode 0x%02x at 0x%04x\n",
5346 decInsn.opCode, insnIdx);
5347 if (!replaceFailingInstruction(meth, insnFlags, insnIdx, failure)) {
5348 LOG_VFY_METH(meth, "VFY: rejecting opcode 0x%02x at 0x%04x\n",
5349 decInsn.opCode, insnIdx);
5350 goto bail;
5351 }
5352 /* IMPORTANT: meth->insns may have been changed */
5353 insns = meth->insns + insnIdx;
5354
5355 /* continue on as if we just handled a throw-verification-error */
5356 failure = VERIFY_ERROR_NONE;
5357 nextFlags = kInstrCanThrow;
5358 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005359 }
5360
5361 /*
5362 * If we didn't just set the result register, clear it out. This
5363 * ensures that you can only use "move-result" immediately after the
Andy McFadden2e1ee502010-03-24 13:25:53 -07005364 * result is set. (We could check this statically, but it's not
5365 * expensive and it makes our debugging output cleaner.)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005366 */
5367 if (!justSetResult) {
5368 int reg = RESULT_REGISTER(insnRegCount);
5369 workRegs[reg] = workRegs[reg+1] = kRegTypeUnknown;
5370 }
5371
5372 /*
5373 * Handle "continue". Tag the next consecutive instruction.
5374 */
5375 if ((nextFlags & kInstrCanContinue) != 0) {
5376 int insnWidth = dvmInsnGetWidth(insnFlags, insnIdx);
5377 if (insnIdx+insnWidth >= insnsSize) {
5378 LOG_VFY_METH(meth,
5379 "VFY: execution can walk off end of code area (from 0x%x)\n",
5380 insnIdx);
5381 goto bail;
5382 }
5383
5384 /*
5385 * The only way to get to a move-exception instruction is to get
5386 * thrown there. Make sure the next instruction isn't one.
5387 */
5388 if (!checkMoveException(meth, insnIdx+insnWidth, "next"))
5389 goto bail;
5390
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005391 if (getRegisterLine(regTable, insnIdx+insnWidth) != NULL) {
Andy McFadden06b7a282009-05-11 10:44:52 -07005392 /*
5393 * Merge registers into what we have for the next instruction,
5394 * and set the "changed" flag if needed.
5395 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005396 updateRegisters(meth, insnFlags, regTable, insnIdx+insnWidth,
5397 workRegs);
5398 } else {
The Android Open Source Project99409882009-03-18 22:20:24 -07005399 /*
Andy McFadden06b7a282009-05-11 10:44:52 -07005400 * We're not recording register data for the next instruction,
5401 * so we don't know what the prior state was. We have to
5402 * assume that something has changed and re-evaluate it.
The Android Open Source Project99409882009-03-18 22:20:24 -07005403 */
5404 dvmInsnSetChanged(insnFlags, insnIdx+insnWidth, true);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005405 }
5406 }
5407
5408 /*
5409 * Handle "branch". Tag the branch target.
5410 *
5411 * NOTE: instructions like OP_EQZ provide information about the state
5412 * of the register when the branch is taken or not taken. For example,
5413 * somebody could get a reference field, check it for zero, and if the
5414 * branch is taken immediately store that register in a boolean field
5415 * since the value is known to be zero. We do not currently account for
5416 * that, and will reject the code.
5417 */
5418 if ((nextFlags & kInstrCanBranch) != 0) {
5419 bool isConditional;
5420
5421 if (!dvmGetBranchTarget(meth, insnFlags, insnIdx, &branchTarget,
5422 &isConditional))
5423 {
5424 /* should never happen after static verification */
5425 LOG_VFY_METH(meth, "VFY: bad branch at %d\n", insnIdx);
5426 goto bail;
5427 }
5428 assert(isConditional || (nextFlags & kInstrCanContinue) == 0);
5429 assert(!isConditional || (nextFlags & kInstrCanContinue) != 0);
5430
5431 if (!checkMoveException(meth, insnIdx+branchTarget, "branch"))
5432 goto bail;
5433
The Android Open Source Project99409882009-03-18 22:20:24 -07005434 /* update branch target, set "changed" if appropriate */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005435 updateRegisters(meth, insnFlags, regTable, insnIdx+branchTarget,
5436 workRegs);
5437 }
5438
5439 /*
5440 * Handle "switch". Tag all possible branch targets.
5441 *
5442 * We've already verified that the table is structurally sound, so we
5443 * just need to walk through and tag the targets.
5444 */
5445 if ((nextFlags & kInstrCanSwitch) != 0) {
5446 int offsetToSwitch = insns[1] | (((s4)insns[2]) << 16);
5447 const u2* switchInsns = insns + offsetToSwitch;
5448 int switchCount = switchInsns[1];
5449 int offsetToTargets, targ;
5450
5451 if ((*insns & 0xff) == OP_PACKED_SWITCH) {
5452 /* 0=sig, 1=count, 2/3=firstKey */
5453 offsetToTargets = 4;
5454 } else {
5455 /* 0=sig, 1=count, 2..count*2 = keys */
5456 assert((*insns & 0xff) == OP_SPARSE_SWITCH);
5457 offsetToTargets = 2 + 2*switchCount;
5458 }
5459
5460 /* verify each switch target */
5461 for (targ = 0; targ < switchCount; targ++) {
5462 int offset, absOffset;
5463
5464 /* offsets are 32-bit, and only partly endian-swapped */
5465 offset = switchInsns[offsetToTargets + targ*2] |
5466 (((s4) switchInsns[offsetToTargets + targ*2 +1]) << 16);
5467 absOffset = insnIdx + offset;
5468
5469 assert(absOffset >= 0 && absOffset < insnsSize);
5470
5471 if (!checkMoveException(meth, absOffset, "switch"))
5472 goto bail;
5473
5474 updateRegisters(meth, insnFlags, regTable, absOffset, workRegs);
5475 }
5476 }
5477
5478 /*
5479 * Handle instructions that can throw and that are sitting in a
5480 * "try" block. (If they're not in a "try" block when they throw,
5481 * control transfers out of the method.)
5482 */
5483 if ((nextFlags & kInstrCanThrow) != 0 && dvmInsnIsInTry(insnFlags, insnIdx))
5484 {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005485 const DexCode* pCode = dvmGetMethodCode(meth);
5486 DexCatchIterator iterator;
5487
5488 if (dexFindCatchHandler(&iterator, pCode, insnIdx)) {
5489 for (;;) {
5490 DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
5491
5492 if (handler == NULL) {
5493 break;
5494 }
5495
5496 /* note we use entryRegs, not workRegs */
5497 updateRegisters(meth, insnFlags, regTable, handler->address,
5498 entryRegs);
5499 }
5500 }
5501 }
5502
5503 /*
5504 * Update startGuess. Advance to the next instruction of that's
5505 * possible, otherwise use the branch target if one was found. If
5506 * neither of those exists we're in a return or throw; leave startGuess
5507 * alone and let the caller sort it out.
5508 */
5509 if ((nextFlags & kInstrCanContinue) != 0) {
5510 *pStartGuess = insnIdx + dvmInsnGetWidth(insnFlags, insnIdx);
5511 } else if ((nextFlags & kInstrCanBranch) != 0) {
5512 /* we're still okay if branchTarget is zero */
5513 *pStartGuess = insnIdx + branchTarget;
5514 }
5515
5516 assert(*pStartGuess >= 0 && *pStartGuess < insnsSize &&
5517 dvmInsnGetWidth(insnFlags, *pStartGuess) != 0);
5518
5519 result = true;
5520
5521bail:
5522 return result;
5523}
5524
Andy McFaddenb51ea112009-05-08 16:50:17 -07005525
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005526/*
5527 * callback function used in dumpRegTypes to print local vars
5528 * valid at a given address.
5529 */
5530static void logLocalsCb(void *cnxt, u2 reg, u4 startAddress, u4 endAddress,
5531 const char *name, const char *descriptor,
5532 const char *signature)
5533{
5534 int addr = *((int *)cnxt);
5535
5536 if (addr >= (int) startAddress && addr < (int) endAddress)
5537 {
5538 LOGI(" %2d: '%s' %s\n", reg, name, descriptor);
5539 }
5540}
5541
5542/*
5543 * Dump the register types for the specifed address to the log file.
5544 */
5545static void dumpRegTypes(const Method* meth, const InsnFlags* insnFlags,
5546 const RegType* addrRegs, int addr, const char* addrName,
5547 const UninitInstanceMap* uninitMap, int displayFlags)
5548{
5549 int regCount = meth->registersSize;
5550 int fullRegCount = regCount + kExtraRegs;
5551 bool branchTarget = dvmInsnIsBranchTarget(insnFlags, addr);
5552 int i;
5553
5554 assert(addr >= 0 && addr < (int) dvmGetMethodInsnsSize(meth));
5555
5556 int regCharSize = fullRegCount + (fullRegCount-1)/4 + 2 +1;
5557 char regChars[regCharSize +1];
5558 memset(regChars, ' ', regCharSize);
5559 regChars[0] = '[';
5560 if (regCount == 0)
5561 regChars[1] = ']';
5562 else
5563 regChars[1 + (regCount-1) + (regCount-1)/4 +1] = ']';
5564 regChars[regCharSize] = '\0';
5565
5566 //const RegType* addrRegs = getRegisterLine(regTable, addr);
5567
5568 for (i = 0; i < regCount + kExtraRegs; i++) {
5569 char tch;
5570
5571 switch (addrRegs[i]) {
5572 case kRegTypeUnknown: tch = '.'; break;
5573 case kRegTypeConflict: tch = 'X'; break;
5574 case kRegTypeFloat: tch = 'F'; break;
5575 case kRegTypeZero: tch = '0'; break;
5576 case kRegTypeOne: tch = '1'; break;
5577 case kRegTypeBoolean: tch = 'Z'; break;
5578 case kRegTypePosByte: tch = 'b'; break;
5579 case kRegTypeByte: tch = 'B'; break;
5580 case kRegTypePosShort: tch = 's'; break;
5581 case kRegTypeShort: tch = 'S'; break;
5582 case kRegTypeChar: tch = 'C'; break;
5583 case kRegTypeInteger: tch = 'I'; break;
5584 case kRegTypeLongLo: tch = 'J'; break;
5585 case kRegTypeLongHi: tch = 'j'; break;
5586 case kRegTypeDoubleLo: tch = 'D'; break;
5587 case kRegTypeDoubleHi: tch = 'd'; break;
5588 default:
5589 if (regTypeIsReference(addrRegs[i])) {
5590 if (regTypeIsUninitReference(addrRegs[i]))
5591 tch = 'U';
5592 else
5593 tch = 'L';
5594 } else {
5595 tch = '*';
5596 assert(false);
5597 }
5598 break;
5599 }
5600
5601 if (i < regCount)
5602 regChars[1 + i + (i/4)] = tch;
5603 else
5604 regChars[1 + i + (i/4) + 2] = tch;
5605 }
5606
5607 if (addr == 0 && addrName != NULL)
5608 LOGI("%c%s %s\n", branchTarget ? '>' : ' ', addrName, regChars);
5609 else
5610 LOGI("%c0x%04x %s\n", branchTarget ? '>' : ' ', addr, regChars);
5611
5612 if (displayFlags & DRT_SHOW_REF_TYPES) {
5613 for (i = 0; i < regCount + kExtraRegs; i++) {
5614 if (regTypeIsReference(addrRegs[i]) && addrRegs[i] != kRegTypeZero)
5615 {
5616 ClassObject* clazz;
5617
5618 clazz = regTypeReferenceToClass(addrRegs[i], uninitMap);
5619 assert(dvmValidateObject((Object*)clazz));
5620 if (i < regCount) {
5621 LOGI(" %2d: 0x%08x %s%s\n",
5622 i, addrRegs[i],
5623 regTypeIsUninitReference(addrRegs[i]) ? "[U]" : "",
5624 clazz->descriptor);
5625 } else {
5626 LOGI(" RS: 0x%08x %s%s\n",
5627 addrRegs[i],
5628 regTypeIsUninitReference(addrRegs[i]) ? "[U]" : "",
5629 clazz->descriptor);
5630 }
5631 }
5632 }
5633 }
5634 if (displayFlags & DRT_SHOW_LOCALS) {
5635 dexDecodeDebugInfo(meth->clazz->pDvmDex->pDexFile,
5636 dvmGetMethodCode(meth),
5637 meth->clazz->descriptor,
5638 meth->prototype.protoIdx,
5639 meth->accessFlags,
5640 NULL, logLocalsCb, &addr);
5641 }
5642}