blob: 91f54148409e43a110ba356a54a8c18ac1a77df7 [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 */
117static void checkMergeTab(void);
118static bool isInitMethod(const Method* meth);
119static RegType getInvocationThis(const RegType* insnRegs,\
Andy McFadden62a75162009-04-17 17:23:37 -0700120 const int insnRegCount, const DecodedInstruction* pDecInsn,
121 VerifyError* pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800122static void verifyRegisterType(const RegType* insnRegs, const int insnRegCount,\
Andy McFadden62a75162009-04-17 17:23:37 -0700123 u4 vsrc, RegType checkType, VerifyError* pFailure);
Andy McFaddenb51ea112009-05-08 16:50:17 -0700124static bool doCodeVerification(Method* meth, InsnFlags* insnFlags,\
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800125 RegisterTable* regTable, UninitInstanceMap* uninitMap);
Andy McFaddenb51ea112009-05-08 16:50:17 -0700126static bool verifyInstruction(Method* meth, InsnFlags* insnFlags,\
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800127 RegisterTable* regTable, RegType* workRegs, int insnIdx,
128 UninitInstanceMap* uninitMap, int* pStartGuess);
129static ClassObject* findCommonSuperclass(ClassObject* c1, ClassObject* c2);
130static void dumpRegTypes(const Method* meth, const InsnFlags* insnFlags,\
131 const RegType* addrRegs, int addr, const char* addrName,
132 const UninitInstanceMap* uninitMap, int displayFlags);
133
134/* bit values for dumpRegTypes() "displayFlags" */
135enum {
136 DRT_SIMPLE = 0,
137 DRT_SHOW_REF_TYPES = 0x01,
138 DRT_SHOW_LOCALS = 0x02,
139};
140
141
142/*
143 * ===========================================================================
144 * RegType and UninitInstanceMap utility functions
145 * ===========================================================================
146 */
147
148#define __ kRegTypeUnknown
149#define _U kRegTypeUninit
150#define _X kRegTypeConflict
151#define _F kRegTypeFloat
152#define _0 kRegTypeZero
153#define _1 kRegTypeOne
154#define _Z kRegTypeBoolean
155#define _b kRegTypePosByte
156#define _B kRegTypeByte
157#define _s kRegTypePosShort
158#define _S kRegTypeShort
159#define _C kRegTypeChar
160#define _I kRegTypeInteger
161#define _J kRegTypeLongLo
162#define _j kRegTypeLongHi
163#define _D kRegTypeDoubleLo
164#define _d kRegTypeDoubleHi
165
166/*
167 * Merge result table for primitive values. The table is symmetric along
168 * the diagonal.
169 *
170 * Note that 32-bit int/float do not merge into 64-bit long/double. This
171 * is a register merge, not a widening conversion. Only the "implicit"
172 * widening within a category, e.g. byte to short, is allowed.
173 *
174 * Because Dalvik does not draw a distinction between int and float, we
175 * have to allow free exchange between 32-bit int/float and 64-bit
176 * long/double.
177 *
178 * Note that Uninit+Uninit=Uninit. This holds true because we only
179 * use this when the RegType value is exactly equal to kRegTypeUninit, which
180 * can only happen for the zeroeth entry in the table.
181 *
182 * "Unknown" never merges with anything known. The only time a register
183 * transitions from "unknown" to "known" is when we're executing code
184 * for the first time, and we handle that with a simple copy.
185 */
186const char gDvmMergeTab[kRegTypeMAX][kRegTypeMAX] =
187{
188 /* chk: _ U X F 0 1 Z b B s S C I J j D d */
189 { /*_*/ __,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X },
190 { /*U*/ _X,_U,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X },
191 { /*X*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X },
192 { /*F*/ _X,_X,_X,_F,_F,_F,_F,_F,_F,_F,_F,_F,_F,_X,_X,_X,_X },
193 { /*0*/ _X,_X,_X,_F,_0,_Z,_Z,_b,_B,_s,_S,_C,_I,_X,_X,_X,_X },
194 { /*1*/ _X,_X,_X,_F,_Z,_1,_Z,_b,_B,_s,_S,_C,_I,_X,_X,_X,_X },
195 { /*Z*/ _X,_X,_X,_F,_Z,_Z,_Z,_b,_B,_s,_S,_C,_I,_X,_X,_X,_X },
196 { /*b*/ _X,_X,_X,_F,_b,_b,_b,_b,_B,_s,_S,_C,_I,_X,_X,_X,_X },
197 { /*B*/ _X,_X,_X,_F,_B,_B,_B,_B,_B,_S,_S,_I,_I,_X,_X,_X,_X },
198 { /*s*/ _X,_X,_X,_F,_s,_s,_s,_s,_S,_s,_S,_C,_I,_X,_X,_X,_X },
199 { /*S*/ _X,_X,_X,_F,_S,_S,_S,_S,_S,_S,_S,_I,_I,_X,_X,_X,_X },
200 { /*C*/ _X,_X,_X,_F,_C,_C,_C,_C,_I,_C,_I,_C,_I,_X,_X,_X,_X },
201 { /*I*/ _X,_X,_X,_F,_I,_I,_I,_I,_I,_I,_I,_I,_I,_X,_X,_X,_X },
202 { /*J*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_J,_X,_J,_X },
203 { /*j*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_j,_X,_j },
204 { /*D*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_J,_X,_D,_X },
205 { /*d*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_j,_X,_d },
206};
207
208#undef __
209#undef _U
210#undef _X
211#undef _F
212#undef _0
213#undef _1
214#undef _Z
215#undef _b
216#undef _B
217#undef _s
218#undef _S
219#undef _C
220#undef _I
221#undef _J
222#undef _j
223#undef _D
224#undef _d
225
226#ifndef NDEBUG
227/*
228 * Verify symmetry in the conversion table.
229 */
230static void checkMergeTab(void)
231{
232 int i, j;
233
234 for (i = 0; i < kRegTypeMAX; i++) {
235 for (j = i; j < kRegTypeMAX; j++) {
236 if (gDvmMergeTab[i][j] != gDvmMergeTab[j][i]) {
237 LOGE("Symmetry violation: %d,%d vs %d,%d\n", i, j, j, i);
238 dvmAbort();
239 }
240 }
241 }
242}
243#endif
244
245/*
246 * Determine whether we can convert "srcType" to "checkType", where
247 * "checkType" is one of the category-1 non-reference types.
248 *
249 * 32-bit int and float are interchangeable.
250 */
251static bool canConvertTo1nr(RegType srcType, RegType checkType)
252{
253 static const char convTab
254 [kRegType1nrEND-kRegType1nrSTART+1][kRegType1nrEND-kRegType1nrSTART+1] =
255 {
256 /* chk: F 0 1 Z b B s S C I */
257 { /*F*/ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
258 { /*0*/ 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
259 { /*1*/ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 },
260 { /*Z*/ 1, 0, 0, 1, 1, 1, 1, 1, 1, 1 },
261 { /*b*/ 1, 0, 0, 0, 1, 1, 1, 1, 1, 1 },
262 { /*B*/ 1, 0, 0, 0, 0, 1, 0, 1, 0, 1 },
263 { /*s*/ 1, 0, 0, 0, 0, 0, 1, 1, 1, 1 },
264 { /*S*/ 1, 0, 0, 0, 0, 0, 0, 1, 0, 1 },
265 { /*C*/ 1, 0, 0, 0, 0, 0, 0, 0, 1, 1 },
266 { /*I*/ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
267 };
268
269 assert(checkType >= kRegType1nrSTART && checkType <= kRegType1nrEND);
270#if 0
271 if (checkType < kRegType1nrSTART || checkType > kRegType1nrEND) {
272 LOG_VFY("Unexpected checkType %d (srcType=%d)\n", checkType, srcType);
273 assert(false);
274 return false;
275 }
276#endif
277
278 //printf("convTab[%d][%d] = %d\n", srcType, checkType,
279 // convTab[srcType-kRegType1nrSTART][checkType-kRegType1nrSTART]);
280 if (srcType >= kRegType1nrSTART && srcType <= kRegType1nrEND)
281 return (bool) convTab[srcType-kRegType1nrSTART][checkType-kRegType1nrSTART];
282
283 return false;
284}
285
286/*
287 * Determine whether the types are compatible. In Dalvik, 64-bit doubles
288 * and longs are interchangeable.
289 */
290static bool canConvertTo2(RegType srcType, RegType checkType)
291{
292 return ((srcType == kRegTypeLongLo || srcType == kRegTypeDoubleLo) &&
293 (checkType == kRegTypeLongLo || checkType == kRegTypeDoubleLo));
294}
295
296/*
297 * Determine whether or not "instrType" and "targetType" are compatible,
298 * for purposes of getting or setting a value in a field or array. The
299 * idea is that an instruction with a category 1nr type (say, aget-short
300 * or iput-boolean) is accessing a static field, instance field, or array
301 * entry, and we want to make sure sure that the operation is legal.
302 *
303 * At a minimum, source and destination must have the same width. We
304 * further refine this to assert that "short" and "char" are not
305 * compatible, because the sign-extension is different on the "get"
306 * operations. As usual, "float" and "int" are interoperable.
307 *
308 * We're not considering the actual contents of the register, so we'll
309 * never get "pseudo-types" like kRegTypeZero or kRegTypePosShort. We
310 * could get kRegTypeUnknown in "targetType" if a field or array class
311 * lookup failed. Category 2 types and references are checked elsewhere.
312 */
313static bool checkFieldArrayStore1nr(RegType instrType, RegType targetType)
314{
315 if (instrType == targetType)
316 return true; /* quick positive; most common case */
317
318 if ((instrType == kRegTypeInteger && targetType == kRegTypeFloat) ||
319 (instrType == kRegTypeFloat && targetType == kRegTypeInteger))
320 {
321 return true;
322 }
323
324 return false;
325}
326
327/*
328 * Convert a VM PrimitiveType enum value to the equivalent RegType value.
329 */
330static RegType primitiveTypeToRegType(PrimitiveType primType)
331{
The Android Open Source Project99409882009-03-18 22:20:24 -0700332 static const struct {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800333 RegType regType; /* type equivalent */
334 PrimitiveType primType; /* verification */
335 } convTab[] = {
336 /* must match order of enum in Object.h */
337 { kRegTypeBoolean, PRIM_BOOLEAN },
338 { kRegTypeChar, PRIM_CHAR },
339 { kRegTypeFloat, PRIM_FLOAT },
340 { kRegTypeDoubleLo, PRIM_DOUBLE },
341 { kRegTypeByte, PRIM_BYTE },
342 { kRegTypeShort, PRIM_SHORT },
343 { kRegTypeInteger, PRIM_INT },
344 { kRegTypeLongLo, PRIM_LONG },
345 // PRIM_VOID
346 };
347
348 if (primType < 0 || primType > (int) (sizeof(convTab) / sizeof(convTab[0])))
349 {
350 assert(false);
351 return kRegTypeUnknown;
352 }
353
354 assert(convTab[primType].primType == primType);
355 return convTab[primType].regType;
356}
357
358/*
359 * Create a new uninitialized instance map.
360 *
361 * The map is allocated and populated with address entries. The addresses
362 * appear in ascending order to allow binary searching.
363 *
364 * Very few methods have 10 or more new-instance instructions; the
365 * majority have 0 or 1. Occasionally a static initializer will have 200+.
366 */
367UninitInstanceMap* dvmCreateUninitInstanceMap(const Method* meth,
368 const InsnFlags* insnFlags, int newInstanceCount)
369{
370 const int insnsSize = dvmGetMethodInsnsSize(meth);
371 const u2* insns = meth->insns;
372 UninitInstanceMap* uninitMap;
373 bool isInit = false;
374 int idx, addr;
375
376 if (isInitMethod(meth)) {
377 newInstanceCount++;
378 isInit = true;
379 }
380
381 /*
382 * Allocate the header and map as a single unit.
383 *
384 * TODO: consider having a static instance so we can avoid allocations.
385 * I don't think the verifier is guaranteed to be single-threaded when
386 * running in the VM (rather than dexopt), so that must be taken into
387 * account.
388 */
389 int size = offsetof(UninitInstanceMap, map) +
390 newInstanceCount * sizeof(uninitMap->map[0]);
391 uninitMap = calloc(1, size);
392 if (uninitMap == NULL)
393 return NULL;
394 uninitMap->numEntries = newInstanceCount;
395
396 idx = 0;
397 if (isInit) {
398 uninitMap->map[idx++].addr = kUninitThisArgAddr;
399 }
400
401 /*
402 * Run through and find the new-instance instructions.
403 */
404 for (addr = 0; addr < insnsSize; /**/) {
405 int width = dvmInsnGetWidth(insnFlags, addr);
406
407 if ((*insns & 0xff) == OP_NEW_INSTANCE)
408 uninitMap->map[idx++].addr = addr;
409
410 addr += width;
411 insns += width;
412 }
413
414 assert(idx == newInstanceCount);
415 return uninitMap;
416}
417
418/*
419 * Free the map.
420 */
421void dvmFreeUninitInstanceMap(UninitInstanceMap* uninitMap)
422{
423 free(uninitMap);
424}
425
426/*
427 * Set the class object associated with the instruction at "addr".
428 *
429 * Returns the map slot index, or -1 if the address isn't listed in the map
430 * (shouldn't happen) or if a class is already associated with the address
431 * (bad bytecode).
432 *
433 * Entries, once set, do not change -- a given address can only allocate
434 * one type of object.
435 */
436int dvmSetUninitInstance(UninitInstanceMap* uninitMap, int addr,
437 ClassObject* clazz)
438{
439 int idx;
440
441 assert(clazz != NULL);
442
443 /* TODO: binary search when numEntries > 8 */
444 for (idx = uninitMap->numEntries - 1; idx >= 0; idx--) {
445 if (uninitMap->map[idx].addr == addr) {
446 if (uninitMap->map[idx].clazz != NULL &&
447 uninitMap->map[idx].clazz != clazz)
448 {
449 LOG_VFY("VFY: addr %d already set to %p, not setting to %p\n",
450 addr, uninitMap->map[idx].clazz, clazz);
451 return -1; // already set to something else??
452 }
453 uninitMap->map[idx].clazz = clazz;
454 return idx;
455 }
456 }
457
458 LOG_VFY("VFY: addr %d not found in uninit map\n", addr);
459 assert(false); // shouldn't happen
460 return -1;
461}
462
463/*
464 * Get the class object at the specified index.
465 */
466ClassObject* dvmGetUninitInstance(const UninitInstanceMap* uninitMap, int idx)
467{
468 assert(idx >= 0 && idx < uninitMap->numEntries);
469 return uninitMap->map[idx].clazz;
470}
471
472/* determine if "type" is actually an object reference (init/uninit/zero) */
473static inline bool regTypeIsReference(RegType type) {
474 return (type > kRegTypeMAX || type == kRegTypeUninit ||
475 type == kRegTypeZero);
476}
477
478/* determine if "type" is an uninitialized object reference */
479static inline bool regTypeIsUninitReference(RegType type) {
480 return ((type & kRegTypeUninitMask) == kRegTypeUninit);
481}
482
483/* convert the initialized reference "type" to a ClassObject pointer */
484/* (does not expect uninit ref types or "zero") */
485static ClassObject* regTypeInitializedReferenceToClass(RegType type)
486{
487 assert(regTypeIsReference(type) && type != kRegTypeZero);
488 if ((type & 0x01) == 0) {
489 return (ClassObject*) type;
490 } else {
491 //LOG_VFY("VFY: attempted to use uninitialized reference\n");
492 return NULL;
493 }
494}
495
496/* extract the index into the uninitialized instance map table */
497static inline int regTypeToUninitIndex(RegType type) {
498 assert(regTypeIsUninitReference(type));
499 return (type & ~kRegTypeUninitMask) >> kRegTypeUninitShift;
500}
501
502/* convert the reference "type" to a ClassObject pointer */
503static ClassObject* regTypeReferenceToClass(RegType type,
504 const UninitInstanceMap* uninitMap)
505{
506 assert(regTypeIsReference(type) && type != kRegTypeZero);
507 if (regTypeIsUninitReference(type)) {
508 assert(uninitMap != NULL);
509 return dvmGetUninitInstance(uninitMap, regTypeToUninitIndex(type));
510 } else {
511 return (ClassObject*) type;
512 }
513}
514
515/* convert the ClassObject pointer to an (initialized) register type */
516static inline RegType regTypeFromClass(ClassObject* clazz) {
517 return (u4) clazz;
518}
519
520/* return the RegType for the uninitialized reference in slot "uidx" */
521static RegType regTypeFromUninitIndex(int uidx) {
522 return (u4) (kRegTypeUninit | (uidx << kRegTypeUninitShift));
523}
524
525
526/*
527 * ===========================================================================
528 * Signature operations
529 * ===========================================================================
530 */
531
532/*
533 * Is this method a constructor?
534 */
535static bool isInitMethod(const Method* meth)
536{
537 return (*meth->name == '<' && strcmp(meth->name+1, "init>") == 0);
538}
539
540/*
541 * Is this method a class initializer?
542 */
543static bool isClassInitMethod(const Method* meth)
544{
545 return (*meth->name == '<' && strcmp(meth->name+1, "clinit>") == 0);
546}
547
548/*
549 * Look up a class reference given as a simple string descriptor.
Andy McFadden62a75162009-04-17 17:23:37 -0700550 *
551 * If we can't find it, return a generic substitute when possible.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800552 */
553static ClassObject* lookupClassByDescriptor(const Method* meth,
Andy McFadden62a75162009-04-17 17:23:37 -0700554 const char* pDescriptor, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800555{
556 /*
557 * The javac compiler occasionally puts references to nonexistent
558 * classes in signatures. For example, if you have a non-static
559 * inner class with no constructor, the compiler provides
560 * a private <init> for you. Constructing the class
561 * requires <init>(parent), but the outer class can't call
562 * that because the method is private. So the compiler
563 * generates a package-scope <init>(parent,bogus) method that
564 * just calls the regular <init> (the "bogus" part being necessary
565 * to distinguish the signature of the synthetic method).
566 * Treating the bogus class as an instance of java.lang.Object
567 * allows the verifier to process the class successfully.
568 */
569
570 //LOGI("Looking up '%s'\n", typeStr);
571 ClassObject* clazz;
572 clazz = dvmFindClassNoInit(pDescriptor, meth->clazz->classLoader);
573 if (clazz == NULL) {
574 dvmClearOptException(dvmThreadSelf());
575 if (strchr(pDescriptor, '$') != NULL) {
576 LOGV("VFY: unable to find class referenced in signature (%s)\n",
577 pDescriptor);
578 } else {
579 LOG_VFY("VFY: unable to find class referenced in signature (%s)\n",
580 pDescriptor);
581 }
582
583 if (pDescriptor[0] == '[') {
584 /* We are looking at an array descriptor. */
585
586 /*
587 * There should never be a problem loading primitive arrays.
588 */
589 if (pDescriptor[1] != 'L' && pDescriptor[1] != '[') {
590 LOG_VFY("VFY: invalid char in signature in '%s'\n",
591 pDescriptor);
Andy McFadden62a75162009-04-17 17:23:37 -0700592 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800593 }
594
595 /*
596 * Try to continue with base array type. This will let
597 * us pass basic stuff (e.g. get array len) that wouldn't
598 * fly with an Object. This is NOT correct if the
599 * missing type is a primitive array, but we should never
600 * have a problem loading those. (I'm not convinced this
601 * is correct or even useful. Just use Object here?)
602 */
603 clazz = dvmFindClassNoInit("[Ljava/lang/Object;",
604 meth->clazz->classLoader);
605 } else if (pDescriptor[0] == 'L') {
606 /*
607 * We are looking at a non-array reference descriptor;
608 * try to continue with base reference type.
609 */
610 clazz = gDvm.classJavaLangObject;
611 } else {
612 /* We are looking at a primitive type. */
613 LOG_VFY("VFY: invalid char in signature in '%s'\n", pDescriptor);
Andy McFadden62a75162009-04-17 17:23:37 -0700614 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800615 }
616
617 if (clazz == NULL) {
Andy McFadden62a75162009-04-17 17:23:37 -0700618 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800619 }
620 }
621
622 if (dvmIsPrimitiveClass(clazz)) {
623 LOG_VFY("VFY: invalid use of primitive type '%s'\n", pDescriptor);
Andy McFadden62a75162009-04-17 17:23:37 -0700624 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800625 clazz = NULL;
626 }
627
628 return clazz;
629}
630
631/*
632 * Look up a class reference in a signature. Could be an arg or the
633 * return value.
634 *
635 * Advances "*pSig" to the last character in the signature (that is, to
636 * the ';').
637 *
638 * NOTE: this is also expected to verify the signature.
639 */
640static ClassObject* lookupSignatureClass(const Method* meth, const char** pSig,
Andy McFadden62a75162009-04-17 17:23:37 -0700641 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800642{
643 const char* sig = *pSig;
644 const char* endp = sig;
645
646 assert(sig != NULL && *sig == 'L');
647
648 while (*++endp != ';' && *endp != '\0')
649 ;
650 if (*endp != ';') {
651 LOG_VFY("VFY: bad signature component '%s' (missing ';')\n", sig);
Andy McFadden62a75162009-04-17 17:23:37 -0700652 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800653 return NULL;
654 }
655
656 endp++; /* Advance past the ';'. */
657 int typeLen = endp - sig;
658 char typeStr[typeLen+1]; /* +1 for the '\0' */
659 memcpy(typeStr, sig, typeLen);
660 typeStr[typeLen] = '\0';
661
662 *pSig = endp - 1; /* - 1 so that *pSig points at, not past, the ';' */
663
Andy McFadden62a75162009-04-17 17:23:37 -0700664 return lookupClassByDescriptor(meth, typeStr, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800665}
666
667/*
668 * Look up an array class reference in a signature. Could be an arg or the
669 * return value.
670 *
671 * Advances "*pSig" to the last character in the signature.
672 *
673 * NOTE: this is also expected to verify the signature.
674 */
675static ClassObject* lookupSignatureArrayClass(const Method* meth,
Andy McFadden62a75162009-04-17 17:23:37 -0700676 const char** pSig, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800677{
678 const char* sig = *pSig;
679 const char* endp = sig;
680
681 assert(sig != NULL && *sig == '[');
682
683 /* find the end */
684 while (*++endp == '[' && *endp != '\0')
685 ;
686
687 if (*endp == 'L') {
688 while (*++endp != ';' && *endp != '\0')
689 ;
690 if (*endp != ';') {
691 LOG_VFY("VFY: bad signature component '%s' (missing ';')\n", sig);
Andy McFadden62a75162009-04-17 17:23:37 -0700692 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800693 return NULL;
694 }
695 }
696
697 int typeLen = endp - sig +1;
698 char typeStr[typeLen+1];
699 memcpy(typeStr, sig, typeLen);
700 typeStr[typeLen] = '\0';
701
702 *pSig = endp;
703
Andy McFadden62a75162009-04-17 17:23:37 -0700704 return lookupClassByDescriptor(meth, typeStr, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800705}
706
707/*
708 * Set the register types for the first instruction in the method based on
709 * the method signature.
710 *
711 * This has the side-effect of validating the signature.
712 *
713 * Returns "true" on success.
714 */
715static bool setTypesFromSignature(const Method* meth, RegType* regTypes,
716 UninitInstanceMap* uninitMap)
717{
718 DexParameterIterator iterator;
719 int actualArgs, expectedArgs, argStart;
Andy McFadden62a75162009-04-17 17:23:37 -0700720 VerifyError failure = VERIFY_ERROR_NONE;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800721
722 dexParameterIteratorInit(&iterator, &meth->prototype);
723 argStart = meth->registersSize - meth->insSize;
724 expectedArgs = meth->insSize; /* long/double count as two */
725 actualArgs = 0;
726
727 assert(argStart >= 0); /* should have been verified earlier */
728
729 /*
730 * Include the "this" pointer.
731 */
732 if (!dvmIsStaticMethod(meth)) {
733 /*
734 * If this is a constructor for a class other than java.lang.Object,
735 * mark the first ("this") argument as uninitialized. This restricts
736 * field access until the superclass constructor is called.
737 */
738 if (isInitMethod(meth) && meth->clazz != gDvm.classJavaLangObject) {
739 int uidx = dvmSetUninitInstance(uninitMap, kUninitThisArgAddr,
740 meth->clazz);
741 assert(uidx == 0);
742 regTypes[argStart + actualArgs] = regTypeFromUninitIndex(uidx);
743 } else {
744 regTypes[argStart + actualArgs] = regTypeFromClass(meth->clazz);
745 }
746 actualArgs++;
747 }
748
749 for (;;) {
750 const char* descriptor = dexParameterIteratorNextDescriptor(&iterator);
751
752 if (descriptor == NULL) {
753 break;
754 }
755
756 if (actualArgs >= expectedArgs) {
757 LOG_VFY("VFY: expected %d args, found more (%s)\n",
758 expectedArgs, descriptor);
759 goto bad_sig;
760 }
761
762 switch (*descriptor) {
763 case 'L':
764 case '[':
765 /*
766 * We assume that reference arguments are initialized. The
767 * only way it could be otherwise (assuming the caller was
768 * verified) is if the current method is <init>, but in that
769 * case it's effectively considered initialized the instant
770 * we reach here (in the sense that we can return without
771 * doing anything or call virtual methods).
772 */
773 {
774 ClassObject* clazz =
Andy McFadden62a75162009-04-17 17:23:37 -0700775 lookupClassByDescriptor(meth, descriptor, &failure);
776 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800777 goto bad_sig;
778 regTypes[argStart + actualArgs] = regTypeFromClass(clazz);
779 }
780 actualArgs++;
781 break;
782 case 'Z':
783 regTypes[argStart + actualArgs] = kRegTypeBoolean;
784 actualArgs++;
785 break;
786 case 'C':
787 regTypes[argStart + actualArgs] = kRegTypeChar;
788 actualArgs++;
789 break;
790 case 'B':
791 regTypes[argStart + actualArgs] = kRegTypeByte;
792 actualArgs++;
793 break;
794 case 'I':
795 regTypes[argStart + actualArgs] = kRegTypeInteger;
796 actualArgs++;
797 break;
798 case 'S':
799 regTypes[argStart + actualArgs] = kRegTypeShort;
800 actualArgs++;
801 break;
802 case 'F':
803 regTypes[argStart + actualArgs] = kRegTypeFloat;
804 actualArgs++;
805 break;
806 case 'D':
807 regTypes[argStart + actualArgs] = kRegTypeDoubleLo;
808 regTypes[argStart + actualArgs +1] = kRegTypeDoubleHi;
809 actualArgs += 2;
810 break;
811 case 'J':
812 regTypes[argStart + actualArgs] = kRegTypeLongLo;
813 regTypes[argStart + actualArgs +1] = kRegTypeLongHi;
814 actualArgs += 2;
815 break;
816 default:
817 LOG_VFY("VFY: unexpected signature type char '%c'\n", *descriptor);
818 goto bad_sig;
819 }
820 }
821
822 if (actualArgs != expectedArgs) {
823 LOG_VFY("VFY: expected %d args, found %d\n", expectedArgs, actualArgs);
824 goto bad_sig;
825 }
826
827 const char* descriptor = dexProtoGetReturnType(&meth->prototype);
828
829 /*
830 * Validate return type. We don't do the type lookup; just want to make
831 * sure that it has the right format. Only major difference from the
832 * method argument format is that 'V' is supported.
833 */
834 switch (*descriptor) {
835 case 'I':
836 case 'C':
837 case 'S':
838 case 'B':
839 case 'Z':
840 case 'V':
841 case 'F':
842 case 'D':
843 case 'J':
844 if (*(descriptor+1) != '\0')
845 goto bad_sig;
846 break;
847 case '[':
848 /* single/multi, object/primitive */
849 while (*++descriptor == '[')
850 ;
851 if (*descriptor == 'L') {
852 while (*++descriptor != ';' && *descriptor != '\0')
853 ;
854 if (*descriptor != ';')
855 goto bad_sig;
856 } else {
857 if (*(descriptor+1) != '\0')
858 goto bad_sig;
859 }
860 break;
861 case 'L':
862 /* could be more thorough here, but shouldn't be required */
863 while (*++descriptor != ';' && *descriptor != '\0')
864 ;
865 if (*descriptor != ';')
866 goto bad_sig;
867 break;
868 default:
869 goto bad_sig;
870 }
871
872 return true;
873
874//fail:
875// LOG_VFY_METH(meth, "VFY: bad sig\n");
876// return false;
877
878bad_sig:
879 {
880 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
881 LOG_VFY("VFY: bad signature '%s' for %s.%s\n",
882 desc, meth->clazz->descriptor, meth->name);
883 free(desc);
884 }
885 return false;
886}
887
888/*
889 * Return the register type for the method. We can't just use the
890 * already-computed DalvikJniReturnType, because if it's a reference type
891 * we need to do the class lookup.
892 *
893 * Returned references are assumed to be initialized.
894 *
895 * Returns kRegTypeUnknown for "void".
896 */
897static RegType getMethodReturnType(const Method* meth)
898{
899 RegType type;
900 const char* descriptor = dexProtoGetReturnType(&meth->prototype);
901
902 switch (*descriptor) {
903 case 'I':
904 type = kRegTypeInteger;
905 break;
906 case 'C':
907 type = kRegTypeChar;
908 break;
909 case 'S':
910 type = kRegTypeShort;
911 break;
912 case 'B':
913 type = kRegTypeByte;
914 break;
915 case 'Z':
916 type = kRegTypeBoolean;
917 break;
918 case 'V':
919 type = kRegTypeUnknown;
920 break;
921 case 'F':
922 type = kRegTypeFloat;
923 break;
924 case 'D':
925 type = kRegTypeDoubleLo;
926 break;
927 case 'J':
928 type = kRegTypeLongLo;
929 break;
930 case 'L':
931 case '[':
932 {
Andy McFadden62a75162009-04-17 17:23:37 -0700933 VerifyError failure = VERIFY_ERROR_NONE;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800934 ClassObject* clazz =
Andy McFadden62a75162009-04-17 17:23:37 -0700935 lookupClassByDescriptor(meth, descriptor, &failure);
936 assert(VERIFY_OK(failure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800937 type = regTypeFromClass(clazz);
938 }
939 break;
940 default:
941 /* we verified signature return type earlier, so this is impossible */
942 assert(false);
943 type = kRegTypeConflict;
944 break;
945 }
946
947 return type;
948}
949
950/*
951 * Convert a single-character signature value (i.e. a primitive type) to
952 * the corresponding RegType. This is intended for access to object fields
953 * holding primitive types.
954 *
955 * Returns kRegTypeUnknown for objects, arrays, and void.
956 */
957static RegType primSigCharToRegType(char sigChar)
958{
959 RegType type;
960
961 switch (sigChar) {
962 case 'I':
963 type = kRegTypeInteger;
964 break;
965 case 'C':
966 type = kRegTypeChar;
967 break;
968 case 'S':
969 type = kRegTypeShort;
970 break;
971 case 'B':
972 type = kRegTypeByte;
973 break;
974 case 'Z':
975 type = kRegTypeBoolean;
976 break;
977 case 'F':
978 type = kRegTypeFloat;
979 break;
980 case 'D':
981 type = kRegTypeDoubleLo;
982 break;
983 case 'J':
984 type = kRegTypeLongLo;
985 break;
986 case 'V':
987 case 'L':
988 case '[':
989 type = kRegTypeUnknown;
990 break;
991 default:
992 assert(false);
993 type = kRegTypeUnknown;
994 break;
995 }
996
997 return type;
998}
999
1000/*
1001 * Verify the arguments to a method. We're executing in "method", making
1002 * a call to the method reference in vB.
1003 *
1004 * If this is a "direct" invoke, we allow calls to <init>. For calls to
1005 * <init>, the first argument may be an uninitialized reference. Otherwise,
1006 * calls to anything starting with '<' will be rejected, as will any
1007 * uninitialized reference arguments.
1008 *
1009 * For non-static method calls, this will verify that the method call is
1010 * appropriate for the "this" argument.
1011 *
1012 * The method reference is in vBBBB. The "isRange" parameter determines
1013 * whether we use 0-4 "args" values or a range of registers defined by
1014 * vAA and vCCCC.
1015 *
1016 * Widening conversions on integers and references are allowed, but
1017 * narrowing conversions are not.
1018 *
Andy McFadden62a75162009-04-17 17:23:37 -07001019 * Returns the resolved method on success, NULL on failure (with *pFailure
1020 * set appropriately).
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001021 */
1022static Method* verifyInvocationArgs(const Method* meth, const RegType* insnRegs,
1023 const int insnRegCount, const DecodedInstruction* pDecInsn,
1024 UninitInstanceMap* uninitMap, MethodType methodType, bool isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07001025 bool isSuper, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001026{
1027 Method* resMethod;
1028 char* sigOriginal = NULL;
1029
1030 /*
1031 * Resolve the method. This could be an abstract or concrete method
1032 * depending on what sort of call we're making.
1033 */
1034 if (methodType == METHOD_INTERFACE) {
1035 resMethod = dvmOptResolveInterfaceMethod(meth->clazz, pDecInsn->vB);
1036 } else {
Andy McFadden62a75162009-04-17 17:23:37 -07001037 resMethod = dvmOptResolveMethod(meth->clazz, pDecInsn->vB, methodType,
1038 pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001039 }
1040 if (resMethod == NULL) {
1041 /* failed; print a meaningful failure message */
1042 DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
1043 const DexMethodId* pMethodId;
1044 const char* methodName;
1045 char* methodDesc;
1046 const char* classDescriptor;
1047
1048 pMethodId = dexGetMethodId(pDexFile, pDecInsn->vB);
1049 methodName = dexStringById(pDexFile, pMethodId->nameIdx);
1050 methodDesc = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
1051 classDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
1052
1053 if (!gDvm.optimizing) {
1054 char* dotMissingClass = dvmDescriptorToDot(classDescriptor);
1055 char* dotMethClass = dvmDescriptorToDot(meth->clazz->descriptor);
1056 //char* curMethodDesc =
1057 // dexProtoCopyMethodDescriptor(&meth->prototype);
1058
Andy McFaddenb51ea112009-05-08 16:50:17 -07001059 LOGI("Could not find method %s.%s, referenced from "
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001060 "method %s.%s\n",
1061 dotMissingClass, methodName/*, methodDesc*/,
1062 dotMethClass, meth->name/*, curMethodDesc*/);
1063
1064 free(dotMissingClass);
1065 free(dotMethClass);
1066 //free(curMethodDesc);
1067 }
1068
1069 LOG_VFY("VFY: unable to resolve %s method %u: %s.%s %s\n",
1070 dvmMethodTypeStr(methodType), pDecInsn->vB,
1071 classDescriptor, methodName, methodDesc);
1072 free(methodDesc);
Andy McFaddenb51ea112009-05-08 16:50:17 -07001073 if (VERIFY_OK(*pFailure)) /* not set for interface resolve */
1074 *pFailure = VERIFY_ERROR_NO_METHOD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001075 goto fail;
1076 }
1077
1078 /*
1079 * Only time you can explicitly call a method starting with '<' is when
1080 * making a "direct" invocation on "<init>". There are additional
1081 * restrictions but we don't enforce them here.
1082 */
1083 if (resMethod->name[0] == '<') {
1084 if (methodType != METHOD_DIRECT || !isInitMethod(resMethod)) {
1085 LOG_VFY("VFY: invalid call to %s.%s\n",
1086 resMethod->clazz->descriptor, resMethod->name);
1087 goto bad_sig;
1088 }
1089 }
1090
1091 /*
1092 * If we're using invoke-super(method), make sure that the executing
1093 * method's class' superclass has a vtable entry for the target method.
1094 */
1095 if (isSuper) {
1096 assert(methodType == METHOD_VIRTUAL);
1097 ClassObject* super = meth->clazz->super;
1098 if (super == NULL || resMethod->methodIndex > super->vtableCount) {
1099 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1100 LOG_VFY("VFY: invalid invoke-super from %s.%s to super %s.%s %s\n",
1101 meth->clazz->descriptor, meth->name,
1102 (super == NULL) ? "-" : super->descriptor,
1103 resMethod->name, desc);
1104 free(desc);
Andy McFadden62a75162009-04-17 17:23:37 -07001105 *pFailure = VERIFY_ERROR_NO_METHOD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001106 goto fail;
1107 }
1108 }
1109
1110 /*
1111 * We use vAA as our expected arg count, rather than resMethod->insSize,
1112 * because we need to match the call to the signature. Also, we might
1113 * might be calling through an abstract method definition (which doesn't
1114 * have register count values).
1115 */
1116 sigOriginal = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1117 const char* sig = sigOriginal;
1118 int expectedArgs = pDecInsn->vA;
1119 int actualArgs = 0;
1120
1121 if (!isRange && expectedArgs > 5) {
1122 LOG_VFY("VFY: invalid arg count in non-range invoke (%d)\n",
1123 pDecInsn->vA);
1124 goto fail;
1125 }
1126 if (expectedArgs > meth->outsSize) {
1127 LOG_VFY("VFY: invalid arg count (%d) exceeds outsSize (%d)\n",
1128 expectedArgs, meth->outsSize);
1129 goto fail;
1130 }
1131
1132 if (*sig++ != '(')
1133 goto bad_sig;
1134
1135 /*
1136 * Check the "this" argument, which must be an instance of the class
1137 * that declared the method. For an interface class, we don't do the
1138 * full interface merge, so we can't do a rigorous check here (which
1139 * is okay since we have to do it at runtime).
1140 */
1141 if (!dvmIsStaticMethod(resMethod)) {
1142 ClassObject* actualThisRef;
1143 RegType actualArgType;
1144
1145 actualArgType = getInvocationThis(insnRegs, insnRegCount, pDecInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07001146 pFailure);
1147 if (!VERIFY_OK(*pFailure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001148 goto fail;
1149
1150 if (regTypeIsUninitReference(actualArgType) && resMethod->name[0] != '<')
1151 {
1152 LOG_VFY("VFY: 'this' arg must be initialized\n");
1153 goto fail;
1154 }
1155 if (methodType != METHOD_INTERFACE && actualArgType != kRegTypeZero) {
1156 actualThisRef = regTypeReferenceToClass(actualArgType, uninitMap);
1157 if (!dvmInstanceof(actualThisRef, resMethod->clazz)) {
1158 LOG_VFY("VFY: 'this' arg '%s' not instance of '%s'\n",
1159 actualThisRef->descriptor,
1160 resMethod->clazz->descriptor);
1161 goto fail;
1162 }
1163 }
1164 actualArgs++;
1165 }
1166
1167 /*
1168 * Process the target method's signature. This signature may or may not
1169 * have been verified, so we can't assume it's properly formed.
1170 */
1171 while (*sig != '\0' && *sig != ')') {
1172 if (actualArgs >= expectedArgs) {
1173 LOG_VFY("VFY: expected %d args, found more (%c)\n",
1174 expectedArgs, *sig);
1175 goto bad_sig;
1176 }
1177
1178 u4 getReg;
1179 if (isRange)
1180 getReg = pDecInsn->vC + actualArgs;
1181 else
1182 getReg = pDecInsn->arg[actualArgs];
1183
1184 switch (*sig) {
1185 case 'L':
1186 {
Andy McFadden62a75162009-04-17 17:23:37 -07001187 ClassObject* clazz = lookupSignatureClass(meth, &sig, pFailure);
1188 if (!VERIFY_OK(*pFailure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001189 goto bad_sig;
1190 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001191 regTypeFromClass(clazz), pFailure);
1192 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001193 LOG_VFY("VFY: bad arg %d (into %s)\n",
1194 actualArgs, clazz->descriptor);
1195 goto bad_sig;
1196 }
1197 }
1198 actualArgs++;
1199 break;
1200 case '[':
1201 {
1202 ClassObject* clazz =
Andy McFadden62a75162009-04-17 17:23:37 -07001203 lookupSignatureArrayClass(meth, &sig, pFailure);
1204 if (!VERIFY_OK(*pFailure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001205 goto bad_sig;
1206 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001207 regTypeFromClass(clazz), pFailure);
1208 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001209 LOG_VFY("VFY: bad arg %d (into %s)\n",
1210 actualArgs, clazz->descriptor);
1211 goto bad_sig;
1212 }
1213 }
1214 actualArgs++;
1215 break;
1216 case 'Z':
1217 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001218 kRegTypeBoolean, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001219 actualArgs++;
1220 break;
1221 case 'C':
1222 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001223 kRegTypeChar, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001224 actualArgs++;
1225 break;
1226 case 'B':
1227 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001228 kRegTypeByte, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001229 actualArgs++;
1230 break;
1231 case 'I':
1232 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001233 kRegTypeInteger, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001234 actualArgs++;
1235 break;
1236 case 'S':
1237 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001238 kRegTypeShort, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001239 actualArgs++;
1240 break;
1241 case 'F':
1242 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001243 kRegTypeFloat, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001244 actualArgs++;
1245 break;
1246 case 'D':
1247 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001248 kRegTypeDoubleLo, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001249 actualArgs += 2;
1250 break;
1251 case 'J':
1252 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001253 kRegTypeLongLo, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001254 actualArgs += 2;
1255 break;
1256 default:
1257 LOG_VFY("VFY: invocation target: bad signature type char '%c'\n",
1258 *sig);
1259 goto bad_sig;
1260 }
1261
1262 sig++;
1263 }
1264 if (*sig != ')') {
1265 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1266 LOG_VFY("VFY: invocation target: bad signature '%s'\n", desc);
1267 free(desc);
1268 goto bad_sig;
1269 }
1270
1271 if (actualArgs != expectedArgs) {
1272 LOG_VFY("VFY: expected %d args, found %d\n", expectedArgs, actualArgs);
1273 goto bad_sig;
1274 }
1275
1276 free(sigOriginal);
1277 return resMethod;
1278
1279bad_sig:
1280 if (resMethod != NULL) {
1281 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1282 LOG_VFY("VFY: rejecting call to %s.%s %s\n",
Andy McFadden62a75162009-04-17 17:23:37 -07001283 resMethod->clazz->descriptor, resMethod->name, desc);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001284 free(desc);
1285 }
1286
1287fail:
1288 free(sigOriginal);
Andy McFadden62a75162009-04-17 17:23:37 -07001289 if (*pFailure == VERIFY_ERROR_NONE)
1290 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001291 return NULL;
1292}
1293
1294/*
1295 * Get the class object for the type of data stored in a field. This isn't
1296 * stored in the Field struct, so we have to recover it from the signature.
1297 *
1298 * This only works for reference types. Don't call this for primitive types.
1299 *
1300 * If we can't find the class, we return java.lang.Object, so that
1301 * verification can continue if a field is only accessed in trivial ways.
1302 */
1303static ClassObject* getFieldClass(const Method* meth, const Field* field)
1304{
1305 ClassObject* fieldClass;
1306 const char* signature = field->signature;
1307
1308 if ((*signature == 'L') || (*signature == '[')) {
1309 fieldClass = dvmFindClassNoInit(signature,
1310 meth->clazz->classLoader);
1311 } else {
1312 return NULL;
1313 }
1314
1315 if (fieldClass == NULL) {
1316 dvmClearOptException(dvmThreadSelf());
1317 LOGV("VFY: unable to find class '%s' for field %s.%s, trying Object\n",
1318 field->signature, meth->clazz->descriptor, field->name);
1319 fieldClass = gDvm.classJavaLangObject;
1320 } else {
1321 assert(!dvmIsPrimitiveClass(fieldClass));
1322 }
1323 return fieldClass;
1324}
1325
1326
1327/*
1328 * ===========================================================================
1329 * Register operations
1330 * ===========================================================================
1331 */
1332
1333/*
1334 * Get the type of register N, verifying that the register is valid.
1335 *
Andy McFadden62a75162009-04-17 17:23:37 -07001336 * Sets "*pFailure" appropriately if the register number is out of range.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001337 */
1338static inline RegType getRegisterType(const RegType* insnRegs,
Andy McFadden62a75162009-04-17 17:23:37 -07001339 const int insnRegCount, u4 vsrc, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001340{
1341 RegType type;
1342
1343 if (vsrc >= (u4) insnRegCount) {
Andy McFadden62a75162009-04-17 17:23:37 -07001344 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001345 return kRegTypeUnknown;
1346 } else {
1347 return insnRegs[vsrc];
1348 }
1349}
1350
1351/*
1352 * Get the value from a register, and cast it to a ClassObject. Sets
Andy McFadden62a75162009-04-17 17:23:37 -07001353 * "*pFailure" if something fails.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001354 *
1355 * This fails if the register holds an uninitialized class.
1356 *
1357 * If the register holds kRegTypeZero, this returns a NULL pointer.
1358 */
1359static ClassObject* getClassFromRegister(const RegType* insnRegs,
Andy McFadden62a75162009-04-17 17:23:37 -07001360 const int insnRegCount, u4 vsrc, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001361{
1362 ClassObject* clazz = NULL;
1363 RegType type;
1364
1365 /* get the element type of the array held in vsrc */
Andy McFadden62a75162009-04-17 17:23:37 -07001366 type = getRegisterType(insnRegs, insnRegCount, vsrc, pFailure);
1367 if (!VERIFY_OK(*pFailure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001368 goto bail;
1369
1370 /* if "always zero", we allow it to fail at runtime */
1371 if (type == kRegTypeZero)
1372 goto bail;
1373
1374 if (!regTypeIsReference(type)) {
1375 LOG_VFY("VFY: tried to get class from non-ref register v%d (type=%d)\n",
1376 vsrc, type);
Andy McFadden62a75162009-04-17 17:23:37 -07001377 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001378 goto bail;
1379 }
1380 if (regTypeIsUninitReference(type)) {
1381 LOG_VFY("VFY: register %u holds uninitialized reference\n", vsrc);
Andy McFadden62a75162009-04-17 17:23:37 -07001382 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001383 goto bail;
1384 }
1385
1386 clazz = regTypeInitializedReferenceToClass(type);
1387
1388bail:
1389 return clazz;
1390}
1391
1392/*
1393 * Get the "this" pointer from a non-static method invocation. This
1394 * returns the RegType so the caller can decide whether it needs the
1395 * reference to be initialized or not. (Can also return kRegTypeZero
1396 * if the reference can only be zero at this point.)
1397 *
1398 * The argument count is in vA, and the first argument is in vC, for both
1399 * "simple" and "range" versions. We just need to make sure vA is >= 1
1400 * and then return vC.
1401 */
1402static RegType getInvocationThis(const RegType* insnRegs,
Andy McFadden62a75162009-04-17 17:23:37 -07001403 const int insnRegCount, const DecodedInstruction* pDecInsn,
1404 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001405{
1406 RegType thisType = kRegTypeUnknown;
1407
1408 if (pDecInsn->vA < 1) {
1409 LOG_VFY("VFY: invoke lacks 'this'\n");
Andy McFadden62a75162009-04-17 17:23:37 -07001410 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001411 goto bail;
1412 }
1413
1414 /* get the element type of the array held in vsrc */
Andy McFadden62a75162009-04-17 17:23:37 -07001415 thisType = getRegisterType(insnRegs, insnRegCount, pDecInsn->vC, pFailure);
1416 if (!VERIFY_OK(*pFailure)) {
1417 LOG_VFY("VFY: failed to get 'this' from register %u\n", pDecInsn->vC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001418 goto bail;
1419 }
1420
1421 if (!regTypeIsReference(thisType)) {
1422 LOG_VFY("VFY: tried to get class from non-ref register v%d (type=%d)\n",
1423 pDecInsn->vC, thisType);
Andy McFadden62a75162009-04-17 17:23:37 -07001424 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001425 goto bail;
1426 }
1427
1428bail:
1429 return thisType;
1430}
1431
1432/*
1433 * Set the type of register N, verifying that the register is valid. If
1434 * "newType" is the "Lo" part of a 64-bit value, register N+1 will be
1435 * set to "newType+1".
1436 *
Andy McFadden62a75162009-04-17 17:23:37 -07001437 * Sets "*pFailure" if the register number is out of range.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001438 */
1439static void setRegisterType(RegType* insnRegs, const int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001440 u4 vdst, RegType newType, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001441{
1442 //LOGD("set-reg v%u = %d\n", vdst, newType);
1443 switch (newType) {
1444 case kRegTypeUnknown:
1445 case kRegTypeBoolean:
1446 case kRegTypeOne:
1447 case kRegTypeByte:
1448 case kRegTypePosByte:
1449 case kRegTypeShort:
1450 case kRegTypePosShort:
1451 case kRegTypeChar:
1452 case kRegTypeInteger:
1453 case kRegTypeFloat:
1454 case kRegTypeZero:
1455 if (vdst >= (u4) insnRegCount) {
Andy McFadden62a75162009-04-17 17:23:37 -07001456 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001457 } else {
1458 insnRegs[vdst] = newType;
1459 }
1460 break;
1461 case kRegTypeLongLo:
1462 case kRegTypeDoubleLo:
1463 if (vdst+1 >= (u4) insnRegCount) {
Andy McFadden62a75162009-04-17 17:23:37 -07001464 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001465 } else {
1466 insnRegs[vdst] = newType;
1467 insnRegs[vdst+1] = newType+1;
1468 }
1469 break;
1470 case kRegTypeLongHi:
1471 case kRegTypeDoubleHi:
1472 /* should never set these explicitly */
Andy McFadden62a75162009-04-17 17:23:37 -07001473 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001474 break;
1475
1476 case kRegTypeUninit:
1477 default:
1478 if (regTypeIsReference(newType)) {
1479 if (vdst >= (u4) insnRegCount) {
Andy McFadden62a75162009-04-17 17:23:37 -07001480 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001481 break;
1482 }
1483 insnRegs[vdst] = newType;
1484
1485 /*
1486 * In most circumstances we won't see a reference to a primitive
1487 * class here (e.g. "D"), since that would mean the object in the
1488 * register is actually a primitive type. It can happen as the
1489 * result of an assumed-successful check-cast instruction in
1490 * which the second argument refers to a primitive class. (In
1491 * practice, such an instruction will always throw an exception.)
1492 *
1493 * This is not an issue for instructions like const-class, where
1494 * the object in the register is a java.lang.Class instance.
1495 */
1496 break;
1497 }
1498 /* bad - fall through */
1499
1500 case kRegTypeConflict: // should only be set during a merge
1501 LOG_VFY("Unexpected set type %d\n", newType);
1502 assert(false);
Andy McFadden62a75162009-04-17 17:23:37 -07001503 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001504 break;
1505 }
1506}
1507
1508/*
1509 * Verify that the contents of the specified register have the specified
1510 * type (or can be converted to it through an implicit widening conversion).
1511 *
1512 * In theory we could use this to modify the type of the source register,
1513 * e.g. a generic 32-bit constant, once used as a float, would thereafter
1514 * remain a float. There is no compelling reason to require this though.
1515 *
1516 * If "vsrc" is a reference, both it and the "vsrc" register must be
1517 * initialized ("vsrc" may be Zero). This will verify that the value in
1518 * the register is an instance of checkType, or if checkType is an
1519 * interface, verify that the register implements checkType.
1520 */
1521static void verifyRegisterType(const RegType* insnRegs, const int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001522 u4 vsrc, RegType checkType, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001523{
1524 if (vsrc >= (u4) insnRegCount) {
Andy McFadden62a75162009-04-17 17:23:37 -07001525 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001526 return;
1527 }
1528
1529 RegType srcType = insnRegs[vsrc];
1530
1531 //LOGD("check-reg v%u = %d\n", vsrc, checkType);
1532 switch (checkType) {
1533 case kRegTypeFloat:
1534 case kRegTypeBoolean:
1535 case kRegTypePosByte:
1536 case kRegTypeByte:
1537 case kRegTypePosShort:
1538 case kRegTypeShort:
1539 case kRegTypeChar:
1540 case kRegTypeInteger:
1541 if (!canConvertTo1nr(srcType, checkType)) {
1542 LOG_VFY("VFY: register1 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 case kRegTypeLongLo:
1548 case kRegTypeDoubleLo:
1549 if (vsrc+1 >= (u4) insnRegCount) {
1550 LOG_VFY("VFY: register2 v%u out of range (%d)\n",
1551 vsrc, insnRegCount);
Andy McFadden62a75162009-04-17 17:23:37 -07001552 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001553 } else if (insnRegs[vsrc+1] != srcType+1) {
1554 LOG_VFY("VFY: register2 v%u-%u values %d,%d\n",
1555 vsrc, vsrc+1, insnRegs[vsrc], insnRegs[vsrc+1]);
Andy McFadden62a75162009-04-17 17:23:37 -07001556 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001557 } else if (!canConvertTo2(srcType, checkType)) {
1558 LOG_VFY("VFY: register2 v%u type %d, wanted %d\n",
1559 vsrc, srcType, checkType);
Andy McFadden62a75162009-04-17 17:23:37 -07001560 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001561 }
1562 break;
1563
1564 case kRegTypeLongHi:
1565 case kRegTypeDoubleHi:
1566 case kRegTypeZero:
1567 case kRegTypeOne:
1568 case kRegTypeUnknown:
1569 case kRegTypeConflict:
1570 /* should never be checking for these explicitly */
1571 assert(false);
Andy McFadden62a75162009-04-17 17:23:37 -07001572 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001573 return;
1574 case kRegTypeUninit:
1575 default:
1576 /* make sure checkType is initialized reference */
1577 if (!regTypeIsReference(checkType)) {
1578 LOG_VFY("VFY: unexpected check type %d\n", checkType);
1579 assert(false);
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 (regTypeIsUninitReference(checkType)) {
1584 LOG_VFY("VFY: uninitialized ref not expected as reg check\n");
Andy McFadden62a75162009-04-17 17:23:37 -07001585 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001586 break;
1587 }
1588 /* make sure srcType is initialized reference or always-NULL */
1589 if (!regTypeIsReference(srcType)) {
1590 LOG_VFY("VFY: register1 v%u type %d, wanted ref\n", vsrc, srcType);
Andy McFadden62a75162009-04-17 17:23:37 -07001591 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001592 break;
1593 }
1594 if (regTypeIsUninitReference(srcType)) {
1595 LOG_VFY("VFY: register1 v%u holds uninitialized ref\n", vsrc);
Andy McFadden62a75162009-04-17 17:23:37 -07001596 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001597 break;
1598 }
1599 /* if the register isn't Zero, make sure it's an instance of check */
1600 if (srcType != kRegTypeZero) {
1601 ClassObject* srcClass = regTypeInitializedReferenceToClass(srcType);
1602 ClassObject* checkClass = regTypeInitializedReferenceToClass(checkType);
1603 assert(srcClass != NULL);
1604 assert(checkClass != NULL);
1605
1606 if (dvmIsInterfaceClass(checkClass)) {
1607 /*
1608 * All objects implement all interfaces as far as the
1609 * verifier is concerned. The runtime has to sort it out.
1610 * See comments above findCommonSuperclass.
1611 */
1612 /*
1613 if (srcClass != checkClass &&
1614 !dvmImplements(srcClass, checkClass))
1615 {
1616 LOG_VFY("VFY: %s does not implement %s\n",
1617 srcClass->descriptor, checkClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07001618 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001619 }
1620 */
1621 } else {
1622 if (!dvmInstanceof(srcClass, checkClass)) {
1623 LOG_VFY("VFY: %s is not instance of %s\n",
1624 srcClass->descriptor, checkClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07001625 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001626 }
1627 }
1628 }
1629 break;
1630 }
1631}
1632
1633/*
1634 * Set the type of the "result" register. Mostly this exists to expand
1635 * "insnRegCount" to encompass the result register.
1636 */
1637static void setResultRegisterType(RegType* insnRegs, const int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001638 RegType newType, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001639{
1640 setRegisterType(insnRegs, insnRegCount + kExtraRegs,
Andy McFadden62a75162009-04-17 17:23:37 -07001641 RESULT_REGISTER(insnRegCount), newType, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001642}
1643
1644
1645/*
1646 * Update all registers holding "uninitType" to instead hold the
1647 * corresponding initialized reference type. This is called when an
1648 * appropriate <init> method is invoked -- all copies of the reference
1649 * must be marked as initialized.
1650 */
1651static void markRefsAsInitialized(RegType* insnRegs, int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001652 UninitInstanceMap* uninitMap, RegType uninitType, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001653{
1654 ClassObject* clazz;
1655 RegType initType;
1656 int i, changed;
1657
1658 clazz = dvmGetUninitInstance(uninitMap, regTypeToUninitIndex(uninitType));
1659 if (clazz == NULL) {
1660 LOGE("VFY: unable to find type=0x%x (idx=%d)\n",
1661 uninitType, regTypeToUninitIndex(uninitType));
Andy McFadden62a75162009-04-17 17:23:37 -07001662 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001663 return;
1664 }
1665 initType = regTypeFromClass(clazz);
1666
1667 changed = 0;
1668 for (i = 0; i < insnRegCount; i++) {
1669 if (insnRegs[i] == uninitType) {
1670 insnRegs[i] = initType;
1671 changed++;
1672 }
1673 }
1674 //LOGD("VFY: marked %d registers as initialized\n", changed);
1675 assert(changed > 0);
1676
1677 return;
1678}
1679
1680/*
1681 * We're creating a new instance of class C at address A. Any registers
1682 * holding instances previously created at address A must be initialized
1683 * by now. If not, we mark them as "conflict" to prevent them from being
1684 * used (otherwise, markRefsAsInitialized would mark the old ones and the
1685 * new ones at the same time).
1686 */
1687static void markUninitRefsAsInvalid(RegType* insnRegs, int insnRegCount,
1688 UninitInstanceMap* uninitMap, RegType uninitType)
1689{
1690 int i, changed;
1691
1692 changed = 0;
1693 for (i = 0; i < insnRegCount; i++) {
1694 if (insnRegs[i] == uninitType) {
1695 insnRegs[i] = kRegTypeConflict;
1696 changed++;
1697 }
1698 }
1699
1700 //if (changed)
1701 // LOGD("VFY: marked %d uninitialized registers as invalid\n", changed);
1702}
1703
1704/*
1705 * Find the start of the register set for the specified instruction in
1706 * the current method.
1707 */
1708static inline RegType* getRegisterLine(const RegisterTable* regTable,
1709 int insnIdx)
1710{
1711 return regTable->addrRegs[insnIdx];
1712}
1713
1714/*
1715 * Copy a bunch of registers.
1716 */
1717static inline void copyRegisters(RegType* dst, const RegType* src,
1718 int numRegs)
1719{
1720 memcpy(dst, src, numRegs * sizeof(RegType));
1721}
1722
1723/*
1724 * Compare a bunch of registers.
1725 *
1726 * Returns 0 if they match. Using this for a sort is unwise, since the
1727 * value can change based on machine endianness.
1728 */
1729static inline int compareRegisters(const RegType* src1, const RegType* src2,
1730 int numRegs)
1731{
1732 return memcmp(src1, src2, numRegs * sizeof(RegType));
1733}
1734
1735/*
1736 * Register type categories, for type checking.
1737 *
1738 * The spec says category 1 includes boolean, byte, char, short, int, float,
1739 * reference, and returnAddress. Category 2 includes long and double.
1740 *
1741 * We treat object references separately, so we have "category1nr". We
1742 * don't support jsr/ret, so there is no "returnAddress" type.
1743 */
1744typedef enum TypeCategory {
1745 kTypeCategoryUnknown = 0,
1746 kTypeCategory1nr, // byte, char, int, float, boolean
1747 kTypeCategory2, // long, double
1748 kTypeCategoryRef, // object reference
1749} TypeCategory;
1750
1751/*
1752 * See if "type" matches "cat". All we're really looking for here is that
1753 * we're not mixing and matching 32-bit and 64-bit quantities, and we're
1754 * not mixing references with numerics. (For example, the arguments to
1755 * "a < b" could be integers of different sizes, but they must both be
1756 * integers. Dalvik is less specific about int vs. float, so we treat them
1757 * as equivalent here.)
1758 *
1759 * For category 2 values, "type" must be the "low" half of the value.
1760 *
Andy McFadden62a75162009-04-17 17:23:37 -07001761 * Sets "*pFailure" if something looks wrong.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001762 */
Andy McFadden62a75162009-04-17 17:23:37 -07001763static void checkTypeCategory(RegType type, TypeCategory cat,
1764 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001765{
1766 switch (cat) {
1767 case kTypeCategory1nr:
1768 switch (type) {
1769 case kRegTypeFloat:
1770 case kRegTypeZero:
1771 case kRegTypeOne:
1772 case kRegTypeBoolean:
1773 case kRegTypePosByte:
1774 case kRegTypeByte:
1775 case kRegTypePosShort:
1776 case kRegTypeShort:
1777 case kRegTypeChar:
1778 case kRegTypeInteger:
1779 break;
1780 default:
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 break;
1785
1786 case kTypeCategory2:
1787 switch (type) {
1788 case kRegTypeLongLo:
1789 case kRegTypeDoubleLo:
1790 break;
1791 default:
Andy McFadden62a75162009-04-17 17:23:37 -07001792 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001793 break;
1794 }
1795 break;
1796
1797 case kTypeCategoryRef:
1798 if (type != kRegTypeZero && !regTypeIsReference(type))
Andy McFadden62a75162009-04-17 17:23:37 -07001799 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001800 break;
1801
1802 default:
1803 assert(false);
Andy McFadden62a75162009-04-17 17:23:37 -07001804 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001805 break;
1806 }
1807}
1808
1809/*
1810 * For a category 2 register pair, verify that "typeh" is the appropriate
1811 * high part for "typel".
1812 *
1813 * Does not verify that "typel" is in fact the low part of a 64-bit
1814 * register pair.
1815 */
Andy McFadden62a75162009-04-17 17:23:37 -07001816static void checkWidePair(RegType typel, RegType typeh, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001817{
1818 if ((typeh != typel+1))
Andy McFadden62a75162009-04-17 17:23:37 -07001819 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001820}
1821
1822/*
1823 * Implement category-1 "move" instructions. Copy a 32-bit value from
1824 * "vsrc" to "vdst".
1825 *
1826 * "insnRegCount" is the number of registers available. The "vdst" and
1827 * "vsrc" values are checked against this.
1828 */
1829static void copyRegister1(RegType* insnRegs, int insnRegCount, u4 vdst,
Andy McFadden62a75162009-04-17 17:23:37 -07001830 u4 vsrc, TypeCategory cat, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001831{
Andy McFadden62a75162009-04-17 17:23:37 -07001832 RegType type = getRegisterType(insnRegs, insnRegCount, vsrc, pFailure);
1833 if (VERIFY_OK(*pFailure))
1834 checkTypeCategory(type, cat, pFailure);
1835 if (VERIFY_OK(*pFailure))
1836 setRegisterType(insnRegs, insnRegCount, vdst, type, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001837
Andy McFadden62a75162009-04-17 17:23:37 -07001838 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001839 LOG_VFY("VFY: copy1 v%u<-v%u type=%d cat=%d\n", vdst, vsrc, type, cat);
1840 }
1841}
1842
1843/*
1844 * Implement category-2 "move" instructions. Copy a 64-bit value from
1845 * "vsrc" to "vdst". This copies both halves of the register.
1846 */
1847static void copyRegister2(RegType* insnRegs, int insnRegCount, u4 vdst,
Andy McFadden62a75162009-04-17 17:23:37 -07001848 u4 vsrc, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001849{
Andy McFadden62a75162009-04-17 17:23:37 -07001850 RegType typel = getRegisterType(insnRegs, insnRegCount, vsrc, pFailure);
1851 RegType typeh = getRegisterType(insnRegs, insnRegCount, vsrc+1, pFailure);
1852 if (VERIFY_OK(*pFailure)) {
1853 checkTypeCategory(typel, kTypeCategory2, pFailure);
1854 checkWidePair(typel, typeh, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001855 }
Andy McFadden62a75162009-04-17 17:23:37 -07001856 if (VERIFY_OK(*pFailure))
1857 setRegisterType(insnRegs, insnRegCount, vdst, typel, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001858
Andy McFadden62a75162009-04-17 17:23:37 -07001859 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001860 LOG_VFY("VFY: copy2 v%u<-v%u type=%d/%d\n", vdst, vsrc, typel, typeh);
1861 }
1862}
1863
1864/*
1865 * Implement "move-result". Copy the category-1 value from the result
1866 * register to another register, and reset the result register.
1867 *
1868 * We can't just call copyRegister1 with an altered insnRegCount,
1869 * because that would affect the test on "vdst" as well.
1870 */
1871static void copyResultRegister1(RegType* insnRegs, const int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001872 u4 vdst, TypeCategory cat, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001873{
1874 RegType type;
1875 u4 vsrc;
1876
1877 vsrc = RESULT_REGISTER(insnRegCount);
Andy McFadden62a75162009-04-17 17:23:37 -07001878 type = getRegisterType(insnRegs, insnRegCount + kExtraRegs, vsrc, pFailure);
1879 if (VERIFY_OK(*pFailure))
1880 checkTypeCategory(type, cat, pFailure);
1881 if (VERIFY_OK(*pFailure)) {
1882 setRegisterType(insnRegs, insnRegCount, vdst, type, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001883 insnRegs[vsrc] = kRegTypeUnknown;
1884 }
1885
Andy McFadden62a75162009-04-17 17:23:37 -07001886 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001887 LOG_VFY("VFY: copyRes1 v%u<-v%u cat=%d type=%d\n",
1888 vdst, vsrc, cat, type);
1889 }
1890}
1891
1892/*
1893 * Implement "move-result-wide". Copy the category-2 value from the result
1894 * register to another register, and reset the result register.
1895 *
1896 * We can't just call copyRegister2 with an altered insnRegCount,
1897 * because that would affect the test on "vdst" as well.
1898 */
1899static void copyResultRegister2(RegType* insnRegs, const int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001900 u4 vdst, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001901{
1902 RegType typel, typeh;
1903 u4 vsrc;
1904
1905 vsrc = RESULT_REGISTER(insnRegCount);
Andy McFadden62a75162009-04-17 17:23:37 -07001906 typel = getRegisterType(insnRegs, insnRegCount + kExtraRegs, vsrc,
1907 pFailure);
1908 typeh = getRegisterType(insnRegs, insnRegCount + kExtraRegs, vsrc+1,
1909 pFailure);
1910 if (VERIFY_OK(*pFailure)) {
1911 checkTypeCategory(typel, kTypeCategory2, pFailure);
1912 checkWidePair(typel, typeh, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001913 }
Andy McFadden62a75162009-04-17 17:23:37 -07001914 if (VERIFY_OK(*pFailure)) {
1915 setRegisterType(insnRegs, insnRegCount, vdst, typel, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001916 insnRegs[vsrc] = kRegTypeUnknown;
1917 insnRegs[vsrc+1] = kRegTypeUnknown;
1918 }
1919
Andy McFadden62a75162009-04-17 17:23:37 -07001920 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001921 LOG_VFY("VFY: copyRes2 v%u<-v%u type=%d/%d\n",
1922 vdst, vsrc, typel, typeh);
1923 }
1924}
1925
1926/*
1927 * Verify types for a simple two-register instruction (e.g. "neg-int").
1928 * "dstType" is stored into vA, and "srcType" is verified against vB.
1929 */
1930static void checkUnop(RegType* insnRegs, const int insnRegCount,
1931 DecodedInstruction* pDecInsn, RegType dstType, RegType srcType,
Andy McFadden62a75162009-04-17 17:23:37 -07001932 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001933{
Andy McFadden62a75162009-04-17 17:23:37 -07001934 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType, pFailure);
1935 setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001936}
1937
1938/*
1939 * We're performing an operation like "and-int/2addr" that can be
1940 * performed on booleans as well as integers. We get no indication of
1941 * boolean-ness, but we can infer it from the types of the arguments.
1942 *
1943 * Assumes we've already validated reg1/reg2.
1944 *
Andy McFaddenb5f64bc2009-06-10 14:11:07 -07001945 * TODO: consider generalizing this. The key principle is that the
1946 * result of a bitwise operation can only be as wide as the widest of
1947 * the operands. You can safely AND/OR/XOR two chars together and know
1948 * you still have a char, so it's reasonable for the compiler or "dx"
1949 * to skip the int-to-char instruction. (We need to do this for boolean
1950 * because there is no int-to-boolean operation.)
1951 *
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001952 * Returns true if both args are Boolean, Zero, or One.
1953 */
1954static bool upcastBooleanOp(RegType* insnRegs, const int insnRegCount,
1955 u4 reg1, u4 reg2)
1956{
1957 RegType type1, type2;
1958
1959 type1 = insnRegs[reg1];
1960 type2 = insnRegs[reg2];
1961
1962 if ((type1 == kRegTypeBoolean || type1 == kRegTypeZero ||
1963 type1 == kRegTypeOne) &&
1964 (type2 == kRegTypeBoolean || type2 == kRegTypeZero ||
1965 type2 == kRegTypeOne))
1966 {
1967 return true;
1968 }
1969 return false;
1970}
1971
1972/*
1973 * Verify types for A two-register instruction with a literal constant
1974 * (e.g. "add-int/lit8"). "dstType" is stored into vA, and "srcType" is
1975 * verified against vB.
1976 *
1977 * If "checkBooleanOp" is set, we use the constant value in vC.
1978 */
1979static void checkLitop(RegType* insnRegs, const int insnRegCount,
1980 DecodedInstruction* pDecInsn, RegType dstType, RegType srcType,
Andy McFadden62a75162009-04-17 17:23:37 -07001981 bool checkBooleanOp, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001982{
Andy McFadden62a75162009-04-17 17:23:37 -07001983 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType, pFailure);
1984 if (VERIFY_OK(*pFailure) && checkBooleanOp) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001985 assert(dstType == kRegTypeInteger);
1986 /* check vB with the call, then check the constant manually */
1987 if (upcastBooleanOp(insnRegs, insnRegCount, pDecInsn->vB, pDecInsn->vB)
1988 && (pDecInsn->vC == 0 || pDecInsn->vC == 1))
1989 {
1990 dstType = kRegTypeBoolean;
1991 }
1992 }
Andy McFadden62a75162009-04-17 17:23:37 -07001993 setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001994}
1995
1996/*
1997 * Verify types for a simple three-register instruction (e.g. "add-int").
1998 * "dstType" is stored into vA, and "srcType1"/"srcType2" are verified
1999 * against vB/vC.
2000 */
2001static void checkBinop(RegType* insnRegs, const int insnRegCount,
2002 DecodedInstruction* pDecInsn, RegType dstType, RegType srcType1,
Andy McFadden62a75162009-04-17 17:23:37 -07002003 RegType srcType2, bool checkBooleanOp, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002004{
Andy McFadden62a75162009-04-17 17:23:37 -07002005 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType1,
2006 pFailure);
2007 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vC, srcType2,
2008 pFailure);
2009 if (VERIFY_OK(*pFailure) && checkBooleanOp) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002010 assert(dstType == kRegTypeInteger);
2011 if (upcastBooleanOp(insnRegs, insnRegCount, pDecInsn->vB, pDecInsn->vC))
2012 dstType = kRegTypeBoolean;
2013 }
Andy McFadden62a75162009-04-17 17:23:37 -07002014 setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002015}
2016
2017/*
2018 * Verify types for a binary "2addr" operation. "srcType1"/"srcType2"
2019 * are verified against vA/vB, then "dstType" is stored into vA.
2020 */
2021static void checkBinop2addr(RegType* insnRegs, const int insnRegCount,
2022 DecodedInstruction* pDecInsn, RegType dstType, RegType srcType1,
Andy McFadden62a75162009-04-17 17:23:37 -07002023 RegType srcType2, bool checkBooleanOp, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002024{
Andy McFadden62a75162009-04-17 17:23:37 -07002025 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vA, srcType1,
2026 pFailure);
2027 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType2,
2028 pFailure);
2029 if (VERIFY_OK(*pFailure) && checkBooleanOp) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002030 assert(dstType == kRegTypeInteger);
2031 if (upcastBooleanOp(insnRegs, insnRegCount, pDecInsn->vA, pDecInsn->vB))
2032 dstType = kRegTypeBoolean;
2033 }
Andy McFadden62a75162009-04-17 17:23:37 -07002034 setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002035}
2036
Andy McFadden80d25ea2009-06-12 07:26:17 -07002037/*
2038 * Treat right-shifting as a narrowing conversion when possible.
2039 *
2040 * For example, right-shifting an int 24 times results in a value that can
2041 * be treated as a byte.
2042 *
2043 * Things get interesting when contemplating sign extension. Right-
2044 * shifting an integer by 16 yields a value that can be represented in a
2045 * "short" but not a "char", but an unsigned right shift by 16 yields a
2046 * value that belongs in a char rather than a short. (Consider what would
2047 * happen if the result of the shift were cast to a char or short and then
2048 * cast back to an int. If sign extension, or the lack thereof, causes
2049 * a change in the 32-bit representation, then the conversion was lossy.)
2050 *
2051 * A signed right shift by 17 on an integer results in a short. An unsigned
2052 * right shfit by 17 on an integer results in a posshort, which can be
2053 * assigned to a short or a char.
2054 *
2055 * An unsigned right shift on a short can actually expand the result into
2056 * a 32-bit integer. For example, 0xfffff123 >>> 8 becomes 0x00fffff1,
2057 * which can't be represented in anything smaller than an int.
2058 *
2059 * javac does not generate code that takes advantage of this, but some
2060 * of the code optimizers do. It's generally a peephole optimization
2061 * that replaces a particular sequence, e.g. (bipush 24, ishr, i2b) is
2062 * replaced by (bipush 24, ishr). Knowing that shifting a short 8 times
2063 * to the right yields a byte is really more than we need to handle the
2064 * code that's out there, but support is not much more complex than just
2065 * handling integer.
2066 *
2067 * Right-shifting never yields a boolean value.
2068 *
2069 * Returns the new register type.
2070 */
2071static RegType adjustForRightShift(RegType* workRegs, const int insnRegCount,
2072 int reg, unsigned int shiftCount, bool isUnsignedShift,
2073 VerifyError* pFailure)
2074{
2075 RegType srcType = getRegisterType(workRegs, insnRegCount, reg, pFailure);
2076 RegType newType;
2077
2078 /* no-op */
2079 if (shiftCount == 0)
2080 return srcType;
2081
2082 /* safe defaults */
2083 if (isUnsignedShift)
2084 newType = kRegTypeInteger;
2085 else
2086 newType = srcType;
2087
2088 if (shiftCount >= 32) {
2089 LOG_VFY("Got unexpectedly large shift count %u\n", shiftCount);
2090 /* fail? */
2091 return newType;
2092 }
2093
2094 switch (srcType) {
2095 case kRegTypeInteger: /* 32-bit signed value */
2096 case kRegTypeFloat: /* (allowed; treat same as int) */
2097 if (isUnsignedShift) {
2098 if (shiftCount > 24)
2099 newType = kRegTypePosByte;
2100 else if (shiftCount >= 16)
2101 newType = kRegTypeChar;
2102 } else {
2103 if (shiftCount >= 24)
2104 newType = kRegTypeByte;
2105 else if (shiftCount >= 16)
2106 newType = kRegTypeShort;
2107 }
2108 break;
2109 case kRegTypeShort: /* 16-bit signed value */
2110 if (isUnsignedShift) {
2111 /* default (kRegTypeInteger) is correct */
2112 } else {
2113 if (shiftCount >= 8)
2114 newType = kRegTypeByte;
2115 }
2116 break;
2117 case kRegTypePosShort: /* 15-bit unsigned value */
2118 if (shiftCount >= 8)
2119 newType = kRegTypePosByte;
2120 break;
2121 case kRegTypeChar: /* 16-bit unsigned value */
2122 if (shiftCount > 8)
2123 newType = kRegTypePosByte;
2124 break;
2125 case kRegTypeByte: /* 8-bit signed value */
2126 /* defaults (u=kRegTypeInteger / s=srcType) are correct */
2127 break;
2128 case kRegTypePosByte: /* 7-bit unsigned value */
2129 /* always use newType=srcType */
2130 newType = srcType;
2131 break;
2132 case kRegTypeZero: /* 1-bit unsigned value */
2133 case kRegTypeOne:
2134 case kRegTypeBoolean:
2135 /* unnecessary? */
2136 newType = kRegTypeZero;
2137 break;
2138 default:
2139 /* long, double, references; shouldn't be here! */
2140 assert(false);
2141 break;
2142 }
2143
2144 if (newType != srcType) {
2145 LOGVV("narrowing: %d(%d) --> %d to %d\n",
2146 shiftCount, isUnsignedShift, srcType, newType);
2147 } else {
2148 LOGVV("not narrowed: %d(%d) --> %d\n",
2149 shiftCount, isUnsignedShift, srcType);
2150 }
2151 return newType;
2152}
2153
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002154
2155/*
2156 * ===========================================================================
2157 * Register merge
2158 * ===========================================================================
2159 */
2160
2161/*
2162 * Compute the "class depth" of a class. This is the distance from the
2163 * class to the top of the tree, chasing superclass links. java.lang.Object
2164 * has a class depth of 0.
2165 */
2166static int getClassDepth(ClassObject* clazz)
2167{
2168 int depth = 0;
2169
2170 while (clazz->super != NULL) {
2171 clazz = clazz->super;
2172 depth++;
2173 }
2174 return depth;
2175}
2176
2177/*
2178 * Given two classes, walk up the superclass tree to find a common
2179 * ancestor. (Called from findCommonSuperclass().)
2180 *
2181 * TODO: consider caching the class depth in the class object so we don't
2182 * have to search for it here.
2183 */
2184static ClassObject* digForSuperclass(ClassObject* c1, ClassObject* c2)
2185{
2186 int depth1, depth2;
2187
2188 depth1 = getClassDepth(c1);
2189 depth2 = getClassDepth(c2);
2190
2191 if (gDebugVerbose) {
2192 LOGVV("COMMON: %s(%d) + %s(%d)\n",
2193 c1->descriptor, depth1, c2->descriptor, depth2);
2194 }
2195
2196 /* pull the deepest one up */
2197 if (depth1 > depth2) {
2198 while (depth1 > depth2) {
2199 c1 = c1->super;
2200 depth1--;
2201 }
2202 } else {
2203 while (depth2 > depth1) {
2204 c2 = c2->super;
2205 depth2--;
2206 }
2207 }
2208
2209 /* walk up in lock-step */
2210 while (c1 != c2) {
2211 c1 = c1->super;
2212 c2 = c2->super;
2213
2214 assert(c1 != NULL && c2 != NULL);
2215 }
2216
2217 if (gDebugVerbose) {
2218 LOGVV(" : --> %s\n", c1->descriptor);
2219 }
2220 return c1;
2221}
2222
2223/*
2224 * Merge two array classes. We can't use the general "walk up to the
2225 * superclass" merge because the superclass of an array is always Object.
2226 * We want String[] + Integer[] = Object[]. This works for higher dimensions
2227 * as well, e.g. String[][] + Integer[][] = Object[][].
2228 *
2229 * If Foo1 and Foo2 are subclasses of Foo, Foo1[] + Foo2[] = Foo[].
2230 *
2231 * If Class implements Type, Class[] + Type[] = Type[].
2232 *
2233 * If the dimensions don't match, we want to convert to an array of Object
2234 * with the least dimension, e.g. String[][] + String[][][][] = Object[][].
2235 *
2236 * This gets a little awkward because we may have to ask the VM to create
2237 * a new array type with the appropriate element and dimensions. However, we
2238 * shouldn't be doing this often.
2239 */
2240static ClassObject* findCommonArraySuperclass(ClassObject* c1, ClassObject* c2)
2241{
2242 ClassObject* arrayClass = NULL;
2243 ClassObject* commonElem;
2244 int i, numDims;
2245
2246 assert(c1->arrayDim > 0);
2247 assert(c2->arrayDim > 0);
2248
2249 if (c1->arrayDim == c2->arrayDim) {
2250 //commonElem = digForSuperclass(c1->elementClass, c2->elementClass);
2251 commonElem = findCommonSuperclass(c1->elementClass, c2->elementClass);
2252 numDims = c1->arrayDim;
2253 } else {
2254 if (c1->arrayDim < c2->arrayDim)
2255 numDims = c1->arrayDim;
2256 else
2257 numDims = c2->arrayDim;
2258 commonElem = c1->super; // == java.lang.Object
2259 }
2260
2261 /* walk from the element to the (multi-)dimensioned array type */
2262 for (i = 0; i < numDims; i++) {
2263 arrayClass = dvmFindArrayClassForElement(commonElem);
2264 commonElem = arrayClass;
2265 }
2266
2267 LOGVV("ArrayMerge '%s' + '%s' --> '%s'\n",
2268 c1->descriptor, c2->descriptor, arrayClass->descriptor);
2269 return arrayClass;
2270}
2271
2272/*
2273 * Find the first common superclass of the two classes. We're not
2274 * interested in common interfaces.
2275 *
2276 * The easiest way to do this for concrete classes is to compute the "class
2277 * depth" of each, move up toward the root of the deepest one until they're
2278 * at the same depth, then walk both up to the root until they match.
2279 *
2280 * If both classes are arrays of non-primitive types, we need to merge
2281 * based on array depth and element type.
2282 *
2283 * If one class is an interface, we check to see if the other class/interface
2284 * (or one of its predecessors) implements the interface. If so, we return
2285 * the interface; otherwise, we return Object.
2286 *
2287 * NOTE: we continue the tradition of "lazy interface handling". To wit,
2288 * suppose we have three classes:
2289 * One implements Fancy, Free
2290 * Two implements Fancy, Free
2291 * Three implements Free
2292 * where Fancy and Free are unrelated interfaces. The code requires us
2293 * to merge One into Two. Ideally we'd use a common interface, which
2294 * gives us a choice between Fancy and Free, and no guidance on which to
2295 * use. If we use Free, we'll be okay when Three gets merged in, but if
2296 * we choose Fancy, we're hosed. The "ideal" solution is to create a
2297 * set of common interfaces and carry that around, merging further references
2298 * into it. This is a pain. The easy solution is to simply boil them
2299 * down to Objects and let the runtime invokeinterface call fail, which
2300 * is what we do.
2301 */
2302static ClassObject* findCommonSuperclass(ClassObject* c1, ClassObject* c2)
2303{
2304 assert(!dvmIsPrimitiveClass(c1) && !dvmIsPrimitiveClass(c2));
2305
2306 if (c1 == c2)
2307 return c1;
2308
2309 if (dvmIsInterfaceClass(c1) && dvmImplements(c2, c1)) {
2310 if (gDebugVerbose)
2311 LOGVV("COMMON/I1: %s + %s --> %s\n",
2312 c1->descriptor, c2->descriptor, c1->descriptor);
2313 return c1;
2314 }
2315 if (dvmIsInterfaceClass(c2) && dvmImplements(c1, c2)) {
2316 if (gDebugVerbose)
2317 LOGVV("COMMON/I2: %s + %s --> %s\n",
2318 c1->descriptor, c2->descriptor, c2->descriptor);
2319 return c2;
2320 }
2321
2322 if (dvmIsArrayClass(c1) && dvmIsArrayClass(c2) &&
2323 !dvmIsPrimitiveClass(c1->elementClass) &&
2324 !dvmIsPrimitiveClass(c2->elementClass))
2325 {
2326 return findCommonArraySuperclass(c1, c2);
2327 }
2328
2329 return digForSuperclass(c1, c2);
2330}
2331
2332/*
2333 * Merge two RegType values.
2334 *
2335 * Sets "*pChanged" to "true" if the result doesn't match "type1".
2336 */
2337static RegType mergeTypes(RegType type1, RegType type2, bool* pChanged)
2338{
2339 RegType result;
2340
2341 /*
2342 * Check for trivial case so we don't have to hit memory.
2343 */
2344 if (type1 == type2)
2345 return type1;
2346
2347 /*
2348 * Use the table if we can, and reject any attempts to merge something
2349 * from the table with a reference type.
2350 *
2351 * The uninitialized table entry at index zero *will* show up as a
2352 * simple kRegTypeUninit value. Since this cannot be merged with
2353 * anything but itself, the rules do the right thing.
2354 */
2355 if (type1 < kRegTypeMAX) {
2356 if (type2 < kRegTypeMAX) {
2357 result = gDvmMergeTab[type1][type2];
2358 } else {
2359 /* simple + reference == conflict, usually */
2360 if (type1 == kRegTypeZero)
2361 result = type2;
2362 else
2363 result = kRegTypeConflict;
2364 }
2365 } else {
2366 if (type2 < kRegTypeMAX) {
2367 /* reference + simple == conflict, usually */
2368 if (type2 == kRegTypeZero)
2369 result = type1;
2370 else
2371 result = kRegTypeConflict;
2372 } else {
2373 /* merging two references */
2374 if (regTypeIsUninitReference(type1) ||
2375 regTypeIsUninitReference(type2))
2376 {
2377 /* can't merge uninit with anything but self */
2378 result = kRegTypeConflict;
2379 } else {
2380 ClassObject* clazz1 = regTypeInitializedReferenceToClass(type1);
2381 ClassObject* clazz2 = regTypeInitializedReferenceToClass(type2);
2382 ClassObject* mergedClass;
2383
2384 mergedClass = findCommonSuperclass(clazz1, clazz2);
2385 assert(mergedClass != NULL);
2386 result = regTypeFromClass(mergedClass);
2387 }
2388 }
2389 }
2390
2391 if (result != type1)
2392 *pChanged = true;
2393 return result;
2394}
2395
2396/*
2397 * Control can transfer to "nextInsn".
2398 *
2399 * Merge the registers from "workRegs" into "regTypes" at "nextInsn", and
2400 * set the "changed" flag on the target address if the registers have changed.
2401 */
2402static void updateRegisters(const Method* meth, InsnFlags* insnFlags,
2403 RegisterTable* regTable, int nextInsn, const RegType* workRegs)
2404{
2405 RegType* targetRegs = getRegisterLine(regTable, nextInsn);
2406 const int insnRegCount = meth->registersSize;
2407
2408#if 0
2409 if (!dvmInsnIsBranchTarget(insnFlags, nextInsn)) {
2410 LOGE("insnFlags[0x%x]=0x%08x\n", nextInsn, insnFlags[nextInsn]);
2411 LOGE(" In %s.%s %s\n",
2412 meth->clazz->descriptor, meth->name, meth->descriptor);
2413 assert(false);
2414 }
2415#endif
2416
2417 if (!dvmInsnIsVisitedOrChanged(insnFlags, nextInsn)) {
2418 /*
2419 * We haven't processed this instruction before, and we haven't
2420 * touched the registers here, so there's nothing to "merge". Copy
2421 * the registers over and mark it as changed. (This is the only
2422 * way a register can transition out of "unknown", so this is not
2423 * just an optimization.)
2424 */
2425 LOGVV("COPY into 0x%04x\n", nextInsn);
2426 copyRegisters(targetRegs, workRegs, insnRegCount + kExtraRegs);
2427 dvmInsnSetChanged(insnFlags, nextInsn, true);
2428 } else {
2429 if (gDebugVerbose) {
2430 LOGVV("MERGE into 0x%04x\n", nextInsn);
2431 //dumpRegTypes(meth, insnFlags, targetRegs, 0, "targ", NULL, 0);
2432 //dumpRegTypes(meth, insnFlags, workRegs, 0, "work", NULL, 0);
2433 }
2434 /* merge registers, set Changed only if different */
2435 bool changed = false;
2436 int i;
2437
2438 for (i = 0; i < insnRegCount + kExtraRegs; i++) {
2439 targetRegs[i] = mergeTypes(targetRegs[i], workRegs[i], &changed);
2440 }
2441
2442 if (gDebugVerbose) {
2443 //LOGI(" RESULT (changed=%d)\n", changed);
2444 //dumpRegTypes(meth, insnFlags, targetRegs, 0, "rslt", NULL, 0);
2445 }
2446
2447 if (changed)
2448 dvmInsnSetChanged(insnFlags, nextInsn, true);
2449 }
2450}
2451
2452
2453/*
2454 * ===========================================================================
2455 * Utility functions
2456 * ===========================================================================
2457 */
2458
2459/*
2460 * Look up an instance field, specified by "fieldIdx", that is going to be
2461 * accessed in object "objType". This resolves the field and then verifies
2462 * that the class containing the field is an instance of the reference in
2463 * "objType".
2464 *
2465 * It is possible for "objType" to be kRegTypeZero, meaning that we might
2466 * have a null reference. This is a runtime problem, so we allow it,
2467 * skipping some of the type checks.
2468 *
2469 * In general, "objType" must be an initialized reference. However, we
2470 * allow it to be uninitialized if this is an "<init>" method and the field
2471 * is declared within the "objType" class.
2472 *
Andy McFadden62a75162009-04-17 17:23:37 -07002473 * Returns an InstField on success, returns NULL and sets "*pFailure"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002474 * on failure.
2475 */
2476static InstField* getInstField(const Method* meth,
2477 const UninitInstanceMap* uninitMap, RegType objType, int fieldIdx,
Andy McFadden62a75162009-04-17 17:23:37 -07002478 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002479{
2480 InstField* instField = NULL;
2481 ClassObject* objClass;
2482 bool mustBeLocal = false;
2483
2484 if (!regTypeIsReference(objType)) {
Andy McFadden62a75162009-04-17 17:23:37 -07002485 LOG_VFY("VFY: attempt to access field in non-reference type %d\n",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002486 objType);
Andy McFadden62a75162009-04-17 17:23:37 -07002487 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002488 goto bail;
2489 }
2490
Andy McFadden62a75162009-04-17 17:23:37 -07002491 instField = dvmOptResolveInstField(meth->clazz, fieldIdx, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002492 if (instField == NULL) {
2493 LOG_VFY("VFY: unable to resolve instance field %u\n", fieldIdx);
Andy McFadden62a75162009-04-17 17:23:37 -07002494 assert(!VERIFY_OK(*pFailure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002495 goto bail;
2496 }
2497
2498 if (objType == kRegTypeZero)
2499 goto bail;
2500
2501 /*
2502 * Access to fields in uninitialized objects is allowed if this is
2503 * the <init> method for the object and the field in question is
2504 * declared by this class.
2505 */
2506 objClass = regTypeReferenceToClass(objType, uninitMap);
2507 assert(objClass != NULL);
2508 if (regTypeIsUninitReference(objType)) {
2509 if (!isInitMethod(meth) || meth->clazz != objClass) {
2510 LOG_VFY("VFY: attempt to access field via uninitialized ref\n");
Andy McFadden62a75162009-04-17 17:23:37 -07002511 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002512 goto bail;
2513 }
2514 mustBeLocal = true;
2515 }
2516
2517 if (!dvmInstanceof(objClass, instField->field.clazz)) {
2518 LOG_VFY("VFY: invalid field access (field %s.%s, through %s ref)\n",
2519 instField->field.clazz->descriptor, instField->field.name,
2520 objClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07002521 *pFailure = VERIFY_ERROR_NO_FIELD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002522 goto bail;
2523 }
2524
2525 if (mustBeLocal) {
2526 /* for uninit ref, make sure it's defined by this class, not super */
2527 if (instField < objClass->ifields ||
2528 instField >= objClass->ifields + objClass->ifieldCount)
2529 {
2530 LOG_VFY("VFY: invalid constructor field access (field %s in %s)\n",
2531 instField->field.name, objClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07002532 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002533 goto bail;
2534 }
2535 }
2536
2537bail:
2538 return instField;
2539}
2540
2541/*
2542 * Look up a static field.
2543 *
Andy McFadden62a75162009-04-17 17:23:37 -07002544 * Returns a StaticField on success, returns NULL and sets "*pFailure"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002545 * on failure.
2546 */
2547static StaticField* getStaticField(const Method* meth, int fieldIdx,
Andy McFadden62a75162009-04-17 17:23:37 -07002548 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002549{
2550 StaticField* staticField;
2551
Andy McFadden62a75162009-04-17 17:23:37 -07002552 staticField = dvmOptResolveStaticField(meth->clazz, fieldIdx, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002553 if (staticField == NULL) {
2554 DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
2555 const DexFieldId* pFieldId;
2556
2557 pFieldId = dexGetFieldId(pDexFile, fieldIdx);
2558
2559 LOG_VFY("VFY: unable to resolve static field %u (%s) in %s\n", fieldIdx,
2560 dexStringById(pDexFile, pFieldId->nameIdx),
2561 dexStringByTypeIdx(pDexFile, pFieldId->classIdx));
Andy McFadden62a75162009-04-17 17:23:37 -07002562 assert(!VERIFY_OK(*pFailure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002563 goto bail;
2564 }
2565
2566bail:
2567 return staticField;
2568}
2569
2570/*
2571 * If "field" is marked "final", make sure this is the either <clinit>
2572 * or <init> as appropriate.
2573 *
Andy McFadden62a75162009-04-17 17:23:37 -07002574 * Sets "*pFailure" on failure.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002575 */
2576static void checkFinalFieldAccess(const Method* meth, const Field* field,
Andy McFadden62a75162009-04-17 17:23:37 -07002577 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002578{
2579 if (!dvmIsFinalField(field))
2580 return;
2581
2582 /* make sure we're in the same class */
2583 if (meth->clazz != field->clazz) {
2584 LOG_VFY_METH(meth, "VFY: can't modify final field %s.%s\n",
2585 field->clazz->descriptor, field->name);
Andy McFaddenb51ea112009-05-08 16:50:17 -07002586 *pFailure = VERIFY_ERROR_ACCESS_FIELD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002587 return;
2588 }
2589
2590 /*
Andy McFadden62a75162009-04-17 17:23:37 -07002591 * The VM spec descriptions of putfield and putstatic say that
2592 * IllegalAccessError is only thrown when the instructions appear
2593 * outside the declaring class. Our earlier attempts to restrict
2594 * final field modification to constructors are, therefore, wrong.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002595 */
2596#if 0
2597 /* make sure we're in the right kind of constructor */
2598 if (dvmIsStaticField(field)) {
2599 if (!isClassInitMethod(meth)) {
2600 LOG_VFY_METH(meth,
2601 "VFY: can't modify final static field outside <clinit>\n");
Andy McFadden62a75162009-04-17 17:23:37 -07002602 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002603 }
2604 } else {
2605 if (!isInitMethod(meth)) {
2606 LOG_VFY_METH(meth,
2607 "VFY: can't modify final field outside <init>\n");
Andy McFadden62a75162009-04-17 17:23:37 -07002608 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002609 }
2610 }
2611#endif
2612}
2613
2614/*
2615 * Make sure that the register type is suitable for use as an array index.
2616 *
Andy McFadden62a75162009-04-17 17:23:37 -07002617 * Sets "*pFailure" if not.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002618 */
2619static void checkArrayIndexType(const Method* meth, RegType regType,
Andy McFadden62a75162009-04-17 17:23:37 -07002620 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002621{
Andy McFadden62a75162009-04-17 17:23:37 -07002622 if (VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002623 /*
2624 * The 1nr types are interchangeable at this level. We could
2625 * do something special if we can definitively identify it as a
2626 * float, but there's no real value in doing so.
2627 */
Andy McFadden62a75162009-04-17 17:23:37 -07002628 checkTypeCategory(regType, kTypeCategory1nr, pFailure);
2629 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002630 LOG_VFY_METH(meth, "Invalid reg type for array index (%d)\n",
2631 regType);
2632 }
2633 }
2634}
2635
2636/*
2637 * Check constraints on constructor return. Specifically, make sure that
2638 * the "this" argument got initialized.
2639 *
2640 * The "this" argument to <init> uses code offset kUninitThisArgAddr, which
2641 * puts it at the start of the list in slot 0. If we see a register with
2642 * an uninitialized slot 0 reference, we know it somehow didn't get
2643 * initialized.
2644 *
2645 * Returns "true" if all is well.
2646 */
2647static bool checkConstructorReturn(const Method* meth, const RegType* insnRegs,
2648 const int insnRegCount)
2649{
2650 int i;
2651
2652 if (!isInitMethod(meth))
2653 return true;
2654
2655 RegType uninitThis = regTypeFromUninitIndex(kUninitThisArgSlot);
2656
2657 for (i = 0; i < insnRegCount; i++) {
2658 if (insnRegs[i] == uninitThis) {
2659 LOG_VFY("VFY: <init> returning without calling superclass init\n");
2660 return false;
2661 }
2662 }
2663 return true;
2664}
2665
2666/*
2667 * Verify that the target instruction is not "move-exception". It's important
2668 * that the only way to execute a move-exception is as the first instruction
2669 * of an exception handler.
2670 *
2671 * Returns "true" if all is well, "false" if the target instruction is
2672 * move-exception.
2673 */
2674static bool checkMoveException(const Method* meth, int insnIdx,
2675 const char* logNote)
2676{
2677 assert(insnIdx >= 0 && insnIdx < (int)dvmGetMethodInsnsSize(meth));
2678
2679 if ((meth->insns[insnIdx] & 0xff) == OP_MOVE_EXCEPTION) {
2680 LOG_VFY("VFY: invalid use of move-exception\n");
2681 return false;
2682 }
2683 return true;
2684}
2685
2686/*
2687 * For the "move-exception" instruction at "insnIdx", which must be at an
2688 * exception handler address, determine the first common superclass of
2689 * all exceptions that can land here. (For javac output, we're probably
2690 * looking at multiple spans of bytecode covered by one "try" that lands
2691 * at an exception-specific "catch", but in general the handler could be
2692 * shared for multiple exceptions.)
2693 *
2694 * Returns NULL if no matching exception handler can be found, or if the
2695 * exception is not a subclass of Throwable.
2696 */
Andy McFadden62a75162009-04-17 17:23:37 -07002697static ClassObject* getCaughtExceptionType(const Method* meth, int insnIdx,
2698 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002699{
Andy McFadden62a75162009-04-17 17:23:37 -07002700 VerifyError localFailure;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002701 const DexCode* pCode;
2702 DexFile* pDexFile;
2703 ClassObject* commonSuper = NULL;
Andy McFadden62a75162009-04-17 17:23:37 -07002704 bool foundPossibleHandler = false;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002705 u4 handlersSize;
2706 u4 offset;
2707 u4 i;
2708
2709 pDexFile = meth->clazz->pDvmDex->pDexFile;
2710 pCode = dvmGetMethodCode(meth);
2711
2712 if (pCode->triesSize != 0) {
2713 handlersSize = dexGetHandlersSize(pCode);
2714 offset = dexGetFirstHandlerOffset(pCode);
2715 } else {
2716 handlersSize = 0;
2717 offset = 0;
2718 }
2719
2720 for (i = 0; i < handlersSize; i++) {
2721 DexCatchIterator iterator;
2722 dexCatchIteratorInit(&iterator, pCode, offset);
2723
2724 for (;;) {
2725 const DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
2726
2727 if (handler == NULL) {
2728 break;
2729 }
2730
2731 if (handler->address == (u4) insnIdx) {
2732 ClassObject* clazz;
Andy McFadden62a75162009-04-17 17:23:37 -07002733 foundPossibleHandler = true;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002734
2735 if (handler->typeIdx == kDexNoIndex)
2736 clazz = gDvm.classJavaLangThrowable;
2737 else
Andy McFadden62a75162009-04-17 17:23:37 -07002738 clazz = dvmOptResolveClass(meth->clazz, handler->typeIdx,
2739 &localFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002740
2741 if (clazz == NULL) {
2742 LOG_VFY("VFY: unable to resolve exception class %u (%s)\n",
2743 handler->typeIdx,
2744 dexStringByTypeIdx(pDexFile, handler->typeIdx));
Andy McFadden62a75162009-04-17 17:23:37 -07002745 /* TODO: do we want to keep going? If we don't fail
2746 * this we run the risk of having a non-Throwable
2747 * introduced at runtime. However, that won't pass
2748 * an instanceof test, so is essentially harmless. */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002749 } else {
2750 if (commonSuper == NULL)
2751 commonSuper = clazz;
2752 else
2753 commonSuper = findCommonSuperclass(clazz, commonSuper);
2754 }
2755 }
2756 }
2757
2758 offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
2759 }
2760
2761 if (commonSuper == NULL) {
Andy McFadden62a75162009-04-17 17:23:37 -07002762 /* no catch blocks, or no catches with classes we can find */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002763 LOG_VFY_METH(meth,
2764 "VFY: unable to find exception handler at addr 0x%x\n", insnIdx);
Andy McFadden62a75162009-04-17 17:23:37 -07002765 *pFailure = VERIFY_ERROR_GENERIC;
2766 } else {
2767 // TODO: verify the class is an instance of Throwable?
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002768 }
2769
2770 return commonSuper;
2771}
2772
2773/*
2774 * Initialize the RegisterTable.
2775 *
2776 * Every instruction address can have a different set of information about
2777 * what's in which register, but for verification purposes we only need to
2778 * store it at branch target addresses (because we merge into that).
2779 *
2780 * By zeroing out the storage we are effectively initializing the register
2781 * information to kRegTypeUnknown.
2782 */
2783static bool initRegisterTable(const Method* meth, const InsnFlags* insnFlags,
2784 RegisterTable* regTable, RegisterTrackingMode trackRegsFor)
2785{
2786 const int insnsSize = dvmGetMethodInsnsSize(meth);
2787 int i;
2788
2789 regTable->insnRegCountPlus = meth->registersSize + kExtraRegs;
2790 regTable->addrRegs = (RegType**) calloc(insnsSize, sizeof(RegType*));
2791 if (regTable->addrRegs == NULL)
2792 return false;
2793
2794 assert(insnsSize > 0);
2795
2796 /*
2797 * "All" means "every address that holds the start of an instruction".
2798 * "Branches" and "GcPoints" mean just those addresses.
2799 *
2800 * "GcPoints" fills about half the addresses, "Branches" about 15%.
2801 */
2802 int interestingCount = 0;
2803 //int insnCount = 0;
2804
2805 for (i = 0; i < insnsSize; i++) {
2806 bool interesting;
2807
2808 switch (trackRegsFor) {
2809 case kTrackRegsAll:
2810 interesting = dvmInsnIsOpcode(insnFlags, i);
2811 break;
2812 case kTrackRegsGcPoints:
2813 interesting = dvmInsnIsGcPoint(insnFlags, i) ||
2814 dvmInsnIsBranchTarget(insnFlags, i);
2815 break;
2816 case kTrackRegsBranches:
2817 interesting = dvmInsnIsBranchTarget(insnFlags, i);
2818 break;
2819 default:
2820 dvmAbort();
2821 return false;
2822 }
2823
2824 if (interesting)
2825 interestingCount++;
2826
2827 /* count instructions, for display only */
2828 //if (dvmInsnIsOpcode(insnFlags, i))
2829 // insnCount++;
2830 }
2831
2832 regTable->regAlloc = (RegType*)
2833 calloc(regTable->insnRegCountPlus * interestingCount, sizeof(RegType));
2834 if (regTable->regAlloc == NULL)
2835 return false;
2836
2837 RegType* regPtr = regTable->regAlloc;
2838 for (i = 0; i < insnsSize; i++) {
2839 bool interesting;
2840
2841 switch (trackRegsFor) {
2842 case kTrackRegsAll:
2843 interesting = dvmInsnIsOpcode(insnFlags, i);
2844 break;
2845 case kTrackRegsGcPoints:
2846 interesting = dvmInsnIsGcPoint(insnFlags, i) ||
2847 dvmInsnIsBranchTarget(insnFlags, i);
2848 break;
2849 case kTrackRegsBranches:
2850 interesting = dvmInsnIsBranchTarget(insnFlags, i);
2851 break;
2852 default:
2853 dvmAbort();
2854 return false;
2855 }
2856
2857 if (interesting) {
2858 regTable->addrRegs[i] = regPtr;
2859 regPtr += regTable->insnRegCountPlus;
2860 }
2861 }
2862
2863 //LOGD("Tracking registers for %d, total %d of %d(%d) (%d%%)\n",
2864 // TRACK_REGS_FOR, interestingCount, insnCount, insnsSize,
2865 // (interestingCount*100) / insnCount);
2866
2867 assert(regPtr - regTable->regAlloc ==
2868 regTable->insnRegCountPlus * interestingCount);
2869 assert(regTable->addrRegs[0] != NULL);
2870 return true;
2871}
2872
2873
2874/*
2875 * Verify that the arguments in a filled-new-array instruction are valid.
2876 *
2877 * "resClass" is the class refered to by pDecInsn->vB.
2878 */
2879static void verifyFilledNewArrayRegs(const Method* meth,
2880 const RegType* insnRegs, const int insnRegCount,
2881 const DecodedInstruction* pDecInsn, ClassObject* resClass, bool isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07002882 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002883{
2884 u4 argCount = pDecInsn->vA;
2885 RegType expectedType;
2886 PrimitiveType elemType;
2887 unsigned int ui;
2888
2889 assert(dvmIsArrayClass(resClass));
2890 elemType = resClass->elementClass->primitiveType;
2891 if (elemType == PRIM_NOT) {
2892 expectedType = regTypeFromClass(resClass->elementClass);
2893 } else {
2894 expectedType = primitiveTypeToRegType(elemType);
2895 }
2896 //LOGI("filled-new-array: %s -> %d\n", resClass->descriptor, expectedType);
2897
2898 /*
2899 * Verify each register. If "argCount" is bad, verifyRegisterType()
2900 * will run off the end of the list and fail. It's legal, if silly,
2901 * for argCount to be zero.
2902 */
2903 for (ui = 0; ui < argCount; ui++) {
2904 u4 getReg;
2905
2906 if (isRange)
2907 getReg = pDecInsn->vC + ui;
2908 else
2909 getReg = pDecInsn->arg[ui];
2910
Andy McFadden62a75162009-04-17 17:23:37 -07002911 verifyRegisterType(insnRegs, insnRegCount, getReg, expectedType,
2912 pFailure);
2913 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002914 LOG_VFY("VFY: filled-new-array arg %u(%u) not valid\n", ui, getReg);
2915 return;
2916 }
2917 }
2918}
2919
2920
2921/*
Andy McFaddenb51ea112009-05-08 16:50:17 -07002922 * Replace an instruction with "throw-verification-error". This allows us to
2923 * defer error reporting until the code path is first used.
2924 *
Andy McFadden861b3382010-03-05 15:58:31 -08002925 * This is expected to be called during "just in time" verification, not
2926 * from within dexopt. (Verification failures in dexopt will result in
2927 * postponement of verification to first use of the class.)
2928 *
Andy McFaddenb51ea112009-05-08 16:50:17 -07002929 * The throw-verification-error instruction requires two code units. Some
2930 * of the replaced instructions require three; the third code unit will
2931 * receive a "nop". The instruction's length will be left unchanged
2932 * in "insnFlags".
2933 *
Andy McFadden96516932009-10-28 17:39:02 -07002934 * The verifier explicitly locks out breakpoint activity, so there should
2935 * be no clashes with the debugger.
2936 *
Andy McFaddenb51ea112009-05-08 16:50:17 -07002937 * IMPORTANT: this may replace meth->insns with a pointer to a new copy of
2938 * the instructions.
2939 *
2940 * Returns "true" on success.
2941 */
2942static bool replaceFailingInstruction(Method* meth, InsnFlags* insnFlags,
2943 int insnIdx, VerifyError failure)
2944{
Andy McFaddenaf0e8382009-08-28 10:38:37 -07002945 VerifyErrorRefType refType;
Andy McFaddenb51ea112009-05-08 16:50:17 -07002946 const u2* oldInsns = meth->insns + insnIdx;
2947 u2 oldInsn = *oldInsns;
2948 bool result = false;
2949
Andy McFaddenb51ea112009-05-08 16:50:17 -07002950 //LOGD(" was 0x%04x\n", oldInsn);
2951 u2* newInsns = (u2*) meth->insns + insnIdx;
2952
2953 /*
2954 * Generate the new instruction out of the old.
2955 *
2956 * First, make sure this is an instruction we're expecting to stomp on.
2957 */
2958 switch (oldInsn & 0xff) {
2959 case OP_CONST_CLASS: // insn[1] == class ref, 2 bytes
2960 case OP_CHECK_CAST:
2961 case OP_INSTANCE_OF:
2962 case OP_NEW_INSTANCE:
2963 case OP_NEW_ARRAY:
Andy McFaddenb51ea112009-05-08 16:50:17 -07002964 case OP_FILLED_NEW_ARRAY: // insn[1] == class ref, 3 bytes
2965 case OP_FILLED_NEW_ARRAY_RANGE:
Andy McFaddenaf0e8382009-08-28 10:38:37 -07002966 refType = VERIFY_ERROR_REF_CLASS;
2967 break;
Andy McFaddenb51ea112009-05-08 16:50:17 -07002968
2969 case OP_IGET: // insn[1] == field ref, 2 bytes
2970 case OP_IGET_BOOLEAN:
2971 case OP_IGET_BYTE:
2972 case OP_IGET_CHAR:
2973 case OP_IGET_SHORT:
2974 case OP_IGET_WIDE:
2975 case OP_IGET_OBJECT:
2976 case OP_IPUT:
2977 case OP_IPUT_BOOLEAN:
2978 case OP_IPUT_BYTE:
2979 case OP_IPUT_CHAR:
2980 case OP_IPUT_SHORT:
2981 case OP_IPUT_WIDE:
2982 case OP_IPUT_OBJECT:
2983 case OP_SGET:
2984 case OP_SGET_BOOLEAN:
2985 case OP_SGET_BYTE:
2986 case OP_SGET_CHAR:
2987 case OP_SGET_SHORT:
2988 case OP_SGET_WIDE:
2989 case OP_SGET_OBJECT:
2990 case OP_SPUT:
2991 case OP_SPUT_BOOLEAN:
2992 case OP_SPUT_BYTE:
2993 case OP_SPUT_CHAR:
2994 case OP_SPUT_SHORT:
2995 case OP_SPUT_WIDE:
2996 case OP_SPUT_OBJECT:
Andy McFaddenaf0e8382009-08-28 10:38:37 -07002997 refType = VERIFY_ERROR_REF_FIELD;
2998 break;
Andy McFaddenb51ea112009-05-08 16:50:17 -07002999
3000 case OP_INVOKE_VIRTUAL: // insn[1] == method ref, 3 bytes
3001 case OP_INVOKE_VIRTUAL_RANGE:
3002 case OP_INVOKE_SUPER:
3003 case OP_INVOKE_SUPER_RANGE:
3004 case OP_INVOKE_DIRECT:
3005 case OP_INVOKE_DIRECT_RANGE:
3006 case OP_INVOKE_STATIC:
3007 case OP_INVOKE_STATIC_RANGE:
3008 case OP_INVOKE_INTERFACE:
3009 case OP_INVOKE_INTERFACE_RANGE:
Andy McFaddenaf0e8382009-08-28 10:38:37 -07003010 refType = VERIFY_ERROR_REF_METHOD;
Andy McFaddenb51ea112009-05-08 16:50:17 -07003011 break;
Andy McFaddenaf0e8382009-08-28 10:38:37 -07003012
Andy McFaddenb51ea112009-05-08 16:50:17 -07003013 default:
3014 /* could handle this in a generic way, but this is probably safer */
3015 LOG_VFY("GLITCH: verifier asked to replace opcode 0x%02x\n",
3016 oldInsn & 0xff);
3017 goto bail;
3018 }
3019
3020 /* write a NOP over the third code unit, if necessary */
3021 int width = dvmInsnGetWidth(insnFlags, insnIdx);
3022 switch (width) {
3023 case 2:
3024 /* nothing to do */
3025 break;
3026 case 3:
Andy McFadden96516932009-10-28 17:39:02 -07003027 dvmDexChangeDex2(meth->clazz->pDvmDex, newInsns+2, OP_NOP);
3028 //newInsns[2] = OP_NOP;
Andy McFaddenb51ea112009-05-08 16:50:17 -07003029 break;
3030 default:
3031 /* whoops */
3032 LOGE("ERROR: stomped a %d-unit instruction with a verifier error\n",
3033 width);
3034 dvmAbort();
3035 }
3036
3037 /* encode the opcode, with the failure code in the high byte */
Andy McFadden96516932009-10-28 17:39:02 -07003038 u2 newVal = OP_THROW_VERIFICATION_ERROR |
Andy McFaddenaf0e8382009-08-28 10:38:37 -07003039 (failure << 8) | (refType << (8 + kVerifyErrorRefTypeShift));
Andy McFadden96516932009-10-28 17:39:02 -07003040 //newInsns[0] = newVal;
3041 dvmDexChangeDex2(meth->clazz->pDvmDex, newInsns, newVal);
Andy McFaddenb51ea112009-05-08 16:50:17 -07003042
3043 result = true;
3044
3045bail:
Andy McFaddenb51ea112009-05-08 16:50:17 -07003046 return result;
3047}
3048
Andy McFadden861b3382010-03-05 15:58:31 -08003049/*
3050 * Replace {iget,iput,sget,sput}-wide with the -wide-volatile form.
3051 *
3052 * If this is called during dexopt, we can modify the instruction in
3053 * place. If this happens during just-in-time verification, we need to
3054 * use the DEX read/write page feature.
3055 *
3056 * NOTE:
3057 * This shouldn't really be tied to verification. It ought to be a
3058 * separate pass that is run before or after the verifier. However, that
3059 * requires a bunch of extra code, and the only advantage of doing so is
3060 * that the feature isn't disabled when verification is turned off. At
3061 * some point we may need to revisit this choice.
3062 */
3063static void replaceVolatileInstruction(Method* meth, InsnFlags* insnFlags,
3064 int insnIdx)
3065{
3066 u2* oldInsns = (u2*)meth->insns + insnIdx;
3067 u2 oldInsn = *oldInsns;
3068 u2 newVal;
3069
3070 switch (oldInsn & 0xff) {
3071 case OP_IGET_WIDE: newVal = OP_IGET_WIDE_VOLATILE; break;
3072 case OP_IPUT_WIDE: newVal = OP_IPUT_WIDE_VOLATILE; break;
3073 case OP_SGET_WIDE: newVal = OP_SGET_WIDE_VOLATILE; break;
3074 case OP_SPUT_WIDE: newVal = OP_SPUT_WIDE_VOLATILE; break;
3075 default:
3076 LOGE("wide-volatile op mismatch (0x%x)\n", oldInsn);
3077 dvmAbort();
3078 return; // in-lieu-of noreturn attribute
3079 }
3080
3081 /* merge new opcode into 16-bit code unit */
3082 newVal |= (oldInsn & 0xff00);
3083
3084 if (gDvm.optimizing) {
3085 /* dexopt time, alter the output */
3086 *oldInsns = newVal;
3087 } else {
3088 /* runtime, make the page read/write */
3089 dvmDexChangeDex2(meth->clazz->pDvmDex, oldInsns, newVal);
3090 }
3091}
3092
Andy McFaddenb51ea112009-05-08 16:50:17 -07003093
3094/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003095 * ===========================================================================
3096 * Entry point and driver loop
3097 * ===========================================================================
3098 */
3099
3100/*
3101 * Entry point for the detailed code-flow analysis.
3102 */
Andy McFaddenb51ea112009-05-08 16:50:17 -07003103bool dvmVerifyCodeFlow(Method* meth, InsnFlags* insnFlags,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003104 UninitInstanceMap* uninitMap)
3105{
3106 bool result = false;
3107 const int insnsSize = dvmGetMethodInsnsSize(meth);
3108 const u2* insns = meth->insns;
3109 const bool generateRegisterMap = gDvm.generateRegisterMaps;
3110 int i, offset;
3111 bool isConditional;
3112 RegisterTable regTable;
3113
3114 memset(&regTable, 0, sizeof(regTable));
3115
3116#ifndef NDEBUG
3117 checkMergeTab(); // only need to do this if table gets updated
3118#endif
3119
3120 /*
3121 * We rely on these for verification of const-class, const-string,
3122 * and throw instructions. Make sure we have them.
3123 */
3124 if (gDvm.classJavaLangClass == NULL)
3125 gDvm.classJavaLangClass =
3126 dvmFindSystemClassNoInit("Ljava/lang/Class;");
3127 if (gDvm.classJavaLangString == NULL)
3128 gDvm.classJavaLangString =
3129 dvmFindSystemClassNoInit("Ljava/lang/String;");
Andy McFadden686e1e22009-05-26 16:56:30 -07003130 if (gDvm.classJavaLangThrowable == NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003131 gDvm.classJavaLangThrowable =
3132 dvmFindSystemClassNoInit("Ljava/lang/Throwable;");
Andy McFadden686e1e22009-05-26 16:56:30 -07003133 gDvm.offJavaLangThrowable_cause =
3134 dvmFindFieldOffset(gDvm.classJavaLangThrowable,
3135 "cause", "Ljava/lang/Throwable;");
3136 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003137 if (gDvm.classJavaLangObject == NULL)
3138 gDvm.classJavaLangObject =
3139 dvmFindSystemClassNoInit("Ljava/lang/Object;");
3140
3141 if (meth->registersSize * insnsSize > 2*1024*1024) {
3142 /* should probably base this on actual memory requirements */
3143 LOG_VFY_METH(meth,
3144 "VFY: arbitrarily rejecting large method (regs=%d count=%d)\n",
3145 meth->registersSize, insnsSize);
3146 goto bail;
3147 }
3148
3149 /*
3150 * Create register lists, and initialize them to "Unknown". If we're
3151 * also going to create the register map, we need to retain the
3152 * register lists for a larger set of addresses.
3153 */
3154 if (!initRegisterTable(meth, insnFlags, &regTable,
3155 generateRegisterMap ? kTrackRegsGcPoints : kTrackRegsBranches))
3156 goto bail;
3157
3158 /*
3159 * Initialize the types of the registers that correspond to the
3160 * method arguments. We can determine this from the method signature.
3161 */
3162 if (!setTypesFromSignature(meth, regTable.addrRegs[0], uninitMap))
3163 goto bail;
3164
3165 /*
3166 * Run the verifier.
3167 */
3168 if (!doCodeVerification(meth, insnFlags, &regTable, uninitMap))
3169 goto bail;
3170
3171 /*
3172 * Generate a register map.
3173 */
3174 if (generateRegisterMap) {
3175 RegisterMap* pMap;
3176 VerifierData vd;
3177
3178 vd.method = meth;
3179 vd.insnsSize = insnsSize;
3180 vd.insnRegCount = meth->registersSize;
3181 vd.insnFlags = insnFlags;
3182 vd.addrRegs = regTable.addrRegs;
3183
3184 pMap = dvmGenerateRegisterMapV(&vd);
3185 if (pMap != NULL) {
3186 /*
3187 * Tuck it into the Method struct. It will either get used
3188 * directly or, if we're in dexopt, will be packed up and
3189 * appended to the DEX file.
3190 */
3191 dvmSetRegisterMap((Method*)meth, pMap);
3192 }
3193 }
3194
3195 /*
3196 * Success.
3197 */
3198 result = true;
3199
3200bail:
3201 free(regTable.addrRegs);
3202 free(regTable.regAlloc);
3203 return result;
3204}
3205
3206/*
3207 * Grind through the instructions.
3208 *
3209 * The basic strategy is as outlined in v3 4.11.1.2: set the "changed" bit
3210 * on the first instruction, process it (setting additional "changed" bits),
3211 * and repeat until there are no more.
3212 *
3213 * v3 4.11.1.1
3214 * - (N/A) operand stack is always the same size
3215 * - operand stack [registers] contain the correct types of values
3216 * - local variables [registers] contain the correct types of values
3217 * - methods are invoked with the appropriate arguments
3218 * - fields are assigned using values of appropriate types
3219 * - opcodes have the correct type values in operand registers
3220 * - there is never an uninitialized class instance in a local variable in
3221 * code protected by an exception handler (operand stack is okay, because
3222 * the operand stack is discarded when an exception is thrown) [can't
3223 * know what's a local var w/o the debug info -- should fall out of
3224 * register typing]
3225 *
3226 * v3 4.11.1.2
3227 * - execution cannot fall off the end of the code
3228 *
3229 * (We also do many of the items described in the "static checks" sections,
3230 * because it's easier to do them here.)
3231 *
3232 * We need an array of RegType values, one per register, for every
3233 * instruction. In theory this could become quite large -- up to several
3234 * megabytes for a monster function. For self-preservation we reject
3235 * anything that requires more than a certain amount of memory. (Typical
3236 * "large" should be on the order of 4K code units * 8 registers.) This
3237 * will likely have to be adjusted.
3238 *
3239 *
3240 * The spec forbids backward branches when there's an uninitialized reference
3241 * in a register. The idea is to prevent something like this:
3242 * loop:
3243 * move r1, r0
3244 * new-instance r0, MyClass
3245 * ...
3246 * if-eq rN, loop // once
3247 * initialize r0
3248 *
3249 * This leaves us with two different instances, both allocated by the
3250 * same instruction, but only one is initialized. The scheme outlined in
3251 * v3 4.11.1.4 wouldn't catch this, so they work around it by preventing
3252 * backward branches. We achieve identical results without restricting
3253 * code reordering by specifying that you can't execute the new-instance
3254 * instruction if a register contains an uninitialized instance created
3255 * by that same instrutcion.
3256 */
Andy McFaddenb51ea112009-05-08 16:50:17 -07003257static bool doCodeVerification(Method* meth, InsnFlags* insnFlags,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003258 RegisterTable* regTable, UninitInstanceMap* uninitMap)
3259{
3260 const int insnsSize = dvmGetMethodInsnsSize(meth);
3261 const u2* insns = meth->insns;
3262 RegType workRegs[meth->registersSize + kExtraRegs];
3263 bool result = false;
3264 bool debugVerbose = false;
3265 int insnIdx, startGuess, prevAddr;
3266
3267 /*
3268 * Begin by marking the first instruction as "changed".
3269 */
3270 dvmInsnSetChanged(insnFlags, 0, true);
3271
3272 if (doVerboseLogging(meth)) {
3273 IF_LOGI() {
3274 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
3275 LOGI("Now verifying: %s.%s %s (ins=%d regs=%d)\n",
3276 meth->clazz->descriptor, meth->name, desc,
3277 meth->insSize, meth->registersSize);
3278 LOGI(" ------ [0 4 8 12 16 20 24 28 32 36\n");
3279 free(desc);
3280 }
3281 debugVerbose = true;
3282 gDebugVerbose = true;
3283 } else {
3284 gDebugVerbose = false;
3285 }
3286
3287 startGuess = 0;
3288
3289 /*
3290 * Continue until no instructions are marked "changed".
3291 */
3292 while (true) {
3293 /*
3294 * Find the first marked one. Use "startGuess" as a way to find
3295 * one quickly.
3296 */
3297 for (insnIdx = startGuess; insnIdx < insnsSize; insnIdx++) {
3298 if (dvmInsnIsChanged(insnFlags, insnIdx))
3299 break;
3300 }
3301
3302 if (insnIdx == insnsSize) {
3303 if (startGuess != 0) {
3304 /* try again, starting from the top */
3305 startGuess = 0;
3306 continue;
3307 } else {
3308 /* all flags are clear */
3309 break;
3310 }
3311 }
3312
3313 /*
3314 * We carry the working set of registers from instruction to
3315 * instruction. If this address can be the target of a branch
3316 * (or throw) instruction, or if we're skipping around chasing
3317 * "changed" flags, we need to load the set of registers from
3318 * the table.
3319 *
3320 * Because we always prefer to continue on to the next instruction,
3321 * we should never have a situation where we have a stray
3322 * "changed" flag set on an instruction that isn't a branch target.
3323 */
3324 if (dvmInsnIsBranchTarget(insnFlags, insnIdx)) {
3325 RegType* insnRegs = getRegisterLine(regTable, insnIdx);
3326 assert(insnRegs != NULL);
3327 copyRegisters(workRegs, insnRegs, meth->registersSize + kExtraRegs);
3328
3329 if (debugVerbose) {
3330 dumpRegTypes(meth, insnFlags, workRegs, insnIdx, NULL,uninitMap,
3331 SHOW_REG_DETAILS);
3332 }
3333
3334 } else {
3335 if (debugVerbose) {
3336 dumpRegTypes(meth, insnFlags, workRegs, insnIdx, NULL,uninitMap,
3337 SHOW_REG_DETAILS);
3338 }
3339
3340#ifndef NDEBUG
3341 /*
3342 * Sanity check: retrieve the stored register line (assuming
3343 * a full table) and make sure it actually matches.
3344 */
3345 RegType* insnRegs = getRegisterLine(regTable, insnIdx);
3346 if (insnRegs != NULL &&
3347 compareRegisters(workRegs, insnRegs,
3348 meth->registersSize + kExtraRegs) != 0)
3349 {
3350 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
3351 LOG_VFY("HUH? workRegs diverged in %s.%s %s\n",
3352 meth->clazz->descriptor, meth->name, desc);
3353 free(desc);
3354 dumpRegTypes(meth, insnFlags, workRegs, 0, "work",
3355 uninitMap, DRT_SHOW_REF_TYPES | DRT_SHOW_LOCALS);
3356 dumpRegTypes(meth, insnFlags, insnRegs, 0, "insn",
3357 uninitMap, DRT_SHOW_REF_TYPES | DRT_SHOW_LOCALS);
3358 }
3359#endif
3360 }
3361
3362 //LOGI("process %s.%s %s %d\n",
3363 // meth->clazz->descriptor, meth->name, meth->descriptor, insnIdx);
3364 if (!verifyInstruction(meth, insnFlags, regTable, workRegs, insnIdx,
3365 uninitMap, &startGuess))
3366 {
3367 //LOGD("+++ %s bailing at %d\n", meth->name, insnIdx);
3368 goto bail;
3369 }
3370
3371#if 0
3372 {
3373 static const int gcMask = kInstrCanBranch | kInstrCanSwitch |
3374 kInstrCanThrow | kInstrCanReturn;
3375 OpCode opCode = *(meth->insns + insnIdx) & 0xff;
3376 int flags = dexGetInstrFlags(gDvm.instrFlags, opCode);
3377
3378 /* 8, 16, 32, or 32*n -bit regs */
3379 int regWidth = (meth->registersSize + 7) / 8;
3380 if (regWidth == 3)
3381 regWidth = 4;
3382 if (regWidth > 4) {
3383 regWidth = ((regWidth + 3) / 4) * 4;
3384 if (false) {
3385 LOGW("WOW: %d regs -> %d %s.%s\n",
3386 meth->registersSize, regWidth,
3387 meth->clazz->descriptor, meth->name);
3388 //x = true;
3389 }
3390 }
3391
3392 if ((flags & gcMask) != 0) {
3393 /* this is a potential GC point */
3394 gDvm__gcInstr++;
3395
3396 if (insnsSize < 256)
3397 gDvm__gcData += 1;
3398 else
3399 gDvm__gcData += 2;
3400 gDvm__gcData += regWidth;
3401 }
3402 gDvm__gcSimpleData += regWidth;
3403
3404 gDvm__totalInstr++;
3405 }
3406#endif
3407
3408 /*
3409 * Clear "changed" and mark as visited.
3410 */
3411 dvmInsnSetVisited(insnFlags, insnIdx, true);
3412 dvmInsnSetChanged(insnFlags, insnIdx, false);
3413 }
3414
Andy McFaddenb51ea112009-05-08 16:50:17 -07003415 if (DEAD_CODE_SCAN && !IS_METHOD_FLAG_SET(meth, METHOD_ISWRITABLE)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003416 /*
Andy McFaddenb51ea112009-05-08 16:50:17 -07003417 * Scan for dead code. There's nothing "evil" about dead code
3418 * (besides the wasted space), but it indicates a flaw somewhere
3419 * down the line, possibly in the verifier.
3420 *
3421 * If we've rewritten "always throw" instructions into the stream,
3422 * we are almost certainly going to have some dead code.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003423 */
3424 int deadStart = -1;
3425 for (insnIdx = 0; insnIdx < insnsSize;
3426 insnIdx += dvmInsnGetWidth(insnFlags, insnIdx))
3427 {
3428 /*
3429 * Switch-statement data doesn't get "visited" by scanner. It
3430 * may or may not be preceded by a padding NOP.
3431 */
3432 int instr = meth->insns[insnIdx];
3433 if (instr == kPackedSwitchSignature ||
3434 instr == kSparseSwitchSignature ||
3435 instr == kArrayDataSignature ||
3436 (instr == OP_NOP &&
3437 (meth->insns[insnIdx+1] == kPackedSwitchSignature ||
3438 meth->insns[insnIdx+1] == kSparseSwitchSignature ||
3439 meth->insns[insnIdx+1] == kArrayDataSignature)))
3440 {
3441 dvmInsnSetVisited(insnFlags, insnIdx, true);
3442 }
3443
3444 if (!dvmInsnIsVisited(insnFlags, insnIdx)) {
3445 if (deadStart < 0)
3446 deadStart = insnIdx;
3447 } else if (deadStart >= 0) {
3448 IF_LOGD() {
3449 char* desc =
3450 dexProtoCopyMethodDescriptor(&meth->prototype);
3451 LOGD("VFY: dead code 0x%04x-%04x in %s.%s %s\n",
3452 deadStart, insnIdx-1,
3453 meth->clazz->descriptor, meth->name, desc);
3454 free(desc);
3455 }
3456
3457 deadStart = -1;
3458 }
3459 }
3460 if (deadStart >= 0) {
3461 IF_LOGD() {
3462 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
3463 LOGD("VFY: dead code 0x%04x-%04x in %s.%s %s\n",
3464 deadStart, insnIdx-1,
3465 meth->clazz->descriptor, meth->name, desc);
3466 free(desc);
3467 }
3468 }
3469 }
3470
3471 result = true;
3472
3473bail:
3474 return result;
3475}
3476
3477
3478/*
3479 * Perform verification for a single instruction.
3480 *
3481 * This requires fully decoding the instruction to determine the effect
3482 * it has on registers.
3483 *
3484 * Finds zero or more following instructions and sets the "changed" flag
3485 * if execution at that point needs to be (re-)evaluated. Register changes
3486 * are merged into "regTypes" at the target addresses. Does not set or
3487 * clear any other flags in "insnFlags".
Andy McFaddenb51ea112009-05-08 16:50:17 -07003488 *
3489 * This may alter meth->insns if we need to replace an instruction with
3490 * throw-verification-error.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003491 */
Andy McFaddenb51ea112009-05-08 16:50:17 -07003492static bool verifyInstruction(Method* meth, InsnFlags* insnFlags,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003493 RegisterTable* regTable, RegType* workRegs, int insnIdx,
3494 UninitInstanceMap* uninitMap, int* pStartGuess)
3495{
3496 const int insnsSize = dvmGetMethodInsnsSize(meth);
3497 const u2* insns = meth->insns + insnIdx;
3498 bool result = false;
3499
3500 /*
3501 * Once we finish decoding the instruction, we need to figure out where
3502 * we can go from here. There are three possible ways to transfer
3503 * control to another statement:
3504 *
3505 * (1) Continue to the next instruction. Applies to all but
3506 * unconditional branches, method returns, and exception throws.
3507 * (2) Branch to one or more possible locations. Applies to branches
3508 * and switch statements.
3509 * (3) Exception handlers. Applies to any instruction that can
3510 * throw an exception that is handled by an encompassing "try"
3511 * block. (We simplify this to be any instruction that can
3512 * throw any exception.)
3513 *
3514 * We can also return, in which case there is no successor instruction
3515 * from this point.
3516 *
3517 * The behavior can be determined from the InstrFlags.
3518 */
3519
3520 const DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
3521 RegType entryRegs[meth->registersSize + kExtraRegs];
3522 ClassObject* resClass;
3523 const char* className;
3524 int branchTarget = 0;
3525 const int insnRegCount = meth->registersSize;
3526 RegType tmpType;
3527 DecodedInstruction decInsn;
3528 bool justSetResult = false;
Andy McFadden62a75162009-04-17 17:23:37 -07003529 VerifyError failure = VERIFY_ERROR_NONE;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003530
3531#ifndef NDEBUG
3532 memset(&decInsn, 0x81, sizeof(decInsn));
3533#endif
3534 dexDecodeInstruction(gDvm.instrFormat, insns, &decInsn);
3535
Andy McFaddenb51ea112009-05-08 16:50:17 -07003536 int nextFlags = dexGetInstrFlags(gDvm.instrFlags, decInsn.opCode);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003537
3538 /*
3539 * Make a copy of the previous register state. If the instruction
3540 * throws an exception, we merge *this* into the destination rather
3541 * than workRegs, because we don't want the result from the "successful"
3542 * code path (e.g. a check-cast that "improves" a type) to be visible
3543 * to the exception handler.
3544 */
3545 if ((nextFlags & kInstrCanThrow) != 0 && dvmInsnIsInTry(insnFlags, insnIdx))
3546 {
3547 copyRegisters(entryRegs, workRegs, meth->registersSize + kExtraRegs);
3548 } else {
3549#ifndef NDEBUG
3550 memset(entryRegs, 0xdd,
3551 (meth->registersSize + kExtraRegs) * sizeof(RegType));
3552#endif
3553 }
3554
3555 switch (decInsn.opCode) {
3556 case OP_NOP:
3557 /*
3558 * A "pure" NOP has no effect on anything. Data tables start with
3559 * a signature that looks like a NOP; if we see one of these in
3560 * the course of executing code then we have a problem.
3561 */
3562 if (decInsn.vA != 0) {
3563 LOG_VFY("VFY: encountered data table in instruction stream\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003564 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003565 }
3566 break;
3567
3568 case OP_MOVE:
3569 case OP_MOVE_FROM16:
3570 case OP_MOVE_16:
3571 copyRegister1(workRegs, insnRegCount, decInsn.vA, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07003572 kTypeCategory1nr, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003573 break;
3574 case OP_MOVE_WIDE:
3575 case OP_MOVE_WIDE_FROM16:
3576 case OP_MOVE_WIDE_16:
Andy McFadden62a75162009-04-17 17:23:37 -07003577 copyRegister2(workRegs, insnRegCount, decInsn.vA, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003578 break;
3579 case OP_MOVE_OBJECT:
3580 case OP_MOVE_OBJECT_FROM16:
3581 case OP_MOVE_OBJECT_16:
3582 copyRegister1(workRegs, insnRegCount, decInsn.vA, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07003583 kTypeCategoryRef, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003584 break;
3585
3586 /*
3587 * The move-result instructions copy data out of a "pseudo-register"
3588 * with the results from the last method invocation. In practice we
3589 * might want to hold the result in an actual CPU register, so the
3590 * Dalvik spec requires that these only appear immediately after an
3591 * invoke or filled-new-array.
3592 *
3593 * These calls invalidate the "result" register. (This is now
3594 * redundant with the reset done below, but it can make the debug info
3595 * easier to read in some cases.)
3596 */
3597 case OP_MOVE_RESULT:
3598 copyResultRegister1(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003599 kTypeCategory1nr, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003600 break;
3601 case OP_MOVE_RESULT_WIDE:
Andy McFadden62a75162009-04-17 17:23:37 -07003602 copyResultRegister2(workRegs, insnRegCount, decInsn.vA, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003603 break;
3604 case OP_MOVE_RESULT_OBJECT:
3605 copyResultRegister1(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003606 kTypeCategoryRef, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003607 break;
3608
3609 case OP_MOVE_EXCEPTION:
3610 /*
3611 * This statement can only appear as the first instruction in an
3612 * exception handler (though not all exception handlers need to
3613 * have one of these). We verify that as part of extracting the
3614 * exception type from the catch block list.
3615 *
3616 * "resClass" will hold the closest common superclass of all
3617 * exceptions that can be handled here.
3618 */
Andy McFadden62a75162009-04-17 17:23:37 -07003619 resClass = getCaughtExceptionType(meth, insnIdx, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003620 if (resClass == NULL) {
Andy McFadden62a75162009-04-17 17:23:37 -07003621 assert(!VERIFY_OK(failure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003622 } else {
3623 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003624 regTypeFromClass(resClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003625 }
3626 break;
3627
3628 case OP_RETURN_VOID:
Andy McFadden62a75162009-04-17 17:23:37 -07003629 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3630 failure = VERIFY_ERROR_GENERIC;
3631 } else if (getMethodReturnType(meth) != kRegTypeUnknown) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003632 LOG_VFY("VFY: return-void not expected\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003633 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003634 }
3635 break;
3636 case OP_RETURN:
Andy McFadden62a75162009-04-17 17:23:37 -07003637 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3638 failure = VERIFY_ERROR_GENERIC;
3639 } else {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003640 /* check the method signature */
3641 RegType returnType = getMethodReturnType(meth);
Andy McFadden62a75162009-04-17 17:23:37 -07003642 checkTypeCategory(returnType, kTypeCategory1nr, &failure);
3643 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003644 LOG_VFY("VFY: return-32 not expected\n");
3645
3646 /* check the register contents */
3647 returnType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003648 &failure);
3649 checkTypeCategory(returnType, kTypeCategory1nr, &failure);
3650 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003651 LOG_VFY("VFY: return-32 on invalid register v%d\n", decInsn.vA);
3652 }
3653 break;
3654 case OP_RETURN_WIDE:
Andy McFadden62a75162009-04-17 17:23:37 -07003655 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3656 failure = VERIFY_ERROR_GENERIC;
3657 } else {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003658 RegType returnType, returnTypeHi;
3659
3660 /* check the method signature */
3661 returnType = getMethodReturnType(meth);
Andy McFadden62a75162009-04-17 17:23:37 -07003662 checkTypeCategory(returnType, kTypeCategory2, &failure);
3663 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003664 LOG_VFY("VFY: return-wide not expected\n");
3665
3666 /* check the register contents */
3667 returnType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003668 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003669 returnTypeHi = getRegisterType(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003670 decInsn.vA +1, &failure);
3671 if (VERIFY_OK(failure)) {
3672 checkTypeCategory(returnType, kTypeCategory2, &failure);
3673 checkWidePair(returnType, returnTypeHi, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003674 }
Andy McFadden62a75162009-04-17 17:23:37 -07003675 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003676 LOG_VFY("VFY: return-wide on invalid register pair v%d\n",
3677 decInsn.vA);
3678 }
3679 }
3680 break;
3681 case OP_RETURN_OBJECT:
Andy McFadden62a75162009-04-17 17:23:37 -07003682 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3683 failure = VERIFY_ERROR_GENERIC;
3684 } else {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003685 RegType returnType = getMethodReturnType(meth);
Andy McFadden62a75162009-04-17 17:23:37 -07003686 checkTypeCategory(returnType, kTypeCategoryRef, &failure);
3687 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003688 LOG_VFY("VFY: return-object not expected\n");
3689 break;
3690 }
3691
3692 /* returnType is the *expected* return type, not register value */
3693 assert(returnType != kRegTypeZero);
3694 assert(!regTypeIsUninitReference(returnType));
3695
3696 /*
3697 * Verify that the reference in vAA is an instance of the type
3698 * in "returnType". The Zero type is allowed here. If the
3699 * method is declared to return an interface, then any
3700 * initialized reference is acceptable.
3701 *
3702 * Note getClassFromRegister fails if the register holds an
3703 * uninitialized reference, so we do not allow them to be
3704 * returned.
3705 */
3706 ClassObject* declClass;
3707
3708 declClass = regTypeInitializedReferenceToClass(returnType);
3709 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003710 decInsn.vA, &failure);
3711 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003712 break;
3713 if (resClass != NULL) {
3714 if (!dvmIsInterfaceClass(declClass) &&
3715 !dvmInstanceof(resClass, declClass))
3716 {
Andy McFadden86c86432009-05-27 14:40:12 -07003717 LOG_VFY("VFY: returning %s (cl=%p), declared %s (cl=%p)\n",
3718 resClass->descriptor, resClass->classLoader,
3719 declClass->descriptor, declClass->classLoader);
Andy McFadden62a75162009-04-17 17:23:37 -07003720 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003721 break;
3722 }
3723 }
3724 }
3725 break;
3726
3727 case OP_CONST_4:
3728 case OP_CONST_16:
3729 case OP_CONST:
3730 /* could be boolean, int, float, or a null reference */
3731 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003732 dvmDetermineCat1Const((s4)decInsn.vB), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003733 break;
3734 case OP_CONST_HIGH16:
3735 /* could be boolean, int, float, or a null reference */
3736 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003737 dvmDetermineCat1Const((s4) decInsn.vB << 16), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003738 break;
3739 case OP_CONST_WIDE_16:
3740 case OP_CONST_WIDE_32:
3741 case OP_CONST_WIDE:
3742 case OP_CONST_WIDE_HIGH16:
3743 /* could be long or double; default to long and allow conversion */
3744 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003745 kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003746 break;
3747 case OP_CONST_STRING:
3748 case OP_CONST_STRING_JUMBO:
3749 assert(gDvm.classJavaLangString != NULL);
3750 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003751 regTypeFromClass(gDvm.classJavaLangString), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003752 break;
3753 case OP_CONST_CLASS:
3754 assert(gDvm.classJavaLangClass != NULL);
3755 /* make sure we can resolve the class; access check is important */
Andy McFadden62a75162009-04-17 17:23:37 -07003756 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003757 if (resClass == NULL) {
3758 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3759 dvmLogUnableToResolveClass(badClassDesc, meth);
3760 LOG_VFY("VFY: unable to resolve const-class %d (%s) in %s\n",
3761 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003762 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003763 } else {
3764 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003765 regTypeFromClass(gDvm.classJavaLangClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003766 }
3767 break;
3768
3769 case OP_MONITOR_ENTER:
3770 case OP_MONITOR_EXIT:
Andy McFadden62a75162009-04-17 17:23:37 -07003771 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
3772 if (VERIFY_OK(failure)) {
3773 if (!regTypeIsReference(tmpType)) {
3774 LOG_VFY("VFY: monitor op on non-object\n");
3775 failure = VERIFY_ERROR_GENERIC;
3776 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003777 }
3778 break;
3779
3780 case OP_CHECK_CAST:
3781 /*
3782 * If this instruction succeeds, we will promote register vA to
3783 * the type in vB. (This could be a demotion -- not expected, so
3784 * we don't try to address it.)
3785 *
3786 * If it fails, an exception is thrown, which we deal with later
3787 * by ignoring the update to decInsn.vA when branching to a handler.
3788 */
Andy McFadden62a75162009-04-17 17:23:37 -07003789 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003790 if (resClass == NULL) {
3791 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3792 dvmLogUnableToResolveClass(badClassDesc, meth);
3793 LOG_VFY("VFY: unable to resolve check-cast %d (%s) in %s\n",
3794 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003795 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003796 } else {
3797 RegType origType;
3798
3799 origType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003800 &failure);
3801 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003802 break;
3803 if (!regTypeIsReference(origType)) {
3804 LOG_VFY("VFY: check-cast on non-reference in v%u\n",decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07003805 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003806 break;
3807 }
3808 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003809 regTypeFromClass(resClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003810 }
3811 break;
3812 case OP_INSTANCE_OF:
3813 /* make sure we're checking a reference type */
Andy McFadden62a75162009-04-17 17:23:37 -07003814 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vB, &failure);
3815 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003816 break;
3817 if (!regTypeIsReference(tmpType)) {
3818 LOG_VFY("VFY: vB not a reference (%d)\n", tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07003819 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003820 break;
3821 }
3822
3823 /* make sure we can resolve the class; access check is important */
Andy McFadden62a75162009-04-17 17:23:37 -07003824 resClass = dvmOptResolveClass(meth->clazz, decInsn.vC, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003825 if (resClass == NULL) {
3826 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vC);
3827 dvmLogUnableToResolveClass(badClassDesc, meth);
3828 LOG_VFY("VFY: unable to resolve instanceof %d (%s) in %s\n",
3829 decInsn.vC, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003830 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003831 } else {
3832 /* result is boolean */
3833 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003834 kRegTypeBoolean, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003835 }
3836 break;
3837
3838 case OP_ARRAY_LENGTH:
3839 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003840 decInsn.vB, &failure);
3841 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003842 break;
3843 if (resClass != NULL && !dvmIsArrayClass(resClass)) {
3844 LOG_VFY("VFY: array-length on non-array\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003845 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003846 break;
3847 }
3848 setRegisterType(workRegs, insnRegCount, decInsn.vA, kRegTypeInteger,
Andy McFadden62a75162009-04-17 17:23:37 -07003849 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003850 break;
3851
3852 case OP_NEW_INSTANCE:
Andy McFadden62a75162009-04-17 17:23:37 -07003853 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003854 if (resClass == NULL) {
3855 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3856 dvmLogUnableToResolveClass(badClassDesc, meth);
3857 LOG_VFY("VFY: unable to resolve new-instance %d (%s) in %s\n",
3858 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003859 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003860 } else {
3861 RegType uninitType;
3862
Andy McFaddenb51ea112009-05-08 16:50:17 -07003863 /* can't create an instance of an interface or abstract class */
3864 if (dvmIsAbstractClass(resClass) || dvmIsInterfaceClass(resClass)) {
3865 LOG_VFY("VFY: new-instance on interface or abstract class %s\n",
3866 resClass->descriptor);
3867 failure = VERIFY_ERROR_INSTANTIATION;
3868 break;
3869 }
3870
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003871 /* add resolved class to uninit map if not already there */
3872 int uidx = dvmSetUninitInstance(uninitMap, insnIdx, resClass);
3873 assert(uidx >= 0);
3874 uninitType = regTypeFromUninitIndex(uidx);
3875
3876 /*
3877 * Any registers holding previous allocations from this address
3878 * that have not yet been initialized must be marked invalid.
3879 */
3880 markUninitRefsAsInvalid(workRegs, insnRegCount, uninitMap,
3881 uninitType);
3882
3883 /* add the new uninitialized reference to the register ste */
3884 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003885 uninitType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003886 }
3887 break;
3888 case OP_NEW_ARRAY:
Andy McFadden62a75162009-04-17 17:23:37 -07003889 resClass = dvmOptResolveClass(meth->clazz, decInsn.vC, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003890 if (resClass == NULL) {
3891 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vC);
3892 dvmLogUnableToResolveClass(badClassDesc, meth);
3893 LOG_VFY("VFY: unable to resolve new-array %d (%s) in %s\n",
3894 decInsn.vC, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003895 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003896 } else if (!dvmIsArrayClass(resClass)) {
3897 LOG_VFY("VFY: new-array on non-array class\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003898 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003899 } else {
3900 /* make sure "size" register is valid type */
3901 verifyRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07003902 kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003903 /* set register type to array class */
3904 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003905 regTypeFromClass(resClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003906 }
3907 break;
3908 case OP_FILLED_NEW_ARRAY:
3909 case OP_FILLED_NEW_ARRAY_RANGE:
Andy McFadden62a75162009-04-17 17:23:37 -07003910 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003911 if (resClass == NULL) {
3912 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3913 dvmLogUnableToResolveClass(badClassDesc, meth);
3914 LOG_VFY("VFY: unable to resolve filled-array %d (%s) in %s\n",
3915 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003916 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003917 } else if (!dvmIsArrayClass(resClass)) {
3918 LOG_VFY("VFY: filled-new-array on non-array class\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003919 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003920 } else {
3921 bool isRange = (decInsn.opCode == OP_FILLED_NEW_ARRAY_RANGE);
3922
3923 /* check the arguments to the instruction */
3924 verifyFilledNewArrayRegs(meth, workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07003925 resClass, isRange, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003926 /* filled-array result goes into "result" register */
3927 setResultRegisterType(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003928 regTypeFromClass(resClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003929 justSetResult = true;
3930 }
3931 break;
3932
3933 case OP_CMPL_FLOAT:
3934 case OP_CMPG_FLOAT:
3935 verifyRegisterType(workRegs, insnRegCount, decInsn.vB, kRegTypeFloat,
Andy McFadden62a75162009-04-17 17:23:37 -07003936 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003937 verifyRegisterType(workRegs, insnRegCount, decInsn.vC, kRegTypeFloat,
Andy McFadden62a75162009-04-17 17:23:37 -07003938 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003939 setRegisterType(workRegs, insnRegCount, decInsn.vA, kRegTypeBoolean,
Andy McFadden62a75162009-04-17 17:23:37 -07003940 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003941 break;
3942 case OP_CMPL_DOUBLE:
3943 case OP_CMPG_DOUBLE:
3944 verifyRegisterType(workRegs, insnRegCount, decInsn.vB, kRegTypeDoubleLo,
Andy McFadden62a75162009-04-17 17:23:37 -07003945 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003946 verifyRegisterType(workRegs, insnRegCount, decInsn.vC, kRegTypeDoubleLo,
Andy McFadden62a75162009-04-17 17:23:37 -07003947 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003948 setRegisterType(workRegs, insnRegCount, decInsn.vA, kRegTypeBoolean,
Andy McFadden62a75162009-04-17 17:23:37 -07003949 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003950 break;
3951 case OP_CMP_LONG:
3952 verifyRegisterType(workRegs, insnRegCount, decInsn.vB, kRegTypeLongLo,
Andy McFadden62a75162009-04-17 17:23:37 -07003953 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003954 verifyRegisterType(workRegs, insnRegCount, decInsn.vC, kRegTypeLongLo,
Andy McFadden62a75162009-04-17 17:23:37 -07003955 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003956 setRegisterType(workRegs, insnRegCount, decInsn.vA, kRegTypeBoolean,
Andy McFadden62a75162009-04-17 17:23:37 -07003957 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003958 break;
3959
3960 case OP_THROW:
3961 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003962 decInsn.vA, &failure);
3963 if (VERIFY_OK(failure) && resClass != NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003964 if (!dvmInstanceof(resClass, gDvm.classJavaLangThrowable)) {
3965 LOG_VFY("VFY: thrown class %s not instanceof Throwable\n",
3966 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003967 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003968 }
3969 }
3970 break;
3971
3972 case OP_GOTO:
3973 case OP_GOTO_16:
3974 case OP_GOTO_32:
3975 /* no effect on or use of registers */
3976 break;
3977
3978 case OP_PACKED_SWITCH:
3979 case OP_SPARSE_SWITCH:
3980 /* verify that vAA is an integer, or can be converted to one */
3981 verifyRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003982 kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003983 break;
3984
3985 case OP_FILL_ARRAY_DATA:
3986 {
3987 RegType valueType;
3988 const u2 *arrayData;
3989 u2 elemWidth;
3990
3991 /* Similar to the verification done for APUT */
3992 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003993 decInsn.vA, &failure);
3994 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003995 break;
3996
3997 /* resClass can be null if the reg type is Zero */
3998 if (resClass == NULL)
3999 break;
4000
4001 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4002 resClass->elementClass->primitiveType == PRIM_NOT ||
4003 resClass->elementClass->primitiveType == PRIM_VOID)
4004 {
4005 LOG_VFY("VFY: invalid fill-array-data on %s\n",
4006 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004007 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004008 break;
4009 }
4010
4011 valueType = primitiveTypeToRegType(
4012 resClass->elementClass->primitiveType);
4013 assert(valueType != kRegTypeUnknown);
4014
4015 /*
4016 * Now verify if the element width in the table matches the element
4017 * width declared in the array
4018 */
4019 arrayData = insns + (insns[1] | (((s4)insns[2]) << 16));
4020 if (arrayData[0] != kArrayDataSignature) {
4021 LOG_VFY("VFY: invalid magic for array-data\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004022 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004023 break;
4024 }
4025
4026 switch (resClass->elementClass->primitiveType) {
4027 case PRIM_BOOLEAN:
4028 case PRIM_BYTE:
4029 elemWidth = 1;
4030 break;
4031 case PRIM_CHAR:
4032 case PRIM_SHORT:
4033 elemWidth = 2;
4034 break;
4035 case PRIM_FLOAT:
4036 case PRIM_INT:
4037 elemWidth = 4;
4038 break;
4039 case PRIM_DOUBLE:
4040 case PRIM_LONG:
4041 elemWidth = 8;
4042 break;
4043 default:
4044 elemWidth = 0;
4045 break;
4046 }
4047
4048 /*
4049 * Since we don't compress the data in Dex, expect to see equal
4050 * width of data stored in the table and expected from the array
4051 * class.
4052 */
4053 if (arrayData[1] != elemWidth) {
4054 LOG_VFY("VFY: array-data size mismatch (%d vs %d)\n",
4055 arrayData[1], elemWidth);
Andy McFadden62a75162009-04-17 17:23:37 -07004056 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004057 }
4058 }
4059 break;
4060
4061 case OP_IF_EQ:
4062 case OP_IF_NE:
4063 {
4064 RegType type1, type2;
4065 bool tmpResult;
4066
Andy McFadden62a75162009-04-17 17:23:37 -07004067 type1 = getRegisterType(workRegs, insnRegCount, decInsn.vA,
4068 &failure);
4069 type2 = getRegisterType(workRegs, insnRegCount, decInsn.vB,
4070 &failure);
4071 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004072 break;
4073
4074 /* both references? */
4075 if (regTypeIsReference(type1) && regTypeIsReference(type2))
4076 break;
4077
4078 /* both category-1nr? */
Andy McFadden62a75162009-04-17 17:23:37 -07004079 checkTypeCategory(type1, kTypeCategory1nr, &failure);
4080 checkTypeCategory(type2, kTypeCategory1nr, &failure);
4081 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004082 LOG_VFY("VFY: args to if-eq/if-ne must both be refs or cat1\n");
4083 break;
4084 }
4085 }
4086 break;
4087 case OP_IF_LT:
4088 case OP_IF_GE:
4089 case OP_IF_GT:
4090 case OP_IF_LE:
Andy McFadden62a75162009-04-17 17:23:37 -07004091 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4092 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004093 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004094 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
4095 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004096 LOG_VFY("VFY: args to 'if' must be cat-1nr\n");
4097 break;
4098 }
Andy McFadden62a75162009-04-17 17:23:37 -07004099 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vB, &failure);
4100 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004101 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004102 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
4103 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004104 LOG_VFY("VFY: args to 'if' must be cat-1nr\n");
4105 break;
4106 }
4107 break;
4108 case OP_IF_EQZ:
4109 case OP_IF_NEZ:
Andy McFadden62a75162009-04-17 17:23:37 -07004110 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4111 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004112 break;
4113 if (regTypeIsReference(tmpType))
4114 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004115 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
4116 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004117 LOG_VFY("VFY: expected cat-1 arg to if\n");
4118 break;
4119 case OP_IF_LTZ:
4120 case OP_IF_GEZ:
4121 case OP_IF_GTZ:
4122 case OP_IF_LEZ:
Andy McFadden62a75162009-04-17 17:23:37 -07004123 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4124 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004125 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004126 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
4127 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004128 LOG_VFY("VFY: expected cat-1 arg to if\n");
4129 break;
4130
4131 case OP_AGET:
4132 tmpType = kRegTypeInteger;
4133 goto aget_1nr_common;
4134 case OP_AGET_BOOLEAN:
4135 tmpType = kRegTypeBoolean;
4136 goto aget_1nr_common;
4137 case OP_AGET_BYTE:
4138 tmpType = kRegTypeByte;
4139 goto aget_1nr_common;
4140 case OP_AGET_CHAR:
4141 tmpType = kRegTypeChar;
4142 goto aget_1nr_common;
4143 case OP_AGET_SHORT:
4144 tmpType = kRegTypeShort;
4145 goto aget_1nr_common;
4146aget_1nr_common:
4147 {
4148 RegType srcType, indexType;
4149
4150 indexType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004151 &failure);
4152 checkArrayIndexType(meth, indexType, &failure);
4153 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004154 break;
4155
4156 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004157 decInsn.vB, &failure);
4158 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004159 break;
4160 if (resClass != NULL) {
4161 /* verify the class */
4162 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4163 resClass->elementClass->primitiveType == PRIM_NOT)
4164 {
4165 LOG_VFY("VFY: invalid aget-1nr target %s\n",
4166 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004167 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004168 break;
4169 }
4170
4171 /* make sure array type matches instruction */
4172 srcType = primitiveTypeToRegType(
4173 resClass->elementClass->primitiveType);
4174
4175 if (!checkFieldArrayStore1nr(tmpType, srcType)) {
4176 LOG_VFY("VFY: invalid aget-1nr, array type=%d with"
4177 " inst type=%d (on %s)\n",
4178 srcType, tmpType, resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004179 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004180 break;
4181 }
4182
4183 }
4184 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004185 tmpType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004186 }
4187 break;
4188
4189 case OP_AGET_WIDE:
4190 {
4191 RegType dstType, indexType;
4192
4193 indexType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004194 &failure);
4195 checkArrayIndexType(meth, indexType, &failure);
4196 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004197 break;
4198
4199 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004200 decInsn.vB, &failure);
4201 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004202 break;
4203 if (resClass != NULL) {
4204 /* verify the class */
4205 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4206 resClass->elementClass->primitiveType == PRIM_NOT)
4207 {
4208 LOG_VFY("VFY: invalid aget-wide target %s\n",
4209 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004210 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004211 break;
4212 }
4213
4214 /* try to refine "dstType" */
4215 switch (resClass->elementClass->primitiveType) {
4216 case PRIM_LONG:
4217 dstType = kRegTypeLongLo;
4218 break;
4219 case PRIM_DOUBLE:
4220 dstType = kRegTypeDoubleLo;
4221 break;
4222 default:
4223 LOG_VFY("VFY: invalid aget-wide on %s\n",
4224 resClass->descriptor);
4225 dstType = kRegTypeUnknown;
Andy McFadden62a75162009-04-17 17:23:37 -07004226 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004227 break;
4228 }
4229 } else {
4230 /*
4231 * Null array ref; this code path will fail at runtime. We
4232 * know this is either long or double, and we don't really
4233 * discriminate between those during verification, so we
4234 * call it a long.
4235 */
4236 dstType = kRegTypeLongLo;
4237 }
4238 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004239 dstType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004240 }
4241 break;
4242
4243 case OP_AGET_OBJECT:
4244 {
4245 RegType dstType, indexType;
4246
4247 indexType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004248 &failure);
4249 checkArrayIndexType(meth, indexType, &failure);
4250 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004251 break;
4252
4253 /* get the class of the array we're pulling an object from */
4254 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004255 decInsn.vB, &failure);
4256 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004257 break;
4258 if (resClass != NULL) {
4259 ClassObject* elementClass;
4260
4261 assert(resClass != NULL);
4262 if (!dvmIsArrayClass(resClass)) {
4263 LOG_VFY("VFY: aget-object on non-array class\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004264 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004265 break;
4266 }
4267 assert(resClass->elementClass != NULL);
4268
4269 /*
4270 * Find the element class. resClass->elementClass indicates
4271 * the basic type, which won't be what we want for a
4272 * multi-dimensional array.
4273 */
4274 if (resClass->descriptor[1] == '[') {
4275 assert(resClass->arrayDim > 1);
4276 elementClass = dvmFindArrayClass(&resClass->descriptor[1],
4277 resClass->classLoader);
4278 } else if (resClass->descriptor[1] == 'L') {
4279 assert(resClass->arrayDim == 1);
4280 elementClass = resClass->elementClass;
4281 } else {
4282 LOG_VFY("VFY: aget-object on non-ref array class (%s)\n",
4283 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004284 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004285 break;
4286 }
4287
4288 dstType = regTypeFromClass(elementClass);
4289 } else {
4290 /*
4291 * The array reference is NULL, so the current code path will
4292 * throw an exception. For proper merging with later code
4293 * paths, and correct handling of "if-eqz" tests on the
4294 * result of the array get, we want to treat this as a null
4295 * reference.
4296 */
4297 dstType = kRegTypeZero;
4298 }
4299 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004300 dstType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004301 }
4302 break;
4303 case OP_APUT:
4304 tmpType = kRegTypeInteger;
4305 goto aput_1nr_common;
4306 case OP_APUT_BOOLEAN:
4307 tmpType = kRegTypeBoolean;
4308 goto aput_1nr_common;
4309 case OP_APUT_BYTE:
4310 tmpType = kRegTypeByte;
4311 goto aput_1nr_common;
4312 case OP_APUT_CHAR:
4313 tmpType = kRegTypeChar;
4314 goto aput_1nr_common;
4315 case OP_APUT_SHORT:
4316 tmpType = kRegTypeShort;
4317 goto aput_1nr_common;
4318aput_1nr_common:
4319 {
4320 RegType srcType, dstType, indexType;
4321
4322 indexType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004323 &failure);
4324 checkArrayIndexType(meth, indexType, &failure);
4325 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004326 break;
4327
4328 /* make sure the source register has the correct type */
4329 srcType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004330 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004331 if (!canConvertTo1nr(srcType, tmpType)) {
4332 LOG_VFY("VFY: invalid reg type %d on aput instr (need %d)\n",
4333 srcType, tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07004334 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004335 break;
4336 }
4337
4338 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004339 decInsn.vB, &failure);
4340 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004341 break;
4342
4343 /* resClass can be null if the reg type is Zero */
4344 if (resClass == NULL)
4345 break;
4346
4347 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4348 resClass->elementClass->primitiveType == PRIM_NOT)
4349 {
4350 LOG_VFY("VFY: invalid aput-1nr on %s\n", resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004351 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004352 break;
4353 }
4354
4355 /* verify that instruction matches array */
4356 dstType = primitiveTypeToRegType(
4357 resClass->elementClass->primitiveType);
4358 assert(dstType != kRegTypeUnknown);
4359
4360 if (!checkFieldArrayStore1nr(tmpType, dstType)) {
4361 LOG_VFY("VFY: invalid aput-1nr on %s (inst=%d dst=%d)\n",
4362 resClass->descriptor, tmpType, dstType);
Andy McFadden62a75162009-04-17 17:23:37 -07004363 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004364 break;
4365 }
4366 }
4367 break;
4368 case OP_APUT_WIDE:
4369 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004370 &failure);
4371 checkArrayIndexType(meth, tmpType, &failure);
4372 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004373 break;
4374
Andy McFadden62a75162009-04-17 17:23:37 -07004375 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4376 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004377 RegType typeHi =
Andy McFadden62a75162009-04-17 17:23:37 -07004378 getRegisterType(workRegs, insnRegCount, decInsn.vA+1, &failure);
4379 checkTypeCategory(tmpType, kTypeCategory2, &failure);
4380 checkWidePair(tmpType, typeHi, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004381 }
Andy McFadden62a75162009-04-17 17:23:37 -07004382 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004383 break;
4384
4385 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004386 decInsn.vB, &failure);
4387 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004388 break;
4389 if (resClass != NULL) {
4390 /* verify the class and try to refine "dstType" */
4391 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4392 resClass->elementClass->primitiveType == PRIM_NOT)
4393 {
4394 LOG_VFY("VFY: invalid aput-wide on %s\n",
4395 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004396 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004397 break;
4398 }
4399
4400 switch (resClass->elementClass->primitiveType) {
4401 case PRIM_LONG:
4402 case PRIM_DOUBLE:
4403 /* these are okay */
4404 break;
4405 default:
4406 LOG_VFY("VFY: invalid aput-wide on %s\n",
4407 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004408 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004409 break;
4410 }
4411 }
4412 break;
4413 case OP_APUT_OBJECT:
4414 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004415 &failure);
4416 checkArrayIndexType(meth, tmpType, &failure);
4417 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004418 break;
4419
4420 /* get the ref we're storing; Zero is okay, Uninit is not */
4421 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004422 decInsn.vA, &failure);
4423 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004424 break;
4425 if (resClass != NULL) {
4426 ClassObject* arrayClass;
4427 ClassObject* elementClass;
4428
4429 /*
4430 * Get the array class. If the array ref is null, we won't
4431 * have type information (and we'll crash at runtime with a
4432 * null pointer exception).
4433 */
4434 arrayClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004435 decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004436
4437 if (arrayClass != NULL) {
4438 /* see if the array holds a compatible type */
4439 if (!dvmIsArrayClass(arrayClass)) {
4440 LOG_VFY("VFY: invalid aput-object on %s\n",
4441 arrayClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004442 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004443 break;
4444 }
4445
4446 /*
4447 * Find the element class. resClass->elementClass indicates
4448 * the basic type, which won't be what we want for a
4449 * multi-dimensional array.
4450 *
4451 * All we want to check here is that the element type is a
4452 * reference class. We *don't* check instanceof here, because
4453 * you can still put a String into a String[] after the latter
4454 * has been cast to an Object[].
4455 */
4456 if (arrayClass->descriptor[1] == '[') {
4457 assert(arrayClass->arrayDim > 1);
4458 elementClass = dvmFindArrayClass(&arrayClass->descriptor[1],
4459 arrayClass->classLoader);
4460 } else {
4461 assert(arrayClass->arrayDim == 1);
4462 elementClass = arrayClass->elementClass;
4463 }
4464 if (elementClass->primitiveType != PRIM_NOT) {
4465 LOG_VFY("VFY: invalid aput-object of %s into %s\n",
4466 resClass->descriptor, arrayClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004467 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004468 break;
4469 }
4470 }
4471 }
4472 break;
4473
4474 case OP_IGET:
4475 tmpType = kRegTypeInteger;
4476 goto iget_1nr_common;
4477 case OP_IGET_BOOLEAN:
4478 tmpType = kRegTypeBoolean;
4479 goto iget_1nr_common;
4480 case OP_IGET_BYTE:
4481 tmpType = kRegTypeByte;
4482 goto iget_1nr_common;
4483 case OP_IGET_CHAR:
4484 tmpType = kRegTypeChar;
4485 goto iget_1nr_common;
4486 case OP_IGET_SHORT:
4487 tmpType = kRegTypeShort;
4488 goto iget_1nr_common;
4489iget_1nr_common:
4490 {
4491 ClassObject* fieldClass;
4492 InstField* instField;
4493 RegType objType, fieldType;
4494
4495 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004496 &failure);
4497 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004498 break;
4499 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004500 &failure);
4501 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004502 break;
4503
4504 /* make sure the field's type is compatible with expectation */
4505 fieldType = primSigCharToRegType(instField->field.signature[0]);
4506 if (fieldType == kRegTypeUnknown ||
4507 !checkFieldArrayStore1nr(tmpType, fieldType))
4508 {
4509 LOG_VFY("VFY: invalid iget-1nr of %s.%s (inst=%d field=%d)\n",
4510 instField->field.clazz->descriptor,
4511 instField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004512 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004513 break;
4514 }
4515
Andy McFadden62a75162009-04-17 17:23:37 -07004516 setRegisterType(workRegs, insnRegCount, decInsn.vA, tmpType,
4517 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004518 }
4519 break;
4520 case OP_IGET_WIDE:
Andy McFadden861b3382010-03-05 15:58:31 -08004521 case OP_IGET_WIDE_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004522 {
4523 RegType dstType;
4524 ClassObject* fieldClass;
4525 InstField* instField;
4526 RegType objType;
4527
4528 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004529 &failure);
4530 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004531 break;
4532 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004533 &failure);
4534 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004535 break;
4536 /* check the type, which should be prim */
4537 switch (instField->field.signature[0]) {
4538 case 'D':
4539 dstType = kRegTypeDoubleLo;
4540 break;
4541 case 'J':
4542 dstType = kRegTypeLongLo;
4543 break;
4544 default:
4545 LOG_VFY("VFY: invalid iget-wide of %s.%s\n",
4546 instField->field.clazz->descriptor,
4547 instField->field.name);
4548 dstType = kRegTypeUnknown;
Andy McFadden62a75162009-04-17 17:23:37 -07004549 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004550 break;
4551 }
Andy McFadden62a75162009-04-17 17:23:37 -07004552 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004553 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004554 dstType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004555 }
Andy McFadden861b3382010-03-05 15:58:31 -08004556 if (VERIFY_OK(failure)) {
4557 if (decInsn.opCode != OP_IGET_WIDE_VOLATILE &&
4558 dvmIsVolatileField(&instField->field))
4559 {
4560 replaceVolatileInstruction(meth, insnFlags, insnIdx);
4561 }
4562 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004563 }
4564 break;
4565 case OP_IGET_OBJECT:
4566 {
4567 ClassObject* fieldClass;
4568 InstField* instField;
4569 RegType objType;
4570
4571 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004572 &failure);
4573 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004574 break;
4575 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004576 &failure);
4577 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004578 break;
4579 fieldClass = getFieldClass(meth, &instField->field);
4580 if (fieldClass == NULL) {
4581 /* class not found or primitive type */
4582 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4583 instField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004584 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004585 break;
4586 }
Andy McFadden62a75162009-04-17 17:23:37 -07004587 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004588 assert(!dvmIsPrimitiveClass(fieldClass));
4589 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004590 regTypeFromClass(fieldClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004591 }
4592 }
4593 break;
4594 case OP_IPUT:
4595 tmpType = kRegTypeInteger;
4596 goto iput_1nr_common;
4597 case OP_IPUT_BOOLEAN:
4598 tmpType = kRegTypeBoolean;
4599 goto iput_1nr_common;
4600 case OP_IPUT_BYTE:
4601 tmpType = kRegTypeByte;
4602 goto iput_1nr_common;
4603 case OP_IPUT_CHAR:
4604 tmpType = kRegTypeChar;
4605 goto iput_1nr_common;
4606 case OP_IPUT_SHORT:
4607 tmpType = kRegTypeShort;
4608 goto iput_1nr_common;
4609iput_1nr_common:
4610 {
4611 RegType srcType, fieldType, objType;
4612 ClassObject* fieldClass;
4613 InstField* instField;
4614
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004615 srcType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004616 &failure);
Andy McFaddenb5f64bc2009-06-10 14:11:07 -07004617
4618 /*
4619 * javac generates synthetic functions that write byte values
4620 * into boolean fields.
4621 */
4622 if (tmpType == kRegTypeBoolean && srcType == kRegTypeByte)
4623 srcType = kRegTypeBoolean;
4624
4625 /* make sure the source register has the correct type */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004626 if (!canConvertTo1nr(srcType, tmpType)) {
4627 LOG_VFY("VFY: invalid reg type %d on iput instr (need %d)\n",
4628 srcType, tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07004629 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004630 break;
4631 }
4632
4633 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004634 &failure);
4635 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004636 break;
4637 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004638 &failure);
4639 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004640 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004641 checkFinalFieldAccess(meth, &instField->field, &failure);
4642 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004643 break;
4644
4645 /* get type of field we're storing into */
4646 fieldType = primSigCharToRegType(instField->field.signature[0]);
4647 if (fieldType == kRegTypeUnknown ||
4648 !checkFieldArrayStore1nr(tmpType, fieldType))
4649 {
4650 LOG_VFY("VFY: invalid iput-1nr of %s.%s (inst=%d field=%d)\n",
4651 instField->field.clazz->descriptor,
4652 instField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004653 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004654 break;
4655 }
4656 }
4657 break;
4658 case OP_IPUT_WIDE:
Andy McFadden861b3382010-03-05 15:58:31 -08004659 case OP_IPUT_WIDE_VOLATILE:
Andy McFadden62a75162009-04-17 17:23:37 -07004660 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4661 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004662 RegType typeHi =
Andy McFadden62a75162009-04-17 17:23:37 -07004663 getRegisterType(workRegs, insnRegCount, decInsn.vA+1, &failure);
4664 checkTypeCategory(tmpType, kTypeCategory2, &failure);
4665 checkWidePair(tmpType, typeHi, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004666 }
Andy McFadden62a75162009-04-17 17:23:37 -07004667 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004668 ClassObject* fieldClass;
4669 InstField* instField;
4670 RegType objType;
4671
4672 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004673 &failure);
4674 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004675 break;
4676 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004677 &failure);
4678 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004679 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004680 checkFinalFieldAccess(meth, &instField->field, &failure);
4681 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004682 break;
4683
4684 /* check the type, which should be prim */
4685 switch (instField->field.signature[0]) {
4686 case 'D':
4687 case 'J':
4688 /* these are okay (and interchangeable) */
4689 break;
4690 default:
4691 LOG_VFY("VFY: invalid iput-wide of %s.%s\n",
4692 instField->field.clazz->descriptor,
4693 instField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07004694 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004695 break;
4696 }
Andy McFadden861b3382010-03-05 15:58:31 -08004697 if (VERIFY_OK(failure)) {
4698 if (decInsn.opCode != OP_IPUT_WIDE_VOLATILE &&
4699 dvmIsVolatileField(&instField->field))
4700 {
4701 replaceVolatileInstruction(meth, insnFlags, insnIdx);
4702 }
4703 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004704 }
4705 break;
4706 case OP_IPUT_OBJECT:
4707 {
4708 ClassObject* fieldClass;
4709 ClassObject* valueClass;
4710 InstField* instField;
4711 RegType objType, valueType;
4712
4713 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004714 &failure);
4715 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004716 break;
4717 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004718 &failure);
4719 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004720 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004721 checkFinalFieldAccess(meth, &instField->field, &failure);
4722 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004723 break;
4724
4725 fieldClass = getFieldClass(meth, &instField->field);
4726 if (fieldClass == NULL) {
4727 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4728 instField->field.signature);
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
4733 valueType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004734 &failure);
4735 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004736 break;
4737 if (!regTypeIsReference(valueType)) {
4738 LOG_VFY("VFY: storing non-ref v%d into ref field '%s' (%s)\n",
4739 decInsn.vA, instField->field.name,
4740 fieldClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004741 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004742 break;
4743 }
4744 if (valueType != kRegTypeZero) {
4745 valueClass = regTypeInitializedReferenceToClass(valueType);
4746 if (valueClass == NULL) {
4747 LOG_VFY("VFY: storing uninit ref v%d into ref field\n",
4748 decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07004749 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004750 break;
4751 }
4752 /* allow if field is any interface or field is base class */
4753 if (!dvmIsInterfaceClass(fieldClass) &&
4754 !dvmInstanceof(valueClass, fieldClass))
4755 {
4756 LOG_VFY("VFY: storing type '%s' into field type '%s' (%s.%s)\n",
4757 valueClass->descriptor, fieldClass->descriptor,
4758 instField->field.clazz->descriptor,
4759 instField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07004760 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004761 break;
4762 }
4763 }
4764 }
4765 break;
4766
4767 case OP_SGET:
4768 tmpType = kRegTypeInteger;
4769 goto sget_1nr_common;
4770 case OP_SGET_BOOLEAN:
4771 tmpType = kRegTypeBoolean;
4772 goto sget_1nr_common;
4773 case OP_SGET_BYTE:
4774 tmpType = kRegTypeByte;
4775 goto sget_1nr_common;
4776 case OP_SGET_CHAR:
4777 tmpType = kRegTypeChar;
4778 goto sget_1nr_common;
4779 case OP_SGET_SHORT:
4780 tmpType = kRegTypeShort;
4781 goto sget_1nr_common;
4782sget_1nr_common:
4783 {
4784 StaticField* staticField;
4785 RegType fieldType;
4786
Andy McFadden62a75162009-04-17 17:23:37 -07004787 staticField = getStaticField(meth, decInsn.vB, &failure);
4788 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004789 break;
4790
4791 /*
4792 * Make sure the field's type is compatible with expectation.
4793 * We can get ourselves into trouble if we mix & match loads
4794 * and stores with different widths, so rather than just checking
4795 * "canConvertTo1nr" we require that the field types have equal
4796 * widths. (We can't generally require an exact type match,
4797 * because e.g. "int" and "float" are interchangeable.)
4798 */
4799 fieldType = primSigCharToRegType(staticField->field.signature[0]);
4800 if (!checkFieldArrayStore1nr(tmpType, fieldType)) {
4801 LOG_VFY("VFY: invalid sget-1nr of %s.%s (inst=%d actual=%d)\n",
4802 staticField->field.clazz->descriptor,
4803 staticField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004804 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004805 break;
4806 }
4807
Andy McFadden62a75162009-04-17 17:23:37 -07004808 setRegisterType(workRegs, insnRegCount, decInsn.vA, tmpType,
4809 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004810 }
4811 break;
4812 case OP_SGET_WIDE:
Andy McFadden861b3382010-03-05 15:58:31 -08004813 case OP_SGET_WIDE_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004814 {
4815 StaticField* staticField;
4816 RegType dstType;
4817
Andy McFadden62a75162009-04-17 17:23:37 -07004818 staticField = getStaticField(meth, decInsn.vB, &failure);
4819 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004820 break;
4821 /* check the type, which should be prim */
4822 switch (staticField->field.signature[0]) {
4823 case 'D':
4824 dstType = kRegTypeDoubleLo;
4825 break;
4826 case 'J':
4827 dstType = kRegTypeLongLo;
4828 break;
4829 default:
4830 LOG_VFY("VFY: invalid sget-wide of %s.%s\n",
4831 staticField->field.clazz->descriptor,
4832 staticField->field.name);
4833 dstType = kRegTypeUnknown;
Andy McFadden62a75162009-04-17 17:23:37 -07004834 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004835 break;
4836 }
Andy McFadden62a75162009-04-17 17:23:37 -07004837 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004838 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004839 dstType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004840 }
Andy McFadden861b3382010-03-05 15:58:31 -08004841 if (VERIFY_OK(failure)) {
4842 if (decInsn.opCode != OP_SGET_WIDE_VOLATILE &&
4843 dvmIsVolatileField(&staticField->field))
4844 {
4845 replaceVolatileInstruction(meth, insnFlags, insnIdx);
4846 }
4847 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004848 }
4849 break;
4850 case OP_SGET_OBJECT:
4851 {
4852 StaticField* staticField;
4853 ClassObject* fieldClass;
4854
Andy McFadden62a75162009-04-17 17:23:37 -07004855 staticField = getStaticField(meth, decInsn.vB, &failure);
4856 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004857 break;
4858 fieldClass = getFieldClass(meth, &staticField->field);
4859 if (fieldClass == NULL) {
4860 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4861 staticField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004862 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004863 break;
4864 }
4865 if (dvmIsPrimitiveClass(fieldClass)) {
4866 LOG_VFY("VFY: attempt to get prim field with sget-object\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004867 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004868 break;
4869 }
4870 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004871 regTypeFromClass(fieldClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004872 }
4873 break;
4874 case OP_SPUT:
4875 tmpType = kRegTypeInteger;
4876 goto sput_1nr_common;
4877 case OP_SPUT_BOOLEAN:
4878 tmpType = kRegTypeBoolean;
4879 goto sput_1nr_common;
4880 case OP_SPUT_BYTE:
4881 tmpType = kRegTypeByte;
4882 goto sput_1nr_common;
4883 case OP_SPUT_CHAR:
4884 tmpType = kRegTypeChar;
4885 goto sput_1nr_common;
4886 case OP_SPUT_SHORT:
4887 tmpType = kRegTypeShort;
4888 goto sput_1nr_common;
4889sput_1nr_common:
4890 {
4891 RegType srcType, fieldType;
4892 StaticField* staticField;
4893
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004894 srcType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004895 &failure);
Andy McFaddenb5f64bc2009-06-10 14:11:07 -07004896
4897 /*
4898 * javac generates synthetic functions that write byte values
4899 * into boolean fields.
4900 */
4901 if (tmpType == kRegTypeBoolean && srcType == kRegTypeByte)
4902 srcType = kRegTypeBoolean;
4903
4904 /* make sure the source register has the correct type */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004905 if (!canConvertTo1nr(srcType, tmpType)) {
Andy McFaddenb5f64bc2009-06-10 14:11:07 -07004906 LOG_VFY("VFY: invalid reg type %d on sput instr (need %d)\n",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004907 srcType, tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07004908 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004909 break;
4910 }
4911
Andy McFadden62a75162009-04-17 17:23:37 -07004912 staticField = getStaticField(meth, decInsn.vB, &failure);
4913 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004914 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004915 checkFinalFieldAccess(meth, &staticField->field, &failure);
4916 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004917 break;
4918
4919 /*
4920 * Get type of field we're storing into. We know that the
4921 * contents of the register match the instruction, but we also
4922 * need to ensure that the instruction matches the field type.
4923 * Using e.g. sput-short to write into a 32-bit integer field
4924 * can lead to trouble if we do 16-bit writes.
4925 */
4926 fieldType = primSigCharToRegType(staticField->field.signature[0]);
4927 if (!checkFieldArrayStore1nr(tmpType, fieldType)) {
4928 LOG_VFY("VFY: invalid sput-1nr of %s.%s (inst=%d actual=%d)\n",
4929 staticField->field.clazz->descriptor,
4930 staticField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004931 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004932 break;
4933 }
4934 }
4935 break;
4936 case OP_SPUT_WIDE:
Andy McFadden861b3382010-03-05 15:58:31 -08004937 case OP_SPUT_WIDE_VOLATILE:
Andy McFadden62a75162009-04-17 17:23:37 -07004938 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4939 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004940 RegType typeHi =
Andy McFadden62a75162009-04-17 17:23:37 -07004941 getRegisterType(workRegs, insnRegCount, decInsn.vA+1, &failure);
4942 checkTypeCategory(tmpType, kTypeCategory2, &failure);
4943 checkWidePair(tmpType, typeHi, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004944 }
Andy McFadden62a75162009-04-17 17:23:37 -07004945 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004946 StaticField* staticField;
4947
Andy McFadden62a75162009-04-17 17:23:37 -07004948 staticField = getStaticField(meth, decInsn.vB, &failure);
4949 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004950 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004951 checkFinalFieldAccess(meth, &staticField->field, &failure);
4952 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004953 break;
4954
4955 /* check the type, which should be prim */
4956 switch (staticField->field.signature[0]) {
4957 case 'D':
4958 case 'J':
4959 /* these are okay */
4960 break;
4961 default:
4962 LOG_VFY("VFY: invalid sput-wide of %s.%s\n",
4963 staticField->field.clazz->descriptor,
4964 staticField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07004965 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004966 break;
4967 }
Andy McFadden861b3382010-03-05 15:58:31 -08004968 if (VERIFY_OK(failure)) {
4969 if (decInsn.opCode != OP_SPUT_WIDE_VOLATILE &&
4970 dvmIsVolatileField(&staticField->field))
4971 {
4972 replaceVolatileInstruction(meth, insnFlags, insnIdx);
4973 }
4974 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004975 }
4976 break;
4977 case OP_SPUT_OBJECT:
4978 {
4979 ClassObject* fieldClass;
4980 ClassObject* valueClass;
4981 StaticField* staticField;
4982 RegType valueType;
4983
Andy McFadden62a75162009-04-17 17:23:37 -07004984 staticField = getStaticField(meth, decInsn.vB, &failure);
4985 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004986 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004987 checkFinalFieldAccess(meth, &staticField->field, &failure);
4988 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004989 break;
4990
4991 fieldClass = getFieldClass(meth, &staticField->field);
4992 if (fieldClass == NULL) {
4993 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4994 staticField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004995 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004996 break;
4997 }
4998
4999 valueType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07005000 &failure);
5001 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005002 break;
5003 if (!regTypeIsReference(valueType)) {
5004 LOG_VFY("VFY: storing non-ref v%d into ref field '%s' (%s)\n",
5005 decInsn.vA, staticField->field.name,
5006 fieldClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07005007 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005008 break;
5009 }
5010 if (valueType != kRegTypeZero) {
5011 valueClass = regTypeInitializedReferenceToClass(valueType);
5012 if (valueClass == NULL) {
5013 LOG_VFY("VFY: storing uninit ref v%d into ref field\n",
5014 decInsn.vA);
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 /* allow if field is any interface or field is base class */
5019 if (!dvmIsInterfaceClass(fieldClass) &&
5020 !dvmInstanceof(valueClass, fieldClass))
5021 {
5022 LOG_VFY("VFY: storing type '%s' into field type '%s' (%s.%s)\n",
5023 valueClass->descriptor, fieldClass->descriptor,
5024 staticField->field.clazz->descriptor,
5025 staticField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07005026 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005027 break;
5028 }
5029 }
5030 }
5031 break;
5032
5033 case OP_INVOKE_VIRTUAL:
5034 case OP_INVOKE_VIRTUAL_RANGE:
5035 case OP_INVOKE_SUPER:
5036 case OP_INVOKE_SUPER_RANGE:
5037 {
5038 Method* calledMethod;
5039 RegType returnType;
5040 bool isRange;
5041 bool isSuper;
5042
5043 isRange = (decInsn.opCode == OP_INVOKE_VIRTUAL_RANGE ||
5044 decInsn.opCode == OP_INVOKE_SUPER_RANGE);
5045 isSuper = (decInsn.opCode == OP_INVOKE_SUPER ||
5046 decInsn.opCode == OP_INVOKE_SUPER_RANGE);
5047
5048 calledMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
5049 &decInsn, uninitMap, METHOD_VIRTUAL, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07005050 isSuper, &failure);
5051 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005052 break;
5053 returnType = getMethodReturnType(calledMethod);
Andy McFadden62a75162009-04-17 17:23:37 -07005054 setResultRegisterType(workRegs, insnRegCount, returnType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005055 justSetResult = true;
5056 }
5057 break;
5058 case OP_INVOKE_DIRECT:
5059 case OP_INVOKE_DIRECT_RANGE:
5060 {
5061 RegType returnType;
5062 Method* calledMethod;
5063 bool isRange;
5064
5065 isRange = (decInsn.opCode == OP_INVOKE_DIRECT_RANGE);
5066 calledMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
5067 &decInsn, uninitMap, METHOD_DIRECT, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07005068 false, &failure);
5069 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005070 break;
5071
5072 /*
5073 * Some additional checks when calling <init>. We know from
5074 * the invocation arg check that the "this" argument is an
5075 * instance of calledMethod->clazz. Now we further restrict
5076 * that to require that calledMethod->clazz is the same as
5077 * this->clazz or this->super, allowing the latter only if
5078 * the "this" argument is the same as the "this" argument to
5079 * this method (which implies that we're in <init> ourselves).
5080 */
5081 if (isInitMethod(calledMethod)) {
5082 RegType thisType;
5083 thisType = getInvocationThis(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07005084 &decInsn, &failure);
5085 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005086 break;
5087
5088 /* no null refs allowed (?) */
5089 if (thisType == kRegTypeZero) {
5090 LOG_VFY("VFY: unable to initialize null ref\n");
Andy McFadden62a75162009-04-17 17:23:37 -07005091 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005092 break;
5093 }
5094
5095 ClassObject* thisClass;
5096
5097 thisClass = regTypeReferenceToClass(thisType, uninitMap);
5098 assert(thisClass != NULL);
5099
5100 /* must be in same class or in superclass */
5101 if (calledMethod->clazz == thisClass->super) {
5102 if (thisClass != meth->clazz) {
5103 LOG_VFY("VFY: invoke-direct <init> on super only "
5104 "allowed for 'this' in <init>");
Andy McFadden62a75162009-04-17 17:23:37 -07005105 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005106 break;
5107 }
5108 } else if (calledMethod->clazz != thisClass) {
5109 LOG_VFY("VFY: invoke-direct <init> must be on current "
5110 "class or super\n");
Andy McFadden62a75162009-04-17 17:23:37 -07005111 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005112 break;
5113 }
5114
5115 /* arg must be an uninitialized reference */
5116 if (!regTypeIsUninitReference(thisType)) {
5117 LOG_VFY("VFY: can only initialize the uninitialized\n");
Andy McFadden62a75162009-04-17 17:23:37 -07005118 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005119 break;
5120 }
5121
5122 /*
5123 * Replace the uninitialized reference with an initialized
5124 * one, and clear the entry in the uninit map. We need to
5125 * do this for all registers that have the same object
5126 * instance in them, not just the "this" register.
5127 */
5128 int uidx = regTypeToUninitIndex(thisType);
5129 markRefsAsInitialized(workRegs, insnRegCount, uninitMap,
Andy McFadden62a75162009-04-17 17:23:37 -07005130 thisType, &failure);
5131 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005132 break;
5133 }
5134 returnType = getMethodReturnType(calledMethod);
5135 setResultRegisterType(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07005136 returnType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005137 justSetResult = true;
5138 }
5139 break;
5140 case OP_INVOKE_STATIC:
5141 case OP_INVOKE_STATIC_RANGE:
5142 {
5143 RegType returnType;
5144 Method* calledMethod;
5145 bool isRange;
5146
5147 isRange = (decInsn.opCode == OP_INVOKE_STATIC_RANGE);
5148 calledMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
5149 &decInsn, uninitMap, METHOD_STATIC, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07005150 false, &failure);
5151 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005152 break;
5153
5154 returnType = getMethodReturnType(calledMethod);
Andy McFadden62a75162009-04-17 17:23:37 -07005155 setResultRegisterType(workRegs, insnRegCount, returnType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005156 justSetResult = true;
5157 }
5158 break;
5159 case OP_INVOKE_INTERFACE:
5160 case OP_INVOKE_INTERFACE_RANGE:
5161 {
5162 RegType /*thisType,*/ returnType;
5163 Method* absMethod;
5164 bool isRange;
5165
5166 isRange = (decInsn.opCode == OP_INVOKE_INTERFACE_RANGE);
5167 absMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
5168 &decInsn, uninitMap, METHOD_INTERFACE, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07005169 false, &failure);
5170 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005171 break;
5172
5173#if 0 /* can't do this here, fails on dalvik test 052-verifier-fun */
5174 /*
5175 * Get the type of the "this" arg, which should always be an
5176 * interface class. Because we don't do a full merge on
5177 * interface classes, this might have reduced to Object.
5178 */
5179 thisType = getInvocationThis(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07005180 &decInsn, &failure);
5181 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005182 break;
5183
5184 if (thisType == kRegTypeZero) {
5185 /* null pointer always passes (and always fails at runtime) */
5186 } else {
5187 ClassObject* thisClass;
5188
5189 thisClass = regTypeInitializedReferenceToClass(thisType);
5190 if (thisClass == NULL) {
5191 LOG_VFY("VFY: interface call on uninitialized\n");
Andy McFadden62a75162009-04-17 17:23:37 -07005192 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005193 break;
5194 }
5195
5196 /*
5197 * Either "thisClass" needs to be the interface class that
5198 * defined absMethod, or absMethod's class needs to be one
5199 * of the interfaces implemented by "thisClass". (Or, if
5200 * we couldn't complete the merge, this will be Object.)
5201 */
5202 if (thisClass != absMethod->clazz &&
5203 thisClass != gDvm.classJavaLangObject &&
5204 !dvmImplements(thisClass, absMethod->clazz))
5205 {
5206 LOG_VFY("VFY: unable to match absMethod '%s' with %s interfaces\n",
5207 absMethod->name, thisClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07005208 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005209 break;
5210 }
5211 }
5212#endif
5213
5214 /*
5215 * We don't have an object instance, so we can't find the
5216 * concrete method. However, all of the type information is
5217 * in the abstract method, so we're good.
5218 */
5219 returnType = getMethodReturnType(absMethod);
Andy McFadden62a75162009-04-17 17:23:37 -07005220 setResultRegisterType(workRegs, insnRegCount, returnType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005221 justSetResult = true;
5222 }
5223 break;
5224
5225 case OP_NEG_INT:
5226 case OP_NOT_INT:
5227 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005228 kRegTypeInteger, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005229 break;
5230 case OP_NEG_LONG:
5231 case OP_NOT_LONG:
5232 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005233 kRegTypeLongLo, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005234 break;
5235 case OP_NEG_FLOAT:
5236 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005237 kRegTypeFloat, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005238 break;
5239 case OP_NEG_DOUBLE:
5240 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005241 kRegTypeDoubleLo, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005242 break;
5243 case OP_INT_TO_LONG:
5244 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005245 kRegTypeLongLo, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005246 break;
5247 case OP_INT_TO_FLOAT:
5248 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005249 kRegTypeFloat, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005250 break;
5251 case OP_INT_TO_DOUBLE:
5252 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005253 kRegTypeDoubleLo, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005254 break;
5255 case OP_LONG_TO_INT:
5256 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005257 kRegTypeInteger, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005258 break;
5259 case OP_LONG_TO_FLOAT:
5260 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005261 kRegTypeFloat, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005262 break;
5263 case OP_LONG_TO_DOUBLE:
5264 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005265 kRegTypeDoubleLo, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005266 break;
5267 case OP_FLOAT_TO_INT:
5268 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005269 kRegTypeInteger, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005270 break;
5271 case OP_FLOAT_TO_LONG:
5272 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005273 kRegTypeLongLo, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005274 break;
5275 case OP_FLOAT_TO_DOUBLE:
5276 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005277 kRegTypeDoubleLo, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005278 break;
5279 case OP_DOUBLE_TO_INT:
5280 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005281 kRegTypeInteger, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005282 break;
5283 case OP_DOUBLE_TO_LONG:
5284 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005285 kRegTypeLongLo, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005286 break;
5287 case OP_DOUBLE_TO_FLOAT:
5288 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005289 kRegTypeFloat, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005290 break;
5291 case OP_INT_TO_BYTE:
5292 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005293 kRegTypeByte, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005294 break;
5295 case OP_INT_TO_CHAR:
5296 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005297 kRegTypeChar, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005298 break;
5299 case OP_INT_TO_SHORT:
5300 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005301 kRegTypeShort, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005302 break;
5303
5304 case OP_ADD_INT:
5305 case OP_SUB_INT:
5306 case OP_MUL_INT:
5307 case OP_REM_INT:
5308 case OP_DIV_INT:
5309 case OP_SHL_INT:
5310 case OP_SHR_INT:
5311 case OP_USHR_INT:
5312 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005313 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005314 break;
5315 case OP_AND_INT:
5316 case OP_OR_INT:
5317 case OP_XOR_INT:
5318 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005319 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005320 break;
5321 case OP_ADD_LONG:
5322 case OP_SUB_LONG:
5323 case OP_MUL_LONG:
5324 case OP_DIV_LONG:
5325 case OP_REM_LONG:
5326 case OP_AND_LONG:
5327 case OP_OR_LONG:
5328 case OP_XOR_LONG:
5329 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005330 kRegTypeLongLo, kRegTypeLongLo, kRegTypeLongLo, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005331 break;
5332 case OP_SHL_LONG:
5333 case OP_SHR_LONG:
5334 case OP_USHR_LONG:
5335 /* shift distance is Int, making these different from other binops */
5336 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005337 kRegTypeLongLo, kRegTypeLongLo, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005338 break;
5339 case OP_ADD_FLOAT:
5340 case OP_SUB_FLOAT:
5341 case OP_MUL_FLOAT:
5342 case OP_DIV_FLOAT:
5343 case OP_REM_FLOAT:
5344 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005345 kRegTypeFloat, kRegTypeFloat, kRegTypeFloat, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005346 break;
5347 case OP_ADD_DOUBLE:
5348 case OP_SUB_DOUBLE:
5349 case OP_MUL_DOUBLE:
5350 case OP_DIV_DOUBLE:
5351 case OP_REM_DOUBLE:
5352 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005353 kRegTypeDoubleLo, kRegTypeDoubleLo, kRegTypeDoubleLo, false,
5354 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005355 break;
5356 case OP_ADD_INT_2ADDR:
5357 case OP_SUB_INT_2ADDR:
5358 case OP_MUL_INT_2ADDR:
5359 case OP_REM_INT_2ADDR:
5360 case OP_SHL_INT_2ADDR:
5361 case OP_SHR_INT_2ADDR:
5362 case OP_USHR_INT_2ADDR:
5363 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005364 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005365 break;
5366 case OP_AND_INT_2ADDR:
5367 case OP_OR_INT_2ADDR:
5368 case OP_XOR_INT_2ADDR:
5369 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005370 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005371 break;
5372 case OP_DIV_INT_2ADDR:
5373 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005374 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005375 break;
5376 case OP_ADD_LONG_2ADDR:
5377 case OP_SUB_LONG_2ADDR:
5378 case OP_MUL_LONG_2ADDR:
5379 case OP_DIV_LONG_2ADDR:
5380 case OP_REM_LONG_2ADDR:
5381 case OP_AND_LONG_2ADDR:
5382 case OP_OR_LONG_2ADDR:
5383 case OP_XOR_LONG_2ADDR:
5384 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005385 kRegTypeLongLo, kRegTypeLongLo, kRegTypeLongLo, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005386 break;
5387 case OP_SHL_LONG_2ADDR:
5388 case OP_SHR_LONG_2ADDR:
5389 case OP_USHR_LONG_2ADDR:
5390 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005391 kRegTypeLongLo, kRegTypeLongLo, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005392 break;
5393 case OP_ADD_FLOAT_2ADDR:
5394 case OP_SUB_FLOAT_2ADDR:
5395 case OP_MUL_FLOAT_2ADDR:
5396 case OP_DIV_FLOAT_2ADDR:
5397 case OP_REM_FLOAT_2ADDR:
5398 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005399 kRegTypeFloat, kRegTypeFloat, kRegTypeFloat, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005400 break;
5401 case OP_ADD_DOUBLE_2ADDR:
5402 case OP_SUB_DOUBLE_2ADDR:
5403 case OP_MUL_DOUBLE_2ADDR:
5404 case OP_DIV_DOUBLE_2ADDR:
5405 case OP_REM_DOUBLE_2ADDR:
5406 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005407 kRegTypeDoubleLo, kRegTypeDoubleLo, kRegTypeDoubleLo, false,
5408 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005409 break;
5410 case OP_ADD_INT_LIT16:
5411 case OP_RSUB_INT:
5412 case OP_MUL_INT_LIT16:
5413 case OP_DIV_INT_LIT16:
5414 case OP_REM_INT_LIT16:
5415 checkLitop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005416 kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005417 break;
5418 case OP_AND_INT_LIT16:
5419 case OP_OR_INT_LIT16:
5420 case OP_XOR_INT_LIT16:
5421 checkLitop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005422 kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005423 break;
5424 case OP_ADD_INT_LIT8:
5425 case OP_RSUB_INT_LIT8:
5426 case OP_MUL_INT_LIT8:
5427 case OP_DIV_INT_LIT8:
5428 case OP_REM_INT_LIT8:
5429 case OP_SHL_INT_LIT8:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005430 checkLitop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005431 kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005432 break;
Andy McFadden80d25ea2009-06-12 07:26:17 -07005433 case OP_SHR_INT_LIT8:
5434 tmpType = adjustForRightShift(workRegs, insnRegCount,
5435 decInsn.vB, decInsn.vC, false, &failure);
5436 checkLitop(workRegs, insnRegCount, &decInsn,
5437 tmpType, kRegTypeInteger, false, &failure);
5438 break;
5439 case OP_USHR_INT_LIT8:
5440 tmpType = adjustForRightShift(workRegs, insnRegCount,
5441 decInsn.vB, decInsn.vC, true, &failure);
5442 checkLitop(workRegs, insnRegCount, &decInsn,
5443 tmpType, kRegTypeInteger, false, &failure);
5444 break;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005445 case OP_AND_INT_LIT8:
5446 case OP_OR_INT_LIT8:
5447 case OP_XOR_INT_LIT8:
5448 checkLitop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005449 kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005450 break;
5451
Andy McFaddenb51ea112009-05-08 16:50:17 -07005452 /*
5453 * This falls into the general category of "optimized" instructions,
5454 * which don't generally appear during verification. Because it's
5455 * inserted in the course of verification, we can expect to see it here.
5456 */
5457 case OP_THROW_VERIFICATION_ERROR:
5458 break;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005459
5460 /*
5461 * Verifying "quickened" instructions is tricky, because we have
5462 * discarded the original field/method information. The byte offsets
5463 * and vtable indices only have meaning in the context of an object
5464 * instance.
5465 *
5466 * If a piece of code declares a local reference variable, assigns
5467 * null to it, and then issues a virtual method call on it, we
5468 * cannot evaluate the method call during verification. This situation
5469 * isn't hard to handle, since we know the call will always result in an
5470 * NPE, and the arguments and return value don't matter. Any code that
5471 * depends on the result of the method call is inaccessible, so the
5472 * fact that we can't fully verify anything that comes after the bad
5473 * call is not a problem.
5474 *
5475 * We must also consider the case of multiple code paths, only some of
5476 * which involve a null reference. We can completely verify the method
5477 * if we sidestep the results of executing with a null reference.
5478 * For example, if on the first pass through the code we try to do a
5479 * virtual method invocation through a null ref, we have to skip the
5480 * method checks and have the method return a "wildcard" type (which
5481 * merges with anything to become that other thing). The move-result
5482 * will tell us if it's a reference, single-word numeric, or double-word
5483 * value. We continue to perform the verification, and at the end of
5484 * the function any invocations that were never fully exercised are
5485 * marked as null-only.
5486 *
5487 * We would do something similar for the field accesses. The field's
5488 * type, once known, can be used to recover the width of short integers.
5489 * If the object reference was null, the field-get returns the "wildcard"
5490 * type, which is acceptable for any operation.
5491 */
5492 case OP_EXECUTE_INLINE:
Andy McFaddenb0a05412009-11-19 10:23:41 -08005493 case OP_EXECUTE_INLINE_RANGE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005494 case OP_INVOKE_DIRECT_EMPTY:
5495 case OP_IGET_QUICK:
5496 case OP_IGET_WIDE_QUICK:
5497 case OP_IGET_OBJECT_QUICK:
5498 case OP_IPUT_QUICK:
5499 case OP_IPUT_WIDE_QUICK:
5500 case OP_IPUT_OBJECT_QUICK:
5501 case OP_INVOKE_VIRTUAL_QUICK:
5502 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
5503 case OP_INVOKE_SUPER_QUICK:
5504 case OP_INVOKE_SUPER_QUICK_RANGE:
Andy McFadden62a75162009-04-17 17:23:37 -07005505 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005506 break;
5507
Andy McFadden96516932009-10-28 17:39:02 -07005508 /* these should never appear during verification */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005509 case OP_UNUSED_3E:
5510 case OP_UNUSED_3F:
5511 case OP_UNUSED_40:
5512 case OP_UNUSED_41:
5513 case OP_UNUSED_42:
5514 case OP_UNUSED_43:
5515 case OP_UNUSED_73:
5516 case OP_UNUSED_79:
5517 case OP_UNUSED_7A:
5518 case OP_UNUSED_E3:
5519 case OP_UNUSED_E4:
5520 case OP_UNUSED_E5:
5521 case OP_UNUSED_E6:
5522 case OP_UNUSED_E7:
Andy McFadden96516932009-10-28 17:39:02 -07005523 case OP_BREAKPOINT:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005524 case OP_UNUSED_F1:
5525 case OP_UNUSED_FC:
5526 case OP_UNUSED_FD:
5527 case OP_UNUSED_FE:
5528 case OP_UNUSED_FF:
Andy McFadden62a75162009-04-17 17:23:37 -07005529 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005530 break;
5531
5532 /*
5533 * DO NOT add a "default" clause here. Without it the compiler will
5534 * complain if an instruction is missing (which is desirable).
5535 */
5536 }
5537
Andy McFadden62a75162009-04-17 17:23:37 -07005538 if (!VERIFY_OK(failure)) {
Andy McFaddenb51ea112009-05-08 16:50:17 -07005539 if (failure == VERIFY_ERROR_GENERIC || gDvm.optimizing) {
5540 /* immediate failure, reject class */
5541 LOG_VFY_METH(meth, "VFY: rejecting opcode 0x%02x at 0x%04x\n",
5542 decInsn.opCode, insnIdx);
5543 goto bail;
5544 } else {
5545 /* replace opcode and continue on */
5546 LOGD("VFY: replacing opcode 0x%02x at 0x%04x\n",
5547 decInsn.opCode, insnIdx);
5548 if (!replaceFailingInstruction(meth, insnFlags, insnIdx, failure)) {
5549 LOG_VFY_METH(meth, "VFY: rejecting opcode 0x%02x at 0x%04x\n",
5550 decInsn.opCode, insnIdx);
5551 goto bail;
5552 }
5553 /* IMPORTANT: meth->insns may have been changed */
5554 insns = meth->insns + insnIdx;
5555
5556 /* continue on as if we just handled a throw-verification-error */
5557 failure = VERIFY_ERROR_NONE;
5558 nextFlags = kInstrCanThrow;
5559 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005560 }
5561
5562 /*
5563 * If we didn't just set the result register, clear it out. This
5564 * ensures that you can only use "move-result" immediately after the
Andy McFadden2e1ee502010-03-24 13:25:53 -07005565 * result is set. (We could check this statically, but it's not
5566 * expensive and it makes our debugging output cleaner.)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005567 */
5568 if (!justSetResult) {
5569 int reg = RESULT_REGISTER(insnRegCount);
5570 workRegs[reg] = workRegs[reg+1] = kRegTypeUnknown;
5571 }
5572
5573 /*
5574 * Handle "continue". Tag the next consecutive instruction.
5575 */
5576 if ((nextFlags & kInstrCanContinue) != 0) {
5577 int insnWidth = dvmInsnGetWidth(insnFlags, insnIdx);
5578 if (insnIdx+insnWidth >= insnsSize) {
5579 LOG_VFY_METH(meth,
5580 "VFY: execution can walk off end of code area (from 0x%x)\n",
5581 insnIdx);
5582 goto bail;
5583 }
5584
5585 /*
5586 * The only way to get to a move-exception instruction is to get
5587 * thrown there. Make sure the next instruction isn't one.
5588 */
5589 if (!checkMoveException(meth, insnIdx+insnWidth, "next"))
5590 goto bail;
5591
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005592 if (getRegisterLine(regTable, insnIdx+insnWidth) != NULL) {
Andy McFadden06b7a282009-05-11 10:44:52 -07005593 /*
5594 * Merge registers into what we have for the next instruction,
5595 * and set the "changed" flag if needed.
5596 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005597 updateRegisters(meth, insnFlags, regTable, insnIdx+insnWidth,
5598 workRegs);
5599 } else {
The Android Open Source Project99409882009-03-18 22:20:24 -07005600 /*
Andy McFadden06b7a282009-05-11 10:44:52 -07005601 * We're not recording register data for the next instruction,
5602 * so we don't know what the prior state was. We have to
5603 * assume that something has changed and re-evaluate it.
The Android Open Source Project99409882009-03-18 22:20:24 -07005604 */
5605 dvmInsnSetChanged(insnFlags, insnIdx+insnWidth, true);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005606 }
5607 }
5608
5609 /*
5610 * Handle "branch". Tag the branch target.
5611 *
5612 * NOTE: instructions like OP_EQZ provide information about the state
5613 * of the register when the branch is taken or not taken. For example,
5614 * somebody could get a reference field, check it for zero, and if the
5615 * branch is taken immediately store that register in a boolean field
5616 * since the value is known to be zero. We do not currently account for
5617 * that, and will reject the code.
5618 */
5619 if ((nextFlags & kInstrCanBranch) != 0) {
5620 bool isConditional;
5621
5622 if (!dvmGetBranchTarget(meth, insnFlags, insnIdx, &branchTarget,
5623 &isConditional))
5624 {
5625 /* should never happen after static verification */
5626 LOG_VFY_METH(meth, "VFY: bad branch at %d\n", insnIdx);
5627 goto bail;
5628 }
5629 assert(isConditional || (nextFlags & kInstrCanContinue) == 0);
5630 assert(!isConditional || (nextFlags & kInstrCanContinue) != 0);
5631
5632 if (!checkMoveException(meth, insnIdx+branchTarget, "branch"))
5633 goto bail;
5634
The Android Open Source Project99409882009-03-18 22:20:24 -07005635 /* update branch target, set "changed" if appropriate */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005636 updateRegisters(meth, insnFlags, regTable, insnIdx+branchTarget,
5637 workRegs);
5638 }
5639
5640 /*
5641 * Handle "switch". Tag all possible branch targets.
5642 *
5643 * We've already verified that the table is structurally sound, so we
5644 * just need to walk through and tag the targets.
5645 */
5646 if ((nextFlags & kInstrCanSwitch) != 0) {
5647 int offsetToSwitch = insns[1] | (((s4)insns[2]) << 16);
5648 const u2* switchInsns = insns + offsetToSwitch;
5649 int switchCount = switchInsns[1];
5650 int offsetToTargets, targ;
5651
5652 if ((*insns & 0xff) == OP_PACKED_SWITCH) {
5653 /* 0=sig, 1=count, 2/3=firstKey */
5654 offsetToTargets = 4;
5655 } else {
5656 /* 0=sig, 1=count, 2..count*2 = keys */
5657 assert((*insns & 0xff) == OP_SPARSE_SWITCH);
5658 offsetToTargets = 2 + 2*switchCount;
5659 }
5660
5661 /* verify each switch target */
5662 for (targ = 0; targ < switchCount; targ++) {
5663 int offset, absOffset;
5664
5665 /* offsets are 32-bit, and only partly endian-swapped */
5666 offset = switchInsns[offsetToTargets + targ*2] |
5667 (((s4) switchInsns[offsetToTargets + targ*2 +1]) << 16);
5668 absOffset = insnIdx + offset;
5669
5670 assert(absOffset >= 0 && absOffset < insnsSize);
5671
5672 if (!checkMoveException(meth, absOffset, "switch"))
5673 goto bail;
5674
5675 updateRegisters(meth, insnFlags, regTable, absOffset, workRegs);
5676 }
5677 }
5678
5679 /*
5680 * Handle instructions that can throw and that are sitting in a
5681 * "try" block. (If they're not in a "try" block when they throw,
5682 * control transfers out of the method.)
5683 */
5684 if ((nextFlags & kInstrCanThrow) != 0 && dvmInsnIsInTry(insnFlags, insnIdx))
5685 {
5686 DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
5687 const DexCode* pCode = dvmGetMethodCode(meth);
5688 DexCatchIterator iterator;
5689
5690 if (dexFindCatchHandler(&iterator, pCode, insnIdx)) {
5691 for (;;) {
5692 DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
5693
5694 if (handler == NULL) {
5695 break;
5696 }
5697
5698 /* note we use entryRegs, not workRegs */
5699 updateRegisters(meth, insnFlags, regTable, handler->address,
5700 entryRegs);
5701 }
5702 }
5703 }
5704
5705 /*
5706 * Update startGuess. Advance to the next instruction of that's
5707 * possible, otherwise use the branch target if one was found. If
5708 * neither of those exists we're in a return or throw; leave startGuess
5709 * alone and let the caller sort it out.
5710 */
5711 if ((nextFlags & kInstrCanContinue) != 0) {
5712 *pStartGuess = insnIdx + dvmInsnGetWidth(insnFlags, insnIdx);
5713 } else if ((nextFlags & kInstrCanBranch) != 0) {
5714 /* we're still okay if branchTarget is zero */
5715 *pStartGuess = insnIdx + branchTarget;
5716 }
5717
5718 assert(*pStartGuess >= 0 && *pStartGuess < insnsSize &&
5719 dvmInsnGetWidth(insnFlags, *pStartGuess) != 0);
5720
5721 result = true;
5722
5723bail:
5724 return result;
5725}
5726
Andy McFaddenb51ea112009-05-08 16:50:17 -07005727
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005728/*
5729 * callback function used in dumpRegTypes to print local vars
5730 * valid at a given address.
5731 */
5732static void logLocalsCb(void *cnxt, u2 reg, u4 startAddress, u4 endAddress,
5733 const char *name, const char *descriptor,
5734 const char *signature)
5735{
5736 int addr = *((int *)cnxt);
5737
5738 if (addr >= (int) startAddress && addr < (int) endAddress)
5739 {
5740 LOGI(" %2d: '%s' %s\n", reg, name, descriptor);
5741 }
5742}
5743
5744/*
5745 * Dump the register types for the specifed address to the log file.
5746 */
5747static void dumpRegTypes(const Method* meth, const InsnFlags* insnFlags,
5748 const RegType* addrRegs, int addr, const char* addrName,
5749 const UninitInstanceMap* uninitMap, int displayFlags)
5750{
5751 int regCount = meth->registersSize;
5752 int fullRegCount = regCount + kExtraRegs;
5753 bool branchTarget = dvmInsnIsBranchTarget(insnFlags, addr);
5754 int i;
5755
5756 assert(addr >= 0 && addr < (int) dvmGetMethodInsnsSize(meth));
5757
5758 int regCharSize = fullRegCount + (fullRegCount-1)/4 + 2 +1;
5759 char regChars[regCharSize +1];
5760 memset(regChars, ' ', regCharSize);
5761 regChars[0] = '[';
5762 if (regCount == 0)
5763 regChars[1] = ']';
5764 else
5765 regChars[1 + (regCount-1) + (regCount-1)/4 +1] = ']';
5766 regChars[regCharSize] = '\0';
5767
5768 //const RegType* addrRegs = getRegisterLine(regTable, addr);
5769
5770 for (i = 0; i < regCount + kExtraRegs; i++) {
5771 char tch;
5772
5773 switch (addrRegs[i]) {
5774 case kRegTypeUnknown: tch = '.'; break;
5775 case kRegTypeConflict: tch = 'X'; break;
5776 case kRegTypeFloat: tch = 'F'; break;
5777 case kRegTypeZero: tch = '0'; break;
5778 case kRegTypeOne: tch = '1'; break;
5779 case kRegTypeBoolean: tch = 'Z'; break;
5780 case kRegTypePosByte: tch = 'b'; break;
5781 case kRegTypeByte: tch = 'B'; break;
5782 case kRegTypePosShort: tch = 's'; break;
5783 case kRegTypeShort: tch = 'S'; break;
5784 case kRegTypeChar: tch = 'C'; break;
5785 case kRegTypeInteger: tch = 'I'; break;
5786 case kRegTypeLongLo: tch = 'J'; break;
5787 case kRegTypeLongHi: tch = 'j'; break;
5788 case kRegTypeDoubleLo: tch = 'D'; break;
5789 case kRegTypeDoubleHi: tch = 'd'; break;
5790 default:
5791 if (regTypeIsReference(addrRegs[i])) {
5792 if (regTypeIsUninitReference(addrRegs[i]))
5793 tch = 'U';
5794 else
5795 tch = 'L';
5796 } else {
5797 tch = '*';
5798 assert(false);
5799 }
5800 break;
5801 }
5802
5803 if (i < regCount)
5804 regChars[1 + i + (i/4)] = tch;
5805 else
5806 regChars[1 + i + (i/4) + 2] = tch;
5807 }
5808
5809 if (addr == 0 && addrName != NULL)
5810 LOGI("%c%s %s\n", branchTarget ? '>' : ' ', addrName, regChars);
5811 else
5812 LOGI("%c0x%04x %s\n", branchTarget ? '>' : ' ', addr, regChars);
5813
5814 if (displayFlags & DRT_SHOW_REF_TYPES) {
5815 for (i = 0; i < regCount + kExtraRegs; i++) {
5816 if (regTypeIsReference(addrRegs[i]) && addrRegs[i] != kRegTypeZero)
5817 {
5818 ClassObject* clazz;
5819
5820 clazz = regTypeReferenceToClass(addrRegs[i], uninitMap);
5821 assert(dvmValidateObject((Object*)clazz));
5822 if (i < regCount) {
5823 LOGI(" %2d: 0x%08x %s%s\n",
5824 i, addrRegs[i],
5825 regTypeIsUninitReference(addrRegs[i]) ? "[U]" : "",
5826 clazz->descriptor);
5827 } else {
5828 LOGI(" RS: 0x%08x %s%s\n",
5829 addrRegs[i],
5830 regTypeIsUninitReference(addrRegs[i]) ? "[U]" : "",
5831 clazz->descriptor);
5832 }
5833 }
5834 }
5835 }
5836 if (displayFlags & DRT_SHOW_LOCALS) {
5837 dexDecodeDebugInfo(meth->clazz->pDvmDex->pDexFile,
5838 dvmGetMethodCode(meth),
5839 meth->clazz->descriptor,
5840 meth->prototype.protoIdx,
5841 meth->accessFlags,
5842 NULL, logLocalsCb, &addr);
5843 }
5844}
5845