blob: d2b3a2c04dd55d68fa828c00f46613d68e809b57 [file] [log] [blame]
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * Dalvik bytecode structural verifier. The only public entry point
19 * (except for a few shared utility functions) is dvmVerifyCodeFlow().
20 *
21 * TODO: might benefit from a signature-->class lookup cache. Could avoid
22 * some string-peeling and wouldn't need to compute hashes.
23 *
24 * TODO: we do too much stuff in here that could be done in the static
25 * verification pass. It's convenient, because we have all of the
26 * necessary information, but it's more efficient to do it over in
27 * DexVerify.c because in here we may have to process instructions
28 * multiple times.
29 */
30#include "Dalvik.h"
31#include "analysis/CodeVerify.h"
Andy McFadden2e1ee502010-03-24 13:25:53 -070032#include "analysis/Optimize.h"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080033#include "analysis/RegisterMap.h"
34#include "libdex/DexCatch.h"
35#include "libdex/InstrUtils.h"
36
37#include <stddef.h>
38
39
40/*
41 * We don't need to store the register data for many instructions, because
42 * we either only need it at branch points (for verification) or GC points
43 * and branches (for verification + type-precise register analysis).
44 */
45typedef enum RegisterTrackingMode {
46 kTrackRegsBranches,
47 kTrackRegsGcPoints,
48 kTrackRegsAll
49} RegisterTrackingMode;
50
51/*
52 * Set this to enable dead code scanning. This is not required, but it's
53 * very useful when testing changes to the verifier (to make sure we're not
54 * skipping over stuff) and for checking the optimized output from "dx".
55 * The only reason not to do it is that it slightly increases the time
56 * required to perform verification.
57 */
58#define DEAD_CODE_SCAN true
59
60static bool gDebugVerbose = false; // TODO: remove this
61
62#if 0
63int gDvm__totalInstr = 0;
64int gDvm__gcInstr = 0;
65int gDvm__gcData = 0;
66int gDvm__gcSimpleData = 0;
67#endif
68
69/*
70 * Selectively enable verbose debug logging -- use this to activate
71 * dumpRegTypes() calls for all instructions in the specified method.
72 */
73static inline bool doVerboseLogging(const Method* meth) {
74 return false; /* COMMENT OUT to enable verbose debugging */
75
The Android Open Source Project99409882009-03-18 22:20:24 -070076 const char* cd = "Landroid/net/http/Request;";
77 const char* mn = "readResponse";
78 const char* sg = "(Landroid/net/http/AndroidHttpClientConnection;)V";
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080079 return (strcmp(meth->clazz->descriptor, cd) == 0 &&
80 dvmCompareNameDescriptorAndMethod(mn, sg, meth) == 0);
81}
82
83#define SHOW_REG_DETAILS (0 /*| DRT_SHOW_REF_TYPES | DRT_SHOW_LOCALS*/)
84
85/*
86 * We need an extra "pseudo register" to hold the return type briefly. It
87 * can be category 1 or 2, so we need two slots.
88 */
89#define kExtraRegs 2
90#define RESULT_REGISTER(_insnRegCount) (_insnRegCount)
91
92/*
93 * Big fat collection of registers.
94 */
95typedef struct RegisterTable {
96 /*
97 * Array of RegType arrays, one per address in the method. We only
98 * set the pointers for certain addresses, based on what we're trying
99 * to accomplish.
100 */
101 RegType** addrRegs;
102
103 /*
104 * Number of registers we track for each instruction. This is equal
105 * to the method's declared "registersSize" plus kExtraRegs.
106 */
107 int insnRegCountPlus;
108
109 /*
110 * A single large alloc, with all of the storage needed for addrRegs.
111 */
112 RegType* regAlloc;
113} RegisterTable;
114
115
116/* fwd */
Carl Shapiroe3c01da2010-05-20 22:54:18 -0700117#ifndef NDEBUG
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800118static void checkMergeTab(void);
Carl Shapiroe3c01da2010-05-20 22:54:18 -0700119#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800120static bool isInitMethod(const Method* meth);
121static RegType getInvocationThis(const RegType* insnRegs,\
Andy McFadden62a75162009-04-17 17:23:37 -0700122 const int insnRegCount, const DecodedInstruction* pDecInsn,
123 VerifyError* pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800124static void verifyRegisterType(const RegType* insnRegs, const int insnRegCount,\
Andy McFadden62a75162009-04-17 17:23:37 -0700125 u4 vsrc, RegType checkType, VerifyError* pFailure);
Andy McFadden228a6b02010-05-04 15:02:32 -0700126static bool doCodeVerification(const Method* meth, InsnFlags* insnFlags,\
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800127 RegisterTable* regTable, UninitInstanceMap* uninitMap);
Andy McFadden228a6b02010-05-04 15:02:32 -0700128static bool verifyInstruction(const Method* meth, InsnFlags* insnFlags,\
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800129 RegisterTable* regTable, RegType* workRegs, int insnIdx,
130 UninitInstanceMap* uninitMap, int* pStartGuess);
131static ClassObject* findCommonSuperclass(ClassObject* c1, ClassObject* c2);
132static void dumpRegTypes(const Method* meth, const InsnFlags* insnFlags,\
133 const RegType* addrRegs, int addr, const char* addrName,
134 const UninitInstanceMap* uninitMap, int displayFlags);
135
136/* bit values for dumpRegTypes() "displayFlags" */
137enum {
138 DRT_SIMPLE = 0,
139 DRT_SHOW_REF_TYPES = 0x01,
140 DRT_SHOW_LOCALS = 0x02,
141};
142
143
144/*
145 * ===========================================================================
146 * RegType and UninitInstanceMap utility functions
147 * ===========================================================================
148 */
149
150#define __ kRegTypeUnknown
151#define _U kRegTypeUninit
152#define _X kRegTypeConflict
153#define _F kRegTypeFloat
154#define _0 kRegTypeZero
155#define _1 kRegTypeOne
156#define _Z kRegTypeBoolean
157#define _b kRegTypePosByte
158#define _B kRegTypeByte
159#define _s kRegTypePosShort
160#define _S kRegTypeShort
161#define _C kRegTypeChar
162#define _I kRegTypeInteger
163#define _J kRegTypeLongLo
164#define _j kRegTypeLongHi
165#define _D kRegTypeDoubleLo
166#define _d kRegTypeDoubleHi
167
168/*
169 * Merge result table for primitive values. The table is symmetric along
170 * the diagonal.
171 *
172 * Note that 32-bit int/float do not merge into 64-bit long/double. This
173 * is a register merge, not a widening conversion. Only the "implicit"
174 * widening within a category, e.g. byte to short, is allowed.
175 *
176 * Because Dalvik does not draw a distinction between int and float, we
177 * have to allow free exchange between 32-bit int/float and 64-bit
178 * long/double.
179 *
180 * Note that Uninit+Uninit=Uninit. This holds true because we only
181 * use this when the RegType value is exactly equal to kRegTypeUninit, which
182 * can only happen for the zeroeth entry in the table.
183 *
184 * "Unknown" never merges with anything known. The only time a register
185 * transitions from "unknown" to "known" is when we're executing code
186 * for the first time, and we handle that with a simple copy.
187 */
188const char gDvmMergeTab[kRegTypeMAX][kRegTypeMAX] =
189{
190 /* chk: _ U X F 0 1 Z b B s S C I J j D d */
191 { /*_*/ __,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X },
192 { /*U*/ _X,_U,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X },
193 { /*X*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X },
194 { /*F*/ _X,_X,_X,_F,_F,_F,_F,_F,_F,_F,_F,_F,_F,_X,_X,_X,_X },
195 { /*0*/ _X,_X,_X,_F,_0,_Z,_Z,_b,_B,_s,_S,_C,_I,_X,_X,_X,_X },
196 { /*1*/ _X,_X,_X,_F,_Z,_1,_Z,_b,_B,_s,_S,_C,_I,_X,_X,_X,_X },
197 { /*Z*/ _X,_X,_X,_F,_Z,_Z,_Z,_b,_B,_s,_S,_C,_I,_X,_X,_X,_X },
198 { /*b*/ _X,_X,_X,_F,_b,_b,_b,_b,_B,_s,_S,_C,_I,_X,_X,_X,_X },
199 { /*B*/ _X,_X,_X,_F,_B,_B,_B,_B,_B,_S,_S,_I,_I,_X,_X,_X,_X },
200 { /*s*/ _X,_X,_X,_F,_s,_s,_s,_s,_S,_s,_S,_C,_I,_X,_X,_X,_X },
201 { /*S*/ _X,_X,_X,_F,_S,_S,_S,_S,_S,_S,_S,_I,_I,_X,_X,_X,_X },
202 { /*C*/ _X,_X,_X,_F,_C,_C,_C,_C,_I,_C,_I,_C,_I,_X,_X,_X,_X },
203 { /*I*/ _X,_X,_X,_F,_I,_I,_I,_I,_I,_I,_I,_I,_I,_X,_X,_X,_X },
204 { /*J*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_J,_X,_J,_X },
205 { /*j*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_j,_X,_j },
206 { /*D*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_J,_X,_D,_X },
207 { /*d*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_j,_X,_d },
208};
209
210#undef __
211#undef _U
212#undef _X
213#undef _F
214#undef _0
215#undef _1
216#undef _Z
217#undef _b
218#undef _B
219#undef _s
220#undef _S
221#undef _C
222#undef _I
223#undef _J
224#undef _j
225#undef _D
226#undef _d
227
228#ifndef NDEBUG
229/*
230 * Verify symmetry in the conversion table.
231 */
232static void checkMergeTab(void)
233{
234 int i, j;
235
236 for (i = 0; i < kRegTypeMAX; i++) {
237 for (j = i; j < kRegTypeMAX; j++) {
238 if (gDvmMergeTab[i][j] != gDvmMergeTab[j][i]) {
239 LOGE("Symmetry violation: %d,%d vs %d,%d\n", i, j, j, i);
240 dvmAbort();
241 }
242 }
243 }
244}
245#endif
246
247/*
248 * Determine whether we can convert "srcType" to "checkType", where
249 * "checkType" is one of the category-1 non-reference types.
250 *
251 * 32-bit int and float are interchangeable.
252 */
253static bool canConvertTo1nr(RegType srcType, RegType checkType)
254{
255 static const char convTab
256 [kRegType1nrEND-kRegType1nrSTART+1][kRegType1nrEND-kRegType1nrSTART+1] =
257 {
258 /* chk: F 0 1 Z b B s S C I */
259 { /*F*/ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
260 { /*0*/ 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
261 { /*1*/ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 },
262 { /*Z*/ 1, 0, 0, 1, 1, 1, 1, 1, 1, 1 },
263 { /*b*/ 1, 0, 0, 0, 1, 1, 1, 1, 1, 1 },
264 { /*B*/ 1, 0, 0, 0, 0, 1, 0, 1, 0, 1 },
265 { /*s*/ 1, 0, 0, 0, 0, 0, 1, 1, 1, 1 },
266 { /*S*/ 1, 0, 0, 0, 0, 0, 0, 1, 0, 1 },
267 { /*C*/ 1, 0, 0, 0, 0, 0, 0, 0, 1, 1 },
268 { /*I*/ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
269 };
270
271 assert(checkType >= kRegType1nrSTART && checkType <= kRegType1nrEND);
272#if 0
273 if (checkType < kRegType1nrSTART || checkType > kRegType1nrEND) {
274 LOG_VFY("Unexpected checkType %d (srcType=%d)\n", checkType, srcType);
275 assert(false);
276 return false;
277 }
278#endif
279
280 //printf("convTab[%d][%d] = %d\n", srcType, checkType,
281 // convTab[srcType-kRegType1nrSTART][checkType-kRegType1nrSTART]);
282 if (srcType >= kRegType1nrSTART && srcType <= kRegType1nrEND)
283 return (bool) convTab[srcType-kRegType1nrSTART][checkType-kRegType1nrSTART];
284
285 return false;
286}
287
288/*
289 * Determine whether the types are compatible. In Dalvik, 64-bit doubles
290 * and longs are interchangeable.
291 */
292static bool canConvertTo2(RegType srcType, RegType checkType)
293{
294 return ((srcType == kRegTypeLongLo || srcType == kRegTypeDoubleLo) &&
295 (checkType == kRegTypeLongLo || checkType == kRegTypeDoubleLo));
296}
297
298/*
299 * Determine whether or not "instrType" and "targetType" are compatible,
300 * for purposes of getting or setting a value in a field or array. The
301 * idea is that an instruction with a category 1nr type (say, aget-short
302 * or iput-boolean) is accessing a static field, instance field, or array
303 * entry, and we want to make sure sure that the operation is legal.
304 *
305 * At a minimum, source and destination must have the same width. We
306 * further refine this to assert that "short" and "char" are not
307 * compatible, because the sign-extension is different on the "get"
308 * operations. As usual, "float" and "int" are interoperable.
309 *
310 * We're not considering the actual contents of the register, so we'll
311 * never get "pseudo-types" like kRegTypeZero or kRegTypePosShort. We
312 * could get kRegTypeUnknown in "targetType" if a field or array class
313 * lookup failed. Category 2 types and references are checked elsewhere.
314 */
315static bool checkFieldArrayStore1nr(RegType instrType, RegType targetType)
316{
317 if (instrType == targetType)
318 return true; /* quick positive; most common case */
319
320 if ((instrType == kRegTypeInteger && targetType == kRegTypeFloat) ||
321 (instrType == kRegTypeFloat && targetType == kRegTypeInteger))
322 {
323 return true;
324 }
325
326 return false;
327}
328
329/*
330 * Convert a VM PrimitiveType enum value to the equivalent RegType value.
331 */
332static RegType primitiveTypeToRegType(PrimitiveType primType)
333{
The Android Open Source Project99409882009-03-18 22:20:24 -0700334 static const struct {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800335 RegType regType; /* type equivalent */
336 PrimitiveType primType; /* verification */
337 } convTab[] = {
338 /* must match order of enum in Object.h */
339 { kRegTypeBoolean, PRIM_BOOLEAN },
340 { kRegTypeChar, PRIM_CHAR },
341 { kRegTypeFloat, PRIM_FLOAT },
342 { kRegTypeDoubleLo, PRIM_DOUBLE },
343 { kRegTypeByte, PRIM_BYTE },
344 { kRegTypeShort, PRIM_SHORT },
345 { kRegTypeInteger, PRIM_INT },
346 { kRegTypeLongLo, PRIM_LONG },
347 // PRIM_VOID
348 };
349
350 if (primType < 0 || primType > (int) (sizeof(convTab) / sizeof(convTab[0])))
351 {
352 assert(false);
353 return kRegTypeUnknown;
354 }
355
356 assert(convTab[primType].primType == primType);
357 return convTab[primType].regType;
358}
359
360/*
361 * Create a new uninitialized instance map.
362 *
363 * The map is allocated and populated with address entries. The addresses
364 * appear in ascending order to allow binary searching.
365 *
366 * Very few methods have 10 or more new-instance instructions; the
367 * majority have 0 or 1. Occasionally a static initializer will have 200+.
368 */
369UninitInstanceMap* dvmCreateUninitInstanceMap(const Method* meth,
370 const InsnFlags* insnFlags, int newInstanceCount)
371{
372 const int insnsSize = dvmGetMethodInsnsSize(meth);
373 const u2* insns = meth->insns;
374 UninitInstanceMap* uninitMap;
375 bool isInit = false;
376 int idx, addr;
377
378 if (isInitMethod(meth)) {
379 newInstanceCount++;
380 isInit = true;
381 }
382
383 /*
384 * Allocate the header and map as a single unit.
385 *
386 * TODO: consider having a static instance so we can avoid allocations.
387 * I don't think the verifier is guaranteed to be single-threaded when
388 * running in the VM (rather than dexopt), so that must be taken into
389 * account.
390 */
391 int size = offsetof(UninitInstanceMap, map) +
392 newInstanceCount * sizeof(uninitMap->map[0]);
393 uninitMap = calloc(1, size);
394 if (uninitMap == NULL)
395 return NULL;
396 uninitMap->numEntries = newInstanceCount;
397
398 idx = 0;
399 if (isInit) {
400 uninitMap->map[idx++].addr = kUninitThisArgAddr;
401 }
402
403 /*
404 * Run through and find the new-instance instructions.
405 */
406 for (addr = 0; addr < insnsSize; /**/) {
407 int width = dvmInsnGetWidth(insnFlags, addr);
408
409 if ((*insns & 0xff) == OP_NEW_INSTANCE)
410 uninitMap->map[idx++].addr = addr;
411
412 addr += width;
413 insns += width;
414 }
415
416 assert(idx == newInstanceCount);
417 return uninitMap;
418}
419
420/*
421 * Free the map.
422 */
423void dvmFreeUninitInstanceMap(UninitInstanceMap* uninitMap)
424{
425 free(uninitMap);
426}
427
428/*
429 * Set the class object associated with the instruction at "addr".
430 *
431 * Returns the map slot index, or -1 if the address isn't listed in the map
432 * (shouldn't happen) or if a class is already associated with the address
433 * (bad bytecode).
434 *
435 * Entries, once set, do not change -- a given address can only allocate
436 * one type of object.
437 */
438int dvmSetUninitInstance(UninitInstanceMap* uninitMap, int addr,
439 ClassObject* clazz)
440{
441 int idx;
442
443 assert(clazz != NULL);
444
445 /* TODO: binary search when numEntries > 8 */
446 for (idx = uninitMap->numEntries - 1; idx >= 0; idx--) {
447 if (uninitMap->map[idx].addr == addr) {
448 if (uninitMap->map[idx].clazz != NULL &&
449 uninitMap->map[idx].clazz != clazz)
450 {
451 LOG_VFY("VFY: addr %d already set to %p, not setting to %p\n",
452 addr, uninitMap->map[idx].clazz, clazz);
453 return -1; // already set to something else??
454 }
455 uninitMap->map[idx].clazz = clazz;
456 return idx;
457 }
458 }
459
460 LOG_VFY("VFY: addr %d not found in uninit map\n", addr);
461 assert(false); // shouldn't happen
462 return -1;
463}
464
465/*
466 * Get the class object at the specified index.
467 */
468ClassObject* dvmGetUninitInstance(const UninitInstanceMap* uninitMap, int idx)
469{
470 assert(idx >= 0 && idx < uninitMap->numEntries);
471 return uninitMap->map[idx].clazz;
472}
473
474/* determine if "type" is actually an object reference (init/uninit/zero) */
475static inline bool regTypeIsReference(RegType type) {
476 return (type > kRegTypeMAX || type == kRegTypeUninit ||
477 type == kRegTypeZero);
478}
479
480/* determine if "type" is an uninitialized object reference */
481static inline bool regTypeIsUninitReference(RegType type) {
482 return ((type & kRegTypeUninitMask) == kRegTypeUninit);
483}
484
485/* convert the initialized reference "type" to a ClassObject pointer */
486/* (does not expect uninit ref types or "zero") */
487static ClassObject* regTypeInitializedReferenceToClass(RegType type)
488{
489 assert(regTypeIsReference(type) && type != kRegTypeZero);
490 if ((type & 0x01) == 0) {
491 return (ClassObject*) type;
492 } else {
493 //LOG_VFY("VFY: attempted to use uninitialized reference\n");
494 return NULL;
495 }
496}
497
498/* extract the index into the uninitialized instance map table */
499static inline int regTypeToUninitIndex(RegType type) {
500 assert(regTypeIsUninitReference(type));
501 return (type & ~kRegTypeUninitMask) >> kRegTypeUninitShift;
502}
503
504/* convert the reference "type" to a ClassObject pointer */
505static ClassObject* regTypeReferenceToClass(RegType type,
506 const UninitInstanceMap* uninitMap)
507{
508 assert(regTypeIsReference(type) && type != kRegTypeZero);
509 if (regTypeIsUninitReference(type)) {
510 assert(uninitMap != NULL);
511 return dvmGetUninitInstance(uninitMap, regTypeToUninitIndex(type));
512 } else {
513 return (ClassObject*) type;
514 }
515}
516
517/* convert the ClassObject pointer to an (initialized) register type */
518static inline RegType regTypeFromClass(ClassObject* clazz) {
519 return (u4) clazz;
520}
521
522/* return the RegType for the uninitialized reference in slot "uidx" */
523static RegType regTypeFromUninitIndex(int uidx) {
524 return (u4) (kRegTypeUninit | (uidx << kRegTypeUninitShift));
525}
526
527
528/*
529 * ===========================================================================
530 * Signature operations
531 * ===========================================================================
532 */
533
534/*
535 * Is this method a constructor?
536 */
537static bool isInitMethod(const Method* meth)
538{
539 return (*meth->name == '<' && strcmp(meth->name+1, "init>") == 0);
540}
541
542/*
543 * Is this method a class initializer?
544 */
Carl Shapiroe3c01da2010-05-20 22:54:18 -0700545#if 0
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800546static bool isClassInitMethod(const Method* meth)
547{
548 return (*meth->name == '<' && strcmp(meth->name+1, "clinit>") == 0);
549}
Carl Shapiroe3c01da2010-05-20 22:54:18 -0700550#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800551
552/*
553 * Look up a class reference given as a simple string descriptor.
Andy McFadden62a75162009-04-17 17:23:37 -0700554 *
555 * If we can't find it, return a generic substitute when possible.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800556 */
557static ClassObject* lookupClassByDescriptor(const Method* meth,
Andy McFadden62a75162009-04-17 17:23:37 -0700558 const char* pDescriptor, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800559{
560 /*
561 * The javac compiler occasionally puts references to nonexistent
562 * classes in signatures. For example, if you have a non-static
563 * inner class with no constructor, the compiler provides
564 * a private <init> for you. Constructing the class
565 * requires <init>(parent), but the outer class can't call
566 * that because the method is private. So the compiler
567 * generates a package-scope <init>(parent,bogus) method that
568 * just calls the regular <init> (the "bogus" part being necessary
569 * to distinguish the signature of the synthetic method).
570 * Treating the bogus class as an instance of java.lang.Object
571 * allows the verifier to process the class successfully.
572 */
573
574 //LOGI("Looking up '%s'\n", typeStr);
575 ClassObject* clazz;
576 clazz = dvmFindClassNoInit(pDescriptor, meth->clazz->classLoader);
577 if (clazz == NULL) {
578 dvmClearOptException(dvmThreadSelf());
579 if (strchr(pDescriptor, '$') != NULL) {
580 LOGV("VFY: unable to find class referenced in signature (%s)\n",
581 pDescriptor);
582 } else {
583 LOG_VFY("VFY: unable to find class referenced in signature (%s)\n",
584 pDescriptor);
585 }
586
587 if (pDescriptor[0] == '[') {
588 /* We are looking at an array descriptor. */
589
590 /*
591 * There should never be a problem loading primitive arrays.
592 */
593 if (pDescriptor[1] != 'L' && pDescriptor[1] != '[') {
594 LOG_VFY("VFY: invalid char in signature in '%s'\n",
595 pDescriptor);
Andy McFadden62a75162009-04-17 17:23:37 -0700596 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800597 }
598
599 /*
600 * Try to continue with base array type. This will let
601 * us pass basic stuff (e.g. get array len) that wouldn't
602 * fly with an Object. This is NOT correct if the
603 * missing type is a primitive array, but we should never
604 * have a problem loading those. (I'm not convinced this
605 * is correct or even useful. Just use Object here?)
606 */
607 clazz = dvmFindClassNoInit("[Ljava/lang/Object;",
608 meth->clazz->classLoader);
609 } else if (pDescriptor[0] == 'L') {
610 /*
611 * We are looking at a non-array reference descriptor;
612 * try to continue with base reference type.
613 */
614 clazz = gDvm.classJavaLangObject;
615 } else {
616 /* We are looking at a primitive type. */
617 LOG_VFY("VFY: invalid char in signature in '%s'\n", pDescriptor);
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 if (clazz == NULL) {
Andy McFadden62a75162009-04-17 17:23:37 -0700622 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800623 }
624 }
625
626 if (dvmIsPrimitiveClass(clazz)) {
627 LOG_VFY("VFY: invalid use of primitive type '%s'\n", pDescriptor);
Andy McFadden62a75162009-04-17 17:23:37 -0700628 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800629 clazz = NULL;
630 }
631
632 return clazz;
633}
634
635/*
636 * Look up a class reference in a signature. Could be an arg or the
637 * return value.
638 *
639 * Advances "*pSig" to the last character in the signature (that is, to
640 * the ';').
641 *
642 * NOTE: this is also expected to verify the signature.
643 */
644static ClassObject* lookupSignatureClass(const Method* meth, const char** pSig,
Andy McFadden62a75162009-04-17 17:23:37 -0700645 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800646{
647 const char* sig = *pSig;
648 const char* endp = sig;
649
650 assert(sig != NULL && *sig == 'L');
651
652 while (*++endp != ';' && *endp != '\0')
653 ;
654 if (*endp != ';') {
655 LOG_VFY("VFY: bad signature component '%s' (missing ';')\n", sig);
Andy McFadden62a75162009-04-17 17:23:37 -0700656 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800657 return NULL;
658 }
659
660 endp++; /* Advance past the ';'. */
661 int typeLen = endp - sig;
662 char typeStr[typeLen+1]; /* +1 for the '\0' */
663 memcpy(typeStr, sig, typeLen);
664 typeStr[typeLen] = '\0';
665
666 *pSig = endp - 1; /* - 1 so that *pSig points at, not past, the ';' */
667
Andy McFadden62a75162009-04-17 17:23:37 -0700668 return lookupClassByDescriptor(meth, typeStr, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800669}
670
671/*
672 * Look up an array class reference in a signature. Could be an arg or the
673 * return value.
674 *
675 * Advances "*pSig" to the last character in the signature.
676 *
677 * NOTE: this is also expected to verify the signature.
678 */
679static ClassObject* lookupSignatureArrayClass(const Method* meth,
Andy McFadden62a75162009-04-17 17:23:37 -0700680 const char** pSig, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800681{
682 const char* sig = *pSig;
683 const char* endp = sig;
684
685 assert(sig != NULL && *sig == '[');
686
687 /* find the end */
688 while (*++endp == '[' && *endp != '\0')
689 ;
690
691 if (*endp == 'L') {
692 while (*++endp != ';' && *endp != '\0')
693 ;
694 if (*endp != ';') {
695 LOG_VFY("VFY: bad signature component '%s' (missing ';')\n", sig);
Andy McFadden62a75162009-04-17 17:23:37 -0700696 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800697 return NULL;
698 }
699 }
700
701 int typeLen = endp - sig +1;
702 char typeStr[typeLen+1];
703 memcpy(typeStr, sig, typeLen);
704 typeStr[typeLen] = '\0';
705
706 *pSig = endp;
707
Andy McFadden62a75162009-04-17 17:23:37 -0700708 return lookupClassByDescriptor(meth, typeStr, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800709}
710
711/*
712 * Set the register types for the first instruction in the method based on
713 * the method signature.
714 *
715 * This has the side-effect of validating the signature.
716 *
717 * Returns "true" on success.
718 */
719static bool setTypesFromSignature(const Method* meth, RegType* regTypes,
720 UninitInstanceMap* uninitMap)
721{
722 DexParameterIterator iterator;
723 int actualArgs, expectedArgs, argStart;
Andy McFadden62a75162009-04-17 17:23:37 -0700724 VerifyError failure = VERIFY_ERROR_NONE;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800725
726 dexParameterIteratorInit(&iterator, &meth->prototype);
727 argStart = meth->registersSize - meth->insSize;
728 expectedArgs = meth->insSize; /* long/double count as two */
729 actualArgs = 0;
730
731 assert(argStart >= 0); /* should have been verified earlier */
732
733 /*
734 * Include the "this" pointer.
735 */
736 if (!dvmIsStaticMethod(meth)) {
737 /*
738 * If this is a constructor for a class other than java.lang.Object,
739 * mark the first ("this") argument as uninitialized. This restricts
740 * field access until the superclass constructor is called.
741 */
742 if (isInitMethod(meth) && meth->clazz != gDvm.classJavaLangObject) {
743 int uidx = dvmSetUninitInstance(uninitMap, kUninitThisArgAddr,
744 meth->clazz);
745 assert(uidx == 0);
746 regTypes[argStart + actualArgs] = regTypeFromUninitIndex(uidx);
747 } else {
748 regTypes[argStart + actualArgs] = regTypeFromClass(meth->clazz);
749 }
750 actualArgs++;
751 }
752
753 for (;;) {
754 const char* descriptor = dexParameterIteratorNextDescriptor(&iterator);
755
756 if (descriptor == NULL) {
757 break;
758 }
759
760 if (actualArgs >= expectedArgs) {
761 LOG_VFY("VFY: expected %d args, found more (%s)\n",
762 expectedArgs, descriptor);
763 goto bad_sig;
764 }
765
766 switch (*descriptor) {
767 case 'L':
768 case '[':
769 /*
770 * We assume that reference arguments are initialized. The
771 * only way it could be otherwise (assuming the caller was
772 * verified) is if the current method is <init>, but in that
773 * case it's effectively considered initialized the instant
774 * we reach here (in the sense that we can return without
775 * doing anything or call virtual methods).
776 */
777 {
778 ClassObject* clazz =
Andy McFadden62a75162009-04-17 17:23:37 -0700779 lookupClassByDescriptor(meth, descriptor, &failure);
780 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800781 goto bad_sig;
782 regTypes[argStart + actualArgs] = regTypeFromClass(clazz);
783 }
784 actualArgs++;
785 break;
786 case 'Z':
787 regTypes[argStart + actualArgs] = kRegTypeBoolean;
788 actualArgs++;
789 break;
790 case 'C':
791 regTypes[argStart + actualArgs] = kRegTypeChar;
792 actualArgs++;
793 break;
794 case 'B':
795 regTypes[argStart + actualArgs] = kRegTypeByte;
796 actualArgs++;
797 break;
798 case 'I':
799 regTypes[argStart + actualArgs] = kRegTypeInteger;
800 actualArgs++;
801 break;
802 case 'S':
803 regTypes[argStart + actualArgs] = kRegTypeShort;
804 actualArgs++;
805 break;
806 case 'F':
807 regTypes[argStart + actualArgs] = kRegTypeFloat;
808 actualArgs++;
809 break;
810 case 'D':
811 regTypes[argStart + actualArgs] = kRegTypeDoubleLo;
812 regTypes[argStart + actualArgs +1] = kRegTypeDoubleHi;
813 actualArgs += 2;
814 break;
815 case 'J':
816 regTypes[argStart + actualArgs] = kRegTypeLongLo;
817 regTypes[argStart + actualArgs +1] = kRegTypeLongHi;
818 actualArgs += 2;
819 break;
820 default:
821 LOG_VFY("VFY: unexpected signature type char '%c'\n", *descriptor);
822 goto bad_sig;
823 }
824 }
825
826 if (actualArgs != expectedArgs) {
827 LOG_VFY("VFY: expected %d args, found %d\n", expectedArgs, actualArgs);
828 goto bad_sig;
829 }
830
831 const char* descriptor = dexProtoGetReturnType(&meth->prototype);
832
833 /*
834 * Validate return type. We don't do the type lookup; just want to make
835 * sure that it has the right format. Only major difference from the
836 * method argument format is that 'V' is supported.
837 */
838 switch (*descriptor) {
839 case 'I':
840 case 'C':
841 case 'S':
842 case 'B':
843 case 'Z':
844 case 'V':
845 case 'F':
846 case 'D':
847 case 'J':
848 if (*(descriptor+1) != '\0')
849 goto bad_sig;
850 break;
851 case '[':
852 /* single/multi, object/primitive */
853 while (*++descriptor == '[')
854 ;
855 if (*descriptor == 'L') {
856 while (*++descriptor != ';' && *descriptor != '\0')
857 ;
858 if (*descriptor != ';')
859 goto bad_sig;
860 } else {
861 if (*(descriptor+1) != '\0')
862 goto bad_sig;
863 }
864 break;
865 case 'L':
866 /* could be more thorough here, but shouldn't be required */
867 while (*++descriptor != ';' && *descriptor != '\0')
868 ;
869 if (*descriptor != ';')
870 goto bad_sig;
871 break;
872 default:
873 goto bad_sig;
874 }
875
876 return true;
877
878//fail:
879// LOG_VFY_METH(meth, "VFY: bad sig\n");
880// return false;
881
882bad_sig:
883 {
884 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
885 LOG_VFY("VFY: bad signature '%s' for %s.%s\n",
886 desc, meth->clazz->descriptor, meth->name);
887 free(desc);
888 }
889 return false;
890}
891
892/*
893 * Return the register type for the method. We can't just use the
894 * already-computed DalvikJniReturnType, because if it's a reference type
895 * we need to do the class lookup.
896 *
897 * Returned references are assumed to be initialized.
898 *
899 * Returns kRegTypeUnknown for "void".
900 */
901static RegType getMethodReturnType(const Method* meth)
902{
903 RegType type;
904 const char* descriptor = dexProtoGetReturnType(&meth->prototype);
905
906 switch (*descriptor) {
907 case 'I':
908 type = kRegTypeInteger;
909 break;
910 case 'C':
911 type = kRegTypeChar;
912 break;
913 case 'S':
914 type = kRegTypeShort;
915 break;
916 case 'B':
917 type = kRegTypeByte;
918 break;
919 case 'Z':
920 type = kRegTypeBoolean;
921 break;
922 case 'V':
923 type = kRegTypeUnknown;
924 break;
925 case 'F':
926 type = kRegTypeFloat;
927 break;
928 case 'D':
929 type = kRegTypeDoubleLo;
930 break;
931 case 'J':
932 type = kRegTypeLongLo;
933 break;
934 case 'L':
935 case '[':
936 {
Andy McFadden62a75162009-04-17 17:23:37 -0700937 VerifyError failure = VERIFY_ERROR_NONE;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800938 ClassObject* clazz =
Andy McFadden62a75162009-04-17 17:23:37 -0700939 lookupClassByDescriptor(meth, descriptor, &failure);
940 assert(VERIFY_OK(failure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800941 type = regTypeFromClass(clazz);
942 }
943 break;
944 default:
945 /* we verified signature return type earlier, so this is impossible */
946 assert(false);
947 type = kRegTypeConflict;
948 break;
949 }
950
951 return type;
952}
953
954/*
955 * Convert a single-character signature value (i.e. a primitive type) to
956 * the corresponding RegType. This is intended for access to object fields
957 * holding primitive types.
958 *
959 * Returns kRegTypeUnknown for objects, arrays, and void.
960 */
961static RegType primSigCharToRegType(char sigChar)
962{
963 RegType type;
964
965 switch (sigChar) {
966 case 'I':
967 type = kRegTypeInteger;
968 break;
969 case 'C':
970 type = kRegTypeChar;
971 break;
972 case 'S':
973 type = kRegTypeShort;
974 break;
975 case 'B':
976 type = kRegTypeByte;
977 break;
978 case 'Z':
979 type = kRegTypeBoolean;
980 break;
981 case 'F':
982 type = kRegTypeFloat;
983 break;
984 case 'D':
985 type = kRegTypeDoubleLo;
986 break;
987 case 'J':
988 type = kRegTypeLongLo;
989 break;
990 case 'V':
991 case 'L':
992 case '[':
993 type = kRegTypeUnknown;
994 break;
995 default:
996 assert(false);
997 type = kRegTypeUnknown;
998 break;
999 }
1000
1001 return type;
1002}
1003
1004/*
Andy McFadden99a33e72010-10-10 12:59:11 -07001005 * See if the method matches the MethodType.
1006 */
1007static bool isCorrectInvokeKind(MethodType methodType, Method* resMethod)
1008{
1009 switch (methodType) {
1010 case METHOD_DIRECT:
1011 return dvmIsDirectMethod(resMethod);
1012 case METHOD_STATIC:
1013 return dvmIsStaticMethod(resMethod);
1014 case METHOD_VIRTUAL:
1015 case METHOD_INTERFACE:
1016 return !dvmIsDirectMethod(resMethod);
1017 default:
1018 return false;
1019 }
1020}
1021
1022/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001023 * Verify the arguments to a method. We're executing in "method", making
1024 * a call to the method reference in vB.
1025 *
1026 * If this is a "direct" invoke, we allow calls to <init>. For calls to
1027 * <init>, the first argument may be an uninitialized reference. Otherwise,
1028 * calls to anything starting with '<' will be rejected, as will any
1029 * uninitialized reference arguments.
1030 *
1031 * For non-static method calls, this will verify that the method call is
1032 * appropriate for the "this" argument.
1033 *
1034 * The method reference is in vBBBB. The "isRange" parameter determines
1035 * whether we use 0-4 "args" values or a range of registers defined by
1036 * vAA and vCCCC.
1037 *
1038 * Widening conversions on integers and references are allowed, but
1039 * narrowing conversions are not.
1040 *
Andy McFadden62a75162009-04-17 17:23:37 -07001041 * Returns the resolved method on success, NULL on failure (with *pFailure
1042 * set appropriately).
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001043 */
1044static Method* verifyInvocationArgs(const Method* meth, const RegType* insnRegs,
1045 const int insnRegCount, const DecodedInstruction* pDecInsn,
1046 UninitInstanceMap* uninitMap, MethodType methodType, bool isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07001047 bool isSuper, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001048{
1049 Method* resMethod;
1050 char* sigOriginal = NULL;
1051
1052 /*
1053 * Resolve the method. This could be an abstract or concrete method
1054 * depending on what sort of call we're making.
1055 */
1056 if (methodType == METHOD_INTERFACE) {
1057 resMethod = dvmOptResolveInterfaceMethod(meth->clazz, pDecInsn->vB);
1058 } else {
Andy McFadden62a75162009-04-17 17:23:37 -07001059 resMethod = dvmOptResolveMethod(meth->clazz, pDecInsn->vB, methodType,
1060 pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001061 }
1062 if (resMethod == NULL) {
1063 /* failed; print a meaningful failure message */
1064 DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
1065 const DexMethodId* pMethodId;
1066 const char* methodName;
1067 char* methodDesc;
1068 const char* classDescriptor;
1069
1070 pMethodId = dexGetMethodId(pDexFile, pDecInsn->vB);
1071 methodName = dexStringById(pDexFile, pMethodId->nameIdx);
1072 methodDesc = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
1073 classDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
1074
1075 if (!gDvm.optimizing) {
1076 char* dotMissingClass = dvmDescriptorToDot(classDescriptor);
1077 char* dotMethClass = dvmDescriptorToDot(meth->clazz->descriptor);
1078 //char* curMethodDesc =
1079 // dexProtoCopyMethodDescriptor(&meth->prototype);
1080
Andy McFadden99a33e72010-10-10 12:59:11 -07001081 LOGI("Could not find method %s.%s, referenced from method %s.%s\n",
1082 dotMissingClass, methodName/*, methodDesc*/,
1083 dotMethClass, meth->name/*, curMethodDesc*/);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001084
1085 free(dotMissingClass);
1086 free(dotMethClass);
1087 //free(curMethodDesc);
1088 }
1089
1090 LOG_VFY("VFY: unable to resolve %s method %u: %s.%s %s\n",
1091 dvmMethodTypeStr(methodType), pDecInsn->vB,
1092 classDescriptor, methodName, methodDesc);
1093 free(methodDesc);
Andy McFaddenb51ea112009-05-08 16:50:17 -07001094 if (VERIFY_OK(*pFailure)) /* not set for interface resolve */
1095 *pFailure = VERIFY_ERROR_NO_METHOD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001096 goto fail;
1097 }
1098
1099 /*
1100 * Only time you can explicitly call a method starting with '<' is when
1101 * making a "direct" invocation on "<init>". There are additional
1102 * restrictions but we don't enforce them here.
1103 */
1104 if (resMethod->name[0] == '<') {
1105 if (methodType != METHOD_DIRECT || !isInitMethod(resMethod)) {
1106 LOG_VFY("VFY: invalid call to %s.%s\n",
1107 resMethod->clazz->descriptor, resMethod->name);
1108 goto bad_sig;
1109 }
1110 }
1111
1112 /*
Andy McFadden99a33e72010-10-10 12:59:11 -07001113 * See if the method type implied by the invoke instruction matches the
1114 * access flags for the target method.
1115 */
1116 if (!isCorrectInvokeKind(methodType, resMethod)) {
1117 LOG_VFY("VFY: invoke type does not match method type of %s.%s\n",
1118 resMethod->clazz->descriptor, resMethod->name);
1119 goto fail;
1120 }
1121
1122 /*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001123 * If we're using invoke-super(method), make sure that the executing
1124 * method's class' superclass has a vtable entry for the target method.
1125 */
1126 if (isSuper) {
1127 assert(methodType == METHOD_VIRTUAL);
1128 ClassObject* super = meth->clazz->super;
1129 if (super == NULL || resMethod->methodIndex > super->vtableCount) {
1130 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1131 LOG_VFY("VFY: invalid invoke-super from %s.%s to super %s.%s %s\n",
1132 meth->clazz->descriptor, meth->name,
1133 (super == NULL) ? "-" : super->descriptor,
1134 resMethod->name, desc);
1135 free(desc);
Andy McFadden62a75162009-04-17 17:23:37 -07001136 *pFailure = VERIFY_ERROR_NO_METHOD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001137 goto fail;
1138 }
1139 }
1140
1141 /*
1142 * We use vAA as our expected arg count, rather than resMethod->insSize,
1143 * because we need to match the call to the signature. Also, we might
1144 * might be calling through an abstract method definition (which doesn't
1145 * have register count values).
1146 */
1147 sigOriginal = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1148 const char* sig = sigOriginal;
1149 int expectedArgs = pDecInsn->vA;
1150 int actualArgs = 0;
1151
1152 if (!isRange && expectedArgs > 5) {
1153 LOG_VFY("VFY: invalid arg count in non-range invoke (%d)\n",
1154 pDecInsn->vA);
1155 goto fail;
1156 }
1157 if (expectedArgs > meth->outsSize) {
1158 LOG_VFY("VFY: invalid arg count (%d) exceeds outsSize (%d)\n",
1159 expectedArgs, meth->outsSize);
1160 goto fail;
1161 }
1162
1163 if (*sig++ != '(')
1164 goto bad_sig;
1165
1166 /*
1167 * Check the "this" argument, which must be an instance of the class
1168 * that declared the method. For an interface class, we don't do the
1169 * full interface merge, so we can't do a rigorous check here (which
1170 * is okay since we have to do it at runtime).
1171 */
1172 if (!dvmIsStaticMethod(resMethod)) {
1173 ClassObject* actualThisRef;
1174 RegType actualArgType;
1175
1176 actualArgType = getInvocationThis(insnRegs, insnRegCount, pDecInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07001177 pFailure);
1178 if (!VERIFY_OK(*pFailure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001179 goto fail;
1180
1181 if (regTypeIsUninitReference(actualArgType) && resMethod->name[0] != '<')
1182 {
1183 LOG_VFY("VFY: 'this' arg must be initialized\n");
1184 goto fail;
1185 }
1186 if (methodType != METHOD_INTERFACE && actualArgType != kRegTypeZero) {
1187 actualThisRef = regTypeReferenceToClass(actualArgType, uninitMap);
1188 if (!dvmInstanceof(actualThisRef, resMethod->clazz)) {
1189 LOG_VFY("VFY: 'this' arg '%s' not instance of '%s'\n",
1190 actualThisRef->descriptor,
1191 resMethod->clazz->descriptor);
1192 goto fail;
1193 }
1194 }
1195 actualArgs++;
1196 }
1197
1198 /*
1199 * Process the target method's signature. This signature may or may not
1200 * have been verified, so we can't assume it's properly formed.
1201 */
1202 while (*sig != '\0' && *sig != ')') {
1203 if (actualArgs >= expectedArgs) {
1204 LOG_VFY("VFY: expected %d args, found more (%c)\n",
1205 expectedArgs, *sig);
1206 goto bad_sig;
1207 }
1208
1209 u4 getReg;
1210 if (isRange)
1211 getReg = pDecInsn->vC + actualArgs;
1212 else
1213 getReg = pDecInsn->arg[actualArgs];
1214
1215 switch (*sig) {
1216 case 'L':
1217 {
Andy McFadden62a75162009-04-17 17:23:37 -07001218 ClassObject* clazz = lookupSignatureClass(meth, &sig, pFailure);
1219 if (!VERIFY_OK(*pFailure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001220 goto bad_sig;
1221 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001222 regTypeFromClass(clazz), pFailure);
1223 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001224 LOG_VFY("VFY: bad arg %d (into %s)\n",
1225 actualArgs, clazz->descriptor);
1226 goto bad_sig;
1227 }
1228 }
1229 actualArgs++;
1230 break;
1231 case '[':
1232 {
1233 ClassObject* clazz =
Andy McFadden62a75162009-04-17 17:23:37 -07001234 lookupSignatureArrayClass(meth, &sig, pFailure);
1235 if (!VERIFY_OK(*pFailure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001236 goto bad_sig;
1237 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001238 regTypeFromClass(clazz), pFailure);
1239 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001240 LOG_VFY("VFY: bad arg %d (into %s)\n",
1241 actualArgs, clazz->descriptor);
1242 goto bad_sig;
1243 }
1244 }
1245 actualArgs++;
1246 break;
1247 case 'Z':
1248 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001249 kRegTypeBoolean, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001250 actualArgs++;
1251 break;
1252 case 'C':
1253 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001254 kRegTypeChar, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001255 actualArgs++;
1256 break;
1257 case 'B':
1258 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001259 kRegTypeByte, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001260 actualArgs++;
1261 break;
1262 case 'I':
1263 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001264 kRegTypeInteger, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001265 actualArgs++;
1266 break;
1267 case 'S':
1268 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001269 kRegTypeShort, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001270 actualArgs++;
1271 break;
1272 case 'F':
1273 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001274 kRegTypeFloat, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001275 actualArgs++;
1276 break;
1277 case 'D':
1278 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001279 kRegTypeDoubleLo, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001280 actualArgs += 2;
1281 break;
1282 case 'J':
1283 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001284 kRegTypeLongLo, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001285 actualArgs += 2;
1286 break;
1287 default:
1288 LOG_VFY("VFY: invocation target: bad signature type char '%c'\n",
1289 *sig);
1290 goto bad_sig;
1291 }
1292
1293 sig++;
1294 }
1295 if (*sig != ')') {
1296 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1297 LOG_VFY("VFY: invocation target: bad signature '%s'\n", desc);
1298 free(desc);
1299 goto bad_sig;
1300 }
1301
1302 if (actualArgs != expectedArgs) {
1303 LOG_VFY("VFY: expected %d args, found %d\n", expectedArgs, actualArgs);
1304 goto bad_sig;
1305 }
1306
1307 free(sigOriginal);
1308 return resMethod;
1309
1310bad_sig:
1311 if (resMethod != NULL) {
1312 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1313 LOG_VFY("VFY: rejecting call to %s.%s %s\n",
Andy McFadden62a75162009-04-17 17:23:37 -07001314 resMethod->clazz->descriptor, resMethod->name, desc);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001315 free(desc);
1316 }
1317
1318fail:
1319 free(sigOriginal);
Andy McFadden62a75162009-04-17 17:23:37 -07001320 if (*pFailure == VERIFY_ERROR_NONE)
1321 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001322 return NULL;
1323}
1324
1325/*
1326 * Get the class object for the type of data stored in a field. This isn't
1327 * stored in the Field struct, so we have to recover it from the signature.
1328 *
1329 * This only works for reference types. Don't call this for primitive types.
1330 *
1331 * If we can't find the class, we return java.lang.Object, so that
1332 * verification can continue if a field is only accessed in trivial ways.
1333 */
1334static ClassObject* getFieldClass(const Method* meth, const Field* field)
1335{
1336 ClassObject* fieldClass;
1337 const char* signature = field->signature;
1338
1339 if ((*signature == 'L') || (*signature == '[')) {
1340 fieldClass = dvmFindClassNoInit(signature,
1341 meth->clazz->classLoader);
1342 } else {
1343 return NULL;
1344 }
1345
1346 if (fieldClass == NULL) {
1347 dvmClearOptException(dvmThreadSelf());
1348 LOGV("VFY: unable to find class '%s' for field %s.%s, trying Object\n",
1349 field->signature, meth->clazz->descriptor, field->name);
1350 fieldClass = gDvm.classJavaLangObject;
1351 } else {
1352 assert(!dvmIsPrimitiveClass(fieldClass));
1353 }
1354 return fieldClass;
1355}
1356
1357
1358/*
1359 * ===========================================================================
1360 * Register operations
1361 * ===========================================================================
1362 */
1363
1364/*
1365 * Get the type of register N, verifying that the register is valid.
1366 *
Andy McFadden62a75162009-04-17 17:23:37 -07001367 * Sets "*pFailure" appropriately if the register number is out of range.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001368 */
1369static inline RegType getRegisterType(const RegType* insnRegs,
Andy McFadden62a75162009-04-17 17:23:37 -07001370 const int insnRegCount, u4 vsrc, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001371{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001372 if (vsrc >= (u4) insnRegCount) {
Andy McFadden62a75162009-04-17 17:23:37 -07001373 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001374 return kRegTypeUnknown;
1375 } else {
1376 return insnRegs[vsrc];
1377 }
1378}
1379
1380/*
1381 * Get the value from a register, and cast it to a ClassObject. Sets
Andy McFadden62a75162009-04-17 17:23:37 -07001382 * "*pFailure" if something fails.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001383 *
1384 * This fails if the register holds an uninitialized class.
1385 *
1386 * If the register holds kRegTypeZero, this returns a NULL pointer.
1387 */
1388static ClassObject* getClassFromRegister(const RegType* insnRegs,
Andy McFadden62a75162009-04-17 17:23:37 -07001389 const int insnRegCount, u4 vsrc, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001390{
1391 ClassObject* clazz = NULL;
1392 RegType type;
1393
1394 /* get the element type of the array held in vsrc */
Andy McFadden62a75162009-04-17 17:23:37 -07001395 type = getRegisterType(insnRegs, insnRegCount, vsrc, pFailure);
1396 if (!VERIFY_OK(*pFailure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001397 goto bail;
1398
1399 /* if "always zero", we allow it to fail at runtime */
1400 if (type == kRegTypeZero)
1401 goto bail;
1402
1403 if (!regTypeIsReference(type)) {
1404 LOG_VFY("VFY: tried to get class from non-ref register v%d (type=%d)\n",
1405 vsrc, type);
Andy McFadden62a75162009-04-17 17:23:37 -07001406 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001407 goto bail;
1408 }
1409 if (regTypeIsUninitReference(type)) {
1410 LOG_VFY("VFY: register %u holds uninitialized reference\n", vsrc);
Andy McFadden62a75162009-04-17 17:23:37 -07001411 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001412 goto bail;
1413 }
1414
1415 clazz = regTypeInitializedReferenceToClass(type);
1416
1417bail:
1418 return clazz;
1419}
1420
1421/*
1422 * Get the "this" pointer from a non-static method invocation. This
1423 * returns the RegType so the caller can decide whether it needs the
1424 * reference to be initialized or not. (Can also return kRegTypeZero
1425 * if the reference can only be zero at this point.)
1426 *
1427 * The argument count is in vA, and the first argument is in vC, for both
1428 * "simple" and "range" versions. We just need to make sure vA is >= 1
1429 * and then return vC.
1430 */
1431static RegType getInvocationThis(const RegType* insnRegs,
Andy McFadden62a75162009-04-17 17:23:37 -07001432 const int insnRegCount, const DecodedInstruction* pDecInsn,
1433 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001434{
1435 RegType thisType = kRegTypeUnknown;
1436
1437 if (pDecInsn->vA < 1) {
1438 LOG_VFY("VFY: invoke lacks 'this'\n");
Andy McFadden62a75162009-04-17 17:23:37 -07001439 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001440 goto bail;
1441 }
1442
1443 /* get the element type of the array held in vsrc */
Andy McFadden62a75162009-04-17 17:23:37 -07001444 thisType = getRegisterType(insnRegs, insnRegCount, pDecInsn->vC, pFailure);
1445 if (!VERIFY_OK(*pFailure)) {
1446 LOG_VFY("VFY: failed to get 'this' from register %u\n", pDecInsn->vC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001447 goto bail;
1448 }
1449
1450 if (!regTypeIsReference(thisType)) {
1451 LOG_VFY("VFY: tried to get class from non-ref register v%d (type=%d)\n",
1452 pDecInsn->vC, thisType);
Andy McFadden62a75162009-04-17 17:23:37 -07001453 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001454 goto bail;
1455 }
1456
1457bail:
1458 return thisType;
1459}
1460
1461/*
1462 * Set the type of register N, verifying that the register is valid. If
1463 * "newType" is the "Lo" part of a 64-bit value, register N+1 will be
1464 * set to "newType+1".
1465 *
Andy McFadden62a75162009-04-17 17:23:37 -07001466 * Sets "*pFailure" if the register number is out of range.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001467 */
1468static void setRegisterType(RegType* insnRegs, const int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001469 u4 vdst, RegType newType, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001470{
1471 //LOGD("set-reg v%u = %d\n", vdst, newType);
1472 switch (newType) {
1473 case kRegTypeUnknown:
1474 case kRegTypeBoolean:
1475 case kRegTypeOne:
1476 case kRegTypeByte:
1477 case kRegTypePosByte:
1478 case kRegTypeShort:
1479 case kRegTypePosShort:
1480 case kRegTypeChar:
1481 case kRegTypeInteger:
1482 case kRegTypeFloat:
1483 case kRegTypeZero:
1484 if (vdst >= (u4) insnRegCount) {
Andy McFadden62a75162009-04-17 17:23:37 -07001485 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001486 } else {
1487 insnRegs[vdst] = newType;
1488 }
1489 break;
1490 case kRegTypeLongLo:
1491 case kRegTypeDoubleLo:
1492 if (vdst+1 >= (u4) insnRegCount) {
Andy McFadden62a75162009-04-17 17:23:37 -07001493 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001494 } else {
1495 insnRegs[vdst] = newType;
1496 insnRegs[vdst+1] = newType+1;
1497 }
1498 break;
1499 case kRegTypeLongHi:
1500 case kRegTypeDoubleHi:
1501 /* should never set these explicitly */
Andy McFadden62a75162009-04-17 17:23:37 -07001502 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001503 break;
1504
1505 case kRegTypeUninit:
1506 default:
1507 if (regTypeIsReference(newType)) {
1508 if (vdst >= (u4) insnRegCount) {
Andy McFadden62a75162009-04-17 17:23:37 -07001509 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001510 break;
1511 }
1512 insnRegs[vdst] = newType;
1513
1514 /*
1515 * In most circumstances we won't see a reference to a primitive
1516 * class here (e.g. "D"), since that would mean the object in the
1517 * register is actually a primitive type. It can happen as the
1518 * result of an assumed-successful check-cast instruction in
1519 * which the second argument refers to a primitive class. (In
1520 * practice, such an instruction will always throw an exception.)
1521 *
1522 * This is not an issue for instructions like const-class, where
1523 * the object in the register is a java.lang.Class instance.
1524 */
1525 break;
1526 }
1527 /* bad - fall through */
1528
1529 case kRegTypeConflict: // should only be set during a merge
1530 LOG_VFY("Unexpected set type %d\n", newType);
1531 assert(false);
Andy McFadden62a75162009-04-17 17:23:37 -07001532 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001533 break;
1534 }
1535}
1536
1537/*
1538 * Verify that the contents of the specified register have the specified
1539 * type (or can be converted to it through an implicit widening conversion).
1540 *
1541 * In theory we could use this to modify the type of the source register,
1542 * e.g. a generic 32-bit constant, once used as a float, would thereafter
1543 * remain a float. There is no compelling reason to require this though.
1544 *
1545 * If "vsrc" is a reference, both it and the "vsrc" register must be
1546 * initialized ("vsrc" may be Zero). This will verify that the value in
1547 * the register is an instance of checkType, or if checkType is an
1548 * interface, verify that the register implements checkType.
1549 */
1550static void verifyRegisterType(const RegType* insnRegs, const int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001551 u4 vsrc, RegType checkType, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001552{
1553 if (vsrc >= (u4) insnRegCount) {
Andy McFadden62a75162009-04-17 17:23:37 -07001554 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001555 return;
1556 }
1557
1558 RegType srcType = insnRegs[vsrc];
1559
1560 //LOGD("check-reg v%u = %d\n", vsrc, checkType);
1561 switch (checkType) {
1562 case kRegTypeFloat:
1563 case kRegTypeBoolean:
1564 case kRegTypePosByte:
1565 case kRegTypeByte:
1566 case kRegTypePosShort:
1567 case kRegTypeShort:
1568 case kRegTypeChar:
1569 case kRegTypeInteger:
1570 if (!canConvertTo1nr(srcType, checkType)) {
1571 LOG_VFY("VFY: register1 v%u type %d, wanted %d\n",
1572 vsrc, srcType, checkType);
Andy McFadden62a75162009-04-17 17:23:37 -07001573 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001574 }
1575 break;
1576 case kRegTypeLongLo:
1577 case kRegTypeDoubleLo:
1578 if (vsrc+1 >= (u4) insnRegCount) {
1579 LOG_VFY("VFY: register2 v%u out of range (%d)\n",
1580 vsrc, insnRegCount);
Andy McFadden62a75162009-04-17 17:23:37 -07001581 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001582 } else if (insnRegs[vsrc+1] != srcType+1) {
1583 LOG_VFY("VFY: register2 v%u-%u values %d,%d\n",
1584 vsrc, vsrc+1, insnRegs[vsrc], insnRegs[vsrc+1]);
Andy McFadden62a75162009-04-17 17:23:37 -07001585 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001586 } else if (!canConvertTo2(srcType, checkType)) {
1587 LOG_VFY("VFY: register2 v%u type %d, wanted %d\n",
1588 vsrc, srcType, checkType);
Andy McFadden62a75162009-04-17 17:23:37 -07001589 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001590 }
1591 break;
1592
1593 case kRegTypeLongHi:
1594 case kRegTypeDoubleHi:
1595 case kRegTypeZero:
1596 case kRegTypeOne:
1597 case kRegTypeUnknown:
1598 case kRegTypeConflict:
1599 /* should never be checking for these explicitly */
1600 assert(false);
Andy McFadden62a75162009-04-17 17:23:37 -07001601 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001602 return;
1603 case kRegTypeUninit:
1604 default:
1605 /* make sure checkType is initialized reference */
1606 if (!regTypeIsReference(checkType)) {
1607 LOG_VFY("VFY: unexpected check type %d\n", checkType);
1608 assert(false);
Andy McFadden62a75162009-04-17 17:23:37 -07001609 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001610 break;
1611 }
1612 if (regTypeIsUninitReference(checkType)) {
1613 LOG_VFY("VFY: uninitialized ref not expected as reg check\n");
Andy McFadden62a75162009-04-17 17:23:37 -07001614 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001615 break;
1616 }
1617 /* make sure srcType is initialized reference or always-NULL */
1618 if (!regTypeIsReference(srcType)) {
1619 LOG_VFY("VFY: register1 v%u type %d, wanted ref\n", vsrc, srcType);
Andy McFadden62a75162009-04-17 17:23:37 -07001620 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001621 break;
1622 }
1623 if (regTypeIsUninitReference(srcType)) {
1624 LOG_VFY("VFY: register1 v%u holds uninitialized ref\n", vsrc);
Andy McFadden62a75162009-04-17 17:23:37 -07001625 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001626 break;
1627 }
1628 /* if the register isn't Zero, make sure it's an instance of check */
1629 if (srcType != kRegTypeZero) {
1630 ClassObject* srcClass = regTypeInitializedReferenceToClass(srcType);
1631 ClassObject* checkClass = regTypeInitializedReferenceToClass(checkType);
1632 assert(srcClass != NULL);
1633 assert(checkClass != NULL);
1634
1635 if (dvmIsInterfaceClass(checkClass)) {
1636 /*
1637 * All objects implement all interfaces as far as the
1638 * verifier is concerned. The runtime has to sort it out.
1639 * See comments above findCommonSuperclass.
1640 */
1641 /*
1642 if (srcClass != checkClass &&
1643 !dvmImplements(srcClass, checkClass))
1644 {
1645 LOG_VFY("VFY: %s does not implement %s\n",
1646 srcClass->descriptor, checkClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07001647 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001648 }
1649 */
1650 } else {
1651 if (!dvmInstanceof(srcClass, checkClass)) {
1652 LOG_VFY("VFY: %s is not instance of %s\n",
1653 srcClass->descriptor, checkClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07001654 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001655 }
1656 }
1657 }
1658 break;
1659 }
1660}
1661
1662/*
1663 * Set the type of the "result" register. Mostly this exists to expand
1664 * "insnRegCount" to encompass the result register.
1665 */
1666static void setResultRegisterType(RegType* insnRegs, const int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001667 RegType newType, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001668{
1669 setRegisterType(insnRegs, insnRegCount + kExtraRegs,
Andy McFadden62a75162009-04-17 17:23:37 -07001670 RESULT_REGISTER(insnRegCount), newType, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001671}
1672
1673
1674/*
1675 * Update all registers holding "uninitType" to instead hold the
1676 * corresponding initialized reference type. This is called when an
1677 * appropriate <init> method is invoked -- all copies of the reference
1678 * must be marked as initialized.
1679 */
1680static void markRefsAsInitialized(RegType* insnRegs, int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001681 UninitInstanceMap* uninitMap, RegType uninitType, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001682{
1683 ClassObject* clazz;
1684 RegType initType;
1685 int i, changed;
1686
1687 clazz = dvmGetUninitInstance(uninitMap, regTypeToUninitIndex(uninitType));
1688 if (clazz == NULL) {
1689 LOGE("VFY: unable to find type=0x%x (idx=%d)\n",
1690 uninitType, regTypeToUninitIndex(uninitType));
Andy McFadden62a75162009-04-17 17:23:37 -07001691 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001692 return;
1693 }
1694 initType = regTypeFromClass(clazz);
1695
1696 changed = 0;
1697 for (i = 0; i < insnRegCount; i++) {
1698 if (insnRegs[i] == uninitType) {
1699 insnRegs[i] = initType;
1700 changed++;
1701 }
1702 }
1703 //LOGD("VFY: marked %d registers as initialized\n", changed);
1704 assert(changed > 0);
1705
1706 return;
1707}
1708
1709/*
1710 * We're creating a new instance of class C at address A. Any registers
1711 * holding instances previously created at address A must be initialized
1712 * by now. If not, we mark them as "conflict" to prevent them from being
1713 * used (otherwise, markRefsAsInitialized would mark the old ones and the
1714 * new ones at the same time).
1715 */
1716static void markUninitRefsAsInvalid(RegType* insnRegs, int insnRegCount,
1717 UninitInstanceMap* uninitMap, RegType uninitType)
1718{
1719 int i, changed;
1720
1721 changed = 0;
1722 for (i = 0; i < insnRegCount; i++) {
1723 if (insnRegs[i] == uninitType) {
1724 insnRegs[i] = kRegTypeConflict;
1725 changed++;
1726 }
1727 }
1728
1729 //if (changed)
1730 // LOGD("VFY: marked %d uninitialized registers as invalid\n", changed);
1731}
1732
1733/*
1734 * Find the start of the register set for the specified instruction in
1735 * the current method.
1736 */
1737static inline RegType* getRegisterLine(const RegisterTable* regTable,
1738 int insnIdx)
1739{
1740 return regTable->addrRegs[insnIdx];
1741}
1742
1743/*
1744 * Copy a bunch of registers.
1745 */
1746static inline void copyRegisters(RegType* dst, const RegType* src,
1747 int numRegs)
1748{
1749 memcpy(dst, src, numRegs * sizeof(RegType));
1750}
1751
1752/*
1753 * Compare a bunch of registers.
1754 *
1755 * Returns 0 if they match. Using this for a sort is unwise, since the
1756 * value can change based on machine endianness.
1757 */
1758static inline int compareRegisters(const RegType* src1, const RegType* src2,
1759 int numRegs)
1760{
1761 return memcmp(src1, src2, numRegs * sizeof(RegType));
1762}
1763
1764/*
1765 * Register type categories, for type checking.
1766 *
1767 * The spec says category 1 includes boolean, byte, char, short, int, float,
1768 * reference, and returnAddress. Category 2 includes long and double.
1769 *
1770 * We treat object references separately, so we have "category1nr". We
1771 * don't support jsr/ret, so there is no "returnAddress" type.
1772 */
1773typedef enum TypeCategory {
1774 kTypeCategoryUnknown = 0,
1775 kTypeCategory1nr, // byte, char, int, float, boolean
1776 kTypeCategory2, // long, double
1777 kTypeCategoryRef, // object reference
1778} TypeCategory;
1779
1780/*
1781 * See if "type" matches "cat". All we're really looking for here is that
1782 * we're not mixing and matching 32-bit and 64-bit quantities, and we're
1783 * not mixing references with numerics. (For example, the arguments to
1784 * "a < b" could be integers of different sizes, but they must both be
1785 * integers. Dalvik is less specific about int vs. float, so we treat them
1786 * as equivalent here.)
1787 *
1788 * For category 2 values, "type" must be the "low" half of the value.
1789 *
Andy McFadden62a75162009-04-17 17:23:37 -07001790 * Sets "*pFailure" if something looks wrong.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001791 */
Andy McFadden62a75162009-04-17 17:23:37 -07001792static void checkTypeCategory(RegType type, TypeCategory cat,
1793 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001794{
1795 switch (cat) {
1796 case kTypeCategory1nr:
1797 switch (type) {
1798 case kRegTypeFloat:
1799 case kRegTypeZero:
1800 case kRegTypeOne:
1801 case kRegTypeBoolean:
1802 case kRegTypePosByte:
1803 case kRegTypeByte:
1804 case kRegTypePosShort:
1805 case kRegTypeShort:
1806 case kRegTypeChar:
1807 case kRegTypeInteger:
1808 break;
1809 default:
Andy McFadden62a75162009-04-17 17:23:37 -07001810 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001811 break;
1812 }
1813 break;
1814
1815 case kTypeCategory2:
1816 switch (type) {
1817 case kRegTypeLongLo:
1818 case kRegTypeDoubleLo:
1819 break;
1820 default:
Andy McFadden62a75162009-04-17 17:23:37 -07001821 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001822 break;
1823 }
1824 break;
1825
1826 case kTypeCategoryRef:
1827 if (type != kRegTypeZero && !regTypeIsReference(type))
Andy McFadden62a75162009-04-17 17:23:37 -07001828 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001829 break;
1830
1831 default:
1832 assert(false);
Andy McFadden62a75162009-04-17 17:23:37 -07001833 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001834 break;
1835 }
1836}
1837
1838/*
1839 * For a category 2 register pair, verify that "typeh" is the appropriate
1840 * high part for "typel".
1841 *
1842 * Does not verify that "typel" is in fact the low part of a 64-bit
1843 * register pair.
1844 */
Andy McFadden62a75162009-04-17 17:23:37 -07001845static void checkWidePair(RegType typel, RegType typeh, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001846{
1847 if ((typeh != typel+1))
Andy McFadden62a75162009-04-17 17:23:37 -07001848 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001849}
1850
1851/*
1852 * Implement category-1 "move" instructions. Copy a 32-bit value from
1853 * "vsrc" to "vdst".
1854 *
1855 * "insnRegCount" is the number of registers available. The "vdst" and
1856 * "vsrc" values are checked against this.
1857 */
1858static void copyRegister1(RegType* insnRegs, int insnRegCount, u4 vdst,
Andy McFadden62a75162009-04-17 17:23:37 -07001859 u4 vsrc, TypeCategory cat, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001860{
Andy McFadden62a75162009-04-17 17:23:37 -07001861 RegType type = getRegisterType(insnRegs, insnRegCount, vsrc, pFailure);
1862 if (VERIFY_OK(*pFailure))
1863 checkTypeCategory(type, cat, pFailure);
1864 if (VERIFY_OK(*pFailure))
1865 setRegisterType(insnRegs, insnRegCount, vdst, type, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001866
Andy McFadden62a75162009-04-17 17:23:37 -07001867 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001868 LOG_VFY("VFY: copy1 v%u<-v%u type=%d cat=%d\n", vdst, vsrc, type, cat);
1869 }
1870}
1871
1872/*
1873 * Implement category-2 "move" instructions. Copy a 64-bit value from
1874 * "vsrc" to "vdst". This copies both halves of the register.
1875 */
1876static void copyRegister2(RegType* insnRegs, int insnRegCount, u4 vdst,
Andy McFadden62a75162009-04-17 17:23:37 -07001877 u4 vsrc, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001878{
Andy McFadden62a75162009-04-17 17:23:37 -07001879 RegType typel = getRegisterType(insnRegs, insnRegCount, vsrc, pFailure);
1880 RegType typeh = getRegisterType(insnRegs, insnRegCount, vsrc+1, pFailure);
1881 if (VERIFY_OK(*pFailure)) {
1882 checkTypeCategory(typel, kTypeCategory2, pFailure);
1883 checkWidePair(typel, typeh, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001884 }
Andy McFadden62a75162009-04-17 17:23:37 -07001885 if (VERIFY_OK(*pFailure))
1886 setRegisterType(insnRegs, insnRegCount, vdst, typel, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001887
Andy McFadden62a75162009-04-17 17:23:37 -07001888 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001889 LOG_VFY("VFY: copy2 v%u<-v%u type=%d/%d\n", vdst, vsrc, typel, typeh);
1890 }
1891}
1892
1893/*
1894 * Implement "move-result". Copy the category-1 value from the result
1895 * register to another register, and reset the result register.
1896 *
1897 * We can't just call copyRegister1 with an altered insnRegCount,
1898 * because that would affect the test on "vdst" as well.
1899 */
1900static void copyResultRegister1(RegType* insnRegs, const int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001901 u4 vdst, TypeCategory cat, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001902{
1903 RegType type;
1904 u4 vsrc;
1905
1906 vsrc = RESULT_REGISTER(insnRegCount);
Andy McFadden62a75162009-04-17 17:23:37 -07001907 type = getRegisterType(insnRegs, insnRegCount + kExtraRegs, vsrc, pFailure);
1908 if (VERIFY_OK(*pFailure))
1909 checkTypeCategory(type, cat, pFailure);
1910 if (VERIFY_OK(*pFailure)) {
1911 setRegisterType(insnRegs, insnRegCount, vdst, type, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001912 insnRegs[vsrc] = kRegTypeUnknown;
1913 }
1914
Andy McFadden62a75162009-04-17 17:23:37 -07001915 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001916 LOG_VFY("VFY: copyRes1 v%u<-v%u cat=%d type=%d\n",
1917 vdst, vsrc, cat, type);
1918 }
1919}
1920
1921/*
1922 * Implement "move-result-wide". Copy the category-2 value from the result
1923 * register to another register, and reset the result register.
1924 *
1925 * We can't just call copyRegister2 with an altered insnRegCount,
1926 * because that would affect the test on "vdst" as well.
1927 */
1928static void copyResultRegister2(RegType* insnRegs, const int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001929 u4 vdst, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001930{
1931 RegType typel, typeh;
1932 u4 vsrc;
1933
1934 vsrc = RESULT_REGISTER(insnRegCount);
Andy McFadden62a75162009-04-17 17:23:37 -07001935 typel = getRegisterType(insnRegs, insnRegCount + kExtraRegs, vsrc,
1936 pFailure);
1937 typeh = getRegisterType(insnRegs, insnRegCount + kExtraRegs, vsrc+1,
1938 pFailure);
1939 if (VERIFY_OK(*pFailure)) {
1940 checkTypeCategory(typel, kTypeCategory2, pFailure);
1941 checkWidePair(typel, typeh, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001942 }
Andy McFadden62a75162009-04-17 17:23:37 -07001943 if (VERIFY_OK(*pFailure)) {
1944 setRegisterType(insnRegs, insnRegCount, vdst, typel, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001945 insnRegs[vsrc] = kRegTypeUnknown;
1946 insnRegs[vsrc+1] = kRegTypeUnknown;
1947 }
1948
Andy McFadden62a75162009-04-17 17:23:37 -07001949 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001950 LOG_VFY("VFY: copyRes2 v%u<-v%u type=%d/%d\n",
1951 vdst, vsrc, typel, typeh);
1952 }
1953}
1954
1955/*
1956 * Verify types for a simple two-register instruction (e.g. "neg-int").
1957 * "dstType" is stored into vA, and "srcType" is verified against vB.
1958 */
1959static void checkUnop(RegType* insnRegs, const int insnRegCount,
1960 DecodedInstruction* pDecInsn, RegType dstType, RegType srcType,
Andy McFadden62a75162009-04-17 17:23:37 -07001961 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001962{
Andy McFadden62a75162009-04-17 17:23:37 -07001963 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType, pFailure);
1964 setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001965}
1966
1967/*
1968 * We're performing an operation like "and-int/2addr" that can be
1969 * performed on booleans as well as integers. We get no indication of
1970 * boolean-ness, but we can infer it from the types of the arguments.
1971 *
1972 * Assumes we've already validated reg1/reg2.
1973 *
Andy McFaddenb5f64bc2009-06-10 14:11:07 -07001974 * TODO: consider generalizing this. The key principle is that the
1975 * result of a bitwise operation can only be as wide as the widest of
1976 * the operands. You can safely AND/OR/XOR two chars together and know
1977 * you still have a char, so it's reasonable for the compiler or "dx"
1978 * to skip the int-to-char instruction. (We need to do this for boolean
1979 * because there is no int-to-boolean operation.)
1980 *
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001981 * Returns true if both args are Boolean, Zero, or One.
1982 */
1983static bool upcastBooleanOp(RegType* insnRegs, const int insnRegCount,
1984 u4 reg1, u4 reg2)
1985{
1986 RegType type1, type2;
1987
1988 type1 = insnRegs[reg1];
1989 type2 = insnRegs[reg2];
1990
1991 if ((type1 == kRegTypeBoolean || type1 == kRegTypeZero ||
1992 type1 == kRegTypeOne) &&
1993 (type2 == kRegTypeBoolean || type2 == kRegTypeZero ||
1994 type2 == kRegTypeOne))
1995 {
1996 return true;
1997 }
1998 return false;
1999}
2000
2001/*
2002 * Verify types for A two-register instruction with a literal constant
2003 * (e.g. "add-int/lit8"). "dstType" is stored into vA, and "srcType" is
2004 * verified against vB.
2005 *
2006 * If "checkBooleanOp" is set, we use the constant value in vC.
2007 */
2008static void checkLitop(RegType* insnRegs, const int insnRegCount,
2009 DecodedInstruction* pDecInsn, RegType dstType, RegType srcType,
Andy McFadden62a75162009-04-17 17:23:37 -07002010 bool checkBooleanOp, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002011{
Andy McFadden62a75162009-04-17 17:23:37 -07002012 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType, pFailure);
2013 if (VERIFY_OK(*pFailure) && checkBooleanOp) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002014 assert(dstType == kRegTypeInteger);
2015 /* check vB with the call, then check the constant manually */
2016 if (upcastBooleanOp(insnRegs, insnRegCount, pDecInsn->vB, pDecInsn->vB)
2017 && (pDecInsn->vC == 0 || pDecInsn->vC == 1))
2018 {
2019 dstType = kRegTypeBoolean;
2020 }
2021 }
Andy McFadden62a75162009-04-17 17:23:37 -07002022 setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002023}
2024
2025/*
2026 * Verify types for a simple three-register instruction (e.g. "add-int").
2027 * "dstType" is stored into vA, and "srcType1"/"srcType2" are verified
2028 * against vB/vC.
2029 */
2030static void checkBinop(RegType* insnRegs, const int insnRegCount,
2031 DecodedInstruction* pDecInsn, RegType dstType, RegType srcType1,
Andy McFadden62a75162009-04-17 17:23:37 -07002032 RegType srcType2, bool checkBooleanOp, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002033{
Andy McFadden62a75162009-04-17 17:23:37 -07002034 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType1,
2035 pFailure);
2036 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vC, srcType2,
2037 pFailure);
2038 if (VERIFY_OK(*pFailure) && checkBooleanOp) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002039 assert(dstType == kRegTypeInteger);
2040 if (upcastBooleanOp(insnRegs, insnRegCount, pDecInsn->vB, pDecInsn->vC))
2041 dstType = kRegTypeBoolean;
2042 }
Andy McFadden62a75162009-04-17 17:23:37 -07002043 setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002044}
2045
2046/*
2047 * Verify types for a binary "2addr" operation. "srcType1"/"srcType2"
2048 * are verified against vA/vB, then "dstType" is stored into vA.
2049 */
2050static void checkBinop2addr(RegType* insnRegs, const int insnRegCount,
2051 DecodedInstruction* pDecInsn, RegType dstType, RegType srcType1,
Andy McFadden62a75162009-04-17 17:23:37 -07002052 RegType srcType2, bool checkBooleanOp, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002053{
Andy McFadden62a75162009-04-17 17:23:37 -07002054 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vA, srcType1,
2055 pFailure);
2056 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType2,
2057 pFailure);
2058 if (VERIFY_OK(*pFailure) && checkBooleanOp) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002059 assert(dstType == kRegTypeInteger);
2060 if (upcastBooleanOp(insnRegs, insnRegCount, pDecInsn->vA, pDecInsn->vB))
2061 dstType = kRegTypeBoolean;
2062 }
Andy McFadden62a75162009-04-17 17:23:37 -07002063 setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002064}
2065
Andy McFadden80d25ea2009-06-12 07:26:17 -07002066/*
2067 * Treat right-shifting as a narrowing conversion when possible.
2068 *
2069 * For example, right-shifting an int 24 times results in a value that can
2070 * be treated as a byte.
2071 *
2072 * Things get interesting when contemplating sign extension. Right-
2073 * shifting an integer by 16 yields a value that can be represented in a
2074 * "short" but not a "char", but an unsigned right shift by 16 yields a
2075 * value that belongs in a char rather than a short. (Consider what would
2076 * happen if the result of the shift were cast to a char or short and then
2077 * cast back to an int. If sign extension, or the lack thereof, causes
2078 * a change in the 32-bit representation, then the conversion was lossy.)
2079 *
2080 * A signed right shift by 17 on an integer results in a short. An unsigned
2081 * right shfit by 17 on an integer results in a posshort, which can be
2082 * assigned to a short or a char.
2083 *
2084 * An unsigned right shift on a short can actually expand the result into
2085 * a 32-bit integer. For example, 0xfffff123 >>> 8 becomes 0x00fffff1,
2086 * which can't be represented in anything smaller than an int.
2087 *
2088 * javac does not generate code that takes advantage of this, but some
2089 * of the code optimizers do. It's generally a peephole optimization
2090 * that replaces a particular sequence, e.g. (bipush 24, ishr, i2b) is
2091 * replaced by (bipush 24, ishr). Knowing that shifting a short 8 times
2092 * to the right yields a byte is really more than we need to handle the
2093 * code that's out there, but support is not much more complex than just
2094 * handling integer.
2095 *
2096 * Right-shifting never yields a boolean value.
2097 *
2098 * Returns the new register type.
2099 */
2100static RegType adjustForRightShift(RegType* workRegs, const int insnRegCount,
2101 int reg, unsigned int shiftCount, bool isUnsignedShift,
2102 VerifyError* pFailure)
2103{
2104 RegType srcType = getRegisterType(workRegs, insnRegCount, reg, pFailure);
2105 RegType newType;
2106
2107 /* no-op */
2108 if (shiftCount == 0)
2109 return srcType;
2110
2111 /* safe defaults */
2112 if (isUnsignedShift)
2113 newType = kRegTypeInteger;
2114 else
2115 newType = srcType;
2116
2117 if (shiftCount >= 32) {
2118 LOG_VFY("Got unexpectedly large shift count %u\n", shiftCount);
2119 /* fail? */
2120 return newType;
2121 }
2122
2123 switch (srcType) {
2124 case kRegTypeInteger: /* 32-bit signed value */
2125 case kRegTypeFloat: /* (allowed; treat same as int) */
2126 if (isUnsignedShift) {
2127 if (shiftCount > 24)
2128 newType = kRegTypePosByte;
2129 else if (shiftCount >= 16)
2130 newType = kRegTypeChar;
2131 } else {
2132 if (shiftCount >= 24)
2133 newType = kRegTypeByte;
2134 else if (shiftCount >= 16)
2135 newType = kRegTypeShort;
2136 }
2137 break;
2138 case kRegTypeShort: /* 16-bit signed value */
2139 if (isUnsignedShift) {
2140 /* default (kRegTypeInteger) is correct */
2141 } else {
2142 if (shiftCount >= 8)
2143 newType = kRegTypeByte;
2144 }
2145 break;
2146 case kRegTypePosShort: /* 15-bit unsigned value */
2147 if (shiftCount >= 8)
2148 newType = kRegTypePosByte;
2149 break;
2150 case kRegTypeChar: /* 16-bit unsigned value */
2151 if (shiftCount > 8)
2152 newType = kRegTypePosByte;
2153 break;
2154 case kRegTypeByte: /* 8-bit signed value */
2155 /* defaults (u=kRegTypeInteger / s=srcType) are correct */
2156 break;
2157 case kRegTypePosByte: /* 7-bit unsigned value */
2158 /* always use newType=srcType */
2159 newType = srcType;
2160 break;
2161 case kRegTypeZero: /* 1-bit unsigned value */
2162 case kRegTypeOne:
2163 case kRegTypeBoolean:
2164 /* unnecessary? */
2165 newType = kRegTypeZero;
2166 break;
2167 default:
2168 /* long, double, references; shouldn't be here! */
2169 assert(false);
2170 break;
2171 }
2172
2173 if (newType != srcType) {
2174 LOGVV("narrowing: %d(%d) --> %d to %d\n",
2175 shiftCount, isUnsignedShift, srcType, newType);
2176 } else {
2177 LOGVV("not narrowed: %d(%d) --> %d\n",
2178 shiftCount, isUnsignedShift, srcType);
2179 }
2180 return newType;
2181}
2182
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002183
2184/*
2185 * ===========================================================================
2186 * Register merge
2187 * ===========================================================================
2188 */
2189
2190/*
2191 * Compute the "class depth" of a class. This is the distance from the
2192 * class to the top of the tree, chasing superclass links. java.lang.Object
2193 * has a class depth of 0.
2194 */
2195static int getClassDepth(ClassObject* clazz)
2196{
2197 int depth = 0;
2198
2199 while (clazz->super != NULL) {
2200 clazz = clazz->super;
2201 depth++;
2202 }
2203 return depth;
2204}
2205
2206/*
2207 * Given two classes, walk up the superclass tree to find a common
2208 * ancestor. (Called from findCommonSuperclass().)
2209 *
2210 * TODO: consider caching the class depth in the class object so we don't
2211 * have to search for it here.
2212 */
2213static ClassObject* digForSuperclass(ClassObject* c1, ClassObject* c2)
2214{
2215 int depth1, depth2;
2216
2217 depth1 = getClassDepth(c1);
2218 depth2 = getClassDepth(c2);
2219
2220 if (gDebugVerbose) {
2221 LOGVV("COMMON: %s(%d) + %s(%d)\n",
2222 c1->descriptor, depth1, c2->descriptor, depth2);
2223 }
2224
2225 /* pull the deepest one up */
2226 if (depth1 > depth2) {
2227 while (depth1 > depth2) {
2228 c1 = c1->super;
2229 depth1--;
2230 }
2231 } else {
2232 while (depth2 > depth1) {
2233 c2 = c2->super;
2234 depth2--;
2235 }
2236 }
2237
2238 /* walk up in lock-step */
2239 while (c1 != c2) {
2240 c1 = c1->super;
2241 c2 = c2->super;
2242
2243 assert(c1 != NULL && c2 != NULL);
2244 }
2245
2246 if (gDebugVerbose) {
2247 LOGVV(" : --> %s\n", c1->descriptor);
2248 }
2249 return c1;
2250}
2251
2252/*
2253 * Merge two array classes. We can't use the general "walk up to the
2254 * superclass" merge because the superclass of an array is always Object.
2255 * We want String[] + Integer[] = Object[]. This works for higher dimensions
2256 * as well, e.g. String[][] + Integer[][] = Object[][].
2257 *
2258 * If Foo1 and Foo2 are subclasses of Foo, Foo1[] + Foo2[] = Foo[].
2259 *
2260 * If Class implements Type, Class[] + Type[] = Type[].
2261 *
2262 * If the dimensions don't match, we want to convert to an array of Object
2263 * with the least dimension, e.g. String[][] + String[][][][] = Object[][].
2264 *
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002265 * Arrays of primitive types effectively have one less dimension when
2266 * merging. int[] + float[] = Object, int[] + String[] = Object,
2267 * int[][] + float[][] = Object[], int[][] + String[] = Object[]. (The
2268 * only time this function doesn't return an array class is when one of
2269 * the arguments is a 1-dimensional primitive array.)
2270 *
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002271 * This gets a little awkward because we may have to ask the VM to create
2272 * a new array type with the appropriate element and dimensions. However, we
2273 * shouldn't be doing this often.
2274 */
2275static ClassObject* findCommonArraySuperclass(ClassObject* c1, ClassObject* c2)
2276{
2277 ClassObject* arrayClass = NULL;
2278 ClassObject* commonElem;
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002279 int arrayDim1, arrayDim2;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002280 int i, numDims;
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002281 bool hasPrimitive = false;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002282
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002283 arrayDim1 = c1->arrayDim;
2284 arrayDim2 = c2->arrayDim;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002285 assert(c1->arrayDim > 0);
2286 assert(c2->arrayDim > 0);
2287
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002288 if (dvmIsPrimitiveClass(c1->elementClass)) {
2289 arrayDim1--;
2290 hasPrimitive = true;
2291 }
2292 if (dvmIsPrimitiveClass(c2->elementClass)) {
2293 arrayDim2--;
2294 hasPrimitive = true;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002295 }
2296
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002297 if (!hasPrimitive && arrayDim1 == arrayDim2) {
2298 /*
2299 * Two arrays of reference types with equal dimensions. Try to
2300 * find a good match.
2301 */
2302 commonElem = findCommonSuperclass(c1->elementClass, c2->elementClass);
2303 numDims = arrayDim1;
2304 } else {
2305 /*
2306 * Mismatched array depths and/or array(s) of primitives. We want
2307 * Object, or an Object array with appropriate dimensions.
2308 *
2309 * We initialize arrayClass to Object here, because it's possible
2310 * for us to set numDims=0.
2311 */
2312 if (arrayDim1 < arrayDim2)
2313 numDims = arrayDim1;
2314 else
2315 numDims = arrayDim2;
2316 arrayClass = commonElem = c1->super; // == java.lang.Object
2317 }
2318
2319 /*
2320 * Find an appropriately-dimensioned array class. This is easiest
2321 * to do iteratively, using the array class found by the current round
2322 * as the element type for the next round.
2323 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002324 for (i = 0; i < numDims; i++) {
2325 arrayClass = dvmFindArrayClassForElement(commonElem);
2326 commonElem = arrayClass;
2327 }
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002328 assert(arrayClass != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002329
2330 LOGVV("ArrayMerge '%s' + '%s' --> '%s'\n",
2331 c1->descriptor, c2->descriptor, arrayClass->descriptor);
2332 return arrayClass;
2333}
2334
2335/*
2336 * Find the first common superclass of the two classes. We're not
2337 * interested in common interfaces.
2338 *
2339 * The easiest way to do this for concrete classes is to compute the "class
2340 * depth" of each, move up toward the root of the deepest one until they're
2341 * at the same depth, then walk both up to the root until they match.
2342 *
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002343 * If both classes are arrays, we need to merge based on array depth and
2344 * element type.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002345 *
2346 * If one class is an interface, we check to see if the other class/interface
2347 * (or one of its predecessors) implements the interface. If so, we return
2348 * the interface; otherwise, we return Object.
2349 *
2350 * NOTE: we continue the tradition of "lazy interface handling". To wit,
2351 * suppose we have three classes:
2352 * One implements Fancy, Free
2353 * Two implements Fancy, Free
2354 * Three implements Free
2355 * where Fancy and Free are unrelated interfaces. The code requires us
2356 * to merge One into Two. Ideally we'd use a common interface, which
2357 * gives us a choice between Fancy and Free, and no guidance on which to
2358 * use. If we use Free, we'll be okay when Three gets merged in, but if
2359 * we choose Fancy, we're hosed. The "ideal" solution is to create a
2360 * set of common interfaces and carry that around, merging further references
2361 * into it. This is a pain. The easy solution is to simply boil them
2362 * down to Objects and let the runtime invokeinterface call fail, which
2363 * is what we do.
2364 */
2365static ClassObject* findCommonSuperclass(ClassObject* c1, ClassObject* c2)
2366{
2367 assert(!dvmIsPrimitiveClass(c1) && !dvmIsPrimitiveClass(c2));
2368
2369 if (c1 == c2)
2370 return c1;
2371
2372 if (dvmIsInterfaceClass(c1) && dvmImplements(c2, c1)) {
2373 if (gDebugVerbose)
2374 LOGVV("COMMON/I1: %s + %s --> %s\n",
2375 c1->descriptor, c2->descriptor, c1->descriptor);
2376 return c1;
2377 }
2378 if (dvmIsInterfaceClass(c2) && dvmImplements(c1, c2)) {
2379 if (gDebugVerbose)
2380 LOGVV("COMMON/I2: %s + %s --> %s\n",
2381 c1->descriptor, c2->descriptor, c2->descriptor);
2382 return c2;
2383 }
2384
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002385 if (dvmIsArrayClass(c1) && dvmIsArrayClass(c2)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002386 return findCommonArraySuperclass(c1, c2);
2387 }
2388
2389 return digForSuperclass(c1, c2);
2390}
2391
2392/*
2393 * Merge two RegType values.
2394 *
2395 * Sets "*pChanged" to "true" if the result doesn't match "type1".
2396 */
2397static RegType mergeTypes(RegType type1, RegType type2, bool* pChanged)
2398{
2399 RegType result;
2400
2401 /*
2402 * Check for trivial case so we don't have to hit memory.
2403 */
2404 if (type1 == type2)
2405 return type1;
2406
2407 /*
2408 * Use the table if we can, and reject any attempts to merge something
2409 * from the table with a reference type.
2410 *
2411 * The uninitialized table entry at index zero *will* show up as a
2412 * simple kRegTypeUninit value. Since this cannot be merged with
2413 * anything but itself, the rules do the right thing.
2414 */
2415 if (type1 < kRegTypeMAX) {
2416 if (type2 < kRegTypeMAX) {
2417 result = gDvmMergeTab[type1][type2];
2418 } else {
2419 /* simple + reference == conflict, usually */
2420 if (type1 == kRegTypeZero)
2421 result = type2;
2422 else
2423 result = kRegTypeConflict;
2424 }
2425 } else {
2426 if (type2 < kRegTypeMAX) {
2427 /* reference + simple == conflict, usually */
2428 if (type2 == kRegTypeZero)
2429 result = type1;
2430 else
2431 result = kRegTypeConflict;
2432 } else {
2433 /* merging two references */
2434 if (regTypeIsUninitReference(type1) ||
2435 regTypeIsUninitReference(type2))
2436 {
2437 /* can't merge uninit with anything but self */
2438 result = kRegTypeConflict;
2439 } else {
2440 ClassObject* clazz1 = regTypeInitializedReferenceToClass(type1);
2441 ClassObject* clazz2 = regTypeInitializedReferenceToClass(type2);
2442 ClassObject* mergedClass;
2443
2444 mergedClass = findCommonSuperclass(clazz1, clazz2);
2445 assert(mergedClass != NULL);
2446 result = regTypeFromClass(mergedClass);
2447 }
2448 }
2449 }
2450
2451 if (result != type1)
2452 *pChanged = true;
2453 return result;
2454}
2455
2456/*
2457 * Control can transfer to "nextInsn".
2458 *
2459 * Merge the registers from "workRegs" into "regTypes" at "nextInsn", and
2460 * set the "changed" flag on the target address if the registers have changed.
2461 */
2462static void updateRegisters(const Method* meth, InsnFlags* insnFlags,
2463 RegisterTable* regTable, int nextInsn, const RegType* workRegs)
2464{
2465 RegType* targetRegs = getRegisterLine(regTable, nextInsn);
2466 const int insnRegCount = meth->registersSize;
2467
2468#if 0
2469 if (!dvmInsnIsBranchTarget(insnFlags, nextInsn)) {
2470 LOGE("insnFlags[0x%x]=0x%08x\n", nextInsn, insnFlags[nextInsn]);
2471 LOGE(" In %s.%s %s\n",
2472 meth->clazz->descriptor, meth->name, meth->descriptor);
2473 assert(false);
2474 }
2475#endif
2476
2477 if (!dvmInsnIsVisitedOrChanged(insnFlags, nextInsn)) {
2478 /*
2479 * We haven't processed this instruction before, and we haven't
2480 * touched the registers here, so there's nothing to "merge". Copy
2481 * the registers over and mark it as changed. (This is the only
2482 * way a register can transition out of "unknown", so this is not
2483 * just an optimization.)
2484 */
2485 LOGVV("COPY into 0x%04x\n", nextInsn);
2486 copyRegisters(targetRegs, workRegs, insnRegCount + kExtraRegs);
2487 dvmInsnSetChanged(insnFlags, nextInsn, true);
2488 } else {
2489 if (gDebugVerbose) {
2490 LOGVV("MERGE into 0x%04x\n", nextInsn);
2491 //dumpRegTypes(meth, insnFlags, targetRegs, 0, "targ", NULL, 0);
2492 //dumpRegTypes(meth, insnFlags, workRegs, 0, "work", NULL, 0);
2493 }
2494 /* merge registers, set Changed only if different */
2495 bool changed = false;
2496 int i;
2497
2498 for (i = 0; i < insnRegCount + kExtraRegs; i++) {
2499 targetRegs[i] = mergeTypes(targetRegs[i], workRegs[i], &changed);
2500 }
2501
2502 if (gDebugVerbose) {
2503 //LOGI(" RESULT (changed=%d)\n", changed);
2504 //dumpRegTypes(meth, insnFlags, targetRegs, 0, "rslt", NULL, 0);
2505 }
2506
2507 if (changed)
2508 dvmInsnSetChanged(insnFlags, nextInsn, true);
2509 }
2510}
2511
2512
2513/*
2514 * ===========================================================================
2515 * Utility functions
2516 * ===========================================================================
2517 */
2518
2519/*
2520 * Look up an instance field, specified by "fieldIdx", that is going to be
2521 * accessed in object "objType". This resolves the field and then verifies
2522 * that the class containing the field is an instance of the reference in
2523 * "objType".
2524 *
2525 * It is possible for "objType" to be kRegTypeZero, meaning that we might
2526 * have a null reference. This is a runtime problem, so we allow it,
2527 * skipping some of the type checks.
2528 *
2529 * In general, "objType" must be an initialized reference. However, we
2530 * allow it to be uninitialized if this is an "<init>" method and the field
2531 * is declared within the "objType" class.
2532 *
Andy McFadden62a75162009-04-17 17:23:37 -07002533 * Returns an InstField on success, returns NULL and sets "*pFailure"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002534 * on failure.
2535 */
2536static InstField* getInstField(const Method* meth,
2537 const UninitInstanceMap* uninitMap, RegType objType, int fieldIdx,
Andy McFadden62a75162009-04-17 17:23:37 -07002538 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002539{
2540 InstField* instField = NULL;
2541 ClassObject* objClass;
2542 bool mustBeLocal = false;
2543
2544 if (!regTypeIsReference(objType)) {
Andy McFadden62a75162009-04-17 17:23:37 -07002545 LOG_VFY("VFY: attempt to access field in non-reference type %d\n",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002546 objType);
Andy McFadden62a75162009-04-17 17:23:37 -07002547 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002548 goto bail;
2549 }
2550
Andy McFadden62a75162009-04-17 17:23:37 -07002551 instField = dvmOptResolveInstField(meth->clazz, fieldIdx, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002552 if (instField == NULL) {
2553 LOG_VFY("VFY: unable to resolve instance field %u\n", fieldIdx);
Andy McFadden62a75162009-04-17 17:23:37 -07002554 assert(!VERIFY_OK(*pFailure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002555 goto bail;
2556 }
2557
2558 if (objType == kRegTypeZero)
2559 goto bail;
2560
2561 /*
2562 * Access to fields in uninitialized objects is allowed if this is
2563 * the <init> method for the object and the field in question is
2564 * declared by this class.
2565 */
2566 objClass = regTypeReferenceToClass(objType, uninitMap);
2567 assert(objClass != NULL);
2568 if (regTypeIsUninitReference(objType)) {
2569 if (!isInitMethod(meth) || meth->clazz != objClass) {
2570 LOG_VFY("VFY: attempt to access field via uninitialized ref\n");
Andy McFadden62a75162009-04-17 17:23:37 -07002571 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002572 goto bail;
2573 }
2574 mustBeLocal = true;
2575 }
2576
2577 if (!dvmInstanceof(objClass, instField->field.clazz)) {
2578 LOG_VFY("VFY: invalid field access (field %s.%s, through %s ref)\n",
2579 instField->field.clazz->descriptor, instField->field.name,
2580 objClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07002581 *pFailure = VERIFY_ERROR_NO_FIELD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002582 goto bail;
2583 }
2584
2585 if (mustBeLocal) {
2586 /* for uninit ref, make sure it's defined by this class, not super */
2587 if (instField < objClass->ifields ||
2588 instField >= objClass->ifields + objClass->ifieldCount)
2589 {
2590 LOG_VFY("VFY: invalid constructor field access (field %s in %s)\n",
2591 instField->field.name, objClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07002592 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002593 goto bail;
2594 }
2595 }
2596
2597bail:
2598 return instField;
2599}
2600
2601/*
2602 * Look up a static field.
2603 *
Andy McFadden62a75162009-04-17 17:23:37 -07002604 * Returns a StaticField on success, returns NULL and sets "*pFailure"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002605 * on failure.
2606 */
2607static StaticField* getStaticField(const Method* meth, int fieldIdx,
Andy McFadden62a75162009-04-17 17:23:37 -07002608 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002609{
2610 StaticField* staticField;
2611
Andy McFadden62a75162009-04-17 17:23:37 -07002612 staticField = dvmOptResolveStaticField(meth->clazz, fieldIdx, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002613 if (staticField == NULL) {
2614 DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
2615 const DexFieldId* pFieldId;
2616
2617 pFieldId = dexGetFieldId(pDexFile, fieldIdx);
2618
2619 LOG_VFY("VFY: unable to resolve static field %u (%s) in %s\n", fieldIdx,
2620 dexStringById(pDexFile, pFieldId->nameIdx),
2621 dexStringByTypeIdx(pDexFile, pFieldId->classIdx));
Andy McFadden62a75162009-04-17 17:23:37 -07002622 assert(!VERIFY_OK(*pFailure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002623 goto bail;
2624 }
2625
2626bail:
2627 return staticField;
2628}
2629
2630/*
2631 * If "field" is marked "final", make sure this is the either <clinit>
2632 * or <init> as appropriate.
2633 *
Andy McFadden62a75162009-04-17 17:23:37 -07002634 * Sets "*pFailure" on failure.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002635 */
2636static void checkFinalFieldAccess(const Method* meth, const Field* field,
Andy McFadden62a75162009-04-17 17:23:37 -07002637 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002638{
2639 if (!dvmIsFinalField(field))
2640 return;
2641
2642 /* make sure we're in the same class */
2643 if (meth->clazz != field->clazz) {
2644 LOG_VFY_METH(meth, "VFY: can't modify final field %s.%s\n",
2645 field->clazz->descriptor, field->name);
Andy McFaddenb51ea112009-05-08 16:50:17 -07002646 *pFailure = VERIFY_ERROR_ACCESS_FIELD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002647 return;
2648 }
2649
2650 /*
Andy McFadden62a75162009-04-17 17:23:37 -07002651 * The VM spec descriptions of putfield and putstatic say that
2652 * IllegalAccessError is only thrown when the instructions appear
2653 * outside the declaring class. Our earlier attempts to restrict
2654 * final field modification to constructors are, therefore, wrong.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002655 */
2656#if 0
2657 /* make sure we're in the right kind of constructor */
2658 if (dvmIsStaticField(field)) {
2659 if (!isClassInitMethod(meth)) {
2660 LOG_VFY_METH(meth,
2661 "VFY: can't modify final static field outside <clinit>\n");
Andy McFadden62a75162009-04-17 17:23:37 -07002662 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002663 }
2664 } else {
2665 if (!isInitMethod(meth)) {
2666 LOG_VFY_METH(meth,
2667 "VFY: can't modify final field outside <init>\n");
Andy McFadden62a75162009-04-17 17:23:37 -07002668 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002669 }
2670 }
2671#endif
2672}
2673
2674/*
2675 * Make sure that the register type is suitable for use as an array index.
2676 *
Andy McFadden62a75162009-04-17 17:23:37 -07002677 * Sets "*pFailure" if not.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002678 */
2679static void checkArrayIndexType(const Method* meth, RegType regType,
Andy McFadden62a75162009-04-17 17:23:37 -07002680 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002681{
Andy McFadden62a75162009-04-17 17:23:37 -07002682 if (VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002683 /*
2684 * The 1nr types are interchangeable at this level. We could
2685 * do something special if we can definitively identify it as a
2686 * float, but there's no real value in doing so.
2687 */
Andy McFadden62a75162009-04-17 17:23:37 -07002688 checkTypeCategory(regType, kTypeCategory1nr, pFailure);
2689 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002690 LOG_VFY_METH(meth, "Invalid reg type for array index (%d)\n",
2691 regType);
2692 }
2693 }
2694}
2695
2696/*
2697 * Check constraints on constructor return. Specifically, make sure that
2698 * the "this" argument got initialized.
2699 *
2700 * The "this" argument to <init> uses code offset kUninitThisArgAddr, which
2701 * puts it at the start of the list in slot 0. If we see a register with
2702 * an uninitialized slot 0 reference, we know it somehow didn't get
2703 * initialized.
2704 *
2705 * Returns "true" if all is well.
2706 */
2707static bool checkConstructorReturn(const Method* meth, const RegType* insnRegs,
2708 const int insnRegCount)
2709{
2710 int i;
2711
2712 if (!isInitMethod(meth))
2713 return true;
2714
2715 RegType uninitThis = regTypeFromUninitIndex(kUninitThisArgSlot);
2716
2717 for (i = 0; i < insnRegCount; i++) {
2718 if (insnRegs[i] == uninitThis) {
2719 LOG_VFY("VFY: <init> returning without calling superclass init\n");
2720 return false;
2721 }
2722 }
2723 return true;
2724}
2725
2726/*
2727 * Verify that the target instruction is not "move-exception". It's important
2728 * that the only way to execute a move-exception is as the first instruction
2729 * of an exception handler.
2730 *
2731 * Returns "true" if all is well, "false" if the target instruction is
2732 * move-exception.
2733 */
2734static bool checkMoveException(const Method* meth, int insnIdx,
2735 const char* logNote)
2736{
2737 assert(insnIdx >= 0 && insnIdx < (int)dvmGetMethodInsnsSize(meth));
2738
2739 if ((meth->insns[insnIdx] & 0xff) == OP_MOVE_EXCEPTION) {
2740 LOG_VFY("VFY: invalid use of move-exception\n");
2741 return false;
2742 }
2743 return true;
2744}
2745
2746/*
2747 * For the "move-exception" instruction at "insnIdx", which must be at an
2748 * exception handler address, determine the first common superclass of
2749 * all exceptions that can land here. (For javac output, we're probably
2750 * looking at multiple spans of bytecode covered by one "try" that lands
2751 * at an exception-specific "catch", but in general the handler could be
2752 * shared for multiple exceptions.)
2753 *
2754 * Returns NULL if no matching exception handler can be found, or if the
2755 * exception is not a subclass of Throwable.
2756 */
Andy McFadden62a75162009-04-17 17:23:37 -07002757static ClassObject* getCaughtExceptionType(const Method* meth, int insnIdx,
2758 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002759{
Andy McFadden62a75162009-04-17 17:23:37 -07002760 VerifyError localFailure;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002761 const DexCode* pCode;
2762 DexFile* pDexFile;
2763 ClassObject* commonSuper = NULL;
Andy McFadden62a75162009-04-17 17:23:37 -07002764 bool foundPossibleHandler = false;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002765 u4 handlersSize;
2766 u4 offset;
2767 u4 i;
2768
2769 pDexFile = meth->clazz->pDvmDex->pDexFile;
2770 pCode = dvmGetMethodCode(meth);
2771
2772 if (pCode->triesSize != 0) {
2773 handlersSize = dexGetHandlersSize(pCode);
2774 offset = dexGetFirstHandlerOffset(pCode);
2775 } else {
2776 handlersSize = 0;
2777 offset = 0;
2778 }
2779
2780 for (i = 0; i < handlersSize; i++) {
2781 DexCatchIterator iterator;
2782 dexCatchIteratorInit(&iterator, pCode, offset);
2783
2784 for (;;) {
2785 const DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
2786
2787 if (handler == NULL) {
2788 break;
2789 }
2790
2791 if (handler->address == (u4) insnIdx) {
2792 ClassObject* clazz;
Andy McFadden62a75162009-04-17 17:23:37 -07002793 foundPossibleHandler = true;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002794
2795 if (handler->typeIdx == kDexNoIndex)
2796 clazz = gDvm.classJavaLangThrowable;
2797 else
Andy McFadden62a75162009-04-17 17:23:37 -07002798 clazz = dvmOptResolveClass(meth->clazz, handler->typeIdx,
2799 &localFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002800
2801 if (clazz == NULL) {
2802 LOG_VFY("VFY: unable to resolve exception class %u (%s)\n",
2803 handler->typeIdx,
2804 dexStringByTypeIdx(pDexFile, handler->typeIdx));
Andy McFadden62a75162009-04-17 17:23:37 -07002805 /* TODO: do we want to keep going? If we don't fail
2806 * this we run the risk of having a non-Throwable
2807 * introduced at runtime. However, that won't pass
2808 * an instanceof test, so is essentially harmless. */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002809 } else {
2810 if (commonSuper == NULL)
2811 commonSuper = clazz;
2812 else
2813 commonSuper = findCommonSuperclass(clazz, commonSuper);
2814 }
2815 }
2816 }
2817
2818 offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
2819 }
2820
2821 if (commonSuper == NULL) {
Andy McFadden62a75162009-04-17 17:23:37 -07002822 /* no catch blocks, or no catches with classes we can find */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002823 LOG_VFY_METH(meth,
2824 "VFY: unable to find exception handler at addr 0x%x\n", insnIdx);
Andy McFadden62a75162009-04-17 17:23:37 -07002825 *pFailure = VERIFY_ERROR_GENERIC;
2826 } else {
2827 // TODO: verify the class is an instance of Throwable?
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002828 }
2829
2830 return commonSuper;
2831}
2832
2833/*
2834 * Initialize the RegisterTable.
2835 *
2836 * Every instruction address can have a different set of information about
2837 * what's in which register, but for verification purposes we only need to
2838 * store it at branch target addresses (because we merge into that).
2839 *
2840 * By zeroing out the storage we are effectively initializing the register
2841 * information to kRegTypeUnknown.
2842 */
2843static bool initRegisterTable(const Method* meth, const InsnFlags* insnFlags,
2844 RegisterTable* regTable, RegisterTrackingMode trackRegsFor)
2845{
2846 const int insnsSize = dvmGetMethodInsnsSize(meth);
2847 int i;
2848
2849 regTable->insnRegCountPlus = meth->registersSize + kExtraRegs;
2850 regTable->addrRegs = (RegType**) calloc(insnsSize, sizeof(RegType*));
2851 if (regTable->addrRegs == NULL)
2852 return false;
2853
2854 assert(insnsSize > 0);
2855
2856 /*
2857 * "All" means "every address that holds the start of an instruction".
2858 * "Branches" and "GcPoints" mean just those addresses.
2859 *
2860 * "GcPoints" fills about half the addresses, "Branches" about 15%.
2861 */
2862 int interestingCount = 0;
2863 //int insnCount = 0;
2864
2865 for (i = 0; i < insnsSize; i++) {
2866 bool interesting;
2867
2868 switch (trackRegsFor) {
2869 case kTrackRegsAll:
2870 interesting = dvmInsnIsOpcode(insnFlags, i);
2871 break;
2872 case kTrackRegsGcPoints:
2873 interesting = dvmInsnIsGcPoint(insnFlags, i) ||
2874 dvmInsnIsBranchTarget(insnFlags, i);
2875 break;
2876 case kTrackRegsBranches:
2877 interesting = dvmInsnIsBranchTarget(insnFlags, i);
2878 break;
2879 default:
2880 dvmAbort();
2881 return false;
2882 }
2883
2884 if (interesting)
2885 interestingCount++;
2886
2887 /* count instructions, for display only */
2888 //if (dvmInsnIsOpcode(insnFlags, i))
2889 // insnCount++;
2890 }
2891
2892 regTable->regAlloc = (RegType*)
2893 calloc(regTable->insnRegCountPlus * interestingCount, sizeof(RegType));
2894 if (regTable->regAlloc == NULL)
2895 return false;
2896
2897 RegType* regPtr = regTable->regAlloc;
2898 for (i = 0; i < insnsSize; i++) {
2899 bool interesting;
2900
2901 switch (trackRegsFor) {
2902 case kTrackRegsAll:
2903 interesting = dvmInsnIsOpcode(insnFlags, i);
2904 break;
2905 case kTrackRegsGcPoints:
2906 interesting = dvmInsnIsGcPoint(insnFlags, i) ||
2907 dvmInsnIsBranchTarget(insnFlags, i);
2908 break;
2909 case kTrackRegsBranches:
2910 interesting = dvmInsnIsBranchTarget(insnFlags, i);
2911 break;
2912 default:
2913 dvmAbort();
2914 return false;
2915 }
2916
2917 if (interesting) {
2918 regTable->addrRegs[i] = regPtr;
2919 regPtr += regTable->insnRegCountPlus;
2920 }
2921 }
2922
2923 //LOGD("Tracking registers for %d, total %d of %d(%d) (%d%%)\n",
2924 // TRACK_REGS_FOR, interestingCount, insnCount, insnsSize,
2925 // (interestingCount*100) / insnCount);
2926
2927 assert(regPtr - regTable->regAlloc ==
2928 regTable->insnRegCountPlus * interestingCount);
2929 assert(regTable->addrRegs[0] != NULL);
2930 return true;
2931}
2932
2933
2934/*
2935 * Verify that the arguments in a filled-new-array instruction are valid.
2936 *
2937 * "resClass" is the class refered to by pDecInsn->vB.
2938 */
2939static void verifyFilledNewArrayRegs(const Method* meth,
2940 const RegType* insnRegs, const int insnRegCount,
2941 const DecodedInstruction* pDecInsn, ClassObject* resClass, bool isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07002942 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002943{
2944 u4 argCount = pDecInsn->vA;
2945 RegType expectedType;
2946 PrimitiveType elemType;
2947 unsigned int ui;
2948
2949 assert(dvmIsArrayClass(resClass));
2950 elemType = resClass->elementClass->primitiveType;
2951 if (elemType == PRIM_NOT) {
2952 expectedType = regTypeFromClass(resClass->elementClass);
2953 } else {
2954 expectedType = primitiveTypeToRegType(elemType);
2955 }
2956 //LOGI("filled-new-array: %s -> %d\n", resClass->descriptor, expectedType);
2957
2958 /*
2959 * Verify each register. If "argCount" is bad, verifyRegisterType()
2960 * will run off the end of the list and fail. It's legal, if silly,
2961 * for argCount to be zero.
2962 */
2963 for (ui = 0; ui < argCount; ui++) {
2964 u4 getReg;
2965
2966 if (isRange)
2967 getReg = pDecInsn->vC + ui;
2968 else
2969 getReg = pDecInsn->arg[ui];
2970
Andy McFadden62a75162009-04-17 17:23:37 -07002971 verifyRegisterType(insnRegs, insnRegCount, getReg, expectedType,
2972 pFailure);
2973 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002974 LOG_VFY("VFY: filled-new-array arg %u(%u) not valid\n", ui, getReg);
2975 return;
2976 }
2977 }
2978}
2979
2980
2981/*
Andy McFaddenb51ea112009-05-08 16:50:17 -07002982 * Replace an instruction with "throw-verification-error". This allows us to
2983 * defer error reporting until the code path is first used.
2984 *
Andy McFadden861b3382010-03-05 15:58:31 -08002985 * This is expected to be called during "just in time" verification, not
2986 * from within dexopt. (Verification failures in dexopt will result in
2987 * postponement of verification to first use of the class.)
2988 *
Andy McFaddenb51ea112009-05-08 16:50:17 -07002989 * The throw-verification-error instruction requires two code units. Some
2990 * of the replaced instructions require three; the third code unit will
2991 * receive a "nop". The instruction's length will be left unchanged
2992 * in "insnFlags".
2993 *
Andy McFadden96516932009-10-28 17:39:02 -07002994 * The verifier explicitly locks out breakpoint activity, so there should
2995 * be no clashes with the debugger.
2996 *
Andy McFaddenb51ea112009-05-08 16:50:17 -07002997 * Returns "true" on success.
2998 */
Andy McFadden228a6b02010-05-04 15:02:32 -07002999static bool replaceFailingInstruction(const Method* meth, InsnFlags* insnFlags,
Andy McFaddenb51ea112009-05-08 16:50:17 -07003000 int insnIdx, VerifyError failure)
3001{
Andy McFaddenaf0e8382009-08-28 10:38:37 -07003002 VerifyErrorRefType refType;
Andy McFaddenb51ea112009-05-08 16:50:17 -07003003 const u2* oldInsns = meth->insns + insnIdx;
3004 u2 oldInsn = *oldInsns;
3005 bool result = false;
3006
Andy McFaddenfb119e62010-06-28 16:21:20 -07003007 if (gDvm.optimizing)
3008 LOGD("Weird: RFI during dexopt?");
3009
Andy McFaddenb51ea112009-05-08 16:50:17 -07003010 //LOGD(" was 0x%04x\n", oldInsn);
3011 u2* newInsns = (u2*) meth->insns + insnIdx;
3012
3013 /*
3014 * Generate the new instruction out of the old.
3015 *
3016 * First, make sure this is an instruction we're expecting to stomp on.
3017 */
3018 switch (oldInsn & 0xff) {
3019 case OP_CONST_CLASS: // insn[1] == class ref, 2 bytes
3020 case OP_CHECK_CAST:
3021 case OP_INSTANCE_OF:
3022 case OP_NEW_INSTANCE:
3023 case OP_NEW_ARRAY:
Andy McFaddenb51ea112009-05-08 16:50:17 -07003024 case OP_FILLED_NEW_ARRAY: // insn[1] == class ref, 3 bytes
3025 case OP_FILLED_NEW_ARRAY_RANGE:
Andy McFaddenaf0e8382009-08-28 10:38:37 -07003026 refType = VERIFY_ERROR_REF_CLASS;
3027 break;
Andy McFaddenb51ea112009-05-08 16:50:17 -07003028
3029 case OP_IGET: // insn[1] == field ref, 2 bytes
3030 case OP_IGET_BOOLEAN:
3031 case OP_IGET_BYTE:
3032 case OP_IGET_CHAR:
3033 case OP_IGET_SHORT:
3034 case OP_IGET_WIDE:
3035 case OP_IGET_OBJECT:
3036 case OP_IPUT:
3037 case OP_IPUT_BOOLEAN:
3038 case OP_IPUT_BYTE:
3039 case OP_IPUT_CHAR:
3040 case OP_IPUT_SHORT:
3041 case OP_IPUT_WIDE:
3042 case OP_IPUT_OBJECT:
3043 case OP_SGET:
3044 case OP_SGET_BOOLEAN:
3045 case OP_SGET_BYTE:
3046 case OP_SGET_CHAR:
3047 case OP_SGET_SHORT:
3048 case OP_SGET_WIDE:
3049 case OP_SGET_OBJECT:
3050 case OP_SPUT:
3051 case OP_SPUT_BOOLEAN:
3052 case OP_SPUT_BYTE:
3053 case OP_SPUT_CHAR:
3054 case OP_SPUT_SHORT:
3055 case OP_SPUT_WIDE:
3056 case OP_SPUT_OBJECT:
Andy McFaddenaf0e8382009-08-28 10:38:37 -07003057 refType = VERIFY_ERROR_REF_FIELD;
3058 break;
Andy McFaddenb51ea112009-05-08 16:50:17 -07003059
3060 case OP_INVOKE_VIRTUAL: // insn[1] == method ref, 3 bytes
3061 case OP_INVOKE_VIRTUAL_RANGE:
3062 case OP_INVOKE_SUPER:
3063 case OP_INVOKE_SUPER_RANGE:
3064 case OP_INVOKE_DIRECT:
3065 case OP_INVOKE_DIRECT_RANGE:
3066 case OP_INVOKE_STATIC:
3067 case OP_INVOKE_STATIC_RANGE:
3068 case OP_INVOKE_INTERFACE:
3069 case OP_INVOKE_INTERFACE_RANGE:
Andy McFaddenaf0e8382009-08-28 10:38:37 -07003070 refType = VERIFY_ERROR_REF_METHOD;
Andy McFaddenb51ea112009-05-08 16:50:17 -07003071 break;
Andy McFaddenaf0e8382009-08-28 10:38:37 -07003072
Andy McFaddenb51ea112009-05-08 16:50:17 -07003073 default:
3074 /* could handle this in a generic way, but this is probably safer */
3075 LOG_VFY("GLITCH: verifier asked to replace opcode 0x%02x\n",
3076 oldInsn & 0xff);
3077 goto bail;
3078 }
3079
3080 /* write a NOP over the third code unit, if necessary */
3081 int width = dvmInsnGetWidth(insnFlags, insnIdx);
3082 switch (width) {
3083 case 2:
3084 /* nothing to do */
3085 break;
3086 case 3:
Andy McFadden96516932009-10-28 17:39:02 -07003087 dvmDexChangeDex2(meth->clazz->pDvmDex, newInsns+2, OP_NOP);
3088 //newInsns[2] = OP_NOP;
Andy McFaddenb51ea112009-05-08 16:50:17 -07003089 break;
3090 default:
3091 /* whoops */
3092 LOGE("ERROR: stomped a %d-unit instruction with a verifier error\n",
3093 width);
3094 dvmAbort();
3095 }
3096
3097 /* encode the opcode, with the failure code in the high byte */
Andy McFadden96516932009-10-28 17:39:02 -07003098 u2 newVal = OP_THROW_VERIFICATION_ERROR |
Andy McFaddenaf0e8382009-08-28 10:38:37 -07003099 (failure << 8) | (refType << (8 + kVerifyErrorRefTypeShift));
Andy McFadden96516932009-10-28 17:39:02 -07003100 //newInsns[0] = newVal;
3101 dvmDexChangeDex2(meth->clazz->pDvmDex, newInsns, newVal);
Andy McFaddenb51ea112009-05-08 16:50:17 -07003102
3103 result = true;
3104
3105bail:
Andy McFaddenb51ea112009-05-08 16:50:17 -07003106 return result;
3107}
3108
3109
3110/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003111 * ===========================================================================
3112 * Entry point and driver loop
3113 * ===========================================================================
3114 */
3115
3116/*
3117 * Entry point for the detailed code-flow analysis.
3118 */
Andy McFadden228a6b02010-05-04 15:02:32 -07003119bool dvmVerifyCodeFlow(VerifierData* vdata)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003120{
3121 bool result = false;
Andy McFadden228a6b02010-05-04 15:02:32 -07003122 const Method* meth = vdata->method;
3123 const int insnsSize = vdata->insnsSize;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003124 const bool generateRegisterMap = gDvm.generateRegisterMaps;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003125 RegisterTable regTable;
3126
3127 memset(&regTable, 0, sizeof(regTable));
3128
3129#ifndef NDEBUG
3130 checkMergeTab(); // only need to do this if table gets updated
3131#endif
3132
3133 /*
3134 * We rely on these for verification of const-class, const-string,
3135 * and throw instructions. Make sure we have them.
3136 */
3137 if (gDvm.classJavaLangClass == NULL)
3138 gDvm.classJavaLangClass =
3139 dvmFindSystemClassNoInit("Ljava/lang/Class;");
3140 if (gDvm.classJavaLangString == NULL)
3141 gDvm.classJavaLangString =
3142 dvmFindSystemClassNoInit("Ljava/lang/String;");
Andy McFadden686e1e22009-05-26 16:56:30 -07003143 if (gDvm.classJavaLangThrowable == NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003144 gDvm.classJavaLangThrowable =
3145 dvmFindSystemClassNoInit("Ljava/lang/Throwable;");
Andy McFadden686e1e22009-05-26 16:56:30 -07003146 gDvm.offJavaLangThrowable_cause =
3147 dvmFindFieldOffset(gDvm.classJavaLangThrowable,
3148 "cause", "Ljava/lang/Throwable;");
3149 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003150 if (gDvm.classJavaLangObject == NULL)
3151 gDvm.classJavaLangObject =
3152 dvmFindSystemClassNoInit("Ljava/lang/Object;");
3153
Andy McFadden6be954f2010-06-14 13:37:49 -07003154 if (meth->registersSize * insnsSize > 4*1024*1024) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003155 LOG_VFY_METH(meth,
Andy McFadden34e314a2010-09-28 13:58:16 -07003156 "VFY: warning: method is huge (regs=%d insnsSize=%d)\n",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003157 meth->registersSize, insnsSize);
Andy McFadden34e314a2010-09-28 13:58:16 -07003158 /* might be bogus data, might be some huge generated method */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003159 }
3160
3161 /*
3162 * Create register lists, and initialize them to "Unknown". If we're
3163 * also going to create the register map, we need to retain the
3164 * register lists for a larger set of addresses.
3165 */
Andy McFadden228a6b02010-05-04 15:02:32 -07003166 if (!initRegisterTable(meth, vdata->insnFlags, &regTable,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003167 generateRegisterMap ? kTrackRegsGcPoints : kTrackRegsBranches))
3168 goto bail;
3169
Andy McFadden228a6b02010-05-04 15:02:32 -07003170 vdata->addrRegs = NULL; /* don't set this until we need it */
3171
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003172 /*
3173 * Initialize the types of the registers that correspond to the
3174 * method arguments. We can determine this from the method signature.
3175 */
Andy McFadden228a6b02010-05-04 15:02:32 -07003176 if (!setTypesFromSignature(meth, regTable.addrRegs[0], vdata->uninitMap))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003177 goto bail;
3178
3179 /*
3180 * Run the verifier.
3181 */
Andy McFadden228a6b02010-05-04 15:02:32 -07003182 if (!doCodeVerification(meth, vdata->insnFlags, &regTable, vdata->uninitMap))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003183 goto bail;
3184
3185 /*
3186 * Generate a register map.
3187 */
3188 if (generateRegisterMap) {
Andy McFadden228a6b02010-05-04 15:02:32 -07003189 vdata->addrRegs = regTable.addrRegs;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003190
Andy McFadden228a6b02010-05-04 15:02:32 -07003191 RegisterMap* pMap = dvmGenerateRegisterMapV(vdata);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003192 if (pMap != NULL) {
3193 /*
3194 * Tuck it into the Method struct. It will either get used
3195 * directly or, if we're in dexopt, will be packed up and
3196 * appended to the DEX file.
3197 */
3198 dvmSetRegisterMap((Method*)meth, pMap);
3199 }
3200 }
3201
3202 /*
3203 * Success.
3204 */
3205 result = true;
3206
3207bail:
3208 free(regTable.addrRegs);
3209 free(regTable.regAlloc);
3210 return result;
3211}
3212
3213/*
3214 * Grind through the instructions.
3215 *
3216 * The basic strategy is as outlined in v3 4.11.1.2: set the "changed" bit
3217 * on the first instruction, process it (setting additional "changed" bits),
3218 * and repeat until there are no more.
3219 *
3220 * v3 4.11.1.1
3221 * - (N/A) operand stack is always the same size
3222 * - operand stack [registers] contain the correct types of values
3223 * - local variables [registers] contain the correct types of values
3224 * - methods are invoked with the appropriate arguments
3225 * - fields are assigned using values of appropriate types
3226 * - opcodes have the correct type values in operand registers
3227 * - there is never an uninitialized class instance in a local variable in
3228 * code protected by an exception handler (operand stack is okay, because
3229 * the operand stack is discarded when an exception is thrown) [can't
3230 * know what's a local var w/o the debug info -- should fall out of
3231 * register typing]
3232 *
3233 * v3 4.11.1.2
3234 * - execution cannot fall off the end of the code
3235 *
3236 * (We also do many of the items described in the "static checks" sections,
3237 * because it's easier to do them here.)
3238 *
3239 * We need an array of RegType values, one per register, for every
3240 * instruction. In theory this could become quite large -- up to several
3241 * megabytes for a monster function. For self-preservation we reject
3242 * anything that requires more than a certain amount of memory. (Typical
3243 * "large" should be on the order of 4K code units * 8 registers.) This
3244 * will likely have to be adjusted.
3245 *
3246 *
3247 * The spec forbids backward branches when there's an uninitialized reference
3248 * in a register. The idea is to prevent something like this:
3249 * loop:
3250 * move r1, r0
3251 * new-instance r0, MyClass
3252 * ...
3253 * if-eq rN, loop // once
3254 * initialize r0
3255 *
3256 * This leaves us with two different instances, both allocated by the
3257 * same instruction, but only one is initialized. The scheme outlined in
3258 * v3 4.11.1.4 wouldn't catch this, so they work around it by preventing
3259 * backward branches. We achieve identical results without restricting
3260 * code reordering by specifying that you can't execute the new-instance
3261 * instruction if a register contains an uninitialized instance created
3262 * by that same instrutcion.
3263 */
Andy McFadden228a6b02010-05-04 15:02:32 -07003264static bool doCodeVerification(const Method* meth, InsnFlags* insnFlags,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003265 RegisterTable* regTable, UninitInstanceMap* uninitMap)
3266{
3267 const int insnsSize = dvmGetMethodInsnsSize(meth);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003268 RegType workRegs[meth->registersSize + kExtraRegs];
3269 bool result = false;
3270 bool debugVerbose = false;
Carl Shapiroe3c01da2010-05-20 22:54:18 -07003271 int insnIdx, startGuess;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003272
3273 /*
3274 * Begin by marking the first instruction as "changed".
3275 */
3276 dvmInsnSetChanged(insnFlags, 0, true);
3277
3278 if (doVerboseLogging(meth)) {
3279 IF_LOGI() {
3280 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
3281 LOGI("Now verifying: %s.%s %s (ins=%d regs=%d)\n",
3282 meth->clazz->descriptor, meth->name, desc,
3283 meth->insSize, meth->registersSize);
3284 LOGI(" ------ [0 4 8 12 16 20 24 28 32 36\n");
3285 free(desc);
3286 }
3287 debugVerbose = true;
3288 gDebugVerbose = true;
3289 } else {
3290 gDebugVerbose = false;
3291 }
3292
3293 startGuess = 0;
3294
3295 /*
3296 * Continue until no instructions are marked "changed".
3297 */
3298 while (true) {
3299 /*
3300 * Find the first marked one. Use "startGuess" as a way to find
3301 * one quickly.
3302 */
3303 for (insnIdx = startGuess; insnIdx < insnsSize; insnIdx++) {
3304 if (dvmInsnIsChanged(insnFlags, insnIdx))
3305 break;
3306 }
3307
3308 if (insnIdx == insnsSize) {
3309 if (startGuess != 0) {
3310 /* try again, starting from the top */
3311 startGuess = 0;
3312 continue;
3313 } else {
3314 /* all flags are clear */
3315 break;
3316 }
3317 }
3318
3319 /*
3320 * We carry the working set of registers from instruction to
3321 * instruction. If this address can be the target of a branch
3322 * (or throw) instruction, or if we're skipping around chasing
3323 * "changed" flags, we need to load the set of registers from
3324 * the table.
3325 *
3326 * Because we always prefer to continue on to the next instruction,
3327 * we should never have a situation where we have a stray
3328 * "changed" flag set on an instruction that isn't a branch target.
3329 */
3330 if (dvmInsnIsBranchTarget(insnFlags, insnIdx)) {
3331 RegType* insnRegs = getRegisterLine(regTable, insnIdx);
3332 assert(insnRegs != NULL);
3333 copyRegisters(workRegs, insnRegs, meth->registersSize + kExtraRegs);
3334
3335 if (debugVerbose) {
3336 dumpRegTypes(meth, insnFlags, workRegs, insnIdx, NULL,uninitMap,
3337 SHOW_REG_DETAILS);
3338 }
3339
3340 } else {
3341 if (debugVerbose) {
3342 dumpRegTypes(meth, insnFlags, workRegs, insnIdx, NULL,uninitMap,
3343 SHOW_REG_DETAILS);
3344 }
3345
3346#ifndef NDEBUG
3347 /*
3348 * Sanity check: retrieve the stored register line (assuming
3349 * a full table) and make sure it actually matches.
3350 */
3351 RegType* insnRegs = getRegisterLine(regTable, insnIdx);
3352 if (insnRegs != NULL &&
3353 compareRegisters(workRegs, insnRegs,
3354 meth->registersSize + kExtraRegs) != 0)
3355 {
3356 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
3357 LOG_VFY("HUH? workRegs diverged in %s.%s %s\n",
3358 meth->clazz->descriptor, meth->name, desc);
3359 free(desc);
3360 dumpRegTypes(meth, insnFlags, workRegs, 0, "work",
3361 uninitMap, DRT_SHOW_REF_TYPES | DRT_SHOW_LOCALS);
3362 dumpRegTypes(meth, insnFlags, insnRegs, 0, "insn",
3363 uninitMap, DRT_SHOW_REF_TYPES | DRT_SHOW_LOCALS);
3364 }
3365#endif
3366 }
3367
3368 //LOGI("process %s.%s %s %d\n",
3369 // meth->clazz->descriptor, meth->name, meth->descriptor, insnIdx);
3370 if (!verifyInstruction(meth, insnFlags, regTable, workRegs, insnIdx,
3371 uninitMap, &startGuess))
3372 {
3373 //LOGD("+++ %s bailing at %d\n", meth->name, insnIdx);
3374 goto bail;
3375 }
3376
3377#if 0
3378 {
3379 static const int gcMask = kInstrCanBranch | kInstrCanSwitch |
3380 kInstrCanThrow | kInstrCanReturn;
3381 OpCode opCode = *(meth->insns + insnIdx) & 0xff;
3382 int flags = dexGetInstrFlags(gDvm.instrFlags, opCode);
3383
3384 /* 8, 16, 32, or 32*n -bit regs */
3385 int regWidth = (meth->registersSize + 7) / 8;
3386 if (regWidth == 3)
3387 regWidth = 4;
3388 if (regWidth > 4) {
3389 regWidth = ((regWidth + 3) / 4) * 4;
3390 if (false) {
3391 LOGW("WOW: %d regs -> %d %s.%s\n",
3392 meth->registersSize, regWidth,
3393 meth->clazz->descriptor, meth->name);
3394 //x = true;
3395 }
3396 }
3397
3398 if ((flags & gcMask) != 0) {
3399 /* this is a potential GC point */
3400 gDvm__gcInstr++;
3401
3402 if (insnsSize < 256)
3403 gDvm__gcData += 1;
3404 else
3405 gDvm__gcData += 2;
3406 gDvm__gcData += regWidth;
3407 }
3408 gDvm__gcSimpleData += regWidth;
3409
3410 gDvm__totalInstr++;
3411 }
3412#endif
3413
3414 /*
3415 * Clear "changed" and mark as visited.
3416 */
3417 dvmInsnSetVisited(insnFlags, insnIdx, true);
3418 dvmInsnSetChanged(insnFlags, insnIdx, false);
3419 }
3420
Andy McFaddenb51ea112009-05-08 16:50:17 -07003421 if (DEAD_CODE_SCAN && !IS_METHOD_FLAG_SET(meth, METHOD_ISWRITABLE)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003422 /*
Andy McFaddenb51ea112009-05-08 16:50:17 -07003423 * Scan for dead code. There's nothing "evil" about dead code
3424 * (besides the wasted space), but it indicates a flaw somewhere
3425 * down the line, possibly in the verifier.
3426 *
3427 * If we've rewritten "always throw" instructions into the stream,
3428 * we are almost certainly going to have some dead code.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003429 */
3430 int deadStart = -1;
3431 for (insnIdx = 0; insnIdx < insnsSize;
3432 insnIdx += dvmInsnGetWidth(insnFlags, insnIdx))
3433 {
3434 /*
3435 * Switch-statement data doesn't get "visited" by scanner. It
3436 * may or may not be preceded by a padding NOP.
3437 */
3438 int instr = meth->insns[insnIdx];
3439 if (instr == kPackedSwitchSignature ||
3440 instr == kSparseSwitchSignature ||
3441 instr == kArrayDataSignature ||
3442 (instr == OP_NOP &&
3443 (meth->insns[insnIdx+1] == kPackedSwitchSignature ||
3444 meth->insns[insnIdx+1] == kSparseSwitchSignature ||
3445 meth->insns[insnIdx+1] == kArrayDataSignature)))
3446 {
3447 dvmInsnSetVisited(insnFlags, insnIdx, true);
3448 }
3449
3450 if (!dvmInsnIsVisited(insnFlags, insnIdx)) {
3451 if (deadStart < 0)
3452 deadStart = insnIdx;
3453 } else if (deadStart >= 0) {
3454 IF_LOGD() {
3455 char* desc =
3456 dexProtoCopyMethodDescriptor(&meth->prototype);
3457 LOGD("VFY: dead code 0x%04x-%04x in %s.%s %s\n",
3458 deadStart, insnIdx-1,
3459 meth->clazz->descriptor, meth->name, desc);
3460 free(desc);
3461 }
3462
3463 deadStart = -1;
3464 }
3465 }
3466 if (deadStart >= 0) {
3467 IF_LOGD() {
3468 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
3469 LOGD("VFY: dead code 0x%04x-%04x in %s.%s %s\n",
3470 deadStart, insnIdx-1,
3471 meth->clazz->descriptor, meth->name, desc);
3472 free(desc);
3473 }
3474 }
3475 }
3476
3477 result = true;
3478
3479bail:
3480 return result;
3481}
3482
3483
3484/*
3485 * Perform verification for a single instruction.
3486 *
3487 * This requires fully decoding the instruction to determine the effect
3488 * it has on registers.
3489 *
3490 * Finds zero or more following instructions and sets the "changed" flag
3491 * if execution at that point needs to be (re-)evaluated. Register changes
3492 * are merged into "regTypes" at the target addresses. Does not set or
3493 * clear any other flags in "insnFlags".
Andy McFaddenb51ea112009-05-08 16:50:17 -07003494 *
3495 * This may alter meth->insns if we need to replace an instruction with
3496 * throw-verification-error.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003497 */
Andy McFadden228a6b02010-05-04 15:02:32 -07003498static bool verifyInstruction(const Method* meth, InsnFlags* insnFlags,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003499 RegisterTable* regTable, RegType* workRegs, int insnIdx,
3500 UninitInstanceMap* uninitMap, int* pStartGuess)
3501{
3502 const int insnsSize = dvmGetMethodInsnsSize(meth);
3503 const u2* insns = meth->insns + insnIdx;
3504 bool result = false;
3505
3506 /*
3507 * Once we finish decoding the instruction, we need to figure out where
3508 * we can go from here. There are three possible ways to transfer
3509 * control to another statement:
3510 *
3511 * (1) Continue to the next instruction. Applies to all but
3512 * unconditional branches, method returns, and exception throws.
3513 * (2) Branch to one or more possible locations. Applies to branches
3514 * and switch statements.
3515 * (3) Exception handlers. Applies to any instruction that can
3516 * throw an exception that is handled by an encompassing "try"
Andy McFadden228a6b02010-05-04 15:02:32 -07003517 * block.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003518 *
3519 * We can also return, in which case there is no successor instruction
3520 * from this point.
3521 *
Andy McFadden228a6b02010-05-04 15:02:32 -07003522 * The behavior can be determined from the InstructionFlags.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003523 */
3524
3525 const DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
3526 RegType entryRegs[meth->registersSize + kExtraRegs];
3527 ClassObject* resClass;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003528 int branchTarget = 0;
3529 const int insnRegCount = meth->registersSize;
3530 RegType tmpType;
3531 DecodedInstruction decInsn;
3532 bool justSetResult = false;
Andy McFadden62a75162009-04-17 17:23:37 -07003533 VerifyError failure = VERIFY_ERROR_NONE;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003534
3535#ifndef NDEBUG
3536 memset(&decInsn, 0x81, sizeof(decInsn));
3537#endif
3538 dexDecodeInstruction(gDvm.instrFormat, insns, &decInsn);
3539
Andy McFaddenb51ea112009-05-08 16:50:17 -07003540 int nextFlags = dexGetInstrFlags(gDvm.instrFlags, decInsn.opCode);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003541
3542 /*
3543 * Make a copy of the previous register state. If the instruction
3544 * throws an exception, we merge *this* into the destination rather
3545 * than workRegs, because we don't want the result from the "successful"
3546 * code path (e.g. a check-cast that "improves" a type) to be visible
3547 * to the exception handler.
3548 */
3549 if ((nextFlags & kInstrCanThrow) != 0 && dvmInsnIsInTry(insnFlags, insnIdx))
3550 {
3551 copyRegisters(entryRegs, workRegs, meth->registersSize + kExtraRegs);
3552 } else {
3553#ifndef NDEBUG
3554 memset(entryRegs, 0xdd,
3555 (meth->registersSize + kExtraRegs) * sizeof(RegType));
3556#endif
3557 }
3558
3559 switch (decInsn.opCode) {
3560 case OP_NOP:
3561 /*
3562 * A "pure" NOP has no effect on anything. Data tables start with
3563 * a signature that looks like a NOP; if we see one of these in
3564 * the course of executing code then we have a problem.
3565 */
3566 if (decInsn.vA != 0) {
3567 LOG_VFY("VFY: encountered data table in instruction stream\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003568 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003569 }
3570 break;
3571
3572 case OP_MOVE:
3573 case OP_MOVE_FROM16:
3574 case OP_MOVE_16:
3575 copyRegister1(workRegs, insnRegCount, decInsn.vA, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07003576 kTypeCategory1nr, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003577 break;
3578 case OP_MOVE_WIDE:
3579 case OP_MOVE_WIDE_FROM16:
3580 case OP_MOVE_WIDE_16:
Andy McFadden62a75162009-04-17 17:23:37 -07003581 copyRegister2(workRegs, insnRegCount, decInsn.vA, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003582 break;
3583 case OP_MOVE_OBJECT:
3584 case OP_MOVE_OBJECT_FROM16:
3585 case OP_MOVE_OBJECT_16:
3586 copyRegister1(workRegs, insnRegCount, decInsn.vA, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07003587 kTypeCategoryRef, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003588 break;
3589
3590 /*
3591 * The move-result instructions copy data out of a "pseudo-register"
3592 * with the results from the last method invocation. In practice we
3593 * might want to hold the result in an actual CPU register, so the
3594 * Dalvik spec requires that these only appear immediately after an
3595 * invoke or filled-new-array.
3596 *
3597 * These calls invalidate the "result" register. (This is now
3598 * redundant with the reset done below, but it can make the debug info
3599 * easier to read in some cases.)
3600 */
3601 case OP_MOVE_RESULT:
3602 copyResultRegister1(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003603 kTypeCategory1nr, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003604 break;
3605 case OP_MOVE_RESULT_WIDE:
Andy McFadden62a75162009-04-17 17:23:37 -07003606 copyResultRegister2(workRegs, insnRegCount, decInsn.vA, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003607 break;
3608 case OP_MOVE_RESULT_OBJECT:
3609 copyResultRegister1(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003610 kTypeCategoryRef, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003611 break;
3612
3613 case OP_MOVE_EXCEPTION:
3614 /*
3615 * This statement can only appear as the first instruction in an
3616 * exception handler (though not all exception handlers need to
3617 * have one of these). We verify that as part of extracting the
3618 * exception type from the catch block list.
3619 *
3620 * "resClass" will hold the closest common superclass of all
3621 * exceptions that can be handled here.
3622 */
Andy McFadden62a75162009-04-17 17:23:37 -07003623 resClass = getCaughtExceptionType(meth, insnIdx, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003624 if (resClass == NULL) {
Andy McFadden62a75162009-04-17 17:23:37 -07003625 assert(!VERIFY_OK(failure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003626 } else {
3627 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003628 regTypeFromClass(resClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003629 }
3630 break;
3631
3632 case OP_RETURN_VOID:
Andy McFadden62a75162009-04-17 17:23:37 -07003633 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3634 failure = VERIFY_ERROR_GENERIC;
3635 } else if (getMethodReturnType(meth) != kRegTypeUnknown) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003636 LOG_VFY("VFY: return-void not expected\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003637 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003638 }
3639 break;
3640 case OP_RETURN:
Andy McFadden62a75162009-04-17 17:23:37 -07003641 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3642 failure = VERIFY_ERROR_GENERIC;
3643 } else {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003644 /* check the method signature */
3645 RegType returnType = getMethodReturnType(meth);
Andy McFadden62a75162009-04-17 17:23:37 -07003646 checkTypeCategory(returnType, kTypeCategory1nr, &failure);
3647 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003648 LOG_VFY("VFY: return-32 not expected\n");
3649
3650 /* check the register contents */
3651 returnType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003652 &failure);
3653 checkTypeCategory(returnType, kTypeCategory1nr, &failure);
3654 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003655 LOG_VFY("VFY: return-32 on invalid register v%d\n", decInsn.vA);
3656 }
3657 break;
3658 case OP_RETURN_WIDE:
Andy McFadden62a75162009-04-17 17:23:37 -07003659 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3660 failure = VERIFY_ERROR_GENERIC;
3661 } else {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003662 RegType returnType, returnTypeHi;
3663
3664 /* check the method signature */
3665 returnType = getMethodReturnType(meth);
Andy McFadden62a75162009-04-17 17:23:37 -07003666 checkTypeCategory(returnType, kTypeCategory2, &failure);
3667 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003668 LOG_VFY("VFY: return-wide not expected\n");
3669
3670 /* check the register contents */
3671 returnType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003672 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003673 returnTypeHi = getRegisterType(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003674 decInsn.vA +1, &failure);
3675 if (VERIFY_OK(failure)) {
3676 checkTypeCategory(returnType, kTypeCategory2, &failure);
3677 checkWidePair(returnType, returnTypeHi, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003678 }
Andy McFadden62a75162009-04-17 17:23:37 -07003679 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003680 LOG_VFY("VFY: return-wide on invalid register pair v%d\n",
3681 decInsn.vA);
3682 }
3683 }
3684 break;
3685 case OP_RETURN_OBJECT:
Andy McFadden62a75162009-04-17 17:23:37 -07003686 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3687 failure = VERIFY_ERROR_GENERIC;
3688 } else {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003689 RegType returnType = getMethodReturnType(meth);
Andy McFadden62a75162009-04-17 17:23:37 -07003690 checkTypeCategory(returnType, kTypeCategoryRef, &failure);
3691 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003692 LOG_VFY("VFY: return-object not expected\n");
3693 break;
3694 }
3695
3696 /* returnType is the *expected* return type, not register value */
3697 assert(returnType != kRegTypeZero);
3698 assert(!regTypeIsUninitReference(returnType));
3699
3700 /*
3701 * Verify that the reference in vAA is an instance of the type
3702 * in "returnType". The Zero type is allowed here. If the
3703 * method is declared to return an interface, then any
3704 * initialized reference is acceptable.
3705 *
3706 * Note getClassFromRegister fails if the register holds an
3707 * uninitialized reference, so we do not allow them to be
3708 * returned.
3709 */
3710 ClassObject* declClass;
3711
3712 declClass = regTypeInitializedReferenceToClass(returnType);
3713 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003714 decInsn.vA, &failure);
3715 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003716 break;
3717 if (resClass != NULL) {
3718 if (!dvmIsInterfaceClass(declClass) &&
3719 !dvmInstanceof(resClass, declClass))
3720 {
Andy McFadden86c86432009-05-27 14:40:12 -07003721 LOG_VFY("VFY: returning %s (cl=%p), declared %s (cl=%p)\n",
3722 resClass->descriptor, resClass->classLoader,
3723 declClass->descriptor, declClass->classLoader);
Andy McFadden62a75162009-04-17 17:23:37 -07003724 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003725 break;
3726 }
3727 }
3728 }
3729 break;
3730
3731 case OP_CONST_4:
3732 case OP_CONST_16:
3733 case OP_CONST:
3734 /* could be boolean, int, float, or a null reference */
3735 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003736 dvmDetermineCat1Const((s4)decInsn.vB), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003737 break;
3738 case OP_CONST_HIGH16:
3739 /* could be boolean, int, float, or a null reference */
3740 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003741 dvmDetermineCat1Const((s4) decInsn.vB << 16), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003742 break;
3743 case OP_CONST_WIDE_16:
3744 case OP_CONST_WIDE_32:
3745 case OP_CONST_WIDE:
3746 case OP_CONST_WIDE_HIGH16:
3747 /* could be long or double; default to long and allow conversion */
3748 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003749 kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003750 break;
3751 case OP_CONST_STRING:
3752 case OP_CONST_STRING_JUMBO:
3753 assert(gDvm.classJavaLangString != NULL);
3754 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003755 regTypeFromClass(gDvm.classJavaLangString), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003756 break;
3757 case OP_CONST_CLASS:
3758 assert(gDvm.classJavaLangClass != NULL);
3759 /* make sure we can resolve the class; access check is important */
Andy McFadden62a75162009-04-17 17:23:37 -07003760 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003761 if (resClass == NULL) {
3762 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3763 dvmLogUnableToResolveClass(badClassDesc, meth);
3764 LOG_VFY("VFY: unable to resolve const-class %d (%s) in %s\n",
3765 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003766 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003767 } else {
3768 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003769 regTypeFromClass(gDvm.classJavaLangClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003770 }
3771 break;
3772
3773 case OP_MONITOR_ENTER:
3774 case OP_MONITOR_EXIT:
Andy McFadden62a75162009-04-17 17:23:37 -07003775 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
3776 if (VERIFY_OK(failure)) {
3777 if (!regTypeIsReference(tmpType)) {
3778 LOG_VFY("VFY: monitor op on non-object\n");
3779 failure = VERIFY_ERROR_GENERIC;
3780 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003781 }
3782 break;
3783
3784 case OP_CHECK_CAST:
3785 /*
3786 * If this instruction succeeds, we will promote register vA to
3787 * the type in vB. (This could be a demotion -- not expected, so
3788 * we don't try to address it.)
3789 *
3790 * If it fails, an exception is thrown, which we deal with later
3791 * by ignoring the update to decInsn.vA when branching to a handler.
3792 */
Andy McFadden62a75162009-04-17 17:23:37 -07003793 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003794 if (resClass == NULL) {
3795 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3796 dvmLogUnableToResolveClass(badClassDesc, meth);
3797 LOG_VFY("VFY: unable to resolve check-cast %d (%s) in %s\n",
3798 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003799 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003800 } else {
3801 RegType origType;
3802
3803 origType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003804 &failure);
3805 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003806 break;
3807 if (!regTypeIsReference(origType)) {
3808 LOG_VFY("VFY: check-cast on non-reference in v%u\n",decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07003809 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003810 break;
3811 }
3812 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003813 regTypeFromClass(resClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003814 }
3815 break;
3816 case OP_INSTANCE_OF:
3817 /* make sure we're checking a reference type */
Andy McFadden62a75162009-04-17 17:23:37 -07003818 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vB, &failure);
3819 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003820 break;
3821 if (!regTypeIsReference(tmpType)) {
3822 LOG_VFY("VFY: vB not a reference (%d)\n", tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07003823 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003824 break;
3825 }
3826
3827 /* make sure we can resolve the class; access check is important */
Andy McFadden62a75162009-04-17 17:23:37 -07003828 resClass = dvmOptResolveClass(meth->clazz, decInsn.vC, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003829 if (resClass == NULL) {
3830 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vC);
3831 dvmLogUnableToResolveClass(badClassDesc, meth);
3832 LOG_VFY("VFY: unable to resolve instanceof %d (%s) in %s\n",
3833 decInsn.vC, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003834 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003835 } else {
3836 /* result is boolean */
3837 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003838 kRegTypeBoolean, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003839 }
3840 break;
3841
3842 case OP_ARRAY_LENGTH:
3843 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003844 decInsn.vB, &failure);
3845 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003846 break;
3847 if (resClass != NULL && !dvmIsArrayClass(resClass)) {
3848 LOG_VFY("VFY: array-length on non-array\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003849 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003850 break;
3851 }
3852 setRegisterType(workRegs, insnRegCount, decInsn.vA, kRegTypeInteger,
Andy McFadden62a75162009-04-17 17:23:37 -07003853 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003854 break;
3855
3856 case OP_NEW_INSTANCE:
Andy McFadden62a75162009-04-17 17:23:37 -07003857 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003858 if (resClass == NULL) {
3859 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3860 dvmLogUnableToResolveClass(badClassDesc, meth);
3861 LOG_VFY("VFY: unable to resolve new-instance %d (%s) in %s\n",
3862 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003863 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003864 } else {
3865 RegType uninitType;
3866
Andy McFaddenb51ea112009-05-08 16:50:17 -07003867 /* can't create an instance of an interface or abstract class */
3868 if (dvmIsAbstractClass(resClass) || dvmIsInterfaceClass(resClass)) {
3869 LOG_VFY("VFY: new-instance on interface or abstract class %s\n",
3870 resClass->descriptor);
3871 failure = VERIFY_ERROR_INSTANTIATION;
3872 break;
3873 }
3874
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003875 /* add resolved class to uninit map if not already there */
3876 int uidx = dvmSetUninitInstance(uninitMap, insnIdx, resClass);
3877 assert(uidx >= 0);
3878 uninitType = regTypeFromUninitIndex(uidx);
3879
3880 /*
3881 * Any registers holding previous allocations from this address
3882 * that have not yet been initialized must be marked invalid.
3883 */
3884 markUninitRefsAsInvalid(workRegs, insnRegCount, uninitMap,
3885 uninitType);
3886
3887 /* add the new uninitialized reference to the register ste */
3888 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003889 uninitType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003890 }
3891 break;
3892 case OP_NEW_ARRAY:
Andy McFadden62a75162009-04-17 17:23:37 -07003893 resClass = dvmOptResolveClass(meth->clazz, decInsn.vC, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003894 if (resClass == NULL) {
3895 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vC);
3896 dvmLogUnableToResolveClass(badClassDesc, meth);
3897 LOG_VFY("VFY: unable to resolve new-array %d (%s) in %s\n",
3898 decInsn.vC, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003899 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003900 } else if (!dvmIsArrayClass(resClass)) {
3901 LOG_VFY("VFY: new-array on non-array class\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003902 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003903 } else {
3904 /* make sure "size" register is valid type */
3905 verifyRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07003906 kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003907 /* set register type to array class */
3908 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003909 regTypeFromClass(resClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003910 }
3911 break;
3912 case OP_FILLED_NEW_ARRAY:
3913 case OP_FILLED_NEW_ARRAY_RANGE:
Andy McFadden62a75162009-04-17 17:23:37 -07003914 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003915 if (resClass == NULL) {
3916 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3917 dvmLogUnableToResolveClass(badClassDesc, meth);
3918 LOG_VFY("VFY: unable to resolve filled-array %d (%s) in %s\n",
3919 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003920 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003921 } else if (!dvmIsArrayClass(resClass)) {
3922 LOG_VFY("VFY: filled-new-array on non-array class\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003923 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003924 } else {
3925 bool isRange = (decInsn.opCode == OP_FILLED_NEW_ARRAY_RANGE);
3926
3927 /* check the arguments to the instruction */
3928 verifyFilledNewArrayRegs(meth, workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07003929 resClass, isRange, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003930 /* filled-array result goes into "result" register */
3931 setResultRegisterType(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003932 regTypeFromClass(resClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003933 justSetResult = true;
3934 }
3935 break;
3936
3937 case OP_CMPL_FLOAT:
3938 case OP_CMPG_FLOAT:
3939 verifyRegisterType(workRegs, insnRegCount, decInsn.vB, kRegTypeFloat,
Andy McFadden62a75162009-04-17 17:23:37 -07003940 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003941 verifyRegisterType(workRegs, insnRegCount, decInsn.vC, kRegTypeFloat,
Andy McFadden62a75162009-04-17 17:23:37 -07003942 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003943 setRegisterType(workRegs, insnRegCount, decInsn.vA, kRegTypeBoolean,
Andy McFadden62a75162009-04-17 17:23:37 -07003944 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003945 break;
3946 case OP_CMPL_DOUBLE:
3947 case OP_CMPG_DOUBLE:
3948 verifyRegisterType(workRegs, insnRegCount, decInsn.vB, kRegTypeDoubleLo,
Andy McFadden62a75162009-04-17 17:23:37 -07003949 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003950 verifyRegisterType(workRegs, insnRegCount, decInsn.vC, kRegTypeDoubleLo,
Andy McFadden62a75162009-04-17 17:23:37 -07003951 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003952 setRegisterType(workRegs, insnRegCount, decInsn.vA, kRegTypeBoolean,
Andy McFadden62a75162009-04-17 17:23:37 -07003953 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003954 break;
3955 case OP_CMP_LONG:
3956 verifyRegisterType(workRegs, insnRegCount, decInsn.vB, kRegTypeLongLo,
Andy McFadden62a75162009-04-17 17:23:37 -07003957 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003958 verifyRegisterType(workRegs, insnRegCount, decInsn.vC, kRegTypeLongLo,
Andy McFadden62a75162009-04-17 17:23:37 -07003959 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003960 setRegisterType(workRegs, insnRegCount, decInsn.vA, kRegTypeBoolean,
Andy McFadden62a75162009-04-17 17:23:37 -07003961 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003962 break;
3963
3964 case OP_THROW:
3965 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003966 decInsn.vA, &failure);
3967 if (VERIFY_OK(failure) && resClass != NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003968 if (!dvmInstanceof(resClass, gDvm.classJavaLangThrowable)) {
3969 LOG_VFY("VFY: thrown class %s not instanceof Throwable\n",
3970 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003971 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003972 }
3973 }
3974 break;
3975
3976 case OP_GOTO:
3977 case OP_GOTO_16:
3978 case OP_GOTO_32:
3979 /* no effect on or use of registers */
3980 break;
3981
3982 case OP_PACKED_SWITCH:
3983 case OP_SPARSE_SWITCH:
3984 /* verify that vAA is an integer, or can be converted to one */
3985 verifyRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003986 kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003987 break;
3988
3989 case OP_FILL_ARRAY_DATA:
3990 {
3991 RegType valueType;
3992 const u2 *arrayData;
3993 u2 elemWidth;
3994
3995 /* Similar to the verification done for APUT */
3996 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003997 decInsn.vA, &failure);
3998 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003999 break;
4000
4001 /* resClass can be null if the reg type is Zero */
4002 if (resClass == NULL)
4003 break;
4004
4005 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4006 resClass->elementClass->primitiveType == PRIM_NOT ||
4007 resClass->elementClass->primitiveType == PRIM_VOID)
4008 {
4009 LOG_VFY("VFY: invalid fill-array-data on %s\n",
4010 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004011 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004012 break;
4013 }
4014
4015 valueType = primitiveTypeToRegType(
4016 resClass->elementClass->primitiveType);
4017 assert(valueType != kRegTypeUnknown);
4018
4019 /*
4020 * Now verify if the element width in the table matches the element
4021 * width declared in the array
4022 */
4023 arrayData = insns + (insns[1] | (((s4)insns[2]) << 16));
4024 if (arrayData[0] != kArrayDataSignature) {
4025 LOG_VFY("VFY: invalid magic for array-data\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004026 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004027 break;
4028 }
4029
4030 switch (resClass->elementClass->primitiveType) {
4031 case PRIM_BOOLEAN:
4032 case PRIM_BYTE:
4033 elemWidth = 1;
4034 break;
4035 case PRIM_CHAR:
4036 case PRIM_SHORT:
4037 elemWidth = 2;
4038 break;
4039 case PRIM_FLOAT:
4040 case PRIM_INT:
4041 elemWidth = 4;
4042 break;
4043 case PRIM_DOUBLE:
4044 case PRIM_LONG:
4045 elemWidth = 8;
4046 break;
4047 default:
4048 elemWidth = 0;
4049 break;
4050 }
4051
4052 /*
4053 * Since we don't compress the data in Dex, expect to see equal
4054 * width of data stored in the table and expected from the array
4055 * class.
4056 */
4057 if (arrayData[1] != elemWidth) {
4058 LOG_VFY("VFY: array-data size mismatch (%d vs %d)\n",
4059 arrayData[1], elemWidth);
Andy McFadden62a75162009-04-17 17:23:37 -07004060 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004061 }
4062 }
4063 break;
4064
4065 case OP_IF_EQ:
4066 case OP_IF_NE:
4067 {
4068 RegType type1, type2;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004069
Andy McFadden62a75162009-04-17 17:23:37 -07004070 type1 = getRegisterType(workRegs, insnRegCount, decInsn.vA,
4071 &failure);
4072 type2 = getRegisterType(workRegs, insnRegCount, decInsn.vB,
4073 &failure);
4074 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004075 break;
4076
4077 /* both references? */
4078 if (regTypeIsReference(type1) && regTypeIsReference(type2))
4079 break;
4080
4081 /* both category-1nr? */
Andy McFadden62a75162009-04-17 17:23:37 -07004082 checkTypeCategory(type1, kTypeCategory1nr, &failure);
4083 checkTypeCategory(type2, kTypeCategory1nr, &failure);
4084 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004085 LOG_VFY("VFY: args to if-eq/if-ne must both be refs or cat1\n");
4086 break;
4087 }
4088 }
4089 break;
4090 case OP_IF_LT:
4091 case OP_IF_GE:
4092 case OP_IF_GT:
4093 case OP_IF_LE:
Andy McFadden62a75162009-04-17 17:23:37 -07004094 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4095 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004096 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004097 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
4098 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004099 LOG_VFY("VFY: args to 'if' must be cat-1nr\n");
4100 break;
4101 }
Andy McFadden62a75162009-04-17 17:23:37 -07004102 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vB, &failure);
4103 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004104 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004105 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
4106 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004107 LOG_VFY("VFY: args to 'if' must be cat-1nr\n");
4108 break;
4109 }
4110 break;
4111 case OP_IF_EQZ:
4112 case OP_IF_NEZ:
Andy McFadden62a75162009-04-17 17:23:37 -07004113 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4114 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004115 break;
4116 if (regTypeIsReference(tmpType))
4117 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004118 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
4119 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004120 LOG_VFY("VFY: expected cat-1 arg to if\n");
4121 break;
4122 case OP_IF_LTZ:
4123 case OP_IF_GEZ:
4124 case OP_IF_GTZ:
4125 case OP_IF_LEZ:
Andy McFadden62a75162009-04-17 17:23:37 -07004126 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4127 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004128 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004129 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
4130 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004131 LOG_VFY("VFY: expected cat-1 arg to if\n");
4132 break;
4133
4134 case OP_AGET:
4135 tmpType = kRegTypeInteger;
4136 goto aget_1nr_common;
4137 case OP_AGET_BOOLEAN:
4138 tmpType = kRegTypeBoolean;
4139 goto aget_1nr_common;
4140 case OP_AGET_BYTE:
4141 tmpType = kRegTypeByte;
4142 goto aget_1nr_common;
4143 case OP_AGET_CHAR:
4144 tmpType = kRegTypeChar;
4145 goto aget_1nr_common;
4146 case OP_AGET_SHORT:
4147 tmpType = kRegTypeShort;
4148 goto aget_1nr_common;
4149aget_1nr_common:
4150 {
4151 RegType srcType, indexType;
4152
4153 indexType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004154 &failure);
4155 checkArrayIndexType(meth, indexType, &failure);
4156 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004157 break;
4158
4159 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004160 decInsn.vB, &failure);
4161 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004162 break;
4163 if (resClass != NULL) {
4164 /* verify the class */
4165 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4166 resClass->elementClass->primitiveType == PRIM_NOT)
4167 {
4168 LOG_VFY("VFY: invalid aget-1nr target %s\n",
4169 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004170 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004171 break;
4172 }
4173
4174 /* make sure array type matches instruction */
4175 srcType = primitiveTypeToRegType(
4176 resClass->elementClass->primitiveType);
4177
4178 if (!checkFieldArrayStore1nr(tmpType, srcType)) {
4179 LOG_VFY("VFY: invalid aget-1nr, array type=%d with"
4180 " inst type=%d (on %s)\n",
4181 srcType, tmpType, resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004182 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004183 break;
4184 }
4185
4186 }
4187 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004188 tmpType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004189 }
4190 break;
4191
4192 case OP_AGET_WIDE:
4193 {
4194 RegType dstType, indexType;
4195
4196 indexType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004197 &failure);
4198 checkArrayIndexType(meth, indexType, &failure);
4199 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004200 break;
4201
4202 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004203 decInsn.vB, &failure);
4204 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004205 break;
4206 if (resClass != NULL) {
4207 /* verify the class */
4208 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4209 resClass->elementClass->primitiveType == PRIM_NOT)
4210 {
4211 LOG_VFY("VFY: invalid aget-wide target %s\n",
4212 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004213 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004214 break;
4215 }
4216
4217 /* try to refine "dstType" */
4218 switch (resClass->elementClass->primitiveType) {
4219 case PRIM_LONG:
4220 dstType = kRegTypeLongLo;
4221 break;
4222 case PRIM_DOUBLE:
4223 dstType = kRegTypeDoubleLo;
4224 break;
4225 default:
4226 LOG_VFY("VFY: invalid aget-wide on %s\n",
4227 resClass->descriptor);
4228 dstType = kRegTypeUnknown;
Andy McFadden62a75162009-04-17 17:23:37 -07004229 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004230 break;
4231 }
4232 } else {
4233 /*
4234 * Null array ref; this code path will fail at runtime. We
4235 * know this is either long or double, and we don't really
4236 * discriminate between those during verification, so we
4237 * call it a long.
4238 */
4239 dstType = kRegTypeLongLo;
4240 }
4241 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004242 dstType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004243 }
4244 break;
4245
4246 case OP_AGET_OBJECT:
4247 {
4248 RegType dstType, indexType;
4249
4250 indexType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004251 &failure);
4252 checkArrayIndexType(meth, indexType, &failure);
4253 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004254 break;
4255
4256 /* get the class of the array we're pulling an object from */
4257 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004258 decInsn.vB, &failure);
4259 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004260 break;
4261 if (resClass != NULL) {
4262 ClassObject* elementClass;
4263
4264 assert(resClass != NULL);
4265 if (!dvmIsArrayClass(resClass)) {
4266 LOG_VFY("VFY: aget-object on non-array class\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004267 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004268 break;
4269 }
4270 assert(resClass->elementClass != NULL);
4271
4272 /*
4273 * Find the element class. resClass->elementClass indicates
4274 * the basic type, which won't be what we want for a
4275 * multi-dimensional array.
4276 */
4277 if (resClass->descriptor[1] == '[') {
4278 assert(resClass->arrayDim > 1);
4279 elementClass = dvmFindArrayClass(&resClass->descriptor[1],
4280 resClass->classLoader);
4281 } else if (resClass->descriptor[1] == 'L') {
4282 assert(resClass->arrayDim == 1);
4283 elementClass = resClass->elementClass;
4284 } else {
4285 LOG_VFY("VFY: aget-object on non-ref array class (%s)\n",
4286 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004287 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004288 break;
4289 }
4290
4291 dstType = regTypeFromClass(elementClass);
4292 } else {
4293 /*
4294 * The array reference is NULL, so the current code path will
4295 * throw an exception. For proper merging with later code
4296 * paths, and correct handling of "if-eqz" tests on the
4297 * result of the array get, we want to treat this as a null
4298 * reference.
4299 */
4300 dstType = kRegTypeZero;
4301 }
4302 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004303 dstType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004304 }
4305 break;
4306 case OP_APUT:
4307 tmpType = kRegTypeInteger;
4308 goto aput_1nr_common;
4309 case OP_APUT_BOOLEAN:
4310 tmpType = kRegTypeBoolean;
4311 goto aput_1nr_common;
4312 case OP_APUT_BYTE:
4313 tmpType = kRegTypeByte;
4314 goto aput_1nr_common;
4315 case OP_APUT_CHAR:
4316 tmpType = kRegTypeChar;
4317 goto aput_1nr_common;
4318 case OP_APUT_SHORT:
4319 tmpType = kRegTypeShort;
4320 goto aput_1nr_common;
4321aput_1nr_common:
4322 {
4323 RegType srcType, dstType, indexType;
4324
4325 indexType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004326 &failure);
4327 checkArrayIndexType(meth, indexType, &failure);
4328 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004329 break;
4330
4331 /* make sure the source register has the correct type */
4332 srcType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004333 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004334 if (!canConvertTo1nr(srcType, tmpType)) {
4335 LOG_VFY("VFY: invalid reg type %d on aput instr (need %d)\n",
4336 srcType, tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07004337 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004338 break;
4339 }
4340
4341 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004342 decInsn.vB, &failure);
4343 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004344 break;
4345
4346 /* resClass can be null if the reg type is Zero */
4347 if (resClass == NULL)
4348 break;
4349
4350 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4351 resClass->elementClass->primitiveType == PRIM_NOT)
4352 {
4353 LOG_VFY("VFY: invalid aput-1nr on %s\n", resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004354 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004355 break;
4356 }
4357
4358 /* verify that instruction matches array */
4359 dstType = primitiveTypeToRegType(
4360 resClass->elementClass->primitiveType);
4361 assert(dstType != kRegTypeUnknown);
4362
4363 if (!checkFieldArrayStore1nr(tmpType, dstType)) {
4364 LOG_VFY("VFY: invalid aput-1nr on %s (inst=%d dst=%d)\n",
4365 resClass->descriptor, tmpType, dstType);
Andy McFadden62a75162009-04-17 17:23:37 -07004366 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004367 break;
4368 }
4369 }
4370 break;
4371 case OP_APUT_WIDE:
4372 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004373 &failure);
4374 checkArrayIndexType(meth, tmpType, &failure);
4375 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004376 break;
4377
Andy McFadden62a75162009-04-17 17:23:37 -07004378 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4379 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004380 RegType typeHi =
Andy McFadden62a75162009-04-17 17:23:37 -07004381 getRegisterType(workRegs, insnRegCount, decInsn.vA+1, &failure);
4382 checkTypeCategory(tmpType, kTypeCategory2, &failure);
4383 checkWidePair(tmpType, typeHi, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004384 }
Andy McFadden62a75162009-04-17 17:23:37 -07004385 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004386 break;
4387
4388 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004389 decInsn.vB, &failure);
4390 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004391 break;
4392 if (resClass != NULL) {
4393 /* verify the class and try to refine "dstType" */
4394 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4395 resClass->elementClass->primitiveType == PRIM_NOT)
4396 {
4397 LOG_VFY("VFY: invalid aput-wide on %s\n",
4398 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004399 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004400 break;
4401 }
4402
4403 switch (resClass->elementClass->primitiveType) {
4404 case PRIM_LONG:
4405 case PRIM_DOUBLE:
4406 /* these are okay */
4407 break;
4408 default:
4409 LOG_VFY("VFY: invalid aput-wide on %s\n",
4410 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004411 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004412 break;
4413 }
4414 }
4415 break;
4416 case OP_APUT_OBJECT:
4417 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004418 &failure);
4419 checkArrayIndexType(meth, tmpType, &failure);
4420 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004421 break;
4422
4423 /* get the ref we're storing; Zero is okay, Uninit is not */
4424 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004425 decInsn.vA, &failure);
4426 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004427 break;
4428 if (resClass != NULL) {
4429 ClassObject* arrayClass;
4430 ClassObject* elementClass;
4431
4432 /*
4433 * Get the array class. If the array ref is null, we won't
4434 * have type information (and we'll crash at runtime with a
4435 * null pointer exception).
4436 */
4437 arrayClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004438 decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004439
4440 if (arrayClass != NULL) {
4441 /* see if the array holds a compatible type */
4442 if (!dvmIsArrayClass(arrayClass)) {
4443 LOG_VFY("VFY: invalid aput-object on %s\n",
4444 arrayClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004445 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004446 break;
4447 }
4448
4449 /*
4450 * Find the element class. resClass->elementClass indicates
4451 * the basic type, which won't be what we want for a
4452 * multi-dimensional array.
4453 *
4454 * All we want to check here is that the element type is a
4455 * reference class. We *don't* check instanceof here, because
4456 * you can still put a String into a String[] after the latter
4457 * has been cast to an Object[].
4458 */
4459 if (arrayClass->descriptor[1] == '[') {
4460 assert(arrayClass->arrayDim > 1);
4461 elementClass = dvmFindArrayClass(&arrayClass->descriptor[1],
4462 arrayClass->classLoader);
4463 } else {
4464 assert(arrayClass->arrayDim == 1);
4465 elementClass = arrayClass->elementClass;
4466 }
4467 if (elementClass->primitiveType != PRIM_NOT) {
4468 LOG_VFY("VFY: invalid aput-object of %s into %s\n",
4469 resClass->descriptor, arrayClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004470 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004471 break;
4472 }
4473 }
4474 }
4475 break;
4476
4477 case OP_IGET:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004478 case OP_IGET_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004479 tmpType = kRegTypeInteger;
4480 goto iget_1nr_common;
4481 case OP_IGET_BOOLEAN:
4482 tmpType = kRegTypeBoolean;
4483 goto iget_1nr_common;
4484 case OP_IGET_BYTE:
4485 tmpType = kRegTypeByte;
4486 goto iget_1nr_common;
4487 case OP_IGET_CHAR:
4488 tmpType = kRegTypeChar;
4489 goto iget_1nr_common;
4490 case OP_IGET_SHORT:
4491 tmpType = kRegTypeShort;
4492 goto iget_1nr_common;
4493iget_1nr_common:
4494 {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004495 InstField* instField;
4496 RegType objType, fieldType;
4497
4498 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004499 &failure);
4500 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004501 break;
4502 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004503 &failure);
4504 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004505 break;
4506
4507 /* make sure the field's type is compatible with expectation */
4508 fieldType = primSigCharToRegType(instField->field.signature[0]);
4509 if (fieldType == kRegTypeUnknown ||
4510 !checkFieldArrayStore1nr(tmpType, fieldType))
4511 {
4512 LOG_VFY("VFY: invalid iget-1nr of %s.%s (inst=%d field=%d)\n",
4513 instField->field.clazz->descriptor,
4514 instField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004515 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004516 break;
4517 }
4518
Andy McFadden62a75162009-04-17 17:23:37 -07004519 setRegisterType(workRegs, insnRegCount, decInsn.vA, tmpType,
4520 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004521 }
4522 break;
4523 case OP_IGET_WIDE:
Andy McFadden861b3382010-03-05 15:58:31 -08004524 case OP_IGET_WIDE_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004525 {
4526 RegType dstType;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004527 InstField* instField;
4528 RegType objType;
4529
4530 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004531 &failure);
4532 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004533 break;
4534 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004535 &failure);
4536 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004537 break;
4538 /* check the type, which should be prim */
4539 switch (instField->field.signature[0]) {
4540 case 'D':
4541 dstType = kRegTypeDoubleLo;
4542 break;
4543 case 'J':
4544 dstType = kRegTypeLongLo;
4545 break;
4546 default:
4547 LOG_VFY("VFY: invalid iget-wide of %s.%s\n",
4548 instField->field.clazz->descriptor,
4549 instField->field.name);
4550 dstType = kRegTypeUnknown;
Andy McFadden62a75162009-04-17 17:23:37 -07004551 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004552 break;
4553 }
Andy McFadden62a75162009-04-17 17:23:37 -07004554 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004555 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004556 dstType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004557 }
4558 }
4559 break;
4560 case OP_IGET_OBJECT:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004561 case OP_IGET_OBJECT_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004562 {
4563 ClassObject* fieldClass;
4564 InstField* instField;
4565 RegType objType;
4566
4567 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004568 &failure);
4569 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004570 break;
4571 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
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 fieldClass = getFieldClass(meth, &instField->field);
4576 if (fieldClass == NULL) {
4577 /* class not found or primitive type */
4578 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4579 instField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004580 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004581 break;
4582 }
Andy McFadden62a75162009-04-17 17:23:37 -07004583 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004584 assert(!dvmIsPrimitiveClass(fieldClass));
4585 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004586 regTypeFromClass(fieldClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004587 }
4588 }
4589 break;
4590 case OP_IPUT:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004591 case OP_IPUT_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004592 tmpType = kRegTypeInteger;
4593 goto iput_1nr_common;
4594 case OP_IPUT_BOOLEAN:
4595 tmpType = kRegTypeBoolean;
4596 goto iput_1nr_common;
4597 case OP_IPUT_BYTE:
4598 tmpType = kRegTypeByte;
4599 goto iput_1nr_common;
4600 case OP_IPUT_CHAR:
4601 tmpType = kRegTypeChar;
4602 goto iput_1nr_common;
4603 case OP_IPUT_SHORT:
4604 tmpType = kRegTypeShort;
4605 goto iput_1nr_common;
4606iput_1nr_common:
4607 {
4608 RegType srcType, fieldType, objType;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004609 InstField* instField;
4610
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004611 srcType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004612 &failure);
Andy McFaddenb5f64bc2009-06-10 14:11:07 -07004613
4614 /*
4615 * javac generates synthetic functions that write byte values
4616 * into boolean fields.
4617 */
4618 if (tmpType == kRegTypeBoolean && srcType == kRegTypeByte)
4619 srcType = kRegTypeBoolean;
4620
4621 /* make sure the source register has the correct type */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004622 if (!canConvertTo1nr(srcType, tmpType)) {
4623 LOG_VFY("VFY: invalid reg type %d on iput instr (need %d)\n",
4624 srcType, tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07004625 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004626 break;
4627 }
4628
4629 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004630 &failure);
4631 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004632 break;
4633 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
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;
Andy McFadden62a75162009-04-17 17:23:37 -07004637 checkFinalFieldAccess(meth, &instField->field, &failure);
4638 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004639 break;
4640
4641 /* get type of field we're storing into */
4642 fieldType = primSigCharToRegType(instField->field.signature[0]);
4643 if (fieldType == kRegTypeUnknown ||
4644 !checkFieldArrayStore1nr(tmpType, fieldType))
4645 {
4646 LOG_VFY("VFY: invalid iput-1nr of %s.%s (inst=%d field=%d)\n",
4647 instField->field.clazz->descriptor,
4648 instField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004649 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004650 break;
4651 }
4652 }
4653 break;
4654 case OP_IPUT_WIDE:
Andy McFadden861b3382010-03-05 15:58:31 -08004655 case OP_IPUT_WIDE_VOLATILE:
Andy McFadden62a75162009-04-17 17:23:37 -07004656 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4657 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004658 RegType typeHi =
Andy McFadden62a75162009-04-17 17:23:37 -07004659 getRegisterType(workRegs, insnRegCount, decInsn.vA+1, &failure);
4660 checkTypeCategory(tmpType, kTypeCategory2, &failure);
4661 checkWidePair(tmpType, typeHi, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004662 }
Andy McFadden62a75162009-04-17 17:23:37 -07004663 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004664 InstField* instField;
4665 RegType objType;
4666
4667 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004668 &failure);
4669 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004670 break;
4671 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004672 &failure);
4673 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004674 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004675 checkFinalFieldAccess(meth, &instField->field, &failure);
4676 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004677 break;
4678
4679 /* check the type, which should be prim */
4680 switch (instField->field.signature[0]) {
4681 case 'D':
4682 case 'J':
4683 /* these are okay (and interchangeable) */
4684 break;
4685 default:
4686 LOG_VFY("VFY: invalid iput-wide of %s.%s\n",
4687 instField->field.clazz->descriptor,
4688 instField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07004689 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004690 break;
4691 }
4692 }
4693 break;
4694 case OP_IPUT_OBJECT:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004695 case OP_IPUT_OBJECT_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004696 {
4697 ClassObject* fieldClass;
4698 ClassObject* valueClass;
4699 InstField* instField;
4700 RegType objType, valueType;
4701
4702 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004703 &failure);
4704 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004705 break;
4706 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004707 &failure);
4708 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004709 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004710 checkFinalFieldAccess(meth, &instField->field, &failure);
4711 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004712 break;
4713
4714 fieldClass = getFieldClass(meth, &instField->field);
4715 if (fieldClass == NULL) {
4716 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4717 instField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004718 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004719 break;
4720 }
4721
4722 valueType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004723 &failure);
4724 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004725 break;
4726 if (!regTypeIsReference(valueType)) {
4727 LOG_VFY("VFY: storing non-ref v%d into ref field '%s' (%s)\n",
4728 decInsn.vA, instField->field.name,
4729 fieldClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004730 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004731 break;
4732 }
4733 if (valueType != kRegTypeZero) {
4734 valueClass = regTypeInitializedReferenceToClass(valueType);
4735 if (valueClass == NULL) {
4736 LOG_VFY("VFY: storing uninit ref v%d into ref field\n",
4737 decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07004738 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004739 break;
4740 }
4741 /* allow if field is any interface or field is base class */
4742 if (!dvmIsInterfaceClass(fieldClass) &&
4743 !dvmInstanceof(valueClass, fieldClass))
4744 {
4745 LOG_VFY("VFY: storing type '%s' into field type '%s' (%s.%s)\n",
4746 valueClass->descriptor, fieldClass->descriptor,
4747 instField->field.clazz->descriptor,
4748 instField->field.name);
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 }
4753 }
4754 break;
4755
4756 case OP_SGET:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004757 case OP_SGET_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004758 tmpType = kRegTypeInteger;
4759 goto sget_1nr_common;
4760 case OP_SGET_BOOLEAN:
4761 tmpType = kRegTypeBoolean;
4762 goto sget_1nr_common;
4763 case OP_SGET_BYTE:
4764 tmpType = kRegTypeByte;
4765 goto sget_1nr_common;
4766 case OP_SGET_CHAR:
4767 tmpType = kRegTypeChar;
4768 goto sget_1nr_common;
4769 case OP_SGET_SHORT:
4770 tmpType = kRegTypeShort;
4771 goto sget_1nr_common;
4772sget_1nr_common:
4773 {
4774 StaticField* staticField;
4775 RegType fieldType;
4776
Andy McFadden62a75162009-04-17 17:23:37 -07004777 staticField = getStaticField(meth, decInsn.vB, &failure);
4778 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004779 break;
4780
4781 /*
4782 * Make sure the field's type is compatible with expectation.
4783 * We can get ourselves into trouble if we mix & match loads
4784 * and stores with different widths, so rather than just checking
4785 * "canConvertTo1nr" we require that the field types have equal
4786 * widths. (We can't generally require an exact type match,
4787 * because e.g. "int" and "float" are interchangeable.)
4788 */
4789 fieldType = primSigCharToRegType(staticField->field.signature[0]);
4790 if (!checkFieldArrayStore1nr(tmpType, fieldType)) {
4791 LOG_VFY("VFY: invalid sget-1nr of %s.%s (inst=%d actual=%d)\n",
4792 staticField->field.clazz->descriptor,
4793 staticField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004794 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004795 break;
4796 }
4797
Andy McFadden62a75162009-04-17 17:23:37 -07004798 setRegisterType(workRegs, insnRegCount, decInsn.vA, tmpType,
4799 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004800 }
4801 break;
4802 case OP_SGET_WIDE:
Andy McFadden861b3382010-03-05 15:58:31 -08004803 case OP_SGET_WIDE_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004804 {
4805 StaticField* staticField;
4806 RegType dstType;
4807
Andy McFadden62a75162009-04-17 17:23:37 -07004808 staticField = getStaticField(meth, decInsn.vB, &failure);
4809 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004810 break;
4811 /* check the type, which should be prim */
4812 switch (staticField->field.signature[0]) {
4813 case 'D':
4814 dstType = kRegTypeDoubleLo;
4815 break;
4816 case 'J':
4817 dstType = kRegTypeLongLo;
4818 break;
4819 default:
4820 LOG_VFY("VFY: invalid sget-wide of %s.%s\n",
4821 staticField->field.clazz->descriptor,
4822 staticField->field.name);
4823 dstType = kRegTypeUnknown;
Andy McFadden62a75162009-04-17 17:23:37 -07004824 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004825 break;
4826 }
Andy McFadden62a75162009-04-17 17:23:37 -07004827 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004828 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004829 dstType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004830 }
4831 }
4832 break;
4833 case OP_SGET_OBJECT:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004834 case OP_SGET_OBJECT_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004835 {
4836 StaticField* staticField;
4837 ClassObject* fieldClass;
4838
Andy McFadden62a75162009-04-17 17:23:37 -07004839 staticField = getStaticField(meth, decInsn.vB, &failure);
4840 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004841 break;
4842 fieldClass = getFieldClass(meth, &staticField->field);
4843 if (fieldClass == NULL) {
4844 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4845 staticField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004846 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004847 break;
4848 }
4849 if (dvmIsPrimitiveClass(fieldClass)) {
4850 LOG_VFY("VFY: attempt to get prim field with sget-object\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004851 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004852 break;
4853 }
4854 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004855 regTypeFromClass(fieldClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004856 }
4857 break;
4858 case OP_SPUT:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004859 case OP_SPUT_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004860 tmpType = kRegTypeInteger;
4861 goto sput_1nr_common;
4862 case OP_SPUT_BOOLEAN:
4863 tmpType = kRegTypeBoolean;
4864 goto sput_1nr_common;
4865 case OP_SPUT_BYTE:
4866 tmpType = kRegTypeByte;
4867 goto sput_1nr_common;
4868 case OP_SPUT_CHAR:
4869 tmpType = kRegTypeChar;
4870 goto sput_1nr_common;
4871 case OP_SPUT_SHORT:
4872 tmpType = kRegTypeShort;
4873 goto sput_1nr_common;
4874sput_1nr_common:
4875 {
4876 RegType srcType, fieldType;
4877 StaticField* staticField;
4878
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004879 srcType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004880 &failure);
Andy McFaddenb5f64bc2009-06-10 14:11:07 -07004881
4882 /*
4883 * javac generates synthetic functions that write byte values
4884 * into boolean fields.
4885 */
4886 if (tmpType == kRegTypeBoolean && srcType == kRegTypeByte)
4887 srcType = kRegTypeBoolean;
4888
4889 /* make sure the source register has the correct type */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004890 if (!canConvertTo1nr(srcType, tmpType)) {
Andy McFaddenb5f64bc2009-06-10 14:11:07 -07004891 LOG_VFY("VFY: invalid reg type %d on sput instr (need %d)\n",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004892 srcType, tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07004893 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004894 break;
4895 }
4896
Andy McFadden62a75162009-04-17 17:23:37 -07004897 staticField = getStaticField(meth, decInsn.vB, &failure);
4898 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004899 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004900 checkFinalFieldAccess(meth, &staticField->field, &failure);
4901 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004902 break;
4903
4904 /*
4905 * Get type of field we're storing into. We know that the
4906 * contents of the register match the instruction, but we also
4907 * need to ensure that the instruction matches the field type.
4908 * Using e.g. sput-short to write into a 32-bit integer field
4909 * can lead to trouble if we do 16-bit writes.
4910 */
4911 fieldType = primSigCharToRegType(staticField->field.signature[0]);
4912 if (!checkFieldArrayStore1nr(tmpType, fieldType)) {
4913 LOG_VFY("VFY: invalid sput-1nr of %s.%s (inst=%d actual=%d)\n",
4914 staticField->field.clazz->descriptor,
4915 staticField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004916 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004917 break;
4918 }
4919 }
4920 break;
4921 case OP_SPUT_WIDE:
Andy McFadden861b3382010-03-05 15:58:31 -08004922 case OP_SPUT_WIDE_VOLATILE:
Andy McFadden62a75162009-04-17 17:23:37 -07004923 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4924 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004925 RegType typeHi =
Andy McFadden62a75162009-04-17 17:23:37 -07004926 getRegisterType(workRegs, insnRegCount, decInsn.vA+1, &failure);
4927 checkTypeCategory(tmpType, kTypeCategory2, &failure);
4928 checkWidePair(tmpType, typeHi, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004929 }
Andy McFadden62a75162009-04-17 17:23:37 -07004930 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004931 StaticField* staticField;
4932
Andy McFadden62a75162009-04-17 17:23:37 -07004933 staticField = getStaticField(meth, decInsn.vB, &failure);
4934 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004935 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004936 checkFinalFieldAccess(meth, &staticField->field, &failure);
4937 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004938 break;
4939
4940 /* check the type, which should be prim */
4941 switch (staticField->field.signature[0]) {
4942 case 'D':
4943 case 'J':
4944 /* these are okay */
4945 break;
4946 default:
4947 LOG_VFY("VFY: invalid sput-wide of %s.%s\n",
4948 staticField->field.clazz->descriptor,
4949 staticField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07004950 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004951 break;
4952 }
4953 }
4954 break;
4955 case OP_SPUT_OBJECT:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004956 case OP_SPUT_OBJECT_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004957 {
4958 ClassObject* fieldClass;
4959 ClassObject* valueClass;
4960 StaticField* staticField;
4961 RegType valueType;
4962
Andy McFadden62a75162009-04-17 17:23:37 -07004963 staticField = getStaticField(meth, decInsn.vB, &failure);
4964 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004965 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004966 checkFinalFieldAccess(meth, &staticField->field, &failure);
4967 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004968 break;
4969
4970 fieldClass = getFieldClass(meth, &staticField->field);
4971 if (fieldClass == NULL) {
4972 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4973 staticField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004974 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004975 break;
4976 }
4977
4978 valueType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004979 &failure);
4980 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004981 break;
4982 if (!regTypeIsReference(valueType)) {
4983 LOG_VFY("VFY: storing non-ref v%d into ref field '%s' (%s)\n",
4984 decInsn.vA, staticField->field.name,
4985 fieldClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004986 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004987 break;
4988 }
4989 if (valueType != kRegTypeZero) {
4990 valueClass = regTypeInitializedReferenceToClass(valueType);
4991 if (valueClass == NULL) {
4992 LOG_VFY("VFY: storing uninit ref v%d into ref field\n",
4993 decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07004994 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004995 break;
4996 }
4997 /* allow if field is any interface or field is base class */
4998 if (!dvmIsInterfaceClass(fieldClass) &&
4999 !dvmInstanceof(valueClass, fieldClass))
5000 {
5001 LOG_VFY("VFY: storing type '%s' into field type '%s' (%s.%s)\n",
5002 valueClass->descriptor, fieldClass->descriptor,
5003 staticField->field.clazz->descriptor,
5004 staticField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07005005 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005006 break;
5007 }
5008 }
5009 }
5010 break;
5011
5012 case OP_INVOKE_VIRTUAL:
5013 case OP_INVOKE_VIRTUAL_RANGE:
5014 case OP_INVOKE_SUPER:
5015 case OP_INVOKE_SUPER_RANGE:
5016 {
5017 Method* calledMethod;
5018 RegType returnType;
5019 bool isRange;
5020 bool isSuper;
5021
5022 isRange = (decInsn.opCode == OP_INVOKE_VIRTUAL_RANGE ||
5023 decInsn.opCode == OP_INVOKE_SUPER_RANGE);
5024 isSuper = (decInsn.opCode == OP_INVOKE_SUPER ||
5025 decInsn.opCode == OP_INVOKE_SUPER_RANGE);
5026
5027 calledMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
5028 &decInsn, uninitMap, METHOD_VIRTUAL, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07005029 isSuper, &failure);
5030 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005031 break;
5032 returnType = getMethodReturnType(calledMethod);
Andy McFadden62a75162009-04-17 17:23:37 -07005033 setResultRegisterType(workRegs, insnRegCount, returnType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005034 justSetResult = true;
5035 }
5036 break;
5037 case OP_INVOKE_DIRECT:
5038 case OP_INVOKE_DIRECT_RANGE:
5039 {
5040 RegType returnType;
5041 Method* calledMethod;
5042 bool isRange;
5043
5044 isRange = (decInsn.opCode == OP_INVOKE_DIRECT_RANGE);
5045 calledMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
5046 &decInsn, uninitMap, METHOD_DIRECT, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07005047 false, &failure);
5048 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005049 break;
5050
5051 /*
5052 * Some additional checks when calling <init>. We know from
5053 * the invocation arg check that the "this" argument is an
5054 * instance of calledMethod->clazz. Now we further restrict
5055 * that to require that calledMethod->clazz is the same as
5056 * this->clazz or this->super, allowing the latter only if
5057 * the "this" argument is the same as the "this" argument to
5058 * this method (which implies that we're in <init> ourselves).
5059 */
5060 if (isInitMethod(calledMethod)) {
5061 RegType thisType;
5062 thisType = getInvocationThis(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07005063 &decInsn, &failure);
5064 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005065 break;
5066
5067 /* no null refs allowed (?) */
5068 if (thisType == kRegTypeZero) {
5069 LOG_VFY("VFY: unable to initialize null ref\n");
Andy McFadden62a75162009-04-17 17:23:37 -07005070 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005071 break;
5072 }
5073
5074 ClassObject* thisClass;
5075
5076 thisClass = regTypeReferenceToClass(thisType, uninitMap);
5077 assert(thisClass != NULL);
5078
5079 /* must be in same class or in superclass */
5080 if (calledMethod->clazz == thisClass->super) {
5081 if (thisClass != meth->clazz) {
5082 LOG_VFY("VFY: invoke-direct <init> on super only "
5083 "allowed for 'this' in <init>");
Andy McFadden62a75162009-04-17 17:23:37 -07005084 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005085 break;
5086 }
5087 } else if (calledMethod->clazz != thisClass) {
5088 LOG_VFY("VFY: invoke-direct <init> must be on current "
5089 "class or super\n");
Andy McFadden62a75162009-04-17 17:23:37 -07005090 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005091 break;
5092 }
5093
5094 /* arg must be an uninitialized reference */
5095 if (!regTypeIsUninitReference(thisType)) {
5096 LOG_VFY("VFY: can only initialize the uninitialized\n");
Andy McFadden62a75162009-04-17 17:23:37 -07005097 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005098 break;
5099 }
5100
5101 /*
5102 * Replace the uninitialized reference with an initialized
5103 * one, and clear the entry in the uninit map. We need to
5104 * do this for all registers that have the same object
5105 * instance in them, not just the "this" register.
5106 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005107 markRefsAsInitialized(workRegs, insnRegCount, uninitMap,
Andy McFadden62a75162009-04-17 17:23:37 -07005108 thisType, &failure);
5109 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005110 break;
5111 }
5112 returnType = getMethodReturnType(calledMethod);
5113 setResultRegisterType(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07005114 returnType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005115 justSetResult = true;
5116 }
5117 break;
5118 case OP_INVOKE_STATIC:
5119 case OP_INVOKE_STATIC_RANGE:
5120 {
5121 RegType returnType;
5122 Method* calledMethod;
5123 bool isRange;
5124
5125 isRange = (decInsn.opCode == OP_INVOKE_STATIC_RANGE);
5126 calledMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
5127 &decInsn, uninitMap, METHOD_STATIC, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07005128 false, &failure);
5129 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005130 break;
5131
5132 returnType = getMethodReturnType(calledMethod);
Andy McFadden62a75162009-04-17 17:23:37 -07005133 setResultRegisterType(workRegs, insnRegCount, returnType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005134 justSetResult = true;
5135 }
5136 break;
5137 case OP_INVOKE_INTERFACE:
5138 case OP_INVOKE_INTERFACE_RANGE:
5139 {
5140 RegType /*thisType,*/ returnType;
5141 Method* absMethod;
5142 bool isRange;
5143
5144 isRange = (decInsn.opCode == OP_INVOKE_INTERFACE_RANGE);
5145 absMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
5146 &decInsn, uninitMap, METHOD_INTERFACE, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07005147 false, &failure);
5148 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005149 break;
5150
5151#if 0 /* can't do this here, fails on dalvik test 052-verifier-fun */
5152 /*
5153 * Get the type of the "this" arg, which should always be an
5154 * interface class. Because we don't do a full merge on
5155 * interface classes, this might have reduced to Object.
5156 */
5157 thisType = getInvocationThis(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07005158 &decInsn, &failure);
5159 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005160 break;
5161
5162 if (thisType == kRegTypeZero) {
5163 /* null pointer always passes (and always fails at runtime) */
5164 } else {
5165 ClassObject* thisClass;
5166
5167 thisClass = regTypeInitializedReferenceToClass(thisType);
5168 if (thisClass == NULL) {
5169 LOG_VFY("VFY: interface call on uninitialized\n");
Andy McFadden62a75162009-04-17 17:23:37 -07005170 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005171 break;
5172 }
5173
5174 /*
5175 * Either "thisClass" needs to be the interface class that
5176 * defined absMethod, or absMethod's class needs to be one
5177 * of the interfaces implemented by "thisClass". (Or, if
5178 * we couldn't complete the merge, this will be Object.)
5179 */
5180 if (thisClass != absMethod->clazz &&
5181 thisClass != gDvm.classJavaLangObject &&
5182 !dvmImplements(thisClass, absMethod->clazz))
5183 {
5184 LOG_VFY("VFY: unable to match absMethod '%s' with %s interfaces\n",
5185 absMethod->name, thisClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07005186 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005187 break;
5188 }
5189 }
5190#endif
5191
5192 /*
5193 * We don't have an object instance, so we can't find the
5194 * concrete method. However, all of the type information is
5195 * in the abstract method, so we're good.
5196 */
5197 returnType = getMethodReturnType(absMethod);
Andy McFadden62a75162009-04-17 17:23:37 -07005198 setResultRegisterType(workRegs, insnRegCount, returnType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005199 justSetResult = true;
5200 }
5201 break;
5202
5203 case OP_NEG_INT:
5204 case OP_NOT_INT:
5205 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005206 kRegTypeInteger, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005207 break;
5208 case OP_NEG_LONG:
5209 case OP_NOT_LONG:
5210 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005211 kRegTypeLongLo, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005212 break;
5213 case OP_NEG_FLOAT:
5214 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005215 kRegTypeFloat, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005216 break;
5217 case OP_NEG_DOUBLE:
5218 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005219 kRegTypeDoubleLo, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005220 break;
5221 case OP_INT_TO_LONG:
5222 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005223 kRegTypeLongLo, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005224 break;
5225 case OP_INT_TO_FLOAT:
5226 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005227 kRegTypeFloat, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005228 break;
5229 case OP_INT_TO_DOUBLE:
5230 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005231 kRegTypeDoubleLo, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005232 break;
5233 case OP_LONG_TO_INT:
5234 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005235 kRegTypeInteger, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005236 break;
5237 case OP_LONG_TO_FLOAT:
5238 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005239 kRegTypeFloat, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005240 break;
5241 case OP_LONG_TO_DOUBLE:
5242 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005243 kRegTypeDoubleLo, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005244 break;
5245 case OP_FLOAT_TO_INT:
5246 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005247 kRegTypeInteger, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005248 break;
5249 case OP_FLOAT_TO_LONG:
5250 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005251 kRegTypeLongLo, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005252 break;
5253 case OP_FLOAT_TO_DOUBLE:
5254 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005255 kRegTypeDoubleLo, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005256 break;
5257 case OP_DOUBLE_TO_INT:
5258 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005259 kRegTypeInteger, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005260 break;
5261 case OP_DOUBLE_TO_LONG:
5262 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005263 kRegTypeLongLo, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005264 break;
5265 case OP_DOUBLE_TO_FLOAT:
5266 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005267 kRegTypeFloat, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005268 break;
5269 case OP_INT_TO_BYTE:
5270 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005271 kRegTypeByte, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005272 break;
5273 case OP_INT_TO_CHAR:
5274 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005275 kRegTypeChar, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005276 break;
5277 case OP_INT_TO_SHORT:
5278 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005279 kRegTypeShort, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005280 break;
5281
5282 case OP_ADD_INT:
5283 case OP_SUB_INT:
5284 case OP_MUL_INT:
5285 case OP_REM_INT:
5286 case OP_DIV_INT:
5287 case OP_SHL_INT:
5288 case OP_SHR_INT:
5289 case OP_USHR_INT:
5290 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005291 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005292 break;
5293 case OP_AND_INT:
5294 case OP_OR_INT:
5295 case OP_XOR_INT:
5296 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005297 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005298 break;
5299 case OP_ADD_LONG:
5300 case OP_SUB_LONG:
5301 case OP_MUL_LONG:
5302 case OP_DIV_LONG:
5303 case OP_REM_LONG:
5304 case OP_AND_LONG:
5305 case OP_OR_LONG:
5306 case OP_XOR_LONG:
5307 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005308 kRegTypeLongLo, kRegTypeLongLo, kRegTypeLongLo, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005309 break;
5310 case OP_SHL_LONG:
5311 case OP_SHR_LONG:
5312 case OP_USHR_LONG:
5313 /* shift distance is Int, making these different from other binops */
5314 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005315 kRegTypeLongLo, kRegTypeLongLo, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005316 break;
5317 case OP_ADD_FLOAT:
5318 case OP_SUB_FLOAT:
5319 case OP_MUL_FLOAT:
5320 case OP_DIV_FLOAT:
5321 case OP_REM_FLOAT:
5322 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005323 kRegTypeFloat, kRegTypeFloat, kRegTypeFloat, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005324 break;
5325 case OP_ADD_DOUBLE:
5326 case OP_SUB_DOUBLE:
5327 case OP_MUL_DOUBLE:
5328 case OP_DIV_DOUBLE:
5329 case OP_REM_DOUBLE:
5330 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005331 kRegTypeDoubleLo, kRegTypeDoubleLo, kRegTypeDoubleLo, false,
5332 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005333 break;
5334 case OP_ADD_INT_2ADDR:
5335 case OP_SUB_INT_2ADDR:
5336 case OP_MUL_INT_2ADDR:
5337 case OP_REM_INT_2ADDR:
5338 case OP_SHL_INT_2ADDR:
5339 case OP_SHR_INT_2ADDR:
5340 case OP_USHR_INT_2ADDR:
5341 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005342 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005343 break;
5344 case OP_AND_INT_2ADDR:
5345 case OP_OR_INT_2ADDR:
5346 case OP_XOR_INT_2ADDR:
5347 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005348 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005349 break;
5350 case OP_DIV_INT_2ADDR:
5351 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005352 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005353 break;
5354 case OP_ADD_LONG_2ADDR:
5355 case OP_SUB_LONG_2ADDR:
5356 case OP_MUL_LONG_2ADDR:
5357 case OP_DIV_LONG_2ADDR:
5358 case OP_REM_LONG_2ADDR:
5359 case OP_AND_LONG_2ADDR:
5360 case OP_OR_LONG_2ADDR:
5361 case OP_XOR_LONG_2ADDR:
5362 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005363 kRegTypeLongLo, kRegTypeLongLo, kRegTypeLongLo, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005364 break;
5365 case OP_SHL_LONG_2ADDR:
5366 case OP_SHR_LONG_2ADDR:
5367 case OP_USHR_LONG_2ADDR:
5368 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005369 kRegTypeLongLo, kRegTypeLongLo, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005370 break;
5371 case OP_ADD_FLOAT_2ADDR:
5372 case OP_SUB_FLOAT_2ADDR:
5373 case OP_MUL_FLOAT_2ADDR:
5374 case OP_DIV_FLOAT_2ADDR:
5375 case OP_REM_FLOAT_2ADDR:
5376 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005377 kRegTypeFloat, kRegTypeFloat, kRegTypeFloat, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005378 break;
5379 case OP_ADD_DOUBLE_2ADDR:
5380 case OP_SUB_DOUBLE_2ADDR:
5381 case OP_MUL_DOUBLE_2ADDR:
5382 case OP_DIV_DOUBLE_2ADDR:
5383 case OP_REM_DOUBLE_2ADDR:
5384 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005385 kRegTypeDoubleLo, kRegTypeDoubleLo, kRegTypeDoubleLo, false,
5386 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005387 break;
5388 case OP_ADD_INT_LIT16:
5389 case OP_RSUB_INT:
5390 case OP_MUL_INT_LIT16:
5391 case OP_DIV_INT_LIT16:
5392 case OP_REM_INT_LIT16:
5393 checkLitop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005394 kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005395 break;
5396 case OP_AND_INT_LIT16:
5397 case OP_OR_INT_LIT16:
5398 case OP_XOR_INT_LIT16:
5399 checkLitop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005400 kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005401 break;
5402 case OP_ADD_INT_LIT8:
5403 case OP_RSUB_INT_LIT8:
5404 case OP_MUL_INT_LIT8:
5405 case OP_DIV_INT_LIT8:
5406 case OP_REM_INT_LIT8:
5407 case OP_SHL_INT_LIT8:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005408 checkLitop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005409 kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005410 break;
Andy McFadden80d25ea2009-06-12 07:26:17 -07005411 case OP_SHR_INT_LIT8:
5412 tmpType = adjustForRightShift(workRegs, insnRegCount,
5413 decInsn.vB, decInsn.vC, false, &failure);
5414 checkLitop(workRegs, insnRegCount, &decInsn,
5415 tmpType, kRegTypeInteger, false, &failure);
5416 break;
5417 case OP_USHR_INT_LIT8:
5418 tmpType = adjustForRightShift(workRegs, insnRegCount,
5419 decInsn.vB, decInsn.vC, true, &failure);
5420 checkLitop(workRegs, insnRegCount, &decInsn,
5421 tmpType, kRegTypeInteger, false, &failure);
5422 break;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005423 case OP_AND_INT_LIT8:
5424 case OP_OR_INT_LIT8:
5425 case OP_XOR_INT_LIT8:
5426 checkLitop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005427 kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005428 break;
5429
Andy McFaddenb51ea112009-05-08 16:50:17 -07005430 /*
5431 * This falls into the general category of "optimized" instructions,
5432 * which don't generally appear during verification. Because it's
5433 * inserted in the course of verification, we can expect to see it here.
5434 */
5435 case OP_THROW_VERIFICATION_ERROR:
5436 break;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005437
5438 /*
5439 * Verifying "quickened" instructions is tricky, because we have
5440 * discarded the original field/method information. The byte offsets
5441 * and vtable indices only have meaning in the context of an object
5442 * instance.
5443 *
5444 * If a piece of code declares a local reference variable, assigns
5445 * null to it, and then issues a virtual method call on it, we
5446 * cannot evaluate the method call during verification. This situation
5447 * isn't hard to handle, since we know the call will always result in an
5448 * NPE, and the arguments and return value don't matter. Any code that
5449 * depends on the result of the method call is inaccessible, so the
5450 * fact that we can't fully verify anything that comes after the bad
5451 * call is not a problem.
5452 *
5453 * We must also consider the case of multiple code paths, only some of
5454 * which involve a null reference. We can completely verify the method
5455 * if we sidestep the results of executing with a null reference.
5456 * For example, if on the first pass through the code we try to do a
5457 * virtual method invocation through a null ref, we have to skip the
5458 * method checks and have the method return a "wildcard" type (which
5459 * merges with anything to become that other thing). The move-result
5460 * will tell us if it's a reference, single-word numeric, or double-word
5461 * value. We continue to perform the verification, and at the end of
5462 * the function any invocations that were never fully exercised are
5463 * marked as null-only.
5464 *
5465 * We would do something similar for the field accesses. The field's
5466 * type, once known, can be used to recover the width of short integers.
5467 * If the object reference was null, the field-get returns the "wildcard"
5468 * type, which is acceptable for any operation.
5469 */
5470 case OP_EXECUTE_INLINE:
Andy McFaddenb0a05412009-11-19 10:23:41 -08005471 case OP_EXECUTE_INLINE_RANGE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005472 case OP_INVOKE_DIRECT_EMPTY:
5473 case OP_IGET_QUICK:
5474 case OP_IGET_WIDE_QUICK:
5475 case OP_IGET_OBJECT_QUICK:
5476 case OP_IPUT_QUICK:
5477 case OP_IPUT_WIDE_QUICK:
5478 case OP_IPUT_OBJECT_QUICK:
5479 case OP_INVOKE_VIRTUAL_QUICK:
5480 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
5481 case OP_INVOKE_SUPER_QUICK:
5482 case OP_INVOKE_SUPER_QUICK_RANGE:
Andy McFadden291758c2010-09-10 08:04:52 -07005483 case OP_RETURN_VOID_BARRIER:
Andy McFadden62a75162009-04-17 17:23:37 -07005484 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005485 break;
5486
Andy McFadden96516932009-10-28 17:39:02 -07005487 /* these should never appear during verification */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005488 case OP_UNUSED_3E:
5489 case OP_UNUSED_3F:
5490 case OP_UNUSED_40:
5491 case OP_UNUSED_41:
5492 case OP_UNUSED_42:
5493 case OP_UNUSED_43:
5494 case OP_UNUSED_73:
5495 case OP_UNUSED_79:
5496 case OP_UNUSED_7A:
Andy McFadden96516932009-10-28 17:39:02 -07005497 case OP_BREAKPOINT:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005498 case OP_UNUSED_FF:
Andy McFadden62a75162009-04-17 17:23:37 -07005499 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005500 break;
5501
5502 /*
5503 * DO NOT add a "default" clause here. Without it the compiler will
5504 * complain if an instruction is missing (which is desirable).
5505 */
5506 }
5507
Andy McFadden62a75162009-04-17 17:23:37 -07005508 if (!VERIFY_OK(failure)) {
Andy McFaddenb51ea112009-05-08 16:50:17 -07005509 if (failure == VERIFY_ERROR_GENERIC || gDvm.optimizing) {
5510 /* immediate failure, reject class */
5511 LOG_VFY_METH(meth, "VFY: rejecting opcode 0x%02x at 0x%04x\n",
5512 decInsn.opCode, insnIdx);
5513 goto bail;
5514 } else {
5515 /* replace opcode and continue on */
5516 LOGD("VFY: replacing opcode 0x%02x at 0x%04x\n",
5517 decInsn.opCode, insnIdx);
5518 if (!replaceFailingInstruction(meth, insnFlags, insnIdx, failure)) {
5519 LOG_VFY_METH(meth, "VFY: rejecting opcode 0x%02x at 0x%04x\n",
5520 decInsn.opCode, insnIdx);
5521 goto bail;
5522 }
5523 /* IMPORTANT: meth->insns may have been changed */
5524 insns = meth->insns + insnIdx;
5525
5526 /* continue on as if we just handled a throw-verification-error */
5527 failure = VERIFY_ERROR_NONE;
5528 nextFlags = kInstrCanThrow;
5529 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005530 }
5531
5532 /*
5533 * If we didn't just set the result register, clear it out. This
5534 * ensures that you can only use "move-result" immediately after the
Andy McFadden2e1ee502010-03-24 13:25:53 -07005535 * result is set. (We could check this statically, but it's not
5536 * expensive and it makes our debugging output cleaner.)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005537 */
5538 if (!justSetResult) {
5539 int reg = RESULT_REGISTER(insnRegCount);
5540 workRegs[reg] = workRegs[reg+1] = kRegTypeUnknown;
5541 }
5542
5543 /*
5544 * Handle "continue". Tag the next consecutive instruction.
5545 */
5546 if ((nextFlags & kInstrCanContinue) != 0) {
5547 int insnWidth = dvmInsnGetWidth(insnFlags, insnIdx);
5548 if (insnIdx+insnWidth >= insnsSize) {
5549 LOG_VFY_METH(meth,
5550 "VFY: execution can walk off end of code area (from 0x%x)\n",
5551 insnIdx);
5552 goto bail;
5553 }
5554
5555 /*
5556 * The only way to get to a move-exception instruction is to get
5557 * thrown there. Make sure the next instruction isn't one.
5558 */
5559 if (!checkMoveException(meth, insnIdx+insnWidth, "next"))
5560 goto bail;
5561
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005562 if (getRegisterLine(regTable, insnIdx+insnWidth) != NULL) {
Andy McFadden06b7a282009-05-11 10:44:52 -07005563 /*
5564 * Merge registers into what we have for the next instruction,
5565 * and set the "changed" flag if needed.
5566 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005567 updateRegisters(meth, insnFlags, regTable, insnIdx+insnWidth,
5568 workRegs);
5569 } else {
The Android Open Source Project99409882009-03-18 22:20:24 -07005570 /*
Andy McFadden06b7a282009-05-11 10:44:52 -07005571 * We're not recording register data for the next instruction,
5572 * so we don't know what the prior state was. We have to
5573 * assume that something has changed and re-evaluate it.
The Android Open Source Project99409882009-03-18 22:20:24 -07005574 */
5575 dvmInsnSetChanged(insnFlags, insnIdx+insnWidth, true);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005576 }
5577 }
5578
5579 /*
5580 * Handle "branch". Tag the branch target.
5581 *
5582 * NOTE: instructions like OP_EQZ provide information about the state
5583 * of the register when the branch is taken or not taken. For example,
5584 * somebody could get a reference field, check it for zero, and if the
5585 * branch is taken immediately store that register in a boolean field
5586 * since the value is known to be zero. We do not currently account for
5587 * that, and will reject the code.
5588 */
5589 if ((nextFlags & kInstrCanBranch) != 0) {
5590 bool isConditional;
5591
5592 if (!dvmGetBranchTarget(meth, insnFlags, insnIdx, &branchTarget,
5593 &isConditional))
5594 {
5595 /* should never happen after static verification */
5596 LOG_VFY_METH(meth, "VFY: bad branch at %d\n", insnIdx);
5597 goto bail;
5598 }
5599 assert(isConditional || (nextFlags & kInstrCanContinue) == 0);
5600 assert(!isConditional || (nextFlags & kInstrCanContinue) != 0);
5601
5602 if (!checkMoveException(meth, insnIdx+branchTarget, "branch"))
5603 goto bail;
5604
The Android Open Source Project99409882009-03-18 22:20:24 -07005605 /* update branch target, set "changed" if appropriate */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005606 updateRegisters(meth, insnFlags, regTable, insnIdx+branchTarget,
5607 workRegs);
5608 }
5609
5610 /*
5611 * Handle "switch". Tag all possible branch targets.
5612 *
5613 * We've already verified that the table is structurally sound, so we
5614 * just need to walk through and tag the targets.
5615 */
5616 if ((nextFlags & kInstrCanSwitch) != 0) {
5617 int offsetToSwitch = insns[1] | (((s4)insns[2]) << 16);
5618 const u2* switchInsns = insns + offsetToSwitch;
5619 int switchCount = switchInsns[1];
5620 int offsetToTargets, targ;
5621
5622 if ((*insns & 0xff) == OP_PACKED_SWITCH) {
5623 /* 0=sig, 1=count, 2/3=firstKey */
5624 offsetToTargets = 4;
5625 } else {
5626 /* 0=sig, 1=count, 2..count*2 = keys */
5627 assert((*insns & 0xff) == OP_SPARSE_SWITCH);
5628 offsetToTargets = 2 + 2*switchCount;
5629 }
5630
5631 /* verify each switch target */
5632 for (targ = 0; targ < switchCount; targ++) {
5633 int offset, absOffset;
5634
5635 /* offsets are 32-bit, and only partly endian-swapped */
5636 offset = switchInsns[offsetToTargets + targ*2] |
5637 (((s4) switchInsns[offsetToTargets + targ*2 +1]) << 16);
5638 absOffset = insnIdx + offset;
5639
5640 assert(absOffset >= 0 && absOffset < insnsSize);
5641
5642 if (!checkMoveException(meth, absOffset, "switch"))
5643 goto bail;
5644
5645 updateRegisters(meth, insnFlags, regTable, absOffset, workRegs);
5646 }
5647 }
5648
5649 /*
5650 * Handle instructions that can throw and that are sitting in a
5651 * "try" block. (If they're not in a "try" block when they throw,
5652 * control transfers out of the method.)
5653 */
5654 if ((nextFlags & kInstrCanThrow) != 0 && dvmInsnIsInTry(insnFlags, insnIdx))
5655 {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005656 const DexCode* pCode = dvmGetMethodCode(meth);
5657 DexCatchIterator iterator;
5658
5659 if (dexFindCatchHandler(&iterator, pCode, insnIdx)) {
5660 for (;;) {
5661 DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
5662
5663 if (handler == NULL) {
5664 break;
5665 }
5666
5667 /* note we use entryRegs, not workRegs */
5668 updateRegisters(meth, insnFlags, regTable, handler->address,
5669 entryRegs);
5670 }
5671 }
5672 }
5673
5674 /*
5675 * Update startGuess. Advance to the next instruction of that's
5676 * possible, otherwise use the branch target if one was found. If
5677 * neither of those exists we're in a return or throw; leave startGuess
5678 * alone and let the caller sort it out.
5679 */
5680 if ((nextFlags & kInstrCanContinue) != 0) {
5681 *pStartGuess = insnIdx + dvmInsnGetWidth(insnFlags, insnIdx);
5682 } else if ((nextFlags & kInstrCanBranch) != 0) {
5683 /* we're still okay if branchTarget is zero */
5684 *pStartGuess = insnIdx + branchTarget;
5685 }
5686
5687 assert(*pStartGuess >= 0 && *pStartGuess < insnsSize &&
5688 dvmInsnGetWidth(insnFlags, *pStartGuess) != 0);
5689
5690 result = true;
5691
5692bail:
5693 return result;
5694}
5695
Andy McFaddenb51ea112009-05-08 16:50:17 -07005696
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005697/*
5698 * callback function used in dumpRegTypes to print local vars
5699 * valid at a given address.
5700 */
5701static void logLocalsCb(void *cnxt, u2 reg, u4 startAddress, u4 endAddress,
5702 const char *name, const char *descriptor,
5703 const char *signature)
5704{
5705 int addr = *((int *)cnxt);
5706
5707 if (addr >= (int) startAddress && addr < (int) endAddress)
5708 {
5709 LOGI(" %2d: '%s' %s\n", reg, name, descriptor);
5710 }
5711}
5712
5713/*
5714 * Dump the register types for the specifed address to the log file.
5715 */
5716static void dumpRegTypes(const Method* meth, const InsnFlags* insnFlags,
5717 const RegType* addrRegs, int addr, const char* addrName,
5718 const UninitInstanceMap* uninitMap, int displayFlags)
5719{
5720 int regCount = meth->registersSize;
5721 int fullRegCount = regCount + kExtraRegs;
5722 bool branchTarget = dvmInsnIsBranchTarget(insnFlags, addr);
5723 int i;
5724
5725 assert(addr >= 0 && addr < (int) dvmGetMethodInsnsSize(meth));
5726
5727 int regCharSize = fullRegCount + (fullRegCount-1)/4 + 2 +1;
5728 char regChars[regCharSize +1];
5729 memset(regChars, ' ', regCharSize);
5730 regChars[0] = '[';
5731 if (regCount == 0)
5732 regChars[1] = ']';
5733 else
5734 regChars[1 + (regCount-1) + (regCount-1)/4 +1] = ']';
5735 regChars[regCharSize] = '\0';
5736
5737 //const RegType* addrRegs = getRegisterLine(regTable, addr);
5738
5739 for (i = 0; i < regCount + kExtraRegs; i++) {
5740 char tch;
5741
5742 switch (addrRegs[i]) {
5743 case kRegTypeUnknown: tch = '.'; break;
5744 case kRegTypeConflict: tch = 'X'; break;
5745 case kRegTypeFloat: tch = 'F'; break;
5746 case kRegTypeZero: tch = '0'; break;
5747 case kRegTypeOne: tch = '1'; break;
5748 case kRegTypeBoolean: tch = 'Z'; break;
5749 case kRegTypePosByte: tch = 'b'; break;
5750 case kRegTypeByte: tch = 'B'; break;
5751 case kRegTypePosShort: tch = 's'; break;
5752 case kRegTypeShort: tch = 'S'; break;
5753 case kRegTypeChar: tch = 'C'; break;
5754 case kRegTypeInteger: tch = 'I'; break;
5755 case kRegTypeLongLo: tch = 'J'; break;
5756 case kRegTypeLongHi: tch = 'j'; break;
5757 case kRegTypeDoubleLo: tch = 'D'; break;
5758 case kRegTypeDoubleHi: tch = 'd'; break;
5759 default:
5760 if (regTypeIsReference(addrRegs[i])) {
5761 if (regTypeIsUninitReference(addrRegs[i]))
5762 tch = 'U';
5763 else
5764 tch = 'L';
5765 } else {
5766 tch = '*';
5767 assert(false);
5768 }
5769 break;
5770 }
5771
5772 if (i < regCount)
5773 regChars[1 + i + (i/4)] = tch;
5774 else
5775 regChars[1 + i + (i/4) + 2] = tch;
5776 }
5777
5778 if (addr == 0 && addrName != NULL)
5779 LOGI("%c%s %s\n", branchTarget ? '>' : ' ', addrName, regChars);
5780 else
5781 LOGI("%c0x%04x %s\n", branchTarget ? '>' : ' ', addr, regChars);
5782
5783 if (displayFlags & DRT_SHOW_REF_TYPES) {
5784 for (i = 0; i < regCount + kExtraRegs; i++) {
5785 if (regTypeIsReference(addrRegs[i]) && addrRegs[i] != kRegTypeZero)
5786 {
5787 ClassObject* clazz;
5788
5789 clazz = regTypeReferenceToClass(addrRegs[i], uninitMap);
5790 assert(dvmValidateObject((Object*)clazz));
5791 if (i < regCount) {
5792 LOGI(" %2d: 0x%08x %s%s\n",
5793 i, addrRegs[i],
5794 regTypeIsUninitReference(addrRegs[i]) ? "[U]" : "",
5795 clazz->descriptor);
5796 } else {
5797 LOGI(" RS: 0x%08x %s%s\n",
5798 addrRegs[i],
5799 regTypeIsUninitReference(addrRegs[i]) ? "[U]" : "",
5800 clazz->descriptor);
5801 }
5802 }
5803 }
5804 }
5805 if (displayFlags & DRT_SHOW_LOCALS) {
5806 dexDecodeDebugInfo(meth->clazz->pDvmDex->pDexFile,
5807 dvmGetMethodCode(meth),
5808 meth->clazz->descriptor,
5809 meth->prototype.protoIdx,
5810 meth->accessFlags,
5811 NULL, logLocalsCb, &addr);
5812 }
5813}