blob: 30670ec8c552d495413f25f29f3cada6a3445134 [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/*
1005 * Verify the arguments to a method. We're executing in "method", making
1006 * a call to the method reference in vB.
1007 *
1008 * If this is a "direct" invoke, we allow calls to <init>. For calls to
1009 * <init>, the first argument may be an uninitialized reference. Otherwise,
1010 * calls to anything starting with '<' will be rejected, as will any
1011 * uninitialized reference arguments.
1012 *
1013 * For non-static method calls, this will verify that the method call is
1014 * appropriate for the "this" argument.
1015 *
1016 * The method reference is in vBBBB. The "isRange" parameter determines
1017 * whether we use 0-4 "args" values or a range of registers defined by
1018 * vAA and vCCCC.
1019 *
1020 * Widening conversions on integers and references are allowed, but
1021 * narrowing conversions are not.
1022 *
Andy McFadden62a75162009-04-17 17:23:37 -07001023 * Returns the resolved method on success, NULL on failure (with *pFailure
1024 * set appropriately).
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001025 */
1026static Method* verifyInvocationArgs(const Method* meth, const RegType* insnRegs,
1027 const int insnRegCount, const DecodedInstruction* pDecInsn,
1028 UninitInstanceMap* uninitMap, MethodType methodType, bool isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07001029 bool isSuper, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001030{
1031 Method* resMethod;
1032 char* sigOriginal = NULL;
1033
1034 /*
1035 * Resolve the method. This could be an abstract or concrete method
1036 * depending on what sort of call we're making.
1037 */
1038 if (methodType == METHOD_INTERFACE) {
1039 resMethod = dvmOptResolveInterfaceMethod(meth->clazz, pDecInsn->vB);
1040 } else {
Andy McFadden62a75162009-04-17 17:23:37 -07001041 resMethod = dvmOptResolveMethod(meth->clazz, pDecInsn->vB, methodType,
1042 pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001043 }
1044 if (resMethod == NULL) {
1045 /* failed; print a meaningful failure message */
1046 DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
1047 const DexMethodId* pMethodId;
1048 const char* methodName;
1049 char* methodDesc;
1050 const char* classDescriptor;
1051
1052 pMethodId = dexGetMethodId(pDexFile, pDecInsn->vB);
1053 methodName = dexStringById(pDexFile, pMethodId->nameIdx);
1054 methodDesc = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
1055 classDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
1056
1057 if (!gDvm.optimizing) {
1058 char* dotMissingClass = dvmDescriptorToDot(classDescriptor);
1059 char* dotMethClass = dvmDescriptorToDot(meth->clazz->descriptor);
1060 //char* curMethodDesc =
1061 // dexProtoCopyMethodDescriptor(&meth->prototype);
1062
Andy McFaddenb51ea112009-05-08 16:50:17 -07001063 LOGI("Could not find method %s.%s, referenced from "
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001064 "method %s.%s\n",
1065 dotMissingClass, methodName/*, methodDesc*/,
1066 dotMethClass, meth->name/*, curMethodDesc*/);
1067
1068 free(dotMissingClass);
1069 free(dotMethClass);
1070 //free(curMethodDesc);
1071 }
1072
1073 LOG_VFY("VFY: unable to resolve %s method %u: %s.%s %s\n",
1074 dvmMethodTypeStr(methodType), pDecInsn->vB,
1075 classDescriptor, methodName, methodDesc);
1076 free(methodDesc);
Andy McFaddenb51ea112009-05-08 16:50:17 -07001077 if (VERIFY_OK(*pFailure)) /* not set for interface resolve */
1078 *pFailure = VERIFY_ERROR_NO_METHOD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001079 goto fail;
1080 }
1081
1082 /*
1083 * Only time you can explicitly call a method starting with '<' is when
1084 * making a "direct" invocation on "<init>". There are additional
1085 * restrictions but we don't enforce them here.
1086 */
1087 if (resMethod->name[0] == '<') {
1088 if (methodType != METHOD_DIRECT || !isInitMethod(resMethod)) {
1089 LOG_VFY("VFY: invalid call to %s.%s\n",
1090 resMethod->clazz->descriptor, resMethod->name);
1091 goto bad_sig;
1092 }
1093 }
1094
1095 /*
1096 * If we're using invoke-super(method), make sure that the executing
1097 * method's class' superclass has a vtable entry for the target method.
1098 */
1099 if (isSuper) {
1100 assert(methodType == METHOD_VIRTUAL);
1101 ClassObject* super = meth->clazz->super;
1102 if (super == NULL || resMethod->methodIndex > super->vtableCount) {
1103 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1104 LOG_VFY("VFY: invalid invoke-super from %s.%s to super %s.%s %s\n",
1105 meth->clazz->descriptor, meth->name,
1106 (super == NULL) ? "-" : super->descriptor,
1107 resMethod->name, desc);
1108 free(desc);
Andy McFadden62a75162009-04-17 17:23:37 -07001109 *pFailure = VERIFY_ERROR_NO_METHOD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001110 goto fail;
1111 }
1112 }
1113
1114 /*
1115 * We use vAA as our expected arg count, rather than resMethod->insSize,
1116 * because we need to match the call to the signature. Also, we might
1117 * might be calling through an abstract method definition (which doesn't
1118 * have register count values).
1119 */
1120 sigOriginal = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1121 const char* sig = sigOriginal;
1122 int expectedArgs = pDecInsn->vA;
1123 int actualArgs = 0;
1124
1125 if (!isRange && expectedArgs > 5) {
1126 LOG_VFY("VFY: invalid arg count in non-range invoke (%d)\n",
1127 pDecInsn->vA);
1128 goto fail;
1129 }
1130 if (expectedArgs > meth->outsSize) {
1131 LOG_VFY("VFY: invalid arg count (%d) exceeds outsSize (%d)\n",
1132 expectedArgs, meth->outsSize);
1133 goto fail;
1134 }
1135
1136 if (*sig++ != '(')
1137 goto bad_sig;
1138
1139 /*
1140 * Check the "this" argument, which must be an instance of the class
1141 * that declared the method. For an interface class, we don't do the
1142 * full interface merge, so we can't do a rigorous check here (which
1143 * is okay since we have to do it at runtime).
1144 */
1145 if (!dvmIsStaticMethod(resMethod)) {
1146 ClassObject* actualThisRef;
1147 RegType actualArgType;
1148
1149 actualArgType = getInvocationThis(insnRegs, insnRegCount, pDecInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07001150 pFailure);
1151 if (!VERIFY_OK(*pFailure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001152 goto fail;
1153
1154 if (regTypeIsUninitReference(actualArgType) && resMethod->name[0] != '<')
1155 {
1156 LOG_VFY("VFY: 'this' arg must be initialized\n");
1157 goto fail;
1158 }
1159 if (methodType != METHOD_INTERFACE && actualArgType != kRegTypeZero) {
1160 actualThisRef = regTypeReferenceToClass(actualArgType, uninitMap);
1161 if (!dvmInstanceof(actualThisRef, resMethod->clazz)) {
1162 LOG_VFY("VFY: 'this' arg '%s' not instance of '%s'\n",
1163 actualThisRef->descriptor,
1164 resMethod->clazz->descriptor);
1165 goto fail;
1166 }
1167 }
1168 actualArgs++;
1169 }
1170
1171 /*
1172 * Process the target method's signature. This signature may or may not
1173 * have been verified, so we can't assume it's properly formed.
1174 */
1175 while (*sig != '\0' && *sig != ')') {
1176 if (actualArgs >= expectedArgs) {
1177 LOG_VFY("VFY: expected %d args, found more (%c)\n",
1178 expectedArgs, *sig);
1179 goto bad_sig;
1180 }
1181
1182 u4 getReg;
1183 if (isRange)
1184 getReg = pDecInsn->vC + actualArgs;
1185 else
1186 getReg = pDecInsn->arg[actualArgs];
1187
1188 switch (*sig) {
1189 case 'L':
1190 {
Andy McFadden62a75162009-04-17 17:23:37 -07001191 ClassObject* clazz = lookupSignatureClass(meth, &sig, pFailure);
1192 if (!VERIFY_OK(*pFailure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001193 goto bad_sig;
1194 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001195 regTypeFromClass(clazz), pFailure);
1196 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001197 LOG_VFY("VFY: bad arg %d (into %s)\n",
1198 actualArgs, clazz->descriptor);
1199 goto bad_sig;
1200 }
1201 }
1202 actualArgs++;
1203 break;
1204 case '[':
1205 {
1206 ClassObject* clazz =
Andy McFadden62a75162009-04-17 17:23:37 -07001207 lookupSignatureArrayClass(meth, &sig, pFailure);
1208 if (!VERIFY_OK(*pFailure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001209 goto bad_sig;
1210 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001211 regTypeFromClass(clazz), pFailure);
1212 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001213 LOG_VFY("VFY: bad arg %d (into %s)\n",
1214 actualArgs, clazz->descriptor);
1215 goto bad_sig;
1216 }
1217 }
1218 actualArgs++;
1219 break;
1220 case 'Z':
1221 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001222 kRegTypeBoolean, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001223 actualArgs++;
1224 break;
1225 case 'C':
1226 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001227 kRegTypeChar, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001228 actualArgs++;
1229 break;
1230 case 'B':
1231 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001232 kRegTypeByte, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001233 actualArgs++;
1234 break;
1235 case 'I':
1236 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001237 kRegTypeInteger, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001238 actualArgs++;
1239 break;
1240 case 'S':
1241 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001242 kRegTypeShort, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001243 actualArgs++;
1244 break;
1245 case 'F':
1246 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001247 kRegTypeFloat, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001248 actualArgs++;
1249 break;
1250 case 'D':
1251 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001252 kRegTypeDoubleLo, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001253 actualArgs += 2;
1254 break;
1255 case 'J':
1256 verifyRegisterType(insnRegs, insnRegCount, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001257 kRegTypeLongLo, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001258 actualArgs += 2;
1259 break;
1260 default:
1261 LOG_VFY("VFY: invocation target: bad signature type char '%c'\n",
1262 *sig);
1263 goto bad_sig;
1264 }
1265
1266 sig++;
1267 }
1268 if (*sig != ')') {
1269 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1270 LOG_VFY("VFY: invocation target: bad signature '%s'\n", desc);
1271 free(desc);
1272 goto bad_sig;
1273 }
1274
1275 if (actualArgs != expectedArgs) {
1276 LOG_VFY("VFY: expected %d args, found %d\n", expectedArgs, actualArgs);
1277 goto bad_sig;
1278 }
1279
1280 free(sigOriginal);
1281 return resMethod;
1282
1283bad_sig:
1284 if (resMethod != NULL) {
1285 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1286 LOG_VFY("VFY: rejecting call to %s.%s %s\n",
Andy McFadden62a75162009-04-17 17:23:37 -07001287 resMethod->clazz->descriptor, resMethod->name, desc);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001288 free(desc);
1289 }
1290
1291fail:
1292 free(sigOriginal);
Andy McFadden62a75162009-04-17 17:23:37 -07001293 if (*pFailure == VERIFY_ERROR_NONE)
1294 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001295 return NULL;
1296}
1297
1298/*
1299 * Get the class object for the type of data stored in a field. This isn't
1300 * stored in the Field struct, so we have to recover it from the signature.
1301 *
1302 * This only works for reference types. Don't call this for primitive types.
1303 *
1304 * If we can't find the class, we return java.lang.Object, so that
1305 * verification can continue if a field is only accessed in trivial ways.
1306 */
1307static ClassObject* getFieldClass(const Method* meth, const Field* field)
1308{
1309 ClassObject* fieldClass;
1310 const char* signature = field->signature;
1311
1312 if ((*signature == 'L') || (*signature == '[')) {
1313 fieldClass = dvmFindClassNoInit(signature,
1314 meth->clazz->classLoader);
1315 } else {
1316 return NULL;
1317 }
1318
1319 if (fieldClass == NULL) {
1320 dvmClearOptException(dvmThreadSelf());
1321 LOGV("VFY: unable to find class '%s' for field %s.%s, trying Object\n",
1322 field->signature, meth->clazz->descriptor, field->name);
1323 fieldClass = gDvm.classJavaLangObject;
1324 } else {
1325 assert(!dvmIsPrimitiveClass(fieldClass));
1326 }
1327 return fieldClass;
1328}
1329
1330
1331/*
1332 * ===========================================================================
1333 * Register operations
1334 * ===========================================================================
1335 */
1336
1337/*
1338 * Get the type of register N, verifying that the register is valid.
1339 *
Andy McFadden62a75162009-04-17 17:23:37 -07001340 * Sets "*pFailure" appropriately if the register number is out of range.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001341 */
1342static inline RegType getRegisterType(const RegType* insnRegs,
Andy McFadden62a75162009-04-17 17:23:37 -07001343 const int insnRegCount, u4 vsrc, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001344{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001345 if (vsrc >= (u4) insnRegCount) {
Andy McFadden62a75162009-04-17 17:23:37 -07001346 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001347 return kRegTypeUnknown;
1348 } else {
1349 return insnRegs[vsrc];
1350 }
1351}
1352
1353/*
1354 * Get the value from a register, and cast it to a ClassObject. Sets
Andy McFadden62a75162009-04-17 17:23:37 -07001355 * "*pFailure" if something fails.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001356 *
1357 * This fails if the register holds an uninitialized class.
1358 *
1359 * If the register holds kRegTypeZero, this returns a NULL pointer.
1360 */
1361static ClassObject* getClassFromRegister(const RegType* insnRegs,
Andy McFadden62a75162009-04-17 17:23:37 -07001362 const int insnRegCount, u4 vsrc, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001363{
1364 ClassObject* clazz = NULL;
1365 RegType type;
1366
1367 /* get the element type of the array held in vsrc */
Andy McFadden62a75162009-04-17 17:23:37 -07001368 type = getRegisterType(insnRegs, insnRegCount, vsrc, pFailure);
1369 if (!VERIFY_OK(*pFailure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001370 goto bail;
1371
1372 /* if "always zero", we allow it to fail at runtime */
1373 if (type == kRegTypeZero)
1374 goto bail;
1375
1376 if (!regTypeIsReference(type)) {
1377 LOG_VFY("VFY: tried to get class from non-ref register v%d (type=%d)\n",
1378 vsrc, type);
Andy McFadden62a75162009-04-17 17:23:37 -07001379 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001380 goto bail;
1381 }
1382 if (regTypeIsUninitReference(type)) {
1383 LOG_VFY("VFY: register %u holds uninitialized reference\n", vsrc);
Andy McFadden62a75162009-04-17 17:23:37 -07001384 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001385 goto bail;
1386 }
1387
1388 clazz = regTypeInitializedReferenceToClass(type);
1389
1390bail:
1391 return clazz;
1392}
1393
1394/*
1395 * Get the "this" pointer from a non-static method invocation. This
1396 * returns the RegType so the caller can decide whether it needs the
1397 * reference to be initialized or not. (Can also return kRegTypeZero
1398 * if the reference can only be zero at this point.)
1399 *
1400 * The argument count is in vA, and the first argument is in vC, for both
1401 * "simple" and "range" versions. We just need to make sure vA is >= 1
1402 * and then return vC.
1403 */
1404static RegType getInvocationThis(const RegType* insnRegs,
Andy McFadden62a75162009-04-17 17:23:37 -07001405 const int insnRegCount, const DecodedInstruction* pDecInsn,
1406 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001407{
1408 RegType thisType = kRegTypeUnknown;
1409
1410 if (pDecInsn->vA < 1) {
1411 LOG_VFY("VFY: invoke lacks 'this'\n");
Andy McFadden62a75162009-04-17 17:23:37 -07001412 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001413 goto bail;
1414 }
1415
1416 /* get the element type of the array held in vsrc */
Andy McFadden62a75162009-04-17 17:23:37 -07001417 thisType = getRegisterType(insnRegs, insnRegCount, pDecInsn->vC, pFailure);
1418 if (!VERIFY_OK(*pFailure)) {
1419 LOG_VFY("VFY: failed to get 'this' from register %u\n", pDecInsn->vC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001420 goto bail;
1421 }
1422
1423 if (!regTypeIsReference(thisType)) {
1424 LOG_VFY("VFY: tried to get class from non-ref register v%d (type=%d)\n",
1425 pDecInsn->vC, thisType);
Andy McFadden62a75162009-04-17 17:23:37 -07001426 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001427 goto bail;
1428 }
1429
1430bail:
1431 return thisType;
1432}
1433
1434/*
1435 * Set the type of register N, verifying that the register is valid. If
1436 * "newType" is the "Lo" part of a 64-bit value, register N+1 will be
1437 * set to "newType+1".
1438 *
Andy McFadden62a75162009-04-17 17:23:37 -07001439 * Sets "*pFailure" if the register number is out of range.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001440 */
1441static void setRegisterType(RegType* insnRegs, const int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001442 u4 vdst, RegType newType, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001443{
1444 //LOGD("set-reg v%u = %d\n", vdst, newType);
1445 switch (newType) {
1446 case kRegTypeUnknown:
1447 case kRegTypeBoolean:
1448 case kRegTypeOne:
1449 case kRegTypeByte:
1450 case kRegTypePosByte:
1451 case kRegTypeShort:
1452 case kRegTypePosShort:
1453 case kRegTypeChar:
1454 case kRegTypeInteger:
1455 case kRegTypeFloat:
1456 case kRegTypeZero:
1457 if (vdst >= (u4) insnRegCount) {
Andy McFadden62a75162009-04-17 17:23:37 -07001458 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001459 } else {
1460 insnRegs[vdst] = newType;
1461 }
1462 break;
1463 case kRegTypeLongLo:
1464 case kRegTypeDoubleLo:
1465 if (vdst+1 >= (u4) insnRegCount) {
Andy McFadden62a75162009-04-17 17:23:37 -07001466 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001467 } else {
1468 insnRegs[vdst] = newType;
1469 insnRegs[vdst+1] = newType+1;
1470 }
1471 break;
1472 case kRegTypeLongHi:
1473 case kRegTypeDoubleHi:
1474 /* should never set these explicitly */
Andy McFadden62a75162009-04-17 17:23:37 -07001475 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001476 break;
1477
1478 case kRegTypeUninit:
1479 default:
1480 if (regTypeIsReference(newType)) {
1481 if (vdst >= (u4) insnRegCount) {
Andy McFadden62a75162009-04-17 17:23:37 -07001482 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001483 break;
1484 }
1485 insnRegs[vdst] = newType;
1486
1487 /*
1488 * In most circumstances we won't see a reference to a primitive
1489 * class here (e.g. "D"), since that would mean the object in the
1490 * register is actually a primitive type. It can happen as the
1491 * result of an assumed-successful check-cast instruction in
1492 * which the second argument refers to a primitive class. (In
1493 * practice, such an instruction will always throw an exception.)
1494 *
1495 * This is not an issue for instructions like const-class, where
1496 * the object in the register is a java.lang.Class instance.
1497 */
1498 break;
1499 }
1500 /* bad - fall through */
1501
1502 case kRegTypeConflict: // should only be set during a merge
1503 LOG_VFY("Unexpected set type %d\n", newType);
1504 assert(false);
Andy McFadden62a75162009-04-17 17:23:37 -07001505 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001506 break;
1507 }
1508}
1509
1510/*
1511 * Verify that the contents of the specified register have the specified
1512 * type (or can be converted to it through an implicit widening conversion).
1513 *
1514 * In theory we could use this to modify the type of the source register,
1515 * e.g. a generic 32-bit constant, once used as a float, would thereafter
1516 * remain a float. There is no compelling reason to require this though.
1517 *
1518 * If "vsrc" is a reference, both it and the "vsrc" register must be
1519 * initialized ("vsrc" may be Zero). This will verify that the value in
1520 * the register is an instance of checkType, or if checkType is an
1521 * interface, verify that the register implements checkType.
1522 */
1523static void verifyRegisterType(const RegType* insnRegs, const int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001524 u4 vsrc, RegType checkType, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001525{
1526 if (vsrc >= (u4) insnRegCount) {
Andy McFadden62a75162009-04-17 17:23:37 -07001527 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001528 return;
1529 }
1530
1531 RegType srcType = insnRegs[vsrc];
1532
1533 //LOGD("check-reg v%u = %d\n", vsrc, checkType);
1534 switch (checkType) {
1535 case kRegTypeFloat:
1536 case kRegTypeBoolean:
1537 case kRegTypePosByte:
1538 case kRegTypeByte:
1539 case kRegTypePosShort:
1540 case kRegTypeShort:
1541 case kRegTypeChar:
1542 case kRegTypeInteger:
1543 if (!canConvertTo1nr(srcType, checkType)) {
1544 LOG_VFY("VFY: register1 v%u type %d, wanted %d\n",
1545 vsrc, srcType, checkType);
Andy McFadden62a75162009-04-17 17:23:37 -07001546 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001547 }
1548 break;
1549 case kRegTypeLongLo:
1550 case kRegTypeDoubleLo:
1551 if (vsrc+1 >= (u4) insnRegCount) {
1552 LOG_VFY("VFY: register2 v%u out of range (%d)\n",
1553 vsrc, insnRegCount);
Andy McFadden62a75162009-04-17 17:23:37 -07001554 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001555 } else if (insnRegs[vsrc+1] != srcType+1) {
1556 LOG_VFY("VFY: register2 v%u-%u values %d,%d\n",
1557 vsrc, vsrc+1, insnRegs[vsrc], insnRegs[vsrc+1]);
Andy McFadden62a75162009-04-17 17:23:37 -07001558 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001559 } else if (!canConvertTo2(srcType, checkType)) {
1560 LOG_VFY("VFY: register2 v%u type %d, wanted %d\n",
1561 vsrc, srcType, checkType);
Andy McFadden62a75162009-04-17 17:23:37 -07001562 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001563 }
1564 break;
1565
1566 case kRegTypeLongHi:
1567 case kRegTypeDoubleHi:
1568 case kRegTypeZero:
1569 case kRegTypeOne:
1570 case kRegTypeUnknown:
1571 case kRegTypeConflict:
1572 /* should never be checking for these explicitly */
1573 assert(false);
Andy McFadden62a75162009-04-17 17:23:37 -07001574 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001575 return;
1576 case kRegTypeUninit:
1577 default:
1578 /* make sure checkType is initialized reference */
1579 if (!regTypeIsReference(checkType)) {
1580 LOG_VFY("VFY: unexpected check type %d\n", checkType);
1581 assert(false);
Andy McFadden62a75162009-04-17 17:23:37 -07001582 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001583 break;
1584 }
1585 if (regTypeIsUninitReference(checkType)) {
1586 LOG_VFY("VFY: uninitialized ref not expected as reg check\n");
Andy McFadden62a75162009-04-17 17:23:37 -07001587 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001588 break;
1589 }
1590 /* make sure srcType is initialized reference or always-NULL */
1591 if (!regTypeIsReference(srcType)) {
1592 LOG_VFY("VFY: register1 v%u type %d, wanted ref\n", vsrc, srcType);
Andy McFadden62a75162009-04-17 17:23:37 -07001593 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001594 break;
1595 }
1596 if (regTypeIsUninitReference(srcType)) {
1597 LOG_VFY("VFY: register1 v%u holds uninitialized ref\n", vsrc);
Andy McFadden62a75162009-04-17 17:23:37 -07001598 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001599 break;
1600 }
1601 /* if the register isn't Zero, make sure it's an instance of check */
1602 if (srcType != kRegTypeZero) {
1603 ClassObject* srcClass = regTypeInitializedReferenceToClass(srcType);
1604 ClassObject* checkClass = regTypeInitializedReferenceToClass(checkType);
1605 assert(srcClass != NULL);
1606 assert(checkClass != NULL);
1607
1608 if (dvmIsInterfaceClass(checkClass)) {
1609 /*
1610 * All objects implement all interfaces as far as the
1611 * verifier is concerned. The runtime has to sort it out.
1612 * See comments above findCommonSuperclass.
1613 */
1614 /*
1615 if (srcClass != checkClass &&
1616 !dvmImplements(srcClass, checkClass))
1617 {
1618 LOG_VFY("VFY: %s does not implement %s\n",
1619 srcClass->descriptor, checkClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07001620 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001621 }
1622 */
1623 } else {
1624 if (!dvmInstanceof(srcClass, checkClass)) {
1625 LOG_VFY("VFY: %s is not instance of %s\n",
1626 srcClass->descriptor, checkClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07001627 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001628 }
1629 }
1630 }
1631 break;
1632 }
1633}
1634
1635/*
1636 * Set the type of the "result" register. Mostly this exists to expand
1637 * "insnRegCount" to encompass the result register.
1638 */
1639static void setResultRegisterType(RegType* insnRegs, const int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001640 RegType newType, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001641{
1642 setRegisterType(insnRegs, insnRegCount + kExtraRegs,
Andy McFadden62a75162009-04-17 17:23:37 -07001643 RESULT_REGISTER(insnRegCount), newType, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001644}
1645
1646
1647/*
1648 * Update all registers holding "uninitType" to instead hold the
1649 * corresponding initialized reference type. This is called when an
1650 * appropriate <init> method is invoked -- all copies of the reference
1651 * must be marked as initialized.
1652 */
1653static void markRefsAsInitialized(RegType* insnRegs, int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001654 UninitInstanceMap* uninitMap, RegType uninitType, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001655{
1656 ClassObject* clazz;
1657 RegType initType;
1658 int i, changed;
1659
1660 clazz = dvmGetUninitInstance(uninitMap, regTypeToUninitIndex(uninitType));
1661 if (clazz == NULL) {
1662 LOGE("VFY: unable to find type=0x%x (idx=%d)\n",
1663 uninitType, regTypeToUninitIndex(uninitType));
Andy McFadden62a75162009-04-17 17:23:37 -07001664 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001665 return;
1666 }
1667 initType = regTypeFromClass(clazz);
1668
1669 changed = 0;
1670 for (i = 0; i < insnRegCount; i++) {
1671 if (insnRegs[i] == uninitType) {
1672 insnRegs[i] = initType;
1673 changed++;
1674 }
1675 }
1676 //LOGD("VFY: marked %d registers as initialized\n", changed);
1677 assert(changed > 0);
1678
1679 return;
1680}
1681
1682/*
1683 * We're creating a new instance of class C at address A. Any registers
1684 * holding instances previously created at address A must be initialized
1685 * by now. If not, we mark them as "conflict" to prevent them from being
1686 * used (otherwise, markRefsAsInitialized would mark the old ones and the
1687 * new ones at the same time).
1688 */
1689static void markUninitRefsAsInvalid(RegType* insnRegs, int insnRegCount,
1690 UninitInstanceMap* uninitMap, RegType uninitType)
1691{
1692 int i, changed;
1693
1694 changed = 0;
1695 for (i = 0; i < insnRegCount; i++) {
1696 if (insnRegs[i] == uninitType) {
1697 insnRegs[i] = kRegTypeConflict;
1698 changed++;
1699 }
1700 }
1701
1702 //if (changed)
1703 // LOGD("VFY: marked %d uninitialized registers as invalid\n", changed);
1704}
1705
1706/*
1707 * Find the start of the register set for the specified instruction in
1708 * the current method.
1709 */
1710static inline RegType* getRegisterLine(const RegisterTable* regTable,
1711 int insnIdx)
1712{
1713 return regTable->addrRegs[insnIdx];
1714}
1715
1716/*
1717 * Copy a bunch of registers.
1718 */
1719static inline void copyRegisters(RegType* dst, const RegType* src,
1720 int numRegs)
1721{
1722 memcpy(dst, src, numRegs * sizeof(RegType));
1723}
1724
1725/*
1726 * Compare a bunch of registers.
1727 *
1728 * Returns 0 if they match. Using this for a sort is unwise, since the
1729 * value can change based on machine endianness.
1730 */
1731static inline int compareRegisters(const RegType* src1, const RegType* src2,
1732 int numRegs)
1733{
1734 return memcmp(src1, src2, numRegs * sizeof(RegType));
1735}
1736
1737/*
1738 * Register type categories, for type checking.
1739 *
1740 * The spec says category 1 includes boolean, byte, char, short, int, float,
1741 * reference, and returnAddress. Category 2 includes long and double.
1742 *
1743 * We treat object references separately, so we have "category1nr". We
1744 * don't support jsr/ret, so there is no "returnAddress" type.
1745 */
1746typedef enum TypeCategory {
1747 kTypeCategoryUnknown = 0,
1748 kTypeCategory1nr, // byte, char, int, float, boolean
1749 kTypeCategory2, // long, double
1750 kTypeCategoryRef, // object reference
1751} TypeCategory;
1752
1753/*
1754 * See if "type" matches "cat". All we're really looking for here is that
1755 * we're not mixing and matching 32-bit and 64-bit quantities, and we're
1756 * not mixing references with numerics. (For example, the arguments to
1757 * "a < b" could be integers of different sizes, but they must both be
1758 * integers. Dalvik is less specific about int vs. float, so we treat them
1759 * as equivalent here.)
1760 *
1761 * For category 2 values, "type" must be the "low" half of the value.
1762 *
Andy McFadden62a75162009-04-17 17:23:37 -07001763 * Sets "*pFailure" if something looks wrong.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001764 */
Andy McFadden62a75162009-04-17 17:23:37 -07001765static void checkTypeCategory(RegType type, TypeCategory cat,
1766 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001767{
1768 switch (cat) {
1769 case kTypeCategory1nr:
1770 switch (type) {
1771 case kRegTypeFloat:
1772 case kRegTypeZero:
1773 case kRegTypeOne:
1774 case kRegTypeBoolean:
1775 case kRegTypePosByte:
1776 case kRegTypeByte:
1777 case kRegTypePosShort:
1778 case kRegTypeShort:
1779 case kRegTypeChar:
1780 case kRegTypeInteger:
1781 break;
1782 default:
Andy McFadden62a75162009-04-17 17:23:37 -07001783 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001784 break;
1785 }
1786 break;
1787
1788 case kTypeCategory2:
1789 switch (type) {
1790 case kRegTypeLongLo:
1791 case kRegTypeDoubleLo:
1792 break;
1793 default:
Andy McFadden62a75162009-04-17 17:23:37 -07001794 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001795 break;
1796 }
1797 break;
1798
1799 case kTypeCategoryRef:
1800 if (type != kRegTypeZero && !regTypeIsReference(type))
Andy McFadden62a75162009-04-17 17:23:37 -07001801 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001802 break;
1803
1804 default:
1805 assert(false);
Andy McFadden62a75162009-04-17 17:23:37 -07001806 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001807 break;
1808 }
1809}
1810
1811/*
1812 * For a category 2 register pair, verify that "typeh" is the appropriate
1813 * high part for "typel".
1814 *
1815 * Does not verify that "typel" is in fact the low part of a 64-bit
1816 * register pair.
1817 */
Andy McFadden62a75162009-04-17 17:23:37 -07001818static void checkWidePair(RegType typel, RegType typeh, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001819{
1820 if ((typeh != typel+1))
Andy McFadden62a75162009-04-17 17:23:37 -07001821 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001822}
1823
1824/*
1825 * Implement category-1 "move" instructions. Copy a 32-bit value from
1826 * "vsrc" to "vdst".
1827 *
1828 * "insnRegCount" is the number of registers available. The "vdst" and
1829 * "vsrc" values are checked against this.
1830 */
1831static void copyRegister1(RegType* insnRegs, int insnRegCount, u4 vdst,
Andy McFadden62a75162009-04-17 17:23:37 -07001832 u4 vsrc, TypeCategory cat, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001833{
Andy McFadden62a75162009-04-17 17:23:37 -07001834 RegType type = getRegisterType(insnRegs, insnRegCount, vsrc, pFailure);
1835 if (VERIFY_OK(*pFailure))
1836 checkTypeCategory(type, cat, pFailure);
1837 if (VERIFY_OK(*pFailure))
1838 setRegisterType(insnRegs, insnRegCount, vdst, type, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001839
Andy McFadden62a75162009-04-17 17:23:37 -07001840 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001841 LOG_VFY("VFY: copy1 v%u<-v%u type=%d cat=%d\n", vdst, vsrc, type, cat);
1842 }
1843}
1844
1845/*
1846 * Implement category-2 "move" instructions. Copy a 64-bit value from
1847 * "vsrc" to "vdst". This copies both halves of the register.
1848 */
1849static void copyRegister2(RegType* insnRegs, int insnRegCount, u4 vdst,
Andy McFadden62a75162009-04-17 17:23:37 -07001850 u4 vsrc, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001851{
Andy McFadden62a75162009-04-17 17:23:37 -07001852 RegType typel = getRegisterType(insnRegs, insnRegCount, vsrc, pFailure);
1853 RegType typeh = getRegisterType(insnRegs, insnRegCount, vsrc+1, pFailure);
1854 if (VERIFY_OK(*pFailure)) {
1855 checkTypeCategory(typel, kTypeCategory2, pFailure);
1856 checkWidePair(typel, typeh, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001857 }
Andy McFadden62a75162009-04-17 17:23:37 -07001858 if (VERIFY_OK(*pFailure))
1859 setRegisterType(insnRegs, insnRegCount, vdst, typel, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001860
Andy McFadden62a75162009-04-17 17:23:37 -07001861 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001862 LOG_VFY("VFY: copy2 v%u<-v%u type=%d/%d\n", vdst, vsrc, typel, typeh);
1863 }
1864}
1865
1866/*
1867 * Implement "move-result". Copy the category-1 value from the result
1868 * register to another register, and reset the result register.
1869 *
1870 * We can't just call copyRegister1 with an altered insnRegCount,
1871 * because that would affect the test on "vdst" as well.
1872 */
1873static void copyResultRegister1(RegType* insnRegs, const int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001874 u4 vdst, TypeCategory cat, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001875{
1876 RegType type;
1877 u4 vsrc;
1878
1879 vsrc = RESULT_REGISTER(insnRegCount);
Andy McFadden62a75162009-04-17 17:23:37 -07001880 type = getRegisterType(insnRegs, insnRegCount + kExtraRegs, vsrc, pFailure);
1881 if (VERIFY_OK(*pFailure))
1882 checkTypeCategory(type, cat, pFailure);
1883 if (VERIFY_OK(*pFailure)) {
1884 setRegisterType(insnRegs, insnRegCount, vdst, type, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001885 insnRegs[vsrc] = kRegTypeUnknown;
1886 }
1887
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: copyRes1 v%u<-v%u cat=%d type=%d\n",
1890 vdst, vsrc, cat, type);
1891 }
1892}
1893
1894/*
1895 * Implement "move-result-wide". Copy the category-2 value from the result
1896 * register to another register, and reset the result register.
1897 *
1898 * We can't just call copyRegister2 with an altered insnRegCount,
1899 * because that would affect the test on "vdst" as well.
1900 */
1901static void copyResultRegister2(RegType* insnRegs, const int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001902 u4 vdst, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001903{
1904 RegType typel, typeh;
1905 u4 vsrc;
1906
1907 vsrc = RESULT_REGISTER(insnRegCount);
Andy McFadden62a75162009-04-17 17:23:37 -07001908 typel = getRegisterType(insnRegs, insnRegCount + kExtraRegs, vsrc,
1909 pFailure);
1910 typeh = getRegisterType(insnRegs, insnRegCount + kExtraRegs, vsrc+1,
1911 pFailure);
1912 if (VERIFY_OK(*pFailure)) {
1913 checkTypeCategory(typel, kTypeCategory2, pFailure);
1914 checkWidePair(typel, typeh, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001915 }
Andy McFadden62a75162009-04-17 17:23:37 -07001916 if (VERIFY_OK(*pFailure)) {
1917 setRegisterType(insnRegs, insnRegCount, vdst, typel, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001918 insnRegs[vsrc] = kRegTypeUnknown;
1919 insnRegs[vsrc+1] = kRegTypeUnknown;
1920 }
1921
Andy McFadden62a75162009-04-17 17:23:37 -07001922 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001923 LOG_VFY("VFY: copyRes2 v%u<-v%u type=%d/%d\n",
1924 vdst, vsrc, typel, typeh);
1925 }
1926}
1927
1928/*
1929 * Verify types for a simple two-register instruction (e.g. "neg-int").
1930 * "dstType" is stored into vA, and "srcType" is verified against vB.
1931 */
1932static void checkUnop(RegType* insnRegs, const int insnRegCount,
1933 DecodedInstruction* pDecInsn, RegType dstType, RegType srcType,
Andy McFadden62a75162009-04-17 17:23:37 -07001934 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001935{
Andy McFadden62a75162009-04-17 17:23:37 -07001936 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType, pFailure);
1937 setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001938}
1939
1940/*
1941 * We're performing an operation like "and-int/2addr" that can be
1942 * performed on booleans as well as integers. We get no indication of
1943 * boolean-ness, but we can infer it from the types of the arguments.
1944 *
1945 * Assumes we've already validated reg1/reg2.
1946 *
Andy McFaddenb5f64bc2009-06-10 14:11:07 -07001947 * TODO: consider generalizing this. The key principle is that the
1948 * result of a bitwise operation can only be as wide as the widest of
1949 * the operands. You can safely AND/OR/XOR two chars together and know
1950 * you still have a char, so it's reasonable for the compiler or "dx"
1951 * to skip the int-to-char instruction. (We need to do this for boolean
1952 * because there is no int-to-boolean operation.)
1953 *
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001954 * Returns true if both args are Boolean, Zero, or One.
1955 */
1956static bool upcastBooleanOp(RegType* insnRegs, const int insnRegCount,
1957 u4 reg1, u4 reg2)
1958{
1959 RegType type1, type2;
1960
1961 type1 = insnRegs[reg1];
1962 type2 = insnRegs[reg2];
1963
1964 if ((type1 == kRegTypeBoolean || type1 == kRegTypeZero ||
1965 type1 == kRegTypeOne) &&
1966 (type2 == kRegTypeBoolean || type2 == kRegTypeZero ||
1967 type2 == kRegTypeOne))
1968 {
1969 return true;
1970 }
1971 return false;
1972}
1973
1974/*
1975 * Verify types for A two-register instruction with a literal constant
1976 * (e.g. "add-int/lit8"). "dstType" is stored into vA, and "srcType" is
1977 * verified against vB.
1978 *
1979 * If "checkBooleanOp" is set, we use the constant value in vC.
1980 */
1981static void checkLitop(RegType* insnRegs, const int insnRegCount,
1982 DecodedInstruction* pDecInsn, RegType dstType, RegType srcType,
Andy McFadden62a75162009-04-17 17:23:37 -07001983 bool checkBooleanOp, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001984{
Andy McFadden62a75162009-04-17 17:23:37 -07001985 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType, pFailure);
1986 if (VERIFY_OK(*pFailure) && checkBooleanOp) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001987 assert(dstType == kRegTypeInteger);
1988 /* check vB with the call, then check the constant manually */
1989 if (upcastBooleanOp(insnRegs, insnRegCount, pDecInsn->vB, pDecInsn->vB)
1990 && (pDecInsn->vC == 0 || pDecInsn->vC == 1))
1991 {
1992 dstType = kRegTypeBoolean;
1993 }
1994 }
Andy McFadden62a75162009-04-17 17:23:37 -07001995 setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001996}
1997
1998/*
1999 * Verify types for a simple three-register instruction (e.g. "add-int").
2000 * "dstType" is stored into vA, and "srcType1"/"srcType2" are verified
2001 * against vB/vC.
2002 */
2003static void checkBinop(RegType* insnRegs, const int insnRegCount,
2004 DecodedInstruction* pDecInsn, RegType dstType, RegType srcType1,
Andy McFadden62a75162009-04-17 17:23:37 -07002005 RegType srcType2, bool checkBooleanOp, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002006{
Andy McFadden62a75162009-04-17 17:23:37 -07002007 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType1,
2008 pFailure);
2009 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vC, srcType2,
2010 pFailure);
2011 if (VERIFY_OK(*pFailure) && checkBooleanOp) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002012 assert(dstType == kRegTypeInteger);
2013 if (upcastBooleanOp(insnRegs, insnRegCount, pDecInsn->vB, pDecInsn->vC))
2014 dstType = kRegTypeBoolean;
2015 }
Andy McFadden62a75162009-04-17 17:23:37 -07002016 setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002017}
2018
2019/*
2020 * Verify types for a binary "2addr" operation. "srcType1"/"srcType2"
2021 * are verified against vA/vB, then "dstType" is stored into vA.
2022 */
2023static void checkBinop2addr(RegType* insnRegs, const int insnRegCount,
2024 DecodedInstruction* pDecInsn, RegType dstType, RegType srcType1,
Andy McFadden62a75162009-04-17 17:23:37 -07002025 RegType srcType2, bool checkBooleanOp, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002026{
Andy McFadden62a75162009-04-17 17:23:37 -07002027 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vA, srcType1,
2028 pFailure);
2029 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType2,
2030 pFailure);
2031 if (VERIFY_OK(*pFailure) && checkBooleanOp) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002032 assert(dstType == kRegTypeInteger);
2033 if (upcastBooleanOp(insnRegs, insnRegCount, pDecInsn->vA, pDecInsn->vB))
2034 dstType = kRegTypeBoolean;
2035 }
Andy McFadden62a75162009-04-17 17:23:37 -07002036 setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002037}
2038
Andy McFadden80d25ea2009-06-12 07:26:17 -07002039/*
2040 * Treat right-shifting as a narrowing conversion when possible.
2041 *
2042 * For example, right-shifting an int 24 times results in a value that can
2043 * be treated as a byte.
2044 *
2045 * Things get interesting when contemplating sign extension. Right-
2046 * shifting an integer by 16 yields a value that can be represented in a
2047 * "short" but not a "char", but an unsigned right shift by 16 yields a
2048 * value that belongs in a char rather than a short. (Consider what would
2049 * happen if the result of the shift were cast to a char or short and then
2050 * cast back to an int. If sign extension, or the lack thereof, causes
2051 * a change in the 32-bit representation, then the conversion was lossy.)
2052 *
2053 * A signed right shift by 17 on an integer results in a short. An unsigned
2054 * right shfit by 17 on an integer results in a posshort, which can be
2055 * assigned to a short or a char.
2056 *
2057 * An unsigned right shift on a short can actually expand the result into
2058 * a 32-bit integer. For example, 0xfffff123 >>> 8 becomes 0x00fffff1,
2059 * which can't be represented in anything smaller than an int.
2060 *
2061 * javac does not generate code that takes advantage of this, but some
2062 * of the code optimizers do. It's generally a peephole optimization
2063 * that replaces a particular sequence, e.g. (bipush 24, ishr, i2b) is
2064 * replaced by (bipush 24, ishr). Knowing that shifting a short 8 times
2065 * to the right yields a byte is really more than we need to handle the
2066 * code that's out there, but support is not much more complex than just
2067 * handling integer.
2068 *
2069 * Right-shifting never yields a boolean value.
2070 *
2071 * Returns the new register type.
2072 */
2073static RegType adjustForRightShift(RegType* workRegs, const int insnRegCount,
2074 int reg, unsigned int shiftCount, bool isUnsignedShift,
2075 VerifyError* pFailure)
2076{
2077 RegType srcType = getRegisterType(workRegs, insnRegCount, reg, pFailure);
2078 RegType newType;
2079
2080 /* no-op */
2081 if (shiftCount == 0)
2082 return srcType;
2083
2084 /* safe defaults */
2085 if (isUnsignedShift)
2086 newType = kRegTypeInteger;
2087 else
2088 newType = srcType;
2089
2090 if (shiftCount >= 32) {
2091 LOG_VFY("Got unexpectedly large shift count %u\n", shiftCount);
2092 /* fail? */
2093 return newType;
2094 }
2095
2096 switch (srcType) {
2097 case kRegTypeInteger: /* 32-bit signed value */
2098 case kRegTypeFloat: /* (allowed; treat same as int) */
2099 if (isUnsignedShift) {
2100 if (shiftCount > 24)
2101 newType = kRegTypePosByte;
2102 else if (shiftCount >= 16)
2103 newType = kRegTypeChar;
2104 } else {
2105 if (shiftCount >= 24)
2106 newType = kRegTypeByte;
2107 else if (shiftCount >= 16)
2108 newType = kRegTypeShort;
2109 }
2110 break;
2111 case kRegTypeShort: /* 16-bit signed value */
2112 if (isUnsignedShift) {
2113 /* default (kRegTypeInteger) is correct */
2114 } else {
2115 if (shiftCount >= 8)
2116 newType = kRegTypeByte;
2117 }
2118 break;
2119 case kRegTypePosShort: /* 15-bit unsigned value */
2120 if (shiftCount >= 8)
2121 newType = kRegTypePosByte;
2122 break;
2123 case kRegTypeChar: /* 16-bit unsigned value */
2124 if (shiftCount > 8)
2125 newType = kRegTypePosByte;
2126 break;
2127 case kRegTypeByte: /* 8-bit signed value */
2128 /* defaults (u=kRegTypeInteger / s=srcType) are correct */
2129 break;
2130 case kRegTypePosByte: /* 7-bit unsigned value */
2131 /* always use newType=srcType */
2132 newType = srcType;
2133 break;
2134 case kRegTypeZero: /* 1-bit unsigned value */
2135 case kRegTypeOne:
2136 case kRegTypeBoolean:
2137 /* unnecessary? */
2138 newType = kRegTypeZero;
2139 break;
2140 default:
2141 /* long, double, references; shouldn't be here! */
2142 assert(false);
2143 break;
2144 }
2145
2146 if (newType != srcType) {
2147 LOGVV("narrowing: %d(%d) --> %d to %d\n",
2148 shiftCount, isUnsignedShift, srcType, newType);
2149 } else {
2150 LOGVV("not narrowed: %d(%d) --> %d\n",
2151 shiftCount, isUnsignedShift, srcType);
2152 }
2153 return newType;
2154}
2155
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002156
2157/*
2158 * ===========================================================================
2159 * Register merge
2160 * ===========================================================================
2161 */
2162
2163/*
2164 * Compute the "class depth" of a class. This is the distance from the
2165 * class to the top of the tree, chasing superclass links. java.lang.Object
2166 * has a class depth of 0.
2167 */
2168static int getClassDepth(ClassObject* clazz)
2169{
2170 int depth = 0;
2171
2172 while (clazz->super != NULL) {
2173 clazz = clazz->super;
2174 depth++;
2175 }
2176 return depth;
2177}
2178
2179/*
2180 * Given two classes, walk up the superclass tree to find a common
2181 * ancestor. (Called from findCommonSuperclass().)
2182 *
2183 * TODO: consider caching the class depth in the class object so we don't
2184 * have to search for it here.
2185 */
2186static ClassObject* digForSuperclass(ClassObject* c1, ClassObject* c2)
2187{
2188 int depth1, depth2;
2189
2190 depth1 = getClassDepth(c1);
2191 depth2 = getClassDepth(c2);
2192
2193 if (gDebugVerbose) {
2194 LOGVV("COMMON: %s(%d) + %s(%d)\n",
2195 c1->descriptor, depth1, c2->descriptor, depth2);
2196 }
2197
2198 /* pull the deepest one up */
2199 if (depth1 > depth2) {
2200 while (depth1 > depth2) {
2201 c1 = c1->super;
2202 depth1--;
2203 }
2204 } else {
2205 while (depth2 > depth1) {
2206 c2 = c2->super;
2207 depth2--;
2208 }
2209 }
2210
2211 /* walk up in lock-step */
2212 while (c1 != c2) {
2213 c1 = c1->super;
2214 c2 = c2->super;
2215
2216 assert(c1 != NULL && c2 != NULL);
2217 }
2218
2219 if (gDebugVerbose) {
2220 LOGVV(" : --> %s\n", c1->descriptor);
2221 }
2222 return c1;
2223}
2224
2225/*
2226 * Merge two array classes. We can't use the general "walk up to the
2227 * superclass" merge because the superclass of an array is always Object.
2228 * We want String[] + Integer[] = Object[]. This works for higher dimensions
2229 * as well, e.g. String[][] + Integer[][] = Object[][].
2230 *
2231 * If Foo1 and Foo2 are subclasses of Foo, Foo1[] + Foo2[] = Foo[].
2232 *
2233 * If Class implements Type, Class[] + Type[] = Type[].
2234 *
2235 * If the dimensions don't match, we want to convert to an array of Object
2236 * with the least dimension, e.g. String[][] + String[][][][] = Object[][].
2237 *
2238 * This gets a little awkward because we may have to ask the VM to create
2239 * a new array type with the appropriate element and dimensions. However, we
2240 * shouldn't be doing this often.
2241 */
2242static ClassObject* findCommonArraySuperclass(ClassObject* c1, ClassObject* c2)
2243{
2244 ClassObject* arrayClass = NULL;
2245 ClassObject* commonElem;
2246 int i, numDims;
2247
2248 assert(c1->arrayDim > 0);
2249 assert(c2->arrayDim > 0);
2250
2251 if (c1->arrayDim == c2->arrayDim) {
2252 //commonElem = digForSuperclass(c1->elementClass, c2->elementClass);
2253 commonElem = findCommonSuperclass(c1->elementClass, c2->elementClass);
2254 numDims = c1->arrayDim;
2255 } else {
2256 if (c1->arrayDim < c2->arrayDim)
2257 numDims = c1->arrayDim;
2258 else
2259 numDims = c2->arrayDim;
2260 commonElem = c1->super; // == java.lang.Object
2261 }
2262
2263 /* walk from the element to the (multi-)dimensioned array type */
2264 for (i = 0; i < numDims; i++) {
2265 arrayClass = dvmFindArrayClassForElement(commonElem);
2266 commonElem = arrayClass;
2267 }
2268
2269 LOGVV("ArrayMerge '%s' + '%s' --> '%s'\n",
2270 c1->descriptor, c2->descriptor, arrayClass->descriptor);
2271 return arrayClass;
2272}
2273
2274/*
2275 * Find the first common superclass of the two classes. We're not
2276 * interested in common interfaces.
2277 *
2278 * The easiest way to do this for concrete classes is to compute the "class
2279 * depth" of each, move up toward the root of the deepest one until they're
2280 * at the same depth, then walk both up to the root until they match.
2281 *
2282 * If both classes are arrays of non-primitive types, we need to merge
2283 * based on array depth and element type.
2284 *
2285 * If one class is an interface, we check to see if the other class/interface
2286 * (or one of its predecessors) implements the interface. If so, we return
2287 * the interface; otherwise, we return Object.
2288 *
2289 * NOTE: we continue the tradition of "lazy interface handling". To wit,
2290 * suppose we have three classes:
2291 * One implements Fancy, Free
2292 * Two implements Fancy, Free
2293 * Three implements Free
2294 * where Fancy and Free are unrelated interfaces. The code requires us
2295 * to merge One into Two. Ideally we'd use a common interface, which
2296 * gives us a choice between Fancy and Free, and no guidance on which to
2297 * use. If we use Free, we'll be okay when Three gets merged in, but if
2298 * we choose Fancy, we're hosed. The "ideal" solution is to create a
2299 * set of common interfaces and carry that around, merging further references
2300 * into it. This is a pain. The easy solution is to simply boil them
2301 * down to Objects and let the runtime invokeinterface call fail, which
2302 * is what we do.
2303 */
2304static ClassObject* findCommonSuperclass(ClassObject* c1, ClassObject* c2)
2305{
2306 assert(!dvmIsPrimitiveClass(c1) && !dvmIsPrimitiveClass(c2));
2307
2308 if (c1 == c2)
2309 return c1;
2310
2311 if (dvmIsInterfaceClass(c1) && dvmImplements(c2, c1)) {
2312 if (gDebugVerbose)
2313 LOGVV("COMMON/I1: %s + %s --> %s\n",
2314 c1->descriptor, c2->descriptor, c1->descriptor);
2315 return c1;
2316 }
2317 if (dvmIsInterfaceClass(c2) && dvmImplements(c1, c2)) {
2318 if (gDebugVerbose)
2319 LOGVV("COMMON/I2: %s + %s --> %s\n",
2320 c1->descriptor, c2->descriptor, c2->descriptor);
2321 return c2;
2322 }
2323
2324 if (dvmIsArrayClass(c1) && dvmIsArrayClass(c2) &&
2325 !dvmIsPrimitiveClass(c1->elementClass) &&
2326 !dvmIsPrimitiveClass(c2->elementClass))
2327 {
2328 return findCommonArraySuperclass(c1, c2);
2329 }
2330
2331 return digForSuperclass(c1, c2);
2332}
2333
2334/*
2335 * Merge two RegType values.
2336 *
2337 * Sets "*pChanged" to "true" if the result doesn't match "type1".
2338 */
2339static RegType mergeTypes(RegType type1, RegType type2, bool* pChanged)
2340{
2341 RegType result;
2342
2343 /*
2344 * Check for trivial case so we don't have to hit memory.
2345 */
2346 if (type1 == type2)
2347 return type1;
2348
2349 /*
2350 * Use the table if we can, and reject any attempts to merge something
2351 * from the table with a reference type.
2352 *
2353 * The uninitialized table entry at index zero *will* show up as a
2354 * simple kRegTypeUninit value. Since this cannot be merged with
2355 * anything but itself, the rules do the right thing.
2356 */
2357 if (type1 < kRegTypeMAX) {
2358 if (type2 < kRegTypeMAX) {
2359 result = gDvmMergeTab[type1][type2];
2360 } else {
2361 /* simple + reference == conflict, usually */
2362 if (type1 == kRegTypeZero)
2363 result = type2;
2364 else
2365 result = kRegTypeConflict;
2366 }
2367 } else {
2368 if (type2 < kRegTypeMAX) {
2369 /* reference + simple == conflict, usually */
2370 if (type2 == kRegTypeZero)
2371 result = type1;
2372 else
2373 result = kRegTypeConflict;
2374 } else {
2375 /* merging two references */
2376 if (regTypeIsUninitReference(type1) ||
2377 regTypeIsUninitReference(type2))
2378 {
2379 /* can't merge uninit with anything but self */
2380 result = kRegTypeConflict;
2381 } else {
2382 ClassObject* clazz1 = regTypeInitializedReferenceToClass(type1);
2383 ClassObject* clazz2 = regTypeInitializedReferenceToClass(type2);
2384 ClassObject* mergedClass;
2385
2386 mergedClass = findCommonSuperclass(clazz1, clazz2);
2387 assert(mergedClass != NULL);
2388 result = regTypeFromClass(mergedClass);
2389 }
2390 }
2391 }
2392
2393 if (result != type1)
2394 *pChanged = true;
2395 return result;
2396}
2397
2398/*
2399 * Control can transfer to "nextInsn".
2400 *
2401 * Merge the registers from "workRegs" into "regTypes" at "nextInsn", and
2402 * set the "changed" flag on the target address if the registers have changed.
2403 */
2404static void updateRegisters(const Method* meth, InsnFlags* insnFlags,
2405 RegisterTable* regTable, int nextInsn, const RegType* workRegs)
2406{
2407 RegType* targetRegs = getRegisterLine(regTable, nextInsn);
2408 const int insnRegCount = meth->registersSize;
2409
2410#if 0
2411 if (!dvmInsnIsBranchTarget(insnFlags, nextInsn)) {
2412 LOGE("insnFlags[0x%x]=0x%08x\n", nextInsn, insnFlags[nextInsn]);
2413 LOGE(" In %s.%s %s\n",
2414 meth->clazz->descriptor, meth->name, meth->descriptor);
2415 assert(false);
2416 }
2417#endif
2418
2419 if (!dvmInsnIsVisitedOrChanged(insnFlags, nextInsn)) {
2420 /*
2421 * We haven't processed this instruction before, and we haven't
2422 * touched the registers here, so there's nothing to "merge". Copy
2423 * the registers over and mark it as changed. (This is the only
2424 * way a register can transition out of "unknown", so this is not
2425 * just an optimization.)
2426 */
2427 LOGVV("COPY into 0x%04x\n", nextInsn);
2428 copyRegisters(targetRegs, workRegs, insnRegCount + kExtraRegs);
2429 dvmInsnSetChanged(insnFlags, nextInsn, true);
2430 } else {
2431 if (gDebugVerbose) {
2432 LOGVV("MERGE into 0x%04x\n", nextInsn);
2433 //dumpRegTypes(meth, insnFlags, targetRegs, 0, "targ", NULL, 0);
2434 //dumpRegTypes(meth, insnFlags, workRegs, 0, "work", NULL, 0);
2435 }
2436 /* merge registers, set Changed only if different */
2437 bool changed = false;
2438 int i;
2439
2440 for (i = 0; i < insnRegCount + kExtraRegs; i++) {
2441 targetRegs[i] = mergeTypes(targetRegs[i], workRegs[i], &changed);
2442 }
2443
2444 if (gDebugVerbose) {
2445 //LOGI(" RESULT (changed=%d)\n", changed);
2446 //dumpRegTypes(meth, insnFlags, targetRegs, 0, "rslt", NULL, 0);
2447 }
2448
2449 if (changed)
2450 dvmInsnSetChanged(insnFlags, nextInsn, true);
2451 }
2452}
2453
2454
2455/*
2456 * ===========================================================================
2457 * Utility functions
2458 * ===========================================================================
2459 */
2460
2461/*
2462 * Look up an instance field, specified by "fieldIdx", that is going to be
2463 * accessed in object "objType". This resolves the field and then verifies
2464 * that the class containing the field is an instance of the reference in
2465 * "objType".
2466 *
2467 * It is possible for "objType" to be kRegTypeZero, meaning that we might
2468 * have a null reference. This is a runtime problem, so we allow it,
2469 * skipping some of the type checks.
2470 *
2471 * In general, "objType" must be an initialized reference. However, we
2472 * allow it to be uninitialized if this is an "<init>" method and the field
2473 * is declared within the "objType" class.
2474 *
Andy McFadden62a75162009-04-17 17:23:37 -07002475 * Returns an InstField on success, returns NULL and sets "*pFailure"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002476 * on failure.
2477 */
2478static InstField* getInstField(const Method* meth,
2479 const UninitInstanceMap* uninitMap, RegType objType, int fieldIdx,
Andy McFadden62a75162009-04-17 17:23:37 -07002480 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002481{
2482 InstField* instField = NULL;
2483 ClassObject* objClass;
2484 bool mustBeLocal = false;
2485
2486 if (!regTypeIsReference(objType)) {
Andy McFadden62a75162009-04-17 17:23:37 -07002487 LOG_VFY("VFY: attempt to access field in non-reference type %d\n",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002488 objType);
Andy McFadden62a75162009-04-17 17:23:37 -07002489 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002490 goto bail;
2491 }
2492
Andy McFadden62a75162009-04-17 17:23:37 -07002493 instField = dvmOptResolveInstField(meth->clazz, fieldIdx, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002494 if (instField == NULL) {
2495 LOG_VFY("VFY: unable to resolve instance field %u\n", fieldIdx);
Andy McFadden62a75162009-04-17 17:23:37 -07002496 assert(!VERIFY_OK(*pFailure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002497 goto bail;
2498 }
2499
2500 if (objType == kRegTypeZero)
2501 goto bail;
2502
2503 /*
2504 * Access to fields in uninitialized objects is allowed if this is
2505 * the <init> method for the object and the field in question is
2506 * declared by this class.
2507 */
2508 objClass = regTypeReferenceToClass(objType, uninitMap);
2509 assert(objClass != NULL);
2510 if (regTypeIsUninitReference(objType)) {
2511 if (!isInitMethod(meth) || meth->clazz != objClass) {
2512 LOG_VFY("VFY: attempt to access field via uninitialized ref\n");
Andy McFadden62a75162009-04-17 17:23:37 -07002513 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002514 goto bail;
2515 }
2516 mustBeLocal = true;
2517 }
2518
2519 if (!dvmInstanceof(objClass, instField->field.clazz)) {
2520 LOG_VFY("VFY: invalid field access (field %s.%s, through %s ref)\n",
2521 instField->field.clazz->descriptor, instField->field.name,
2522 objClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07002523 *pFailure = VERIFY_ERROR_NO_FIELD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002524 goto bail;
2525 }
2526
2527 if (mustBeLocal) {
2528 /* for uninit ref, make sure it's defined by this class, not super */
2529 if (instField < objClass->ifields ||
2530 instField >= objClass->ifields + objClass->ifieldCount)
2531 {
2532 LOG_VFY("VFY: invalid constructor field access (field %s in %s)\n",
2533 instField->field.name, objClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07002534 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002535 goto bail;
2536 }
2537 }
2538
2539bail:
2540 return instField;
2541}
2542
2543/*
2544 * Look up a static field.
2545 *
Andy McFadden62a75162009-04-17 17:23:37 -07002546 * Returns a StaticField on success, returns NULL and sets "*pFailure"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002547 * on failure.
2548 */
2549static StaticField* getStaticField(const Method* meth, int fieldIdx,
Andy McFadden62a75162009-04-17 17:23:37 -07002550 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002551{
2552 StaticField* staticField;
2553
Andy McFadden62a75162009-04-17 17:23:37 -07002554 staticField = dvmOptResolveStaticField(meth->clazz, fieldIdx, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002555 if (staticField == NULL) {
2556 DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
2557 const DexFieldId* pFieldId;
2558
2559 pFieldId = dexGetFieldId(pDexFile, fieldIdx);
2560
2561 LOG_VFY("VFY: unable to resolve static field %u (%s) in %s\n", fieldIdx,
2562 dexStringById(pDexFile, pFieldId->nameIdx),
2563 dexStringByTypeIdx(pDexFile, pFieldId->classIdx));
Andy McFadden62a75162009-04-17 17:23:37 -07002564 assert(!VERIFY_OK(*pFailure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002565 goto bail;
2566 }
2567
2568bail:
2569 return staticField;
2570}
2571
2572/*
2573 * If "field" is marked "final", make sure this is the either <clinit>
2574 * or <init> as appropriate.
2575 *
Andy McFadden62a75162009-04-17 17:23:37 -07002576 * Sets "*pFailure" on failure.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002577 */
2578static void checkFinalFieldAccess(const Method* meth, const Field* field,
Andy McFadden62a75162009-04-17 17:23:37 -07002579 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002580{
2581 if (!dvmIsFinalField(field))
2582 return;
2583
2584 /* make sure we're in the same class */
2585 if (meth->clazz != field->clazz) {
2586 LOG_VFY_METH(meth, "VFY: can't modify final field %s.%s\n",
2587 field->clazz->descriptor, field->name);
Andy McFaddenb51ea112009-05-08 16:50:17 -07002588 *pFailure = VERIFY_ERROR_ACCESS_FIELD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002589 return;
2590 }
2591
2592 /*
Andy McFadden62a75162009-04-17 17:23:37 -07002593 * The VM spec descriptions of putfield and putstatic say that
2594 * IllegalAccessError is only thrown when the instructions appear
2595 * outside the declaring class. Our earlier attempts to restrict
2596 * final field modification to constructors are, therefore, wrong.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002597 */
2598#if 0
2599 /* make sure we're in the right kind of constructor */
2600 if (dvmIsStaticField(field)) {
2601 if (!isClassInitMethod(meth)) {
2602 LOG_VFY_METH(meth,
2603 "VFY: can't modify final static field outside <clinit>\n");
Andy McFadden62a75162009-04-17 17:23:37 -07002604 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002605 }
2606 } else {
2607 if (!isInitMethod(meth)) {
2608 LOG_VFY_METH(meth,
2609 "VFY: can't modify final field outside <init>\n");
Andy McFadden62a75162009-04-17 17:23:37 -07002610 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002611 }
2612 }
2613#endif
2614}
2615
2616/*
2617 * Make sure that the register type is suitable for use as an array index.
2618 *
Andy McFadden62a75162009-04-17 17:23:37 -07002619 * Sets "*pFailure" if not.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002620 */
2621static void checkArrayIndexType(const Method* meth, RegType regType,
Andy McFadden62a75162009-04-17 17:23:37 -07002622 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002623{
Andy McFadden62a75162009-04-17 17:23:37 -07002624 if (VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002625 /*
2626 * The 1nr types are interchangeable at this level. We could
2627 * do something special if we can definitively identify it as a
2628 * float, but there's no real value in doing so.
2629 */
Andy McFadden62a75162009-04-17 17:23:37 -07002630 checkTypeCategory(regType, kTypeCategory1nr, pFailure);
2631 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002632 LOG_VFY_METH(meth, "Invalid reg type for array index (%d)\n",
2633 regType);
2634 }
2635 }
2636}
2637
2638/*
2639 * Check constraints on constructor return. Specifically, make sure that
2640 * the "this" argument got initialized.
2641 *
2642 * The "this" argument to <init> uses code offset kUninitThisArgAddr, which
2643 * puts it at the start of the list in slot 0. If we see a register with
2644 * an uninitialized slot 0 reference, we know it somehow didn't get
2645 * initialized.
2646 *
2647 * Returns "true" if all is well.
2648 */
2649static bool checkConstructorReturn(const Method* meth, const RegType* insnRegs,
2650 const int insnRegCount)
2651{
2652 int i;
2653
2654 if (!isInitMethod(meth))
2655 return true;
2656
2657 RegType uninitThis = regTypeFromUninitIndex(kUninitThisArgSlot);
2658
2659 for (i = 0; i < insnRegCount; i++) {
2660 if (insnRegs[i] == uninitThis) {
2661 LOG_VFY("VFY: <init> returning without calling superclass init\n");
2662 return false;
2663 }
2664 }
2665 return true;
2666}
2667
2668/*
2669 * Verify that the target instruction is not "move-exception". It's important
2670 * that the only way to execute a move-exception is as the first instruction
2671 * of an exception handler.
2672 *
2673 * Returns "true" if all is well, "false" if the target instruction is
2674 * move-exception.
2675 */
2676static bool checkMoveException(const Method* meth, int insnIdx,
2677 const char* logNote)
2678{
2679 assert(insnIdx >= 0 && insnIdx < (int)dvmGetMethodInsnsSize(meth));
2680
2681 if ((meth->insns[insnIdx] & 0xff) == OP_MOVE_EXCEPTION) {
2682 LOG_VFY("VFY: invalid use of move-exception\n");
2683 return false;
2684 }
2685 return true;
2686}
2687
2688/*
2689 * For the "move-exception" instruction at "insnIdx", which must be at an
2690 * exception handler address, determine the first common superclass of
2691 * all exceptions that can land here. (For javac output, we're probably
2692 * looking at multiple spans of bytecode covered by one "try" that lands
2693 * at an exception-specific "catch", but in general the handler could be
2694 * shared for multiple exceptions.)
2695 *
2696 * Returns NULL if no matching exception handler can be found, or if the
2697 * exception is not a subclass of Throwable.
2698 */
Andy McFadden62a75162009-04-17 17:23:37 -07002699static ClassObject* getCaughtExceptionType(const Method* meth, int insnIdx,
2700 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002701{
Andy McFadden62a75162009-04-17 17:23:37 -07002702 VerifyError localFailure;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002703 const DexCode* pCode;
2704 DexFile* pDexFile;
2705 ClassObject* commonSuper = NULL;
Andy McFadden62a75162009-04-17 17:23:37 -07002706 bool foundPossibleHandler = false;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002707 u4 handlersSize;
2708 u4 offset;
2709 u4 i;
2710
2711 pDexFile = meth->clazz->pDvmDex->pDexFile;
2712 pCode = dvmGetMethodCode(meth);
2713
2714 if (pCode->triesSize != 0) {
2715 handlersSize = dexGetHandlersSize(pCode);
2716 offset = dexGetFirstHandlerOffset(pCode);
2717 } else {
2718 handlersSize = 0;
2719 offset = 0;
2720 }
2721
2722 for (i = 0; i < handlersSize; i++) {
2723 DexCatchIterator iterator;
2724 dexCatchIteratorInit(&iterator, pCode, offset);
2725
2726 for (;;) {
2727 const DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
2728
2729 if (handler == NULL) {
2730 break;
2731 }
2732
2733 if (handler->address == (u4) insnIdx) {
2734 ClassObject* clazz;
Andy McFadden62a75162009-04-17 17:23:37 -07002735 foundPossibleHandler = true;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002736
2737 if (handler->typeIdx == kDexNoIndex)
2738 clazz = gDvm.classJavaLangThrowable;
2739 else
Andy McFadden62a75162009-04-17 17:23:37 -07002740 clazz = dvmOptResolveClass(meth->clazz, handler->typeIdx,
2741 &localFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002742
2743 if (clazz == NULL) {
2744 LOG_VFY("VFY: unable to resolve exception class %u (%s)\n",
2745 handler->typeIdx,
2746 dexStringByTypeIdx(pDexFile, handler->typeIdx));
Andy McFadden62a75162009-04-17 17:23:37 -07002747 /* TODO: do we want to keep going? If we don't fail
2748 * this we run the risk of having a non-Throwable
2749 * introduced at runtime. However, that won't pass
2750 * an instanceof test, so is essentially harmless. */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002751 } else {
2752 if (commonSuper == NULL)
2753 commonSuper = clazz;
2754 else
2755 commonSuper = findCommonSuperclass(clazz, commonSuper);
2756 }
2757 }
2758 }
2759
2760 offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
2761 }
2762
2763 if (commonSuper == NULL) {
Andy McFadden62a75162009-04-17 17:23:37 -07002764 /* no catch blocks, or no catches with classes we can find */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002765 LOG_VFY_METH(meth,
2766 "VFY: unable to find exception handler at addr 0x%x\n", insnIdx);
Andy McFadden62a75162009-04-17 17:23:37 -07002767 *pFailure = VERIFY_ERROR_GENERIC;
2768 } else {
2769 // TODO: verify the class is an instance of Throwable?
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002770 }
2771
2772 return commonSuper;
2773}
2774
2775/*
2776 * Initialize the RegisterTable.
2777 *
2778 * Every instruction address can have a different set of information about
2779 * what's in which register, but for verification purposes we only need to
2780 * store it at branch target addresses (because we merge into that).
2781 *
2782 * By zeroing out the storage we are effectively initializing the register
2783 * information to kRegTypeUnknown.
2784 */
2785static bool initRegisterTable(const Method* meth, const InsnFlags* insnFlags,
2786 RegisterTable* regTable, RegisterTrackingMode trackRegsFor)
2787{
2788 const int insnsSize = dvmGetMethodInsnsSize(meth);
2789 int i;
2790
2791 regTable->insnRegCountPlus = meth->registersSize + kExtraRegs;
2792 regTable->addrRegs = (RegType**) calloc(insnsSize, sizeof(RegType*));
2793 if (regTable->addrRegs == NULL)
2794 return false;
2795
2796 assert(insnsSize > 0);
2797
2798 /*
2799 * "All" means "every address that holds the start of an instruction".
2800 * "Branches" and "GcPoints" mean just those addresses.
2801 *
2802 * "GcPoints" fills about half the addresses, "Branches" about 15%.
2803 */
2804 int interestingCount = 0;
2805 //int insnCount = 0;
2806
2807 for (i = 0; i < insnsSize; i++) {
2808 bool interesting;
2809
2810 switch (trackRegsFor) {
2811 case kTrackRegsAll:
2812 interesting = dvmInsnIsOpcode(insnFlags, i);
2813 break;
2814 case kTrackRegsGcPoints:
2815 interesting = dvmInsnIsGcPoint(insnFlags, i) ||
2816 dvmInsnIsBranchTarget(insnFlags, i);
2817 break;
2818 case kTrackRegsBranches:
2819 interesting = dvmInsnIsBranchTarget(insnFlags, i);
2820 break;
2821 default:
2822 dvmAbort();
2823 return false;
2824 }
2825
2826 if (interesting)
2827 interestingCount++;
2828
2829 /* count instructions, for display only */
2830 //if (dvmInsnIsOpcode(insnFlags, i))
2831 // insnCount++;
2832 }
2833
2834 regTable->regAlloc = (RegType*)
2835 calloc(regTable->insnRegCountPlus * interestingCount, sizeof(RegType));
2836 if (regTable->regAlloc == NULL)
2837 return false;
2838
2839 RegType* regPtr = regTable->regAlloc;
2840 for (i = 0; i < insnsSize; i++) {
2841 bool interesting;
2842
2843 switch (trackRegsFor) {
2844 case kTrackRegsAll:
2845 interesting = dvmInsnIsOpcode(insnFlags, i);
2846 break;
2847 case kTrackRegsGcPoints:
2848 interesting = dvmInsnIsGcPoint(insnFlags, i) ||
2849 dvmInsnIsBranchTarget(insnFlags, i);
2850 break;
2851 case kTrackRegsBranches:
2852 interesting = dvmInsnIsBranchTarget(insnFlags, i);
2853 break;
2854 default:
2855 dvmAbort();
2856 return false;
2857 }
2858
2859 if (interesting) {
2860 regTable->addrRegs[i] = regPtr;
2861 regPtr += regTable->insnRegCountPlus;
2862 }
2863 }
2864
2865 //LOGD("Tracking registers for %d, total %d of %d(%d) (%d%%)\n",
2866 // TRACK_REGS_FOR, interestingCount, insnCount, insnsSize,
2867 // (interestingCount*100) / insnCount);
2868
2869 assert(regPtr - regTable->regAlloc ==
2870 regTable->insnRegCountPlus * interestingCount);
2871 assert(regTable->addrRegs[0] != NULL);
2872 return true;
2873}
2874
2875
2876/*
2877 * Verify that the arguments in a filled-new-array instruction are valid.
2878 *
2879 * "resClass" is the class refered to by pDecInsn->vB.
2880 */
2881static void verifyFilledNewArrayRegs(const Method* meth,
2882 const RegType* insnRegs, const int insnRegCount,
2883 const DecodedInstruction* pDecInsn, ClassObject* resClass, bool isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07002884 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002885{
2886 u4 argCount = pDecInsn->vA;
2887 RegType expectedType;
2888 PrimitiveType elemType;
2889 unsigned int ui;
2890
2891 assert(dvmIsArrayClass(resClass));
2892 elemType = resClass->elementClass->primitiveType;
2893 if (elemType == PRIM_NOT) {
2894 expectedType = regTypeFromClass(resClass->elementClass);
2895 } else {
2896 expectedType = primitiveTypeToRegType(elemType);
2897 }
2898 //LOGI("filled-new-array: %s -> %d\n", resClass->descriptor, expectedType);
2899
2900 /*
2901 * Verify each register. If "argCount" is bad, verifyRegisterType()
2902 * will run off the end of the list and fail. It's legal, if silly,
2903 * for argCount to be zero.
2904 */
2905 for (ui = 0; ui < argCount; ui++) {
2906 u4 getReg;
2907
2908 if (isRange)
2909 getReg = pDecInsn->vC + ui;
2910 else
2911 getReg = pDecInsn->arg[ui];
2912
Andy McFadden62a75162009-04-17 17:23:37 -07002913 verifyRegisterType(insnRegs, insnRegCount, getReg, expectedType,
2914 pFailure);
2915 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002916 LOG_VFY("VFY: filled-new-array arg %u(%u) not valid\n", ui, getReg);
2917 return;
2918 }
2919 }
2920}
2921
2922
2923/*
Andy McFaddenb51ea112009-05-08 16:50:17 -07002924 * Replace an instruction with "throw-verification-error". This allows us to
2925 * defer error reporting until the code path is first used.
2926 *
Andy McFadden861b3382010-03-05 15:58:31 -08002927 * This is expected to be called during "just in time" verification, not
2928 * from within dexopt. (Verification failures in dexopt will result in
2929 * postponement of verification to first use of the class.)
2930 *
Andy McFaddenb51ea112009-05-08 16:50:17 -07002931 * The throw-verification-error instruction requires two code units. Some
2932 * of the replaced instructions require three; the third code unit will
2933 * receive a "nop". The instruction's length will be left unchanged
2934 * in "insnFlags".
2935 *
Andy McFadden96516932009-10-28 17:39:02 -07002936 * The verifier explicitly locks out breakpoint activity, so there should
2937 * be no clashes with the debugger.
2938 *
Andy McFaddenb51ea112009-05-08 16:50:17 -07002939 * Returns "true" on success.
2940 */
Andy McFadden228a6b02010-05-04 15:02:32 -07002941static bool replaceFailingInstruction(const Method* meth, InsnFlags* insnFlags,
Andy McFaddenb51ea112009-05-08 16:50:17 -07002942 int insnIdx, VerifyError failure)
2943{
Andy McFaddenaf0e8382009-08-28 10:38:37 -07002944 VerifyErrorRefType refType;
Andy McFaddenb51ea112009-05-08 16:50:17 -07002945 const u2* oldInsns = meth->insns + insnIdx;
2946 u2 oldInsn = *oldInsns;
2947 bool result = false;
2948
Andy McFaddenb51ea112009-05-08 16:50:17 -07002949 //LOGD(" was 0x%04x\n", oldInsn);
2950 u2* newInsns = (u2*) meth->insns + insnIdx;
2951
2952 /*
2953 * Generate the new instruction out of the old.
2954 *
2955 * First, make sure this is an instruction we're expecting to stomp on.
2956 */
2957 switch (oldInsn & 0xff) {
2958 case OP_CONST_CLASS: // insn[1] == class ref, 2 bytes
2959 case OP_CHECK_CAST:
2960 case OP_INSTANCE_OF:
2961 case OP_NEW_INSTANCE:
2962 case OP_NEW_ARRAY:
Andy McFaddenb51ea112009-05-08 16:50:17 -07002963 case OP_FILLED_NEW_ARRAY: // insn[1] == class ref, 3 bytes
2964 case OP_FILLED_NEW_ARRAY_RANGE:
Andy McFaddenaf0e8382009-08-28 10:38:37 -07002965 refType = VERIFY_ERROR_REF_CLASS;
2966 break;
Andy McFaddenb51ea112009-05-08 16:50:17 -07002967
2968 case OP_IGET: // insn[1] == field ref, 2 bytes
2969 case OP_IGET_BOOLEAN:
2970 case OP_IGET_BYTE:
2971 case OP_IGET_CHAR:
2972 case OP_IGET_SHORT:
2973 case OP_IGET_WIDE:
2974 case OP_IGET_OBJECT:
2975 case OP_IPUT:
2976 case OP_IPUT_BOOLEAN:
2977 case OP_IPUT_BYTE:
2978 case OP_IPUT_CHAR:
2979 case OP_IPUT_SHORT:
2980 case OP_IPUT_WIDE:
2981 case OP_IPUT_OBJECT:
2982 case OP_SGET:
2983 case OP_SGET_BOOLEAN:
2984 case OP_SGET_BYTE:
2985 case OP_SGET_CHAR:
2986 case OP_SGET_SHORT:
2987 case OP_SGET_WIDE:
2988 case OP_SGET_OBJECT:
2989 case OP_SPUT:
2990 case OP_SPUT_BOOLEAN:
2991 case OP_SPUT_BYTE:
2992 case OP_SPUT_CHAR:
2993 case OP_SPUT_SHORT:
2994 case OP_SPUT_WIDE:
2995 case OP_SPUT_OBJECT:
Andy McFaddenaf0e8382009-08-28 10:38:37 -07002996 refType = VERIFY_ERROR_REF_FIELD;
2997 break;
Andy McFaddenb51ea112009-05-08 16:50:17 -07002998
2999 case OP_INVOKE_VIRTUAL: // insn[1] == method ref, 3 bytes
3000 case OP_INVOKE_VIRTUAL_RANGE:
3001 case OP_INVOKE_SUPER:
3002 case OP_INVOKE_SUPER_RANGE:
3003 case OP_INVOKE_DIRECT:
3004 case OP_INVOKE_DIRECT_RANGE:
3005 case OP_INVOKE_STATIC:
3006 case OP_INVOKE_STATIC_RANGE:
3007 case OP_INVOKE_INTERFACE:
3008 case OP_INVOKE_INTERFACE_RANGE:
Andy McFaddenaf0e8382009-08-28 10:38:37 -07003009 refType = VERIFY_ERROR_REF_METHOD;
Andy McFaddenb51ea112009-05-08 16:50:17 -07003010 break;
Andy McFaddenaf0e8382009-08-28 10:38:37 -07003011
Andy McFaddenb51ea112009-05-08 16:50:17 -07003012 default:
3013 /* could handle this in a generic way, but this is probably safer */
3014 LOG_VFY("GLITCH: verifier asked to replace opcode 0x%02x\n",
3015 oldInsn & 0xff);
3016 goto bail;
3017 }
3018
3019 /* write a NOP over the third code unit, if necessary */
3020 int width = dvmInsnGetWidth(insnFlags, insnIdx);
3021 switch (width) {
3022 case 2:
3023 /* nothing to do */
3024 break;
3025 case 3:
Andy McFadden96516932009-10-28 17:39:02 -07003026 dvmDexChangeDex2(meth->clazz->pDvmDex, newInsns+2, OP_NOP);
3027 //newInsns[2] = OP_NOP;
Andy McFaddenb51ea112009-05-08 16:50:17 -07003028 break;
3029 default:
3030 /* whoops */
3031 LOGE("ERROR: stomped a %d-unit instruction with a verifier error\n",
3032 width);
3033 dvmAbort();
3034 }
3035
3036 /* encode the opcode, with the failure code in the high byte */
Andy McFadden96516932009-10-28 17:39:02 -07003037 u2 newVal = OP_THROW_VERIFICATION_ERROR |
Andy McFaddenaf0e8382009-08-28 10:38:37 -07003038 (failure << 8) | (refType << (8 + kVerifyErrorRefTypeShift));
Andy McFadden96516932009-10-28 17:39:02 -07003039 //newInsns[0] = newVal;
3040 dvmDexChangeDex2(meth->clazz->pDvmDex, newInsns, newVal);
Andy McFaddenb51ea112009-05-08 16:50:17 -07003041
3042 result = true;
3043
3044bail:
Andy McFaddenb51ea112009-05-08 16:50:17 -07003045 return result;
3046}
3047
Andy McFadden861b3382010-03-05 15:58:31 -08003048/*
3049 * Replace {iget,iput,sget,sput}-wide with the -wide-volatile form.
3050 *
3051 * If this is called during dexopt, we can modify the instruction in
3052 * place. If this happens during just-in-time verification, we need to
3053 * use the DEX read/write page feature.
3054 *
3055 * NOTE:
3056 * This shouldn't really be tied to verification. It ought to be a
3057 * separate pass that is run before or after the verifier. However, that
3058 * requires a bunch of extra code, and the only advantage of doing so is
3059 * that the feature isn't disabled when verification is turned off. At
3060 * some point we may need to revisit this choice.
3061 */
Andy McFadden228a6b02010-05-04 15:02:32 -07003062static void replaceVolatileInstruction(const Method* meth, InsnFlags* insnFlags,
Andy McFadden861b3382010-03-05 15:58:31 -08003063 int insnIdx)
3064{
3065 u2* oldInsns = (u2*)meth->insns + insnIdx;
3066 u2 oldInsn = *oldInsns;
3067 u2 newVal;
3068
3069 switch (oldInsn & 0xff) {
3070 case OP_IGET_WIDE: newVal = OP_IGET_WIDE_VOLATILE; break;
3071 case OP_IPUT_WIDE: newVal = OP_IPUT_WIDE_VOLATILE; break;
3072 case OP_SGET_WIDE: newVal = OP_SGET_WIDE_VOLATILE; break;
3073 case OP_SPUT_WIDE: newVal = OP_SPUT_WIDE_VOLATILE; break;
3074 default:
3075 LOGE("wide-volatile op mismatch (0x%x)\n", oldInsn);
3076 dvmAbort();
3077 return; // in-lieu-of noreturn attribute
3078 }
3079
3080 /* merge new opcode into 16-bit code unit */
3081 newVal |= (oldInsn & 0xff00);
3082
3083 if (gDvm.optimizing) {
3084 /* dexopt time, alter the output */
3085 *oldInsns = newVal;
3086 } else {
3087 /* runtime, make the page read/write */
3088 dvmDexChangeDex2(meth->clazz->pDvmDex, oldInsns, newVal);
3089 }
3090}
3091
Andy McFaddenb51ea112009-05-08 16:50:17 -07003092
3093/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003094 * ===========================================================================
3095 * Entry point and driver loop
3096 * ===========================================================================
3097 */
3098
3099/*
3100 * Entry point for the detailed code-flow analysis.
3101 */
Andy McFadden228a6b02010-05-04 15:02:32 -07003102bool dvmVerifyCodeFlow(VerifierData* vdata)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003103{
3104 bool result = false;
Andy McFadden228a6b02010-05-04 15:02:32 -07003105 const Method* meth = vdata->method;
3106 const int insnsSize = vdata->insnsSize;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003107 const bool generateRegisterMap = gDvm.generateRegisterMaps;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003108 RegisterTable regTable;
3109
3110 memset(&regTable, 0, sizeof(regTable));
3111
3112#ifndef NDEBUG
3113 checkMergeTab(); // only need to do this if table gets updated
3114#endif
3115
3116 /*
3117 * We rely on these for verification of const-class, const-string,
3118 * and throw instructions. Make sure we have them.
3119 */
3120 if (gDvm.classJavaLangClass == NULL)
3121 gDvm.classJavaLangClass =
3122 dvmFindSystemClassNoInit("Ljava/lang/Class;");
3123 if (gDvm.classJavaLangString == NULL)
3124 gDvm.classJavaLangString =
3125 dvmFindSystemClassNoInit("Ljava/lang/String;");
Andy McFadden686e1e22009-05-26 16:56:30 -07003126 if (gDvm.classJavaLangThrowable == NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003127 gDvm.classJavaLangThrowable =
3128 dvmFindSystemClassNoInit("Ljava/lang/Throwable;");
Andy McFadden686e1e22009-05-26 16:56:30 -07003129 gDvm.offJavaLangThrowable_cause =
3130 dvmFindFieldOffset(gDvm.classJavaLangThrowable,
3131 "cause", "Ljava/lang/Throwable;");
3132 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003133 if (gDvm.classJavaLangObject == NULL)
3134 gDvm.classJavaLangObject =
3135 dvmFindSystemClassNoInit("Ljava/lang/Object;");
3136
Andy McFadden6be954f2010-06-14 13:37:49 -07003137 if (meth->registersSize * insnsSize > 4*1024*1024) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003138 /* should probably base this on actual memory requirements */
3139 LOG_VFY_METH(meth,
3140 "VFY: arbitrarily rejecting large method (regs=%d count=%d)\n",
3141 meth->registersSize, insnsSize);
3142 goto bail;
3143 }
3144
3145 /*
3146 * Create register lists, and initialize them to "Unknown". If we're
3147 * also going to create the register map, we need to retain the
3148 * register lists for a larger set of addresses.
3149 */
Andy McFadden228a6b02010-05-04 15:02:32 -07003150 if (!initRegisterTable(meth, vdata->insnFlags, &regTable,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003151 generateRegisterMap ? kTrackRegsGcPoints : kTrackRegsBranches))
3152 goto bail;
3153
Andy McFadden228a6b02010-05-04 15:02:32 -07003154 vdata->addrRegs = NULL; /* don't set this until we need it */
3155
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003156 /*
3157 * Initialize the types of the registers that correspond to the
3158 * method arguments. We can determine this from the method signature.
3159 */
Andy McFadden228a6b02010-05-04 15:02:32 -07003160 if (!setTypesFromSignature(meth, regTable.addrRegs[0], vdata->uninitMap))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003161 goto bail;
3162
3163 /*
3164 * Run the verifier.
3165 */
Andy McFadden228a6b02010-05-04 15:02:32 -07003166 if (!doCodeVerification(meth, vdata->insnFlags, &regTable, vdata->uninitMap))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003167 goto bail;
3168
3169 /*
3170 * Generate a register map.
3171 */
3172 if (generateRegisterMap) {
Andy McFadden228a6b02010-05-04 15:02:32 -07003173 vdata->addrRegs = regTable.addrRegs;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003174
Andy McFadden228a6b02010-05-04 15:02:32 -07003175 RegisterMap* pMap = dvmGenerateRegisterMapV(vdata);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003176 if (pMap != NULL) {
3177 /*
3178 * Tuck it into the Method struct. It will either get used
3179 * directly or, if we're in dexopt, will be packed up and
3180 * appended to the DEX file.
3181 */
3182 dvmSetRegisterMap((Method*)meth, pMap);
3183 }
3184 }
3185
3186 /*
3187 * Success.
3188 */
3189 result = true;
3190
3191bail:
3192 free(regTable.addrRegs);
3193 free(regTable.regAlloc);
3194 return result;
3195}
3196
3197/*
3198 * Grind through the instructions.
3199 *
3200 * The basic strategy is as outlined in v3 4.11.1.2: set the "changed" bit
3201 * on the first instruction, process it (setting additional "changed" bits),
3202 * and repeat until there are no more.
3203 *
3204 * v3 4.11.1.1
3205 * - (N/A) operand stack is always the same size
3206 * - operand stack [registers] contain the correct types of values
3207 * - local variables [registers] contain the correct types of values
3208 * - methods are invoked with the appropriate arguments
3209 * - fields are assigned using values of appropriate types
3210 * - opcodes have the correct type values in operand registers
3211 * - there is never an uninitialized class instance in a local variable in
3212 * code protected by an exception handler (operand stack is okay, because
3213 * the operand stack is discarded when an exception is thrown) [can't
3214 * know what's a local var w/o the debug info -- should fall out of
3215 * register typing]
3216 *
3217 * v3 4.11.1.2
3218 * - execution cannot fall off the end of the code
3219 *
3220 * (We also do many of the items described in the "static checks" sections,
3221 * because it's easier to do them here.)
3222 *
3223 * We need an array of RegType values, one per register, for every
3224 * instruction. In theory this could become quite large -- up to several
3225 * megabytes for a monster function. For self-preservation we reject
3226 * anything that requires more than a certain amount of memory. (Typical
3227 * "large" should be on the order of 4K code units * 8 registers.) This
3228 * will likely have to be adjusted.
3229 *
3230 *
3231 * The spec forbids backward branches when there's an uninitialized reference
3232 * in a register. The idea is to prevent something like this:
3233 * loop:
3234 * move r1, r0
3235 * new-instance r0, MyClass
3236 * ...
3237 * if-eq rN, loop // once
3238 * initialize r0
3239 *
3240 * This leaves us with two different instances, both allocated by the
3241 * same instruction, but only one is initialized. The scheme outlined in
3242 * v3 4.11.1.4 wouldn't catch this, so they work around it by preventing
3243 * backward branches. We achieve identical results without restricting
3244 * code reordering by specifying that you can't execute the new-instance
3245 * instruction if a register contains an uninitialized instance created
3246 * by that same instrutcion.
3247 */
Andy McFadden228a6b02010-05-04 15:02:32 -07003248static bool doCodeVerification(const Method* meth, InsnFlags* insnFlags,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003249 RegisterTable* regTable, UninitInstanceMap* uninitMap)
3250{
3251 const int insnsSize = dvmGetMethodInsnsSize(meth);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003252 RegType workRegs[meth->registersSize + kExtraRegs];
3253 bool result = false;
3254 bool debugVerbose = false;
Carl Shapiroe3c01da2010-05-20 22:54:18 -07003255 int insnIdx, startGuess;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003256
3257 /*
3258 * Begin by marking the first instruction as "changed".
3259 */
3260 dvmInsnSetChanged(insnFlags, 0, true);
3261
3262 if (doVerboseLogging(meth)) {
3263 IF_LOGI() {
3264 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
3265 LOGI("Now verifying: %s.%s %s (ins=%d regs=%d)\n",
3266 meth->clazz->descriptor, meth->name, desc,
3267 meth->insSize, meth->registersSize);
3268 LOGI(" ------ [0 4 8 12 16 20 24 28 32 36\n");
3269 free(desc);
3270 }
3271 debugVerbose = true;
3272 gDebugVerbose = true;
3273 } else {
3274 gDebugVerbose = false;
3275 }
3276
3277 startGuess = 0;
3278
3279 /*
3280 * Continue until no instructions are marked "changed".
3281 */
3282 while (true) {
3283 /*
3284 * Find the first marked one. Use "startGuess" as a way to find
3285 * one quickly.
3286 */
3287 for (insnIdx = startGuess; insnIdx < insnsSize; insnIdx++) {
3288 if (dvmInsnIsChanged(insnFlags, insnIdx))
3289 break;
3290 }
3291
3292 if (insnIdx == insnsSize) {
3293 if (startGuess != 0) {
3294 /* try again, starting from the top */
3295 startGuess = 0;
3296 continue;
3297 } else {
3298 /* all flags are clear */
3299 break;
3300 }
3301 }
3302
3303 /*
3304 * We carry the working set of registers from instruction to
3305 * instruction. If this address can be the target of a branch
3306 * (or throw) instruction, or if we're skipping around chasing
3307 * "changed" flags, we need to load the set of registers from
3308 * the table.
3309 *
3310 * Because we always prefer to continue on to the next instruction,
3311 * we should never have a situation where we have a stray
3312 * "changed" flag set on an instruction that isn't a branch target.
3313 */
3314 if (dvmInsnIsBranchTarget(insnFlags, insnIdx)) {
3315 RegType* insnRegs = getRegisterLine(regTable, insnIdx);
3316 assert(insnRegs != NULL);
3317 copyRegisters(workRegs, insnRegs, meth->registersSize + kExtraRegs);
3318
3319 if (debugVerbose) {
3320 dumpRegTypes(meth, insnFlags, workRegs, insnIdx, NULL,uninitMap,
3321 SHOW_REG_DETAILS);
3322 }
3323
3324 } else {
3325 if (debugVerbose) {
3326 dumpRegTypes(meth, insnFlags, workRegs, insnIdx, NULL,uninitMap,
3327 SHOW_REG_DETAILS);
3328 }
3329
3330#ifndef NDEBUG
3331 /*
3332 * Sanity check: retrieve the stored register line (assuming
3333 * a full table) and make sure it actually matches.
3334 */
3335 RegType* insnRegs = getRegisterLine(regTable, insnIdx);
3336 if (insnRegs != NULL &&
3337 compareRegisters(workRegs, insnRegs,
3338 meth->registersSize + kExtraRegs) != 0)
3339 {
3340 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
3341 LOG_VFY("HUH? workRegs diverged in %s.%s %s\n",
3342 meth->clazz->descriptor, meth->name, desc);
3343 free(desc);
3344 dumpRegTypes(meth, insnFlags, workRegs, 0, "work",
3345 uninitMap, DRT_SHOW_REF_TYPES | DRT_SHOW_LOCALS);
3346 dumpRegTypes(meth, insnFlags, insnRegs, 0, "insn",
3347 uninitMap, DRT_SHOW_REF_TYPES | DRT_SHOW_LOCALS);
3348 }
3349#endif
3350 }
3351
3352 //LOGI("process %s.%s %s %d\n",
3353 // meth->clazz->descriptor, meth->name, meth->descriptor, insnIdx);
3354 if (!verifyInstruction(meth, insnFlags, regTable, workRegs, insnIdx,
3355 uninitMap, &startGuess))
3356 {
3357 //LOGD("+++ %s bailing at %d\n", meth->name, insnIdx);
3358 goto bail;
3359 }
3360
3361#if 0
3362 {
3363 static const int gcMask = kInstrCanBranch | kInstrCanSwitch |
3364 kInstrCanThrow | kInstrCanReturn;
3365 OpCode opCode = *(meth->insns + insnIdx) & 0xff;
3366 int flags = dexGetInstrFlags(gDvm.instrFlags, opCode);
3367
3368 /* 8, 16, 32, or 32*n -bit regs */
3369 int regWidth = (meth->registersSize + 7) / 8;
3370 if (regWidth == 3)
3371 regWidth = 4;
3372 if (regWidth > 4) {
3373 regWidth = ((regWidth + 3) / 4) * 4;
3374 if (false) {
3375 LOGW("WOW: %d regs -> %d %s.%s\n",
3376 meth->registersSize, regWidth,
3377 meth->clazz->descriptor, meth->name);
3378 //x = true;
3379 }
3380 }
3381
3382 if ((flags & gcMask) != 0) {
3383 /* this is a potential GC point */
3384 gDvm__gcInstr++;
3385
3386 if (insnsSize < 256)
3387 gDvm__gcData += 1;
3388 else
3389 gDvm__gcData += 2;
3390 gDvm__gcData += regWidth;
3391 }
3392 gDvm__gcSimpleData += regWidth;
3393
3394 gDvm__totalInstr++;
3395 }
3396#endif
3397
3398 /*
3399 * Clear "changed" and mark as visited.
3400 */
3401 dvmInsnSetVisited(insnFlags, insnIdx, true);
3402 dvmInsnSetChanged(insnFlags, insnIdx, false);
3403 }
3404
Andy McFaddenb51ea112009-05-08 16:50:17 -07003405 if (DEAD_CODE_SCAN && !IS_METHOD_FLAG_SET(meth, METHOD_ISWRITABLE)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003406 /*
Andy McFaddenb51ea112009-05-08 16:50:17 -07003407 * Scan for dead code. There's nothing "evil" about dead code
3408 * (besides the wasted space), but it indicates a flaw somewhere
3409 * down the line, possibly in the verifier.
3410 *
3411 * If we've rewritten "always throw" instructions into the stream,
3412 * we are almost certainly going to have some dead code.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003413 */
3414 int deadStart = -1;
3415 for (insnIdx = 0; insnIdx < insnsSize;
3416 insnIdx += dvmInsnGetWidth(insnFlags, insnIdx))
3417 {
3418 /*
3419 * Switch-statement data doesn't get "visited" by scanner. It
3420 * may or may not be preceded by a padding NOP.
3421 */
3422 int instr = meth->insns[insnIdx];
3423 if (instr == kPackedSwitchSignature ||
3424 instr == kSparseSwitchSignature ||
3425 instr == kArrayDataSignature ||
3426 (instr == OP_NOP &&
3427 (meth->insns[insnIdx+1] == kPackedSwitchSignature ||
3428 meth->insns[insnIdx+1] == kSparseSwitchSignature ||
3429 meth->insns[insnIdx+1] == kArrayDataSignature)))
3430 {
3431 dvmInsnSetVisited(insnFlags, insnIdx, true);
3432 }
3433
3434 if (!dvmInsnIsVisited(insnFlags, insnIdx)) {
3435 if (deadStart < 0)
3436 deadStart = insnIdx;
3437 } else if (deadStart >= 0) {
3438 IF_LOGD() {
3439 char* desc =
3440 dexProtoCopyMethodDescriptor(&meth->prototype);
3441 LOGD("VFY: dead code 0x%04x-%04x in %s.%s %s\n",
3442 deadStart, insnIdx-1,
3443 meth->clazz->descriptor, meth->name, desc);
3444 free(desc);
3445 }
3446
3447 deadStart = -1;
3448 }
3449 }
3450 if (deadStart >= 0) {
3451 IF_LOGD() {
3452 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
3453 LOGD("VFY: dead code 0x%04x-%04x in %s.%s %s\n",
3454 deadStart, insnIdx-1,
3455 meth->clazz->descriptor, meth->name, desc);
3456 free(desc);
3457 }
3458 }
3459 }
3460
3461 result = true;
3462
3463bail:
3464 return result;
3465}
3466
3467
3468/*
3469 * Perform verification for a single instruction.
3470 *
3471 * This requires fully decoding the instruction to determine the effect
3472 * it has on registers.
3473 *
3474 * Finds zero or more following instructions and sets the "changed" flag
3475 * if execution at that point needs to be (re-)evaluated. Register changes
3476 * are merged into "regTypes" at the target addresses. Does not set or
3477 * clear any other flags in "insnFlags".
Andy McFaddenb51ea112009-05-08 16:50:17 -07003478 *
3479 * This may alter meth->insns if we need to replace an instruction with
3480 * throw-verification-error.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003481 */
Andy McFadden228a6b02010-05-04 15:02:32 -07003482static bool verifyInstruction(const Method* meth, InsnFlags* insnFlags,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003483 RegisterTable* regTable, RegType* workRegs, int insnIdx,
3484 UninitInstanceMap* uninitMap, int* pStartGuess)
3485{
3486 const int insnsSize = dvmGetMethodInsnsSize(meth);
3487 const u2* insns = meth->insns + insnIdx;
3488 bool result = false;
3489
3490 /*
3491 * Once we finish decoding the instruction, we need to figure out where
3492 * we can go from here. There are three possible ways to transfer
3493 * control to another statement:
3494 *
3495 * (1) Continue to the next instruction. Applies to all but
3496 * unconditional branches, method returns, and exception throws.
3497 * (2) Branch to one or more possible locations. Applies to branches
3498 * and switch statements.
3499 * (3) Exception handlers. Applies to any instruction that can
3500 * throw an exception that is handled by an encompassing "try"
Andy McFadden228a6b02010-05-04 15:02:32 -07003501 * block.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003502 *
3503 * We can also return, in which case there is no successor instruction
3504 * from this point.
3505 *
Andy McFadden228a6b02010-05-04 15:02:32 -07003506 * The behavior can be determined from the InstructionFlags.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003507 */
3508
3509 const DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
3510 RegType entryRegs[meth->registersSize + kExtraRegs];
3511 ClassObject* resClass;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003512 int branchTarget = 0;
3513 const int insnRegCount = meth->registersSize;
3514 RegType tmpType;
3515 DecodedInstruction decInsn;
3516 bool justSetResult = false;
Andy McFadden62a75162009-04-17 17:23:37 -07003517 VerifyError failure = VERIFY_ERROR_NONE;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003518
3519#ifndef NDEBUG
3520 memset(&decInsn, 0x81, sizeof(decInsn));
3521#endif
3522 dexDecodeInstruction(gDvm.instrFormat, insns, &decInsn);
3523
Andy McFaddenb51ea112009-05-08 16:50:17 -07003524 int nextFlags = dexGetInstrFlags(gDvm.instrFlags, decInsn.opCode);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003525
3526 /*
3527 * Make a copy of the previous register state. If the instruction
3528 * throws an exception, we merge *this* into the destination rather
3529 * than workRegs, because we don't want the result from the "successful"
3530 * code path (e.g. a check-cast that "improves" a type) to be visible
3531 * to the exception handler.
3532 */
3533 if ((nextFlags & kInstrCanThrow) != 0 && dvmInsnIsInTry(insnFlags, insnIdx))
3534 {
3535 copyRegisters(entryRegs, workRegs, meth->registersSize + kExtraRegs);
3536 } else {
3537#ifndef NDEBUG
3538 memset(entryRegs, 0xdd,
3539 (meth->registersSize + kExtraRegs) * sizeof(RegType));
3540#endif
3541 }
3542
3543 switch (decInsn.opCode) {
3544 case OP_NOP:
3545 /*
3546 * A "pure" NOP has no effect on anything. Data tables start with
3547 * a signature that looks like a NOP; if we see one of these in
3548 * the course of executing code then we have a problem.
3549 */
3550 if (decInsn.vA != 0) {
3551 LOG_VFY("VFY: encountered data table in instruction stream\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003552 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003553 }
3554 break;
3555
3556 case OP_MOVE:
3557 case OP_MOVE_FROM16:
3558 case OP_MOVE_16:
3559 copyRegister1(workRegs, insnRegCount, decInsn.vA, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07003560 kTypeCategory1nr, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003561 break;
3562 case OP_MOVE_WIDE:
3563 case OP_MOVE_WIDE_FROM16:
3564 case OP_MOVE_WIDE_16:
Andy McFadden62a75162009-04-17 17:23:37 -07003565 copyRegister2(workRegs, insnRegCount, decInsn.vA, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003566 break;
3567 case OP_MOVE_OBJECT:
3568 case OP_MOVE_OBJECT_FROM16:
3569 case OP_MOVE_OBJECT_16:
3570 copyRegister1(workRegs, insnRegCount, decInsn.vA, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07003571 kTypeCategoryRef, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003572 break;
3573
3574 /*
3575 * The move-result instructions copy data out of a "pseudo-register"
3576 * with the results from the last method invocation. In practice we
3577 * might want to hold the result in an actual CPU register, so the
3578 * Dalvik spec requires that these only appear immediately after an
3579 * invoke or filled-new-array.
3580 *
3581 * These calls invalidate the "result" register. (This is now
3582 * redundant with the reset done below, but it can make the debug info
3583 * easier to read in some cases.)
3584 */
3585 case OP_MOVE_RESULT:
3586 copyResultRegister1(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003587 kTypeCategory1nr, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003588 break;
3589 case OP_MOVE_RESULT_WIDE:
Andy McFadden62a75162009-04-17 17:23:37 -07003590 copyResultRegister2(workRegs, insnRegCount, decInsn.vA, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003591 break;
3592 case OP_MOVE_RESULT_OBJECT:
3593 copyResultRegister1(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003594 kTypeCategoryRef, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003595 break;
3596
3597 case OP_MOVE_EXCEPTION:
3598 /*
3599 * This statement can only appear as the first instruction in an
3600 * exception handler (though not all exception handlers need to
3601 * have one of these). We verify that as part of extracting the
3602 * exception type from the catch block list.
3603 *
3604 * "resClass" will hold the closest common superclass of all
3605 * exceptions that can be handled here.
3606 */
Andy McFadden62a75162009-04-17 17:23:37 -07003607 resClass = getCaughtExceptionType(meth, insnIdx, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003608 if (resClass == NULL) {
Andy McFadden62a75162009-04-17 17:23:37 -07003609 assert(!VERIFY_OK(failure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003610 } else {
3611 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003612 regTypeFromClass(resClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003613 }
3614 break;
3615
3616 case OP_RETURN_VOID:
Andy McFadden62a75162009-04-17 17:23:37 -07003617 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3618 failure = VERIFY_ERROR_GENERIC;
3619 } else if (getMethodReturnType(meth) != kRegTypeUnknown) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003620 LOG_VFY("VFY: return-void not expected\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003621 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003622 }
3623 break;
3624 case OP_RETURN:
Andy McFadden62a75162009-04-17 17:23:37 -07003625 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3626 failure = VERIFY_ERROR_GENERIC;
3627 } else {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003628 /* check the method signature */
3629 RegType returnType = getMethodReturnType(meth);
Andy McFadden62a75162009-04-17 17:23:37 -07003630 checkTypeCategory(returnType, kTypeCategory1nr, &failure);
3631 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003632 LOG_VFY("VFY: return-32 not expected\n");
3633
3634 /* check the register contents */
3635 returnType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003636 &failure);
3637 checkTypeCategory(returnType, kTypeCategory1nr, &failure);
3638 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003639 LOG_VFY("VFY: return-32 on invalid register v%d\n", decInsn.vA);
3640 }
3641 break;
3642 case OP_RETURN_WIDE:
Andy McFadden62a75162009-04-17 17:23:37 -07003643 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3644 failure = VERIFY_ERROR_GENERIC;
3645 } else {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003646 RegType returnType, returnTypeHi;
3647
3648 /* check the method signature */
3649 returnType = getMethodReturnType(meth);
Andy McFadden62a75162009-04-17 17:23:37 -07003650 checkTypeCategory(returnType, kTypeCategory2, &failure);
3651 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003652 LOG_VFY("VFY: return-wide not expected\n");
3653
3654 /* check the register contents */
3655 returnType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003656 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003657 returnTypeHi = getRegisterType(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003658 decInsn.vA +1, &failure);
3659 if (VERIFY_OK(failure)) {
3660 checkTypeCategory(returnType, kTypeCategory2, &failure);
3661 checkWidePair(returnType, returnTypeHi, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003662 }
Andy McFadden62a75162009-04-17 17:23:37 -07003663 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003664 LOG_VFY("VFY: return-wide on invalid register pair v%d\n",
3665 decInsn.vA);
3666 }
3667 }
3668 break;
3669 case OP_RETURN_OBJECT:
Andy McFadden62a75162009-04-17 17:23:37 -07003670 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3671 failure = VERIFY_ERROR_GENERIC;
3672 } else {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003673 RegType returnType = getMethodReturnType(meth);
Andy McFadden62a75162009-04-17 17:23:37 -07003674 checkTypeCategory(returnType, kTypeCategoryRef, &failure);
3675 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003676 LOG_VFY("VFY: return-object not expected\n");
3677 break;
3678 }
3679
3680 /* returnType is the *expected* return type, not register value */
3681 assert(returnType != kRegTypeZero);
3682 assert(!regTypeIsUninitReference(returnType));
3683
3684 /*
3685 * Verify that the reference in vAA is an instance of the type
3686 * in "returnType". The Zero type is allowed here. If the
3687 * method is declared to return an interface, then any
3688 * initialized reference is acceptable.
3689 *
3690 * Note getClassFromRegister fails if the register holds an
3691 * uninitialized reference, so we do not allow them to be
3692 * returned.
3693 */
3694 ClassObject* declClass;
3695
3696 declClass = regTypeInitializedReferenceToClass(returnType);
3697 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003698 decInsn.vA, &failure);
3699 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003700 break;
3701 if (resClass != NULL) {
3702 if (!dvmIsInterfaceClass(declClass) &&
3703 !dvmInstanceof(resClass, declClass))
3704 {
Andy McFadden86c86432009-05-27 14:40:12 -07003705 LOG_VFY("VFY: returning %s (cl=%p), declared %s (cl=%p)\n",
3706 resClass->descriptor, resClass->classLoader,
3707 declClass->descriptor, declClass->classLoader);
Andy McFadden62a75162009-04-17 17:23:37 -07003708 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003709 break;
3710 }
3711 }
3712 }
3713 break;
3714
3715 case OP_CONST_4:
3716 case OP_CONST_16:
3717 case OP_CONST:
3718 /* could be boolean, int, float, or a null reference */
3719 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003720 dvmDetermineCat1Const((s4)decInsn.vB), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003721 break;
3722 case OP_CONST_HIGH16:
3723 /* could be boolean, int, float, or a null reference */
3724 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003725 dvmDetermineCat1Const((s4) decInsn.vB << 16), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003726 break;
3727 case OP_CONST_WIDE_16:
3728 case OP_CONST_WIDE_32:
3729 case OP_CONST_WIDE:
3730 case OP_CONST_WIDE_HIGH16:
3731 /* could be long or double; default to long and allow conversion */
3732 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003733 kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003734 break;
3735 case OP_CONST_STRING:
3736 case OP_CONST_STRING_JUMBO:
3737 assert(gDvm.classJavaLangString != NULL);
3738 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003739 regTypeFromClass(gDvm.classJavaLangString), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003740 break;
3741 case OP_CONST_CLASS:
3742 assert(gDvm.classJavaLangClass != NULL);
3743 /* make sure we can resolve the class; access check is important */
Andy McFadden62a75162009-04-17 17:23:37 -07003744 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003745 if (resClass == NULL) {
3746 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3747 dvmLogUnableToResolveClass(badClassDesc, meth);
3748 LOG_VFY("VFY: unable to resolve const-class %d (%s) in %s\n",
3749 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003750 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003751 } else {
3752 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003753 regTypeFromClass(gDvm.classJavaLangClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003754 }
3755 break;
3756
3757 case OP_MONITOR_ENTER:
3758 case OP_MONITOR_EXIT:
Andy McFadden62a75162009-04-17 17:23:37 -07003759 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
3760 if (VERIFY_OK(failure)) {
3761 if (!regTypeIsReference(tmpType)) {
3762 LOG_VFY("VFY: monitor op on non-object\n");
3763 failure = VERIFY_ERROR_GENERIC;
3764 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003765 }
3766 break;
3767
3768 case OP_CHECK_CAST:
3769 /*
3770 * If this instruction succeeds, we will promote register vA to
3771 * the type in vB. (This could be a demotion -- not expected, so
3772 * we don't try to address it.)
3773 *
3774 * If it fails, an exception is thrown, which we deal with later
3775 * by ignoring the update to decInsn.vA when branching to a handler.
3776 */
Andy McFadden62a75162009-04-17 17:23:37 -07003777 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003778 if (resClass == NULL) {
3779 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3780 dvmLogUnableToResolveClass(badClassDesc, meth);
3781 LOG_VFY("VFY: unable to resolve check-cast %d (%s) in %s\n",
3782 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003783 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003784 } else {
3785 RegType origType;
3786
3787 origType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003788 &failure);
3789 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003790 break;
3791 if (!regTypeIsReference(origType)) {
3792 LOG_VFY("VFY: check-cast on non-reference in v%u\n",decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07003793 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003794 break;
3795 }
3796 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003797 regTypeFromClass(resClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003798 }
3799 break;
3800 case OP_INSTANCE_OF:
3801 /* make sure we're checking a reference type */
Andy McFadden62a75162009-04-17 17:23:37 -07003802 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vB, &failure);
3803 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003804 break;
3805 if (!regTypeIsReference(tmpType)) {
3806 LOG_VFY("VFY: vB not a reference (%d)\n", tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07003807 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003808 break;
3809 }
3810
3811 /* make sure we can resolve the class; access check is important */
Andy McFadden62a75162009-04-17 17:23:37 -07003812 resClass = dvmOptResolveClass(meth->clazz, decInsn.vC, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003813 if (resClass == NULL) {
3814 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vC);
3815 dvmLogUnableToResolveClass(badClassDesc, meth);
3816 LOG_VFY("VFY: unable to resolve instanceof %d (%s) in %s\n",
3817 decInsn.vC, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003818 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003819 } else {
3820 /* result is boolean */
3821 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003822 kRegTypeBoolean, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003823 }
3824 break;
3825
3826 case OP_ARRAY_LENGTH:
3827 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003828 decInsn.vB, &failure);
3829 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003830 break;
3831 if (resClass != NULL && !dvmIsArrayClass(resClass)) {
3832 LOG_VFY("VFY: array-length on non-array\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003833 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003834 break;
3835 }
3836 setRegisterType(workRegs, insnRegCount, decInsn.vA, kRegTypeInteger,
Andy McFadden62a75162009-04-17 17:23:37 -07003837 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003838 break;
3839
3840 case OP_NEW_INSTANCE:
Andy McFadden62a75162009-04-17 17:23:37 -07003841 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003842 if (resClass == NULL) {
3843 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3844 dvmLogUnableToResolveClass(badClassDesc, meth);
3845 LOG_VFY("VFY: unable to resolve new-instance %d (%s) in %s\n",
3846 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003847 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003848 } else {
3849 RegType uninitType;
3850
Andy McFaddenb51ea112009-05-08 16:50:17 -07003851 /* can't create an instance of an interface or abstract class */
3852 if (dvmIsAbstractClass(resClass) || dvmIsInterfaceClass(resClass)) {
3853 LOG_VFY("VFY: new-instance on interface or abstract class %s\n",
3854 resClass->descriptor);
3855 failure = VERIFY_ERROR_INSTANTIATION;
3856 break;
3857 }
3858
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003859 /* add resolved class to uninit map if not already there */
3860 int uidx = dvmSetUninitInstance(uninitMap, insnIdx, resClass);
3861 assert(uidx >= 0);
3862 uninitType = regTypeFromUninitIndex(uidx);
3863
3864 /*
3865 * Any registers holding previous allocations from this address
3866 * that have not yet been initialized must be marked invalid.
3867 */
3868 markUninitRefsAsInvalid(workRegs, insnRegCount, uninitMap,
3869 uninitType);
3870
3871 /* add the new uninitialized reference to the register ste */
3872 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003873 uninitType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003874 }
3875 break;
3876 case OP_NEW_ARRAY:
Andy McFadden62a75162009-04-17 17:23:37 -07003877 resClass = dvmOptResolveClass(meth->clazz, decInsn.vC, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003878 if (resClass == NULL) {
3879 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vC);
3880 dvmLogUnableToResolveClass(badClassDesc, meth);
3881 LOG_VFY("VFY: unable to resolve new-array %d (%s) in %s\n",
3882 decInsn.vC, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003883 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003884 } else if (!dvmIsArrayClass(resClass)) {
3885 LOG_VFY("VFY: new-array on non-array class\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003886 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003887 } else {
3888 /* make sure "size" register is valid type */
3889 verifyRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07003890 kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003891 /* set register type to array class */
3892 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003893 regTypeFromClass(resClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003894 }
3895 break;
3896 case OP_FILLED_NEW_ARRAY:
3897 case OP_FILLED_NEW_ARRAY_RANGE:
Andy McFadden62a75162009-04-17 17:23:37 -07003898 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003899 if (resClass == NULL) {
3900 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3901 dvmLogUnableToResolveClass(badClassDesc, meth);
3902 LOG_VFY("VFY: unable to resolve filled-array %d (%s) in %s\n",
3903 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003904 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003905 } else if (!dvmIsArrayClass(resClass)) {
3906 LOG_VFY("VFY: filled-new-array on non-array class\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003907 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003908 } else {
3909 bool isRange = (decInsn.opCode == OP_FILLED_NEW_ARRAY_RANGE);
3910
3911 /* check the arguments to the instruction */
3912 verifyFilledNewArrayRegs(meth, workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07003913 resClass, isRange, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003914 /* filled-array result goes into "result" register */
3915 setResultRegisterType(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003916 regTypeFromClass(resClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003917 justSetResult = true;
3918 }
3919 break;
3920
3921 case OP_CMPL_FLOAT:
3922 case OP_CMPG_FLOAT:
3923 verifyRegisterType(workRegs, insnRegCount, decInsn.vB, kRegTypeFloat,
Andy McFadden62a75162009-04-17 17:23:37 -07003924 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003925 verifyRegisterType(workRegs, insnRegCount, decInsn.vC, kRegTypeFloat,
Andy McFadden62a75162009-04-17 17:23:37 -07003926 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003927 setRegisterType(workRegs, insnRegCount, decInsn.vA, kRegTypeBoolean,
Andy McFadden62a75162009-04-17 17:23:37 -07003928 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003929 break;
3930 case OP_CMPL_DOUBLE:
3931 case OP_CMPG_DOUBLE:
3932 verifyRegisterType(workRegs, insnRegCount, decInsn.vB, kRegTypeDoubleLo,
Andy McFadden62a75162009-04-17 17:23:37 -07003933 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003934 verifyRegisterType(workRegs, insnRegCount, decInsn.vC, kRegTypeDoubleLo,
Andy McFadden62a75162009-04-17 17:23:37 -07003935 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003936 setRegisterType(workRegs, insnRegCount, decInsn.vA, kRegTypeBoolean,
Andy McFadden62a75162009-04-17 17:23:37 -07003937 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003938 break;
3939 case OP_CMP_LONG:
3940 verifyRegisterType(workRegs, insnRegCount, decInsn.vB, kRegTypeLongLo,
Andy McFadden62a75162009-04-17 17:23:37 -07003941 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003942 verifyRegisterType(workRegs, insnRegCount, decInsn.vC, kRegTypeLongLo,
Andy McFadden62a75162009-04-17 17:23:37 -07003943 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003944 setRegisterType(workRegs, insnRegCount, decInsn.vA, kRegTypeBoolean,
Andy McFadden62a75162009-04-17 17:23:37 -07003945 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003946 break;
3947
3948 case OP_THROW:
3949 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003950 decInsn.vA, &failure);
3951 if (VERIFY_OK(failure) && resClass != NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003952 if (!dvmInstanceof(resClass, gDvm.classJavaLangThrowable)) {
3953 LOG_VFY("VFY: thrown class %s not instanceof Throwable\n",
3954 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003955 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003956 }
3957 }
3958 break;
3959
3960 case OP_GOTO:
3961 case OP_GOTO_16:
3962 case OP_GOTO_32:
3963 /* no effect on or use of registers */
3964 break;
3965
3966 case OP_PACKED_SWITCH:
3967 case OP_SPARSE_SWITCH:
3968 /* verify that vAA is an integer, or can be converted to one */
3969 verifyRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003970 kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003971 break;
3972
3973 case OP_FILL_ARRAY_DATA:
3974 {
3975 RegType valueType;
3976 const u2 *arrayData;
3977 u2 elemWidth;
3978
3979 /* Similar to the verification done for APUT */
3980 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07003981 decInsn.vA, &failure);
3982 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003983 break;
3984
3985 /* resClass can be null if the reg type is Zero */
3986 if (resClass == NULL)
3987 break;
3988
3989 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
3990 resClass->elementClass->primitiveType == PRIM_NOT ||
3991 resClass->elementClass->primitiveType == PRIM_VOID)
3992 {
3993 LOG_VFY("VFY: invalid fill-array-data on %s\n",
3994 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003995 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003996 break;
3997 }
3998
3999 valueType = primitiveTypeToRegType(
4000 resClass->elementClass->primitiveType);
4001 assert(valueType != kRegTypeUnknown);
4002
4003 /*
4004 * Now verify if the element width in the table matches the element
4005 * width declared in the array
4006 */
4007 arrayData = insns + (insns[1] | (((s4)insns[2]) << 16));
4008 if (arrayData[0] != kArrayDataSignature) {
4009 LOG_VFY("VFY: invalid magic for array-data\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004010 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004011 break;
4012 }
4013
4014 switch (resClass->elementClass->primitiveType) {
4015 case PRIM_BOOLEAN:
4016 case PRIM_BYTE:
4017 elemWidth = 1;
4018 break;
4019 case PRIM_CHAR:
4020 case PRIM_SHORT:
4021 elemWidth = 2;
4022 break;
4023 case PRIM_FLOAT:
4024 case PRIM_INT:
4025 elemWidth = 4;
4026 break;
4027 case PRIM_DOUBLE:
4028 case PRIM_LONG:
4029 elemWidth = 8;
4030 break;
4031 default:
4032 elemWidth = 0;
4033 break;
4034 }
4035
4036 /*
4037 * Since we don't compress the data in Dex, expect to see equal
4038 * width of data stored in the table and expected from the array
4039 * class.
4040 */
4041 if (arrayData[1] != elemWidth) {
4042 LOG_VFY("VFY: array-data size mismatch (%d vs %d)\n",
4043 arrayData[1], elemWidth);
Andy McFadden62a75162009-04-17 17:23:37 -07004044 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004045 }
4046 }
4047 break;
4048
4049 case OP_IF_EQ:
4050 case OP_IF_NE:
4051 {
4052 RegType type1, type2;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004053
Andy McFadden62a75162009-04-17 17:23:37 -07004054 type1 = getRegisterType(workRegs, insnRegCount, decInsn.vA,
4055 &failure);
4056 type2 = getRegisterType(workRegs, insnRegCount, decInsn.vB,
4057 &failure);
4058 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004059 break;
4060
4061 /* both references? */
4062 if (regTypeIsReference(type1) && regTypeIsReference(type2))
4063 break;
4064
4065 /* both category-1nr? */
Andy McFadden62a75162009-04-17 17:23:37 -07004066 checkTypeCategory(type1, kTypeCategory1nr, &failure);
4067 checkTypeCategory(type2, kTypeCategory1nr, &failure);
4068 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004069 LOG_VFY("VFY: args to if-eq/if-ne must both be refs or cat1\n");
4070 break;
4071 }
4072 }
4073 break;
4074 case OP_IF_LT:
4075 case OP_IF_GE:
4076 case OP_IF_GT:
4077 case OP_IF_LE:
Andy McFadden62a75162009-04-17 17:23:37 -07004078 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4079 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004080 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004081 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
4082 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004083 LOG_VFY("VFY: args to 'if' must be cat-1nr\n");
4084 break;
4085 }
Andy McFadden62a75162009-04-17 17:23:37 -07004086 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vB, &failure);
4087 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004088 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004089 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
4090 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004091 LOG_VFY("VFY: args to 'if' must be cat-1nr\n");
4092 break;
4093 }
4094 break;
4095 case OP_IF_EQZ:
4096 case OP_IF_NEZ:
Andy McFadden62a75162009-04-17 17:23:37 -07004097 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4098 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004099 break;
4100 if (regTypeIsReference(tmpType))
4101 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004102 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
4103 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004104 LOG_VFY("VFY: expected cat-1 arg to if\n");
4105 break;
4106 case OP_IF_LTZ:
4107 case OP_IF_GEZ:
4108 case OP_IF_GTZ:
4109 case OP_IF_LEZ:
Andy McFadden62a75162009-04-17 17:23:37 -07004110 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4111 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004112 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004113 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
4114 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004115 LOG_VFY("VFY: expected cat-1 arg to if\n");
4116 break;
4117
4118 case OP_AGET:
4119 tmpType = kRegTypeInteger;
4120 goto aget_1nr_common;
4121 case OP_AGET_BOOLEAN:
4122 tmpType = kRegTypeBoolean;
4123 goto aget_1nr_common;
4124 case OP_AGET_BYTE:
4125 tmpType = kRegTypeByte;
4126 goto aget_1nr_common;
4127 case OP_AGET_CHAR:
4128 tmpType = kRegTypeChar;
4129 goto aget_1nr_common;
4130 case OP_AGET_SHORT:
4131 tmpType = kRegTypeShort;
4132 goto aget_1nr_common;
4133aget_1nr_common:
4134 {
4135 RegType srcType, indexType;
4136
4137 indexType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004138 &failure);
4139 checkArrayIndexType(meth, indexType, &failure);
4140 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004141 break;
4142
4143 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004144 decInsn.vB, &failure);
4145 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004146 break;
4147 if (resClass != NULL) {
4148 /* verify the class */
4149 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4150 resClass->elementClass->primitiveType == PRIM_NOT)
4151 {
4152 LOG_VFY("VFY: invalid aget-1nr target %s\n",
4153 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004154 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004155 break;
4156 }
4157
4158 /* make sure array type matches instruction */
4159 srcType = primitiveTypeToRegType(
4160 resClass->elementClass->primitiveType);
4161
4162 if (!checkFieldArrayStore1nr(tmpType, srcType)) {
4163 LOG_VFY("VFY: invalid aget-1nr, array type=%d with"
4164 " inst type=%d (on %s)\n",
4165 srcType, tmpType, resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004166 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004167 break;
4168 }
4169
4170 }
4171 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004172 tmpType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004173 }
4174 break;
4175
4176 case OP_AGET_WIDE:
4177 {
4178 RegType dstType, indexType;
4179
4180 indexType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004181 &failure);
4182 checkArrayIndexType(meth, indexType, &failure);
4183 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004184 break;
4185
4186 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004187 decInsn.vB, &failure);
4188 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004189 break;
4190 if (resClass != NULL) {
4191 /* verify the class */
4192 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4193 resClass->elementClass->primitiveType == PRIM_NOT)
4194 {
4195 LOG_VFY("VFY: invalid aget-wide target %s\n",
4196 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004197 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004198 break;
4199 }
4200
4201 /* try to refine "dstType" */
4202 switch (resClass->elementClass->primitiveType) {
4203 case PRIM_LONG:
4204 dstType = kRegTypeLongLo;
4205 break;
4206 case PRIM_DOUBLE:
4207 dstType = kRegTypeDoubleLo;
4208 break;
4209 default:
4210 LOG_VFY("VFY: invalid aget-wide on %s\n",
4211 resClass->descriptor);
4212 dstType = kRegTypeUnknown;
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 } else {
4217 /*
4218 * Null array ref; this code path will fail at runtime. We
4219 * know this is either long or double, and we don't really
4220 * discriminate between those during verification, so we
4221 * call it a long.
4222 */
4223 dstType = kRegTypeLongLo;
4224 }
4225 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004226 dstType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004227 }
4228 break;
4229
4230 case OP_AGET_OBJECT:
4231 {
4232 RegType dstType, indexType;
4233
4234 indexType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004235 &failure);
4236 checkArrayIndexType(meth, indexType, &failure);
4237 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004238 break;
4239
4240 /* get the class of the array we're pulling an object from */
4241 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004242 decInsn.vB, &failure);
4243 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004244 break;
4245 if (resClass != NULL) {
4246 ClassObject* elementClass;
4247
4248 assert(resClass != NULL);
4249 if (!dvmIsArrayClass(resClass)) {
4250 LOG_VFY("VFY: aget-object on non-array class\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004251 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004252 break;
4253 }
4254 assert(resClass->elementClass != NULL);
4255
4256 /*
4257 * Find the element class. resClass->elementClass indicates
4258 * the basic type, which won't be what we want for a
4259 * multi-dimensional array.
4260 */
4261 if (resClass->descriptor[1] == '[') {
4262 assert(resClass->arrayDim > 1);
4263 elementClass = dvmFindArrayClass(&resClass->descriptor[1],
4264 resClass->classLoader);
4265 } else if (resClass->descriptor[1] == 'L') {
4266 assert(resClass->arrayDim == 1);
4267 elementClass = resClass->elementClass;
4268 } else {
4269 LOG_VFY("VFY: aget-object on non-ref array class (%s)\n",
4270 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004271 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004272 break;
4273 }
4274
4275 dstType = regTypeFromClass(elementClass);
4276 } else {
4277 /*
4278 * The array reference is NULL, so the current code path will
4279 * throw an exception. For proper merging with later code
4280 * paths, and correct handling of "if-eqz" tests on the
4281 * result of the array get, we want to treat this as a null
4282 * reference.
4283 */
4284 dstType = kRegTypeZero;
4285 }
4286 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004287 dstType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004288 }
4289 break;
4290 case OP_APUT:
4291 tmpType = kRegTypeInteger;
4292 goto aput_1nr_common;
4293 case OP_APUT_BOOLEAN:
4294 tmpType = kRegTypeBoolean;
4295 goto aput_1nr_common;
4296 case OP_APUT_BYTE:
4297 tmpType = kRegTypeByte;
4298 goto aput_1nr_common;
4299 case OP_APUT_CHAR:
4300 tmpType = kRegTypeChar;
4301 goto aput_1nr_common;
4302 case OP_APUT_SHORT:
4303 tmpType = kRegTypeShort;
4304 goto aput_1nr_common;
4305aput_1nr_common:
4306 {
4307 RegType srcType, dstType, indexType;
4308
4309 indexType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004310 &failure);
4311 checkArrayIndexType(meth, indexType, &failure);
4312 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004313 break;
4314
4315 /* make sure the source register has the correct type */
4316 srcType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004317 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004318 if (!canConvertTo1nr(srcType, tmpType)) {
4319 LOG_VFY("VFY: invalid reg type %d on aput instr (need %d)\n",
4320 srcType, tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07004321 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004322 break;
4323 }
4324
4325 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004326 decInsn.vB, &failure);
4327 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004328 break;
4329
4330 /* resClass can be null if the reg type is Zero */
4331 if (resClass == NULL)
4332 break;
4333
4334 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4335 resClass->elementClass->primitiveType == PRIM_NOT)
4336 {
4337 LOG_VFY("VFY: invalid aput-1nr on %s\n", resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004338 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004339 break;
4340 }
4341
4342 /* verify that instruction matches array */
4343 dstType = primitiveTypeToRegType(
4344 resClass->elementClass->primitiveType);
4345 assert(dstType != kRegTypeUnknown);
4346
4347 if (!checkFieldArrayStore1nr(tmpType, dstType)) {
4348 LOG_VFY("VFY: invalid aput-1nr on %s (inst=%d dst=%d)\n",
4349 resClass->descriptor, tmpType, dstType);
Andy McFadden62a75162009-04-17 17:23:37 -07004350 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004351 break;
4352 }
4353 }
4354 break;
4355 case OP_APUT_WIDE:
4356 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004357 &failure);
4358 checkArrayIndexType(meth, tmpType, &failure);
4359 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004360 break;
4361
Andy McFadden62a75162009-04-17 17:23:37 -07004362 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4363 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004364 RegType typeHi =
Andy McFadden62a75162009-04-17 17:23:37 -07004365 getRegisterType(workRegs, insnRegCount, decInsn.vA+1, &failure);
4366 checkTypeCategory(tmpType, kTypeCategory2, &failure);
4367 checkWidePair(tmpType, typeHi, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004368 }
Andy McFadden62a75162009-04-17 17:23:37 -07004369 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004370 break;
4371
4372 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004373 decInsn.vB, &failure);
4374 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004375 break;
4376 if (resClass != NULL) {
4377 /* verify the class and try to refine "dstType" */
4378 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4379 resClass->elementClass->primitiveType == PRIM_NOT)
4380 {
4381 LOG_VFY("VFY: invalid aput-wide on %s\n",
4382 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004383 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004384 break;
4385 }
4386
4387 switch (resClass->elementClass->primitiveType) {
4388 case PRIM_LONG:
4389 case PRIM_DOUBLE:
4390 /* these are okay */
4391 break;
4392 default:
4393 LOG_VFY("VFY: invalid aput-wide on %s\n",
4394 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004395 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004396 break;
4397 }
4398 }
4399 break;
4400 case OP_APUT_OBJECT:
4401 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004402 &failure);
4403 checkArrayIndexType(meth, tmpType, &failure);
4404 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004405 break;
4406
4407 /* get the ref we're storing; Zero is okay, Uninit is not */
4408 resClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004409 decInsn.vA, &failure);
4410 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004411 break;
4412 if (resClass != NULL) {
4413 ClassObject* arrayClass;
4414 ClassObject* elementClass;
4415
4416 /*
4417 * Get the array class. If the array ref is null, we won't
4418 * have type information (and we'll crash at runtime with a
4419 * null pointer exception).
4420 */
4421 arrayClass = getClassFromRegister(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07004422 decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004423
4424 if (arrayClass != NULL) {
4425 /* see if the array holds a compatible type */
4426 if (!dvmIsArrayClass(arrayClass)) {
4427 LOG_VFY("VFY: invalid aput-object on %s\n",
4428 arrayClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004429 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004430 break;
4431 }
4432
4433 /*
4434 * Find the element class. resClass->elementClass indicates
4435 * the basic type, which won't be what we want for a
4436 * multi-dimensional array.
4437 *
4438 * All we want to check here is that the element type is a
4439 * reference class. We *don't* check instanceof here, because
4440 * you can still put a String into a String[] after the latter
4441 * has been cast to an Object[].
4442 */
4443 if (arrayClass->descriptor[1] == '[') {
4444 assert(arrayClass->arrayDim > 1);
4445 elementClass = dvmFindArrayClass(&arrayClass->descriptor[1],
4446 arrayClass->classLoader);
4447 } else {
4448 assert(arrayClass->arrayDim == 1);
4449 elementClass = arrayClass->elementClass;
4450 }
4451 if (elementClass->primitiveType != PRIM_NOT) {
4452 LOG_VFY("VFY: invalid aput-object of %s into %s\n",
4453 resClass->descriptor, arrayClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004454 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004455 break;
4456 }
4457 }
4458 }
4459 break;
4460
4461 case OP_IGET:
4462 tmpType = kRegTypeInteger;
4463 goto iget_1nr_common;
4464 case OP_IGET_BOOLEAN:
4465 tmpType = kRegTypeBoolean;
4466 goto iget_1nr_common;
4467 case OP_IGET_BYTE:
4468 tmpType = kRegTypeByte;
4469 goto iget_1nr_common;
4470 case OP_IGET_CHAR:
4471 tmpType = kRegTypeChar;
4472 goto iget_1nr_common;
4473 case OP_IGET_SHORT:
4474 tmpType = kRegTypeShort;
4475 goto iget_1nr_common;
4476iget_1nr_common:
4477 {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004478 InstField* instField;
4479 RegType objType, fieldType;
4480
4481 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004482 &failure);
4483 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004484 break;
4485 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004486 &failure);
4487 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004488 break;
4489
4490 /* make sure the field's type is compatible with expectation */
4491 fieldType = primSigCharToRegType(instField->field.signature[0]);
4492 if (fieldType == kRegTypeUnknown ||
4493 !checkFieldArrayStore1nr(tmpType, fieldType))
4494 {
4495 LOG_VFY("VFY: invalid iget-1nr of %s.%s (inst=%d field=%d)\n",
4496 instField->field.clazz->descriptor,
4497 instField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004498 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004499 break;
4500 }
4501
Andy McFadden62a75162009-04-17 17:23:37 -07004502 setRegisterType(workRegs, insnRegCount, decInsn.vA, tmpType,
4503 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004504 }
4505 break;
4506 case OP_IGET_WIDE:
Andy McFadden861b3382010-03-05 15:58:31 -08004507 case OP_IGET_WIDE_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004508 {
4509 RegType dstType;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004510 InstField* instField;
4511 RegType objType;
4512
4513 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004514 &failure);
4515 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004516 break;
4517 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004518 &failure);
4519 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004520 break;
4521 /* check the type, which should be prim */
4522 switch (instField->field.signature[0]) {
4523 case 'D':
4524 dstType = kRegTypeDoubleLo;
4525 break;
4526 case 'J':
4527 dstType = kRegTypeLongLo;
4528 break;
4529 default:
4530 LOG_VFY("VFY: invalid iget-wide of %s.%s\n",
4531 instField->field.clazz->descriptor,
4532 instField->field.name);
4533 dstType = kRegTypeUnknown;
Andy McFadden62a75162009-04-17 17:23:37 -07004534 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004535 break;
4536 }
Andy McFadden62a75162009-04-17 17:23:37 -07004537 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004538 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004539 dstType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004540 }
Andy McFadden861b3382010-03-05 15:58:31 -08004541 if (VERIFY_OK(failure)) {
4542 if (decInsn.opCode != OP_IGET_WIDE_VOLATILE &&
4543 dvmIsVolatileField(&instField->field))
4544 {
4545 replaceVolatileInstruction(meth, insnFlags, insnIdx);
4546 }
4547 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004548 }
4549 break;
4550 case OP_IGET_OBJECT:
4551 {
4552 ClassObject* fieldClass;
4553 InstField* instField;
4554 RegType objType;
4555
4556 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004557 &failure);
4558 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004559 break;
4560 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004561 &failure);
4562 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004563 break;
4564 fieldClass = getFieldClass(meth, &instField->field);
4565 if (fieldClass == NULL) {
4566 /* class not found or primitive type */
4567 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4568 instField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004569 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004570 break;
4571 }
Andy McFadden62a75162009-04-17 17:23:37 -07004572 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004573 assert(!dvmIsPrimitiveClass(fieldClass));
4574 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004575 regTypeFromClass(fieldClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004576 }
4577 }
4578 break;
4579 case OP_IPUT:
4580 tmpType = kRegTypeInteger;
4581 goto iput_1nr_common;
4582 case OP_IPUT_BOOLEAN:
4583 tmpType = kRegTypeBoolean;
4584 goto iput_1nr_common;
4585 case OP_IPUT_BYTE:
4586 tmpType = kRegTypeByte;
4587 goto iput_1nr_common;
4588 case OP_IPUT_CHAR:
4589 tmpType = kRegTypeChar;
4590 goto iput_1nr_common;
4591 case OP_IPUT_SHORT:
4592 tmpType = kRegTypeShort;
4593 goto iput_1nr_common;
4594iput_1nr_common:
4595 {
4596 RegType srcType, fieldType, objType;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004597 InstField* instField;
4598
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004599 srcType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004600 &failure);
Andy McFaddenb5f64bc2009-06-10 14:11:07 -07004601
4602 /*
4603 * javac generates synthetic functions that write byte values
4604 * into boolean fields.
4605 */
4606 if (tmpType == kRegTypeBoolean && srcType == kRegTypeByte)
4607 srcType = kRegTypeBoolean;
4608
4609 /* make sure the source register has the correct type */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004610 if (!canConvertTo1nr(srcType, tmpType)) {
4611 LOG_VFY("VFY: invalid reg type %d on iput instr (need %d)\n",
4612 srcType, tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07004613 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004614 break;
4615 }
4616
4617 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004618 &failure);
4619 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004620 break;
4621 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004622 &failure);
4623 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004624 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004625 checkFinalFieldAccess(meth, &instField->field, &failure);
4626 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004627 break;
4628
4629 /* get type of field we're storing into */
4630 fieldType = primSigCharToRegType(instField->field.signature[0]);
4631 if (fieldType == kRegTypeUnknown ||
4632 !checkFieldArrayStore1nr(tmpType, fieldType))
4633 {
4634 LOG_VFY("VFY: invalid iput-1nr of %s.%s (inst=%d field=%d)\n",
4635 instField->field.clazz->descriptor,
4636 instField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004637 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004638 break;
4639 }
4640 }
4641 break;
4642 case OP_IPUT_WIDE:
Andy McFadden861b3382010-03-05 15:58:31 -08004643 case OP_IPUT_WIDE_VOLATILE:
Andy McFadden62a75162009-04-17 17:23:37 -07004644 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4645 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004646 RegType typeHi =
Andy McFadden62a75162009-04-17 17:23:37 -07004647 getRegisterType(workRegs, insnRegCount, decInsn.vA+1, &failure);
4648 checkTypeCategory(tmpType, kTypeCategory2, &failure);
4649 checkWidePair(tmpType, typeHi, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004650 }
Andy McFadden62a75162009-04-17 17:23:37 -07004651 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004652 InstField* instField;
4653 RegType objType;
4654
4655 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004656 &failure);
4657 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004658 break;
4659 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004660 &failure);
4661 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004662 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004663 checkFinalFieldAccess(meth, &instField->field, &failure);
4664 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004665 break;
4666
4667 /* check the type, which should be prim */
4668 switch (instField->field.signature[0]) {
4669 case 'D':
4670 case 'J':
4671 /* these are okay (and interchangeable) */
4672 break;
4673 default:
4674 LOG_VFY("VFY: invalid iput-wide of %s.%s\n",
4675 instField->field.clazz->descriptor,
4676 instField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07004677 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004678 break;
4679 }
Andy McFadden861b3382010-03-05 15:58:31 -08004680 if (VERIFY_OK(failure)) {
4681 if (decInsn.opCode != OP_IPUT_WIDE_VOLATILE &&
4682 dvmIsVolatileField(&instField->field))
4683 {
4684 replaceVolatileInstruction(meth, insnFlags, insnIdx);
4685 }
4686 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004687 }
4688 break;
4689 case OP_IPUT_OBJECT:
4690 {
4691 ClassObject* fieldClass;
4692 ClassObject* valueClass;
4693 InstField* instField;
4694 RegType objType, valueType;
4695
4696 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
Andy McFadden62a75162009-04-17 17:23:37 -07004697 &failure);
4698 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004699 break;
4700 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004701 &failure);
4702 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004703 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004704 checkFinalFieldAccess(meth, &instField->field, &failure);
4705 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004706 break;
4707
4708 fieldClass = getFieldClass(meth, &instField->field);
4709 if (fieldClass == NULL) {
4710 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4711 instField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004712 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004713 break;
4714 }
4715
4716 valueType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004717 &failure);
4718 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004719 break;
4720 if (!regTypeIsReference(valueType)) {
4721 LOG_VFY("VFY: storing non-ref v%d into ref field '%s' (%s)\n",
4722 decInsn.vA, instField->field.name,
4723 fieldClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004724 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004725 break;
4726 }
4727 if (valueType != kRegTypeZero) {
4728 valueClass = regTypeInitializedReferenceToClass(valueType);
4729 if (valueClass == NULL) {
4730 LOG_VFY("VFY: storing uninit ref v%d into ref field\n",
4731 decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07004732 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004733 break;
4734 }
4735 /* allow if field is any interface or field is base class */
4736 if (!dvmIsInterfaceClass(fieldClass) &&
4737 !dvmInstanceof(valueClass, fieldClass))
4738 {
4739 LOG_VFY("VFY: storing type '%s' into field type '%s' (%s.%s)\n",
4740 valueClass->descriptor, fieldClass->descriptor,
4741 instField->field.clazz->descriptor,
4742 instField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07004743 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004744 break;
4745 }
4746 }
4747 }
4748 break;
4749
4750 case OP_SGET:
4751 tmpType = kRegTypeInteger;
4752 goto sget_1nr_common;
4753 case OP_SGET_BOOLEAN:
4754 tmpType = kRegTypeBoolean;
4755 goto sget_1nr_common;
4756 case OP_SGET_BYTE:
4757 tmpType = kRegTypeByte;
4758 goto sget_1nr_common;
4759 case OP_SGET_CHAR:
4760 tmpType = kRegTypeChar;
4761 goto sget_1nr_common;
4762 case OP_SGET_SHORT:
4763 tmpType = kRegTypeShort;
4764 goto sget_1nr_common;
4765sget_1nr_common:
4766 {
4767 StaticField* staticField;
4768 RegType fieldType;
4769
Andy McFadden62a75162009-04-17 17:23:37 -07004770 staticField = getStaticField(meth, decInsn.vB, &failure);
4771 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004772 break;
4773
4774 /*
4775 * Make sure the field's type is compatible with expectation.
4776 * We can get ourselves into trouble if we mix & match loads
4777 * and stores with different widths, so rather than just checking
4778 * "canConvertTo1nr" we require that the field types have equal
4779 * widths. (We can't generally require an exact type match,
4780 * because e.g. "int" and "float" are interchangeable.)
4781 */
4782 fieldType = primSigCharToRegType(staticField->field.signature[0]);
4783 if (!checkFieldArrayStore1nr(tmpType, fieldType)) {
4784 LOG_VFY("VFY: invalid sget-1nr of %s.%s (inst=%d actual=%d)\n",
4785 staticField->field.clazz->descriptor,
4786 staticField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004787 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004788 break;
4789 }
4790
Andy McFadden62a75162009-04-17 17:23:37 -07004791 setRegisterType(workRegs, insnRegCount, decInsn.vA, tmpType,
4792 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004793 }
4794 break;
4795 case OP_SGET_WIDE:
Andy McFadden861b3382010-03-05 15:58:31 -08004796 case OP_SGET_WIDE_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004797 {
4798 StaticField* staticField;
4799 RegType dstType;
4800
Andy McFadden62a75162009-04-17 17:23:37 -07004801 staticField = getStaticField(meth, decInsn.vB, &failure);
4802 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004803 break;
4804 /* check the type, which should be prim */
4805 switch (staticField->field.signature[0]) {
4806 case 'D':
4807 dstType = kRegTypeDoubleLo;
4808 break;
4809 case 'J':
4810 dstType = kRegTypeLongLo;
4811 break;
4812 default:
4813 LOG_VFY("VFY: invalid sget-wide of %s.%s\n",
4814 staticField->field.clazz->descriptor,
4815 staticField->field.name);
4816 dstType = kRegTypeUnknown;
Andy McFadden62a75162009-04-17 17:23:37 -07004817 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004818 break;
4819 }
Andy McFadden62a75162009-04-17 17:23:37 -07004820 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004821 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004822 dstType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004823 }
Andy McFadden861b3382010-03-05 15:58:31 -08004824 if (VERIFY_OK(failure)) {
4825 if (decInsn.opCode != OP_SGET_WIDE_VOLATILE &&
4826 dvmIsVolatileField(&staticField->field))
4827 {
4828 replaceVolatileInstruction(meth, insnFlags, insnIdx);
4829 }
4830 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004831 }
4832 break;
4833 case OP_SGET_OBJECT:
4834 {
4835 StaticField* staticField;
4836 ClassObject* fieldClass;
4837
Andy McFadden62a75162009-04-17 17:23:37 -07004838 staticField = getStaticField(meth, decInsn.vB, &failure);
4839 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004840 break;
4841 fieldClass = getFieldClass(meth, &staticField->field);
4842 if (fieldClass == NULL) {
4843 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4844 staticField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004845 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004846 break;
4847 }
4848 if (dvmIsPrimitiveClass(fieldClass)) {
4849 LOG_VFY("VFY: attempt to get prim field with sget-object\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004850 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004851 break;
4852 }
4853 setRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004854 regTypeFromClass(fieldClass), &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004855 }
4856 break;
4857 case OP_SPUT:
4858 tmpType = kRegTypeInteger;
4859 goto sput_1nr_common;
4860 case OP_SPUT_BOOLEAN:
4861 tmpType = kRegTypeBoolean;
4862 goto sput_1nr_common;
4863 case OP_SPUT_BYTE:
4864 tmpType = kRegTypeByte;
4865 goto sput_1nr_common;
4866 case OP_SPUT_CHAR:
4867 tmpType = kRegTypeChar;
4868 goto sput_1nr_common;
4869 case OP_SPUT_SHORT:
4870 tmpType = kRegTypeShort;
4871 goto sput_1nr_common;
4872sput_1nr_common:
4873 {
4874 RegType srcType, fieldType;
4875 StaticField* staticField;
4876
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004877 srcType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004878 &failure);
Andy McFaddenb5f64bc2009-06-10 14:11:07 -07004879
4880 /*
4881 * javac generates synthetic functions that write byte values
4882 * into boolean fields.
4883 */
4884 if (tmpType == kRegTypeBoolean && srcType == kRegTypeByte)
4885 srcType = kRegTypeBoolean;
4886
4887 /* make sure the source register has the correct type */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004888 if (!canConvertTo1nr(srcType, tmpType)) {
Andy McFaddenb5f64bc2009-06-10 14:11:07 -07004889 LOG_VFY("VFY: invalid reg type %d on sput instr (need %d)\n",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004890 srcType, tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07004891 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004892 break;
4893 }
4894
Andy McFadden62a75162009-04-17 17:23:37 -07004895 staticField = getStaticField(meth, decInsn.vB, &failure);
4896 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004897 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004898 checkFinalFieldAccess(meth, &staticField->field, &failure);
4899 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004900 break;
4901
4902 /*
4903 * Get type of field we're storing into. We know that the
4904 * contents of the register match the instruction, but we also
4905 * need to ensure that the instruction matches the field type.
4906 * Using e.g. sput-short to write into a 32-bit integer field
4907 * can lead to trouble if we do 16-bit writes.
4908 */
4909 fieldType = primSigCharToRegType(staticField->field.signature[0]);
4910 if (!checkFieldArrayStore1nr(tmpType, fieldType)) {
4911 LOG_VFY("VFY: invalid sput-1nr of %s.%s (inst=%d actual=%d)\n",
4912 staticField->field.clazz->descriptor,
4913 staticField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004914 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004915 break;
4916 }
4917 }
4918 break;
4919 case OP_SPUT_WIDE:
Andy McFadden861b3382010-03-05 15:58:31 -08004920 case OP_SPUT_WIDE_VOLATILE:
Andy McFadden62a75162009-04-17 17:23:37 -07004921 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4922 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004923 RegType typeHi =
Andy McFadden62a75162009-04-17 17:23:37 -07004924 getRegisterType(workRegs, insnRegCount, decInsn.vA+1, &failure);
4925 checkTypeCategory(tmpType, kTypeCategory2, &failure);
4926 checkWidePair(tmpType, typeHi, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004927 }
Andy McFadden62a75162009-04-17 17:23:37 -07004928 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004929 StaticField* staticField;
4930
Andy McFadden62a75162009-04-17 17:23:37 -07004931 staticField = getStaticField(meth, decInsn.vB, &failure);
4932 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004933 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004934 checkFinalFieldAccess(meth, &staticField->field, &failure);
4935 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004936 break;
4937
4938 /* check the type, which should be prim */
4939 switch (staticField->field.signature[0]) {
4940 case 'D':
4941 case 'J':
4942 /* these are okay */
4943 break;
4944 default:
4945 LOG_VFY("VFY: invalid sput-wide of %s.%s\n",
4946 staticField->field.clazz->descriptor,
4947 staticField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07004948 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004949 break;
4950 }
Andy McFadden861b3382010-03-05 15:58:31 -08004951 if (VERIFY_OK(failure)) {
4952 if (decInsn.opCode != OP_SPUT_WIDE_VOLATILE &&
4953 dvmIsVolatileField(&staticField->field))
4954 {
4955 replaceVolatileInstruction(meth, insnFlags, insnIdx);
4956 }
4957 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004958 }
4959 break;
4960 case OP_SPUT_OBJECT:
4961 {
4962 ClassObject* fieldClass;
4963 ClassObject* valueClass;
4964 StaticField* staticField;
4965 RegType valueType;
4966
Andy McFadden62a75162009-04-17 17:23:37 -07004967 staticField = getStaticField(meth, decInsn.vB, &failure);
4968 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004969 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004970 checkFinalFieldAccess(meth, &staticField->field, &failure);
4971 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004972 break;
4973
4974 fieldClass = getFieldClass(meth, &staticField->field);
4975 if (fieldClass == NULL) {
4976 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4977 staticField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004978 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004979 break;
4980 }
4981
4982 valueType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07004983 &failure);
4984 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004985 break;
4986 if (!regTypeIsReference(valueType)) {
4987 LOG_VFY("VFY: storing non-ref v%d into ref field '%s' (%s)\n",
4988 decInsn.vA, staticField->field.name,
4989 fieldClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004990 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004991 break;
4992 }
4993 if (valueType != kRegTypeZero) {
4994 valueClass = regTypeInitializedReferenceToClass(valueType);
4995 if (valueClass == NULL) {
4996 LOG_VFY("VFY: storing uninit ref v%d into ref field\n",
4997 decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07004998 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004999 break;
5000 }
5001 /* allow if field is any interface or field is base class */
5002 if (!dvmIsInterfaceClass(fieldClass) &&
5003 !dvmInstanceof(valueClass, fieldClass))
5004 {
5005 LOG_VFY("VFY: storing type '%s' into field type '%s' (%s.%s)\n",
5006 valueClass->descriptor, fieldClass->descriptor,
5007 staticField->field.clazz->descriptor,
5008 staticField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07005009 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005010 break;
5011 }
5012 }
5013 }
5014 break;
5015
5016 case OP_INVOKE_VIRTUAL:
5017 case OP_INVOKE_VIRTUAL_RANGE:
5018 case OP_INVOKE_SUPER:
5019 case OP_INVOKE_SUPER_RANGE:
5020 {
5021 Method* calledMethod;
5022 RegType returnType;
5023 bool isRange;
5024 bool isSuper;
5025
5026 isRange = (decInsn.opCode == OP_INVOKE_VIRTUAL_RANGE ||
5027 decInsn.opCode == OP_INVOKE_SUPER_RANGE);
5028 isSuper = (decInsn.opCode == OP_INVOKE_SUPER ||
5029 decInsn.opCode == OP_INVOKE_SUPER_RANGE);
5030
5031 calledMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
5032 &decInsn, uninitMap, METHOD_VIRTUAL, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07005033 isSuper, &failure);
5034 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005035 break;
5036 returnType = getMethodReturnType(calledMethod);
Andy McFadden62a75162009-04-17 17:23:37 -07005037 setResultRegisterType(workRegs, insnRegCount, returnType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005038 justSetResult = true;
5039 }
5040 break;
5041 case OP_INVOKE_DIRECT:
5042 case OP_INVOKE_DIRECT_RANGE:
5043 {
5044 RegType returnType;
5045 Method* calledMethod;
5046 bool isRange;
5047
5048 isRange = (decInsn.opCode == OP_INVOKE_DIRECT_RANGE);
5049 calledMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
5050 &decInsn, uninitMap, METHOD_DIRECT, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07005051 false, &failure);
5052 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005053 break;
5054
5055 /*
5056 * Some additional checks when calling <init>. We know from
5057 * the invocation arg check that the "this" argument is an
5058 * instance of calledMethod->clazz. Now we further restrict
5059 * that to require that calledMethod->clazz is the same as
5060 * this->clazz or this->super, allowing the latter only if
5061 * the "this" argument is the same as the "this" argument to
5062 * this method (which implies that we're in <init> ourselves).
5063 */
5064 if (isInitMethod(calledMethod)) {
5065 RegType thisType;
5066 thisType = getInvocationThis(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07005067 &decInsn, &failure);
5068 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005069 break;
5070
5071 /* no null refs allowed (?) */
5072 if (thisType == kRegTypeZero) {
5073 LOG_VFY("VFY: unable to initialize null ref\n");
Andy McFadden62a75162009-04-17 17:23:37 -07005074 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005075 break;
5076 }
5077
5078 ClassObject* thisClass;
5079
5080 thisClass = regTypeReferenceToClass(thisType, uninitMap);
5081 assert(thisClass != NULL);
5082
5083 /* must be in same class or in superclass */
5084 if (calledMethod->clazz == thisClass->super) {
5085 if (thisClass != meth->clazz) {
5086 LOG_VFY("VFY: invoke-direct <init> on super only "
5087 "allowed for 'this' in <init>");
Andy McFadden62a75162009-04-17 17:23:37 -07005088 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005089 break;
5090 }
5091 } else if (calledMethod->clazz != thisClass) {
5092 LOG_VFY("VFY: invoke-direct <init> must be on current "
5093 "class or super\n");
Andy McFadden62a75162009-04-17 17:23:37 -07005094 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005095 break;
5096 }
5097
5098 /* arg must be an uninitialized reference */
5099 if (!regTypeIsUninitReference(thisType)) {
5100 LOG_VFY("VFY: can only initialize the uninitialized\n");
Andy McFadden62a75162009-04-17 17:23:37 -07005101 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005102 break;
5103 }
5104
5105 /*
5106 * Replace the uninitialized reference with an initialized
5107 * one, and clear the entry in the uninit map. We need to
5108 * do this for all registers that have the same object
5109 * instance in them, not just the "this" register.
5110 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005111 markRefsAsInitialized(workRegs, insnRegCount, uninitMap,
Andy McFadden62a75162009-04-17 17:23:37 -07005112 thisType, &failure);
5113 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005114 break;
5115 }
5116 returnType = getMethodReturnType(calledMethod);
5117 setResultRegisterType(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07005118 returnType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005119 justSetResult = true;
5120 }
5121 break;
5122 case OP_INVOKE_STATIC:
5123 case OP_INVOKE_STATIC_RANGE:
5124 {
5125 RegType returnType;
5126 Method* calledMethod;
5127 bool isRange;
5128
5129 isRange = (decInsn.opCode == OP_INVOKE_STATIC_RANGE);
5130 calledMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
5131 &decInsn, uninitMap, METHOD_STATIC, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07005132 false, &failure);
5133 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005134 break;
5135
5136 returnType = getMethodReturnType(calledMethod);
Andy McFadden62a75162009-04-17 17:23:37 -07005137 setResultRegisterType(workRegs, insnRegCount, returnType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005138 justSetResult = true;
5139 }
5140 break;
5141 case OP_INVOKE_INTERFACE:
5142 case OP_INVOKE_INTERFACE_RANGE:
5143 {
5144 RegType /*thisType,*/ returnType;
5145 Method* absMethod;
5146 bool isRange;
5147
5148 isRange = (decInsn.opCode == OP_INVOKE_INTERFACE_RANGE);
5149 absMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
5150 &decInsn, uninitMap, METHOD_INTERFACE, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07005151 false, &failure);
5152 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005153 break;
5154
5155#if 0 /* can't do this here, fails on dalvik test 052-verifier-fun */
5156 /*
5157 * Get the type of the "this" arg, which should always be an
5158 * interface class. Because we don't do a full merge on
5159 * interface classes, this might have reduced to Object.
5160 */
5161 thisType = getInvocationThis(workRegs, insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07005162 &decInsn, &failure);
5163 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005164 break;
5165
5166 if (thisType == kRegTypeZero) {
5167 /* null pointer always passes (and always fails at runtime) */
5168 } else {
5169 ClassObject* thisClass;
5170
5171 thisClass = regTypeInitializedReferenceToClass(thisType);
5172 if (thisClass == NULL) {
5173 LOG_VFY("VFY: interface call on uninitialized\n");
Andy McFadden62a75162009-04-17 17:23:37 -07005174 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005175 break;
5176 }
5177
5178 /*
5179 * Either "thisClass" needs to be the interface class that
5180 * defined absMethod, or absMethod's class needs to be one
5181 * of the interfaces implemented by "thisClass". (Or, if
5182 * we couldn't complete the merge, this will be Object.)
5183 */
5184 if (thisClass != absMethod->clazz &&
5185 thisClass != gDvm.classJavaLangObject &&
5186 !dvmImplements(thisClass, absMethod->clazz))
5187 {
5188 LOG_VFY("VFY: unable to match absMethod '%s' with %s interfaces\n",
5189 absMethod->name, thisClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07005190 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005191 break;
5192 }
5193 }
5194#endif
5195
5196 /*
5197 * We don't have an object instance, so we can't find the
5198 * concrete method. However, all of the type information is
5199 * in the abstract method, so we're good.
5200 */
5201 returnType = getMethodReturnType(absMethod);
Andy McFadden62a75162009-04-17 17:23:37 -07005202 setResultRegisterType(workRegs, insnRegCount, returnType, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005203 justSetResult = true;
5204 }
5205 break;
5206
5207 case OP_NEG_INT:
5208 case OP_NOT_INT:
5209 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005210 kRegTypeInteger, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005211 break;
5212 case OP_NEG_LONG:
5213 case OP_NOT_LONG:
5214 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005215 kRegTypeLongLo, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005216 break;
5217 case OP_NEG_FLOAT:
5218 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005219 kRegTypeFloat, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005220 break;
5221 case OP_NEG_DOUBLE:
5222 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005223 kRegTypeDoubleLo, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005224 break;
5225 case OP_INT_TO_LONG:
5226 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005227 kRegTypeLongLo, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005228 break;
5229 case OP_INT_TO_FLOAT:
5230 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005231 kRegTypeFloat, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005232 break;
5233 case OP_INT_TO_DOUBLE:
5234 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005235 kRegTypeDoubleLo, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005236 break;
5237 case OP_LONG_TO_INT:
5238 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005239 kRegTypeInteger, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005240 break;
5241 case OP_LONG_TO_FLOAT:
5242 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005243 kRegTypeFloat, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005244 break;
5245 case OP_LONG_TO_DOUBLE:
5246 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005247 kRegTypeDoubleLo, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005248 break;
5249 case OP_FLOAT_TO_INT:
5250 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005251 kRegTypeInteger, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005252 break;
5253 case OP_FLOAT_TO_LONG:
5254 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005255 kRegTypeLongLo, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005256 break;
5257 case OP_FLOAT_TO_DOUBLE:
5258 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005259 kRegTypeDoubleLo, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005260 break;
5261 case OP_DOUBLE_TO_INT:
5262 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005263 kRegTypeInteger, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005264 break;
5265 case OP_DOUBLE_TO_LONG:
5266 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005267 kRegTypeLongLo, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005268 break;
5269 case OP_DOUBLE_TO_FLOAT:
5270 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005271 kRegTypeFloat, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005272 break;
5273 case OP_INT_TO_BYTE:
5274 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005275 kRegTypeByte, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005276 break;
5277 case OP_INT_TO_CHAR:
5278 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005279 kRegTypeChar, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005280 break;
5281 case OP_INT_TO_SHORT:
5282 checkUnop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005283 kRegTypeShort, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005284 break;
5285
5286 case OP_ADD_INT:
5287 case OP_SUB_INT:
5288 case OP_MUL_INT:
5289 case OP_REM_INT:
5290 case OP_DIV_INT:
5291 case OP_SHL_INT:
5292 case OP_SHR_INT:
5293 case OP_USHR_INT:
5294 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005295 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005296 break;
5297 case OP_AND_INT:
5298 case OP_OR_INT:
5299 case OP_XOR_INT:
5300 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005301 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005302 break;
5303 case OP_ADD_LONG:
5304 case OP_SUB_LONG:
5305 case OP_MUL_LONG:
5306 case OP_DIV_LONG:
5307 case OP_REM_LONG:
5308 case OP_AND_LONG:
5309 case OP_OR_LONG:
5310 case OP_XOR_LONG:
5311 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005312 kRegTypeLongLo, kRegTypeLongLo, kRegTypeLongLo, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005313 break;
5314 case OP_SHL_LONG:
5315 case OP_SHR_LONG:
5316 case OP_USHR_LONG:
5317 /* shift distance is Int, making these different from other binops */
5318 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005319 kRegTypeLongLo, kRegTypeLongLo, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005320 break;
5321 case OP_ADD_FLOAT:
5322 case OP_SUB_FLOAT:
5323 case OP_MUL_FLOAT:
5324 case OP_DIV_FLOAT:
5325 case OP_REM_FLOAT:
5326 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005327 kRegTypeFloat, kRegTypeFloat, kRegTypeFloat, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005328 break;
5329 case OP_ADD_DOUBLE:
5330 case OP_SUB_DOUBLE:
5331 case OP_MUL_DOUBLE:
5332 case OP_DIV_DOUBLE:
5333 case OP_REM_DOUBLE:
5334 checkBinop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005335 kRegTypeDoubleLo, kRegTypeDoubleLo, kRegTypeDoubleLo, false,
5336 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005337 break;
5338 case OP_ADD_INT_2ADDR:
5339 case OP_SUB_INT_2ADDR:
5340 case OP_MUL_INT_2ADDR:
5341 case OP_REM_INT_2ADDR:
5342 case OP_SHL_INT_2ADDR:
5343 case OP_SHR_INT_2ADDR:
5344 case OP_USHR_INT_2ADDR:
5345 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005346 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005347 break;
5348 case OP_AND_INT_2ADDR:
5349 case OP_OR_INT_2ADDR:
5350 case OP_XOR_INT_2ADDR:
5351 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005352 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005353 break;
5354 case OP_DIV_INT_2ADDR:
5355 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005356 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005357 break;
5358 case OP_ADD_LONG_2ADDR:
5359 case OP_SUB_LONG_2ADDR:
5360 case OP_MUL_LONG_2ADDR:
5361 case OP_DIV_LONG_2ADDR:
5362 case OP_REM_LONG_2ADDR:
5363 case OP_AND_LONG_2ADDR:
5364 case OP_OR_LONG_2ADDR:
5365 case OP_XOR_LONG_2ADDR:
5366 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005367 kRegTypeLongLo, kRegTypeLongLo, kRegTypeLongLo, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005368 break;
5369 case OP_SHL_LONG_2ADDR:
5370 case OP_SHR_LONG_2ADDR:
5371 case OP_USHR_LONG_2ADDR:
5372 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005373 kRegTypeLongLo, kRegTypeLongLo, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005374 break;
5375 case OP_ADD_FLOAT_2ADDR:
5376 case OP_SUB_FLOAT_2ADDR:
5377 case OP_MUL_FLOAT_2ADDR:
5378 case OP_DIV_FLOAT_2ADDR:
5379 case OP_REM_FLOAT_2ADDR:
5380 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005381 kRegTypeFloat, kRegTypeFloat, kRegTypeFloat, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005382 break;
5383 case OP_ADD_DOUBLE_2ADDR:
5384 case OP_SUB_DOUBLE_2ADDR:
5385 case OP_MUL_DOUBLE_2ADDR:
5386 case OP_DIV_DOUBLE_2ADDR:
5387 case OP_REM_DOUBLE_2ADDR:
5388 checkBinop2addr(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005389 kRegTypeDoubleLo, kRegTypeDoubleLo, kRegTypeDoubleLo, false,
5390 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005391 break;
5392 case OP_ADD_INT_LIT16:
5393 case OP_RSUB_INT:
5394 case OP_MUL_INT_LIT16:
5395 case OP_DIV_INT_LIT16:
5396 case OP_REM_INT_LIT16:
5397 checkLitop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005398 kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005399 break;
5400 case OP_AND_INT_LIT16:
5401 case OP_OR_INT_LIT16:
5402 case OP_XOR_INT_LIT16:
5403 checkLitop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005404 kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005405 break;
5406 case OP_ADD_INT_LIT8:
5407 case OP_RSUB_INT_LIT8:
5408 case OP_MUL_INT_LIT8:
5409 case OP_DIV_INT_LIT8:
5410 case OP_REM_INT_LIT8:
5411 case OP_SHL_INT_LIT8:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005412 checkLitop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005413 kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005414 break;
Andy McFadden80d25ea2009-06-12 07:26:17 -07005415 case OP_SHR_INT_LIT8:
5416 tmpType = adjustForRightShift(workRegs, insnRegCount,
5417 decInsn.vB, decInsn.vC, false, &failure);
5418 checkLitop(workRegs, insnRegCount, &decInsn,
5419 tmpType, kRegTypeInteger, false, &failure);
5420 break;
5421 case OP_USHR_INT_LIT8:
5422 tmpType = adjustForRightShift(workRegs, insnRegCount,
5423 decInsn.vB, decInsn.vC, true, &failure);
5424 checkLitop(workRegs, insnRegCount, &decInsn,
5425 tmpType, kRegTypeInteger, false, &failure);
5426 break;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005427 case OP_AND_INT_LIT8:
5428 case OP_OR_INT_LIT8:
5429 case OP_XOR_INT_LIT8:
5430 checkLitop(workRegs, insnRegCount, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005431 kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005432 break;
5433
Andy McFaddenb51ea112009-05-08 16:50:17 -07005434 /*
5435 * This falls into the general category of "optimized" instructions,
5436 * which don't generally appear during verification. Because it's
5437 * inserted in the course of verification, we can expect to see it here.
5438 */
5439 case OP_THROW_VERIFICATION_ERROR:
5440 break;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005441
5442 /*
5443 * Verifying "quickened" instructions is tricky, because we have
5444 * discarded the original field/method information. The byte offsets
5445 * and vtable indices only have meaning in the context of an object
5446 * instance.
5447 *
5448 * If a piece of code declares a local reference variable, assigns
5449 * null to it, and then issues a virtual method call on it, we
5450 * cannot evaluate the method call during verification. This situation
5451 * isn't hard to handle, since we know the call will always result in an
5452 * NPE, and the arguments and return value don't matter. Any code that
5453 * depends on the result of the method call is inaccessible, so the
5454 * fact that we can't fully verify anything that comes after the bad
5455 * call is not a problem.
5456 *
5457 * We must also consider the case of multiple code paths, only some of
5458 * which involve a null reference. We can completely verify the method
5459 * if we sidestep the results of executing with a null reference.
5460 * For example, if on the first pass through the code we try to do a
5461 * virtual method invocation through a null ref, we have to skip the
5462 * method checks and have the method return a "wildcard" type (which
5463 * merges with anything to become that other thing). The move-result
5464 * will tell us if it's a reference, single-word numeric, or double-word
5465 * value. We continue to perform the verification, and at the end of
5466 * the function any invocations that were never fully exercised are
5467 * marked as null-only.
5468 *
5469 * We would do something similar for the field accesses. The field's
5470 * type, once known, can be used to recover the width of short integers.
5471 * If the object reference was null, the field-get returns the "wildcard"
5472 * type, which is acceptable for any operation.
5473 */
5474 case OP_EXECUTE_INLINE:
Andy McFaddenb0a05412009-11-19 10:23:41 -08005475 case OP_EXECUTE_INLINE_RANGE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005476 case OP_INVOKE_DIRECT_EMPTY:
5477 case OP_IGET_QUICK:
5478 case OP_IGET_WIDE_QUICK:
5479 case OP_IGET_OBJECT_QUICK:
5480 case OP_IPUT_QUICK:
5481 case OP_IPUT_WIDE_QUICK:
5482 case OP_IPUT_OBJECT_QUICK:
5483 case OP_INVOKE_VIRTUAL_QUICK:
5484 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
5485 case OP_INVOKE_SUPER_QUICK:
5486 case OP_INVOKE_SUPER_QUICK_RANGE:
Andy McFadden62a75162009-04-17 17:23:37 -07005487 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005488 break;
5489
Andy McFadden96516932009-10-28 17:39:02 -07005490 /* these should never appear during verification */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005491 case OP_UNUSED_3E:
5492 case OP_UNUSED_3F:
5493 case OP_UNUSED_40:
5494 case OP_UNUSED_41:
5495 case OP_UNUSED_42:
5496 case OP_UNUSED_43:
5497 case OP_UNUSED_73:
5498 case OP_UNUSED_79:
5499 case OP_UNUSED_7A:
5500 case OP_UNUSED_E3:
5501 case OP_UNUSED_E4:
5502 case OP_UNUSED_E5:
5503 case OP_UNUSED_E6:
5504 case OP_UNUSED_E7:
Andy McFadden96516932009-10-28 17:39:02 -07005505 case OP_BREAKPOINT:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005506 case OP_UNUSED_F1:
5507 case OP_UNUSED_FC:
5508 case OP_UNUSED_FD:
5509 case OP_UNUSED_FE:
5510 case OP_UNUSED_FF:
Andy McFadden62a75162009-04-17 17:23:37 -07005511 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005512 break;
5513
5514 /*
5515 * DO NOT add a "default" clause here. Without it the compiler will
5516 * complain if an instruction is missing (which is desirable).
5517 */
5518 }
5519
Andy McFadden62a75162009-04-17 17:23:37 -07005520 if (!VERIFY_OK(failure)) {
Andy McFaddenb51ea112009-05-08 16:50:17 -07005521 if (failure == VERIFY_ERROR_GENERIC || gDvm.optimizing) {
5522 /* immediate failure, reject class */
5523 LOG_VFY_METH(meth, "VFY: rejecting opcode 0x%02x at 0x%04x\n",
5524 decInsn.opCode, insnIdx);
5525 goto bail;
5526 } else {
5527 /* replace opcode and continue on */
5528 LOGD("VFY: replacing opcode 0x%02x at 0x%04x\n",
5529 decInsn.opCode, insnIdx);
5530 if (!replaceFailingInstruction(meth, insnFlags, insnIdx, failure)) {
5531 LOG_VFY_METH(meth, "VFY: rejecting opcode 0x%02x at 0x%04x\n",
5532 decInsn.opCode, insnIdx);
5533 goto bail;
5534 }
5535 /* IMPORTANT: meth->insns may have been changed */
5536 insns = meth->insns + insnIdx;
5537
5538 /* continue on as if we just handled a throw-verification-error */
5539 failure = VERIFY_ERROR_NONE;
5540 nextFlags = kInstrCanThrow;
5541 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005542 }
5543
5544 /*
5545 * If we didn't just set the result register, clear it out. This
5546 * ensures that you can only use "move-result" immediately after the
Andy McFadden2e1ee502010-03-24 13:25:53 -07005547 * result is set. (We could check this statically, but it's not
5548 * expensive and it makes our debugging output cleaner.)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005549 */
5550 if (!justSetResult) {
5551 int reg = RESULT_REGISTER(insnRegCount);
5552 workRegs[reg] = workRegs[reg+1] = kRegTypeUnknown;
5553 }
5554
5555 /*
5556 * Handle "continue". Tag the next consecutive instruction.
5557 */
5558 if ((nextFlags & kInstrCanContinue) != 0) {
5559 int insnWidth = dvmInsnGetWidth(insnFlags, insnIdx);
5560 if (insnIdx+insnWidth >= insnsSize) {
5561 LOG_VFY_METH(meth,
5562 "VFY: execution can walk off end of code area (from 0x%x)\n",
5563 insnIdx);
5564 goto bail;
5565 }
5566
5567 /*
5568 * The only way to get to a move-exception instruction is to get
5569 * thrown there. Make sure the next instruction isn't one.
5570 */
5571 if (!checkMoveException(meth, insnIdx+insnWidth, "next"))
5572 goto bail;
5573
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005574 if (getRegisterLine(regTable, insnIdx+insnWidth) != NULL) {
Andy McFadden06b7a282009-05-11 10:44:52 -07005575 /*
5576 * Merge registers into what we have for the next instruction,
5577 * and set the "changed" flag if needed.
5578 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005579 updateRegisters(meth, insnFlags, regTable, insnIdx+insnWidth,
5580 workRegs);
5581 } else {
The Android Open Source Project99409882009-03-18 22:20:24 -07005582 /*
Andy McFadden06b7a282009-05-11 10:44:52 -07005583 * We're not recording register data for the next instruction,
5584 * so we don't know what the prior state was. We have to
5585 * assume that something has changed and re-evaluate it.
The Android Open Source Project99409882009-03-18 22:20:24 -07005586 */
5587 dvmInsnSetChanged(insnFlags, insnIdx+insnWidth, true);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005588 }
5589 }
5590
5591 /*
5592 * Handle "branch". Tag the branch target.
5593 *
5594 * NOTE: instructions like OP_EQZ provide information about the state
5595 * of the register when the branch is taken or not taken. For example,
5596 * somebody could get a reference field, check it for zero, and if the
5597 * branch is taken immediately store that register in a boolean field
5598 * since the value is known to be zero. We do not currently account for
5599 * that, and will reject the code.
5600 */
5601 if ((nextFlags & kInstrCanBranch) != 0) {
5602 bool isConditional;
5603
5604 if (!dvmGetBranchTarget(meth, insnFlags, insnIdx, &branchTarget,
5605 &isConditional))
5606 {
5607 /* should never happen after static verification */
5608 LOG_VFY_METH(meth, "VFY: bad branch at %d\n", insnIdx);
5609 goto bail;
5610 }
5611 assert(isConditional || (nextFlags & kInstrCanContinue) == 0);
5612 assert(!isConditional || (nextFlags & kInstrCanContinue) != 0);
5613
5614 if (!checkMoveException(meth, insnIdx+branchTarget, "branch"))
5615 goto bail;
5616
The Android Open Source Project99409882009-03-18 22:20:24 -07005617 /* update branch target, set "changed" if appropriate */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005618 updateRegisters(meth, insnFlags, regTable, insnIdx+branchTarget,
5619 workRegs);
5620 }
5621
5622 /*
5623 * Handle "switch". Tag all possible branch targets.
5624 *
5625 * We've already verified that the table is structurally sound, so we
5626 * just need to walk through and tag the targets.
5627 */
5628 if ((nextFlags & kInstrCanSwitch) != 0) {
5629 int offsetToSwitch = insns[1] | (((s4)insns[2]) << 16);
5630 const u2* switchInsns = insns + offsetToSwitch;
5631 int switchCount = switchInsns[1];
5632 int offsetToTargets, targ;
5633
5634 if ((*insns & 0xff) == OP_PACKED_SWITCH) {
5635 /* 0=sig, 1=count, 2/3=firstKey */
5636 offsetToTargets = 4;
5637 } else {
5638 /* 0=sig, 1=count, 2..count*2 = keys */
5639 assert((*insns & 0xff) == OP_SPARSE_SWITCH);
5640 offsetToTargets = 2 + 2*switchCount;
5641 }
5642
5643 /* verify each switch target */
5644 for (targ = 0; targ < switchCount; targ++) {
5645 int offset, absOffset;
5646
5647 /* offsets are 32-bit, and only partly endian-swapped */
5648 offset = switchInsns[offsetToTargets + targ*2] |
5649 (((s4) switchInsns[offsetToTargets + targ*2 +1]) << 16);
5650 absOffset = insnIdx + offset;
5651
5652 assert(absOffset >= 0 && absOffset < insnsSize);
5653
5654 if (!checkMoveException(meth, absOffset, "switch"))
5655 goto bail;
5656
5657 updateRegisters(meth, insnFlags, regTable, absOffset, workRegs);
5658 }
5659 }
5660
5661 /*
5662 * Handle instructions that can throw and that are sitting in a
5663 * "try" block. (If they're not in a "try" block when they throw,
5664 * control transfers out of the method.)
5665 */
5666 if ((nextFlags & kInstrCanThrow) != 0 && dvmInsnIsInTry(insnFlags, insnIdx))
5667 {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005668 const DexCode* pCode = dvmGetMethodCode(meth);
5669 DexCatchIterator iterator;
5670
5671 if (dexFindCatchHandler(&iterator, pCode, insnIdx)) {
5672 for (;;) {
5673 DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
5674
5675 if (handler == NULL) {
5676 break;
5677 }
5678
5679 /* note we use entryRegs, not workRegs */
5680 updateRegisters(meth, insnFlags, regTable, handler->address,
5681 entryRegs);
5682 }
5683 }
5684 }
5685
5686 /*
5687 * Update startGuess. Advance to the next instruction of that's
5688 * possible, otherwise use the branch target if one was found. If
5689 * neither of those exists we're in a return or throw; leave startGuess
5690 * alone and let the caller sort it out.
5691 */
5692 if ((nextFlags & kInstrCanContinue) != 0) {
5693 *pStartGuess = insnIdx + dvmInsnGetWidth(insnFlags, insnIdx);
5694 } else if ((nextFlags & kInstrCanBranch) != 0) {
5695 /* we're still okay if branchTarget is zero */
5696 *pStartGuess = insnIdx + branchTarget;
5697 }
5698
5699 assert(*pStartGuess >= 0 && *pStartGuess < insnsSize &&
5700 dvmInsnGetWidth(insnFlags, *pStartGuess) != 0);
5701
5702 result = true;
5703
5704bail:
5705 return result;
5706}
5707
Andy McFaddenb51ea112009-05-08 16:50:17 -07005708
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005709/*
5710 * callback function used in dumpRegTypes to print local vars
5711 * valid at a given address.
5712 */
5713static void logLocalsCb(void *cnxt, u2 reg, u4 startAddress, u4 endAddress,
5714 const char *name, const char *descriptor,
5715 const char *signature)
5716{
5717 int addr = *((int *)cnxt);
5718
5719 if (addr >= (int) startAddress && addr < (int) endAddress)
5720 {
5721 LOGI(" %2d: '%s' %s\n", reg, name, descriptor);
5722 }
5723}
5724
5725/*
5726 * Dump the register types for the specifed address to the log file.
5727 */
5728static void dumpRegTypes(const Method* meth, const InsnFlags* insnFlags,
5729 const RegType* addrRegs, int addr, const char* addrName,
5730 const UninitInstanceMap* uninitMap, int displayFlags)
5731{
5732 int regCount = meth->registersSize;
5733 int fullRegCount = regCount + kExtraRegs;
5734 bool branchTarget = dvmInsnIsBranchTarget(insnFlags, addr);
5735 int i;
5736
5737 assert(addr >= 0 && addr < (int) dvmGetMethodInsnsSize(meth));
5738
5739 int regCharSize = fullRegCount + (fullRegCount-1)/4 + 2 +1;
5740 char regChars[regCharSize +1];
5741 memset(regChars, ' ', regCharSize);
5742 regChars[0] = '[';
5743 if (regCount == 0)
5744 regChars[1] = ']';
5745 else
5746 regChars[1 + (regCount-1) + (regCount-1)/4 +1] = ']';
5747 regChars[regCharSize] = '\0';
5748
5749 //const RegType* addrRegs = getRegisterLine(regTable, addr);
5750
5751 for (i = 0; i < regCount + kExtraRegs; i++) {
5752 char tch;
5753
5754 switch (addrRegs[i]) {
5755 case kRegTypeUnknown: tch = '.'; break;
5756 case kRegTypeConflict: tch = 'X'; break;
5757 case kRegTypeFloat: tch = 'F'; break;
5758 case kRegTypeZero: tch = '0'; break;
5759 case kRegTypeOne: tch = '1'; break;
5760 case kRegTypeBoolean: tch = 'Z'; break;
5761 case kRegTypePosByte: tch = 'b'; break;
5762 case kRegTypeByte: tch = 'B'; break;
5763 case kRegTypePosShort: tch = 's'; break;
5764 case kRegTypeShort: tch = 'S'; break;
5765 case kRegTypeChar: tch = 'C'; break;
5766 case kRegTypeInteger: tch = 'I'; break;
5767 case kRegTypeLongLo: tch = 'J'; break;
5768 case kRegTypeLongHi: tch = 'j'; break;
5769 case kRegTypeDoubleLo: tch = 'D'; break;
5770 case kRegTypeDoubleHi: tch = 'd'; break;
5771 default:
5772 if (regTypeIsReference(addrRegs[i])) {
5773 if (regTypeIsUninitReference(addrRegs[i]))
5774 tch = 'U';
5775 else
5776 tch = 'L';
5777 } else {
5778 tch = '*';
5779 assert(false);
5780 }
5781 break;
5782 }
5783
5784 if (i < regCount)
5785 regChars[1 + i + (i/4)] = tch;
5786 else
5787 regChars[1 + i + (i/4) + 2] = tch;
5788 }
5789
5790 if (addr == 0 && addrName != NULL)
5791 LOGI("%c%s %s\n", branchTarget ? '>' : ' ', addrName, regChars);
5792 else
5793 LOGI("%c0x%04x %s\n", branchTarget ? '>' : ' ', addr, regChars);
5794
5795 if (displayFlags & DRT_SHOW_REF_TYPES) {
5796 for (i = 0; i < regCount + kExtraRegs; i++) {
5797 if (regTypeIsReference(addrRegs[i]) && addrRegs[i] != kRegTypeZero)
5798 {
5799 ClassObject* clazz;
5800
5801 clazz = regTypeReferenceToClass(addrRegs[i], uninitMap);
5802 assert(dvmValidateObject((Object*)clazz));
5803 if (i < regCount) {
5804 LOGI(" %2d: 0x%08x %s%s\n",
5805 i, addrRegs[i],
5806 regTypeIsUninitReference(addrRegs[i]) ? "[U]" : "",
5807 clazz->descriptor);
5808 } else {
5809 LOGI(" RS: 0x%08x %s%s\n",
5810 addrRegs[i],
5811 regTypeIsUninitReference(addrRegs[i]) ? "[U]" : "",
5812 clazz->descriptor);
5813 }
5814 }
5815 }
5816 }
5817 if (displayFlags & DRT_SHOW_LOCALS) {
5818 dexDecodeDebugInfo(meth->clazz->pDvmDex->pDexFile,
5819 dvmGetMethodCode(meth),
5820 meth->clazz->descriptor,
5821 meth->prototype.protoIdx,
5822 meth->accessFlags,
5823 NULL, logLocalsCb, &addr);
5824 }
5825}