blob: 20698488517a54e0fac63fd2a9562e88c02c7ed6 [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/*
Andy McFadden319a33b2010-11-10 07:55:14 -080093 * Big fat collection of register data.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080094 */
95typedef struct RegisterTable {
96 /*
Andy McFadden319a33b2010-11-10 07:55:14 -080097 * Array of RegisterLine structs, one per address in the method. We only
98 * set the pointers for certain addresses, based on instruction widths
99 * and what we're trying to accomplish.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800100 */
Andy McFadden319a33b2010-11-10 07:55:14 -0800101 RegisterLine* registerLines;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800102
103 /*
104 * Number of registers we track for each instruction. This is equal
105 * to the method's declared "registersSize" plus kExtraRegs.
106 */
Andy McFadden319a33b2010-11-10 07:55:14 -0800107 size_t insnRegCountPlus;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800108
109 /*
Andy McFadden319a33b2010-11-10 07:55:14 -0800110 * Storage for a register line we're currently working on.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800111 */
Andy McFadden319a33b2010-11-10 07:55:14 -0800112 RegisterLine workLine;
113
114 /*
115 * Storage for a register line we're saving for later.
116 */
117 RegisterLine savedLine;
118
119 /*
120 * A single large alloc, with all of the storage needed for RegisterLine
121 * data (RegType array, MonitorEntries array, monitor stack).
122 */
123 void* lineAlloc;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800124} RegisterTable;
125
126
127/* fwd */
Carl Shapiroe3c01da2010-05-20 22:54:18 -0700128#ifndef NDEBUG
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800129static void checkMergeTab(void);
Carl Shapiroe3c01da2010-05-20 22:54:18 -0700130#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800131static bool isInitMethod(const Method* meth);
Andy McFadden319a33b2010-11-10 07:55:14 -0800132static RegType getInvocationThis(const RegisterLine* registerLine,\
Andy McFaddend3250112010-11-03 14:32:42 -0700133 const DecodedInstruction* pDecInsn, VerifyError* pFailure);
Andy McFadden319a33b2010-11-10 07:55:14 -0800134static void verifyRegisterType(const RegisterLine* registerLine, \
Andy McFadden62a75162009-04-17 17:23:37 -0700135 u4 vsrc, RegType checkType, VerifyError* pFailure);
Andy McFadden228a6b02010-05-04 15:02:32 -0700136static bool doCodeVerification(const Method* meth, InsnFlags* insnFlags,\
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800137 RegisterTable* regTable, UninitInstanceMap* uninitMap);
Andy McFadden228a6b02010-05-04 15:02:32 -0700138static bool verifyInstruction(const Method* meth, InsnFlags* insnFlags,\
Andy McFadden319a33b2010-11-10 07:55:14 -0800139 RegisterTable* regTable, int insnIdx, UninitInstanceMap* uninitMap,
140 int* pStartGuess);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800141static ClassObject* findCommonSuperclass(ClassObject* c1, ClassObject* c2);
142static void dumpRegTypes(const Method* meth, const InsnFlags* insnFlags,\
Andy McFadden319a33b2010-11-10 07:55:14 -0800143 const RegisterLine* registerLine, int addr, const char* addrName,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800144 const UninitInstanceMap* uninitMap, int displayFlags);
145
146/* bit values for dumpRegTypes() "displayFlags" */
147enum {
148 DRT_SIMPLE = 0,
149 DRT_SHOW_REF_TYPES = 0x01,
150 DRT_SHOW_LOCALS = 0x02,
151};
152
153
154/*
155 * ===========================================================================
156 * RegType and UninitInstanceMap utility functions
157 * ===========================================================================
158 */
159
160#define __ kRegTypeUnknown
161#define _U kRegTypeUninit
162#define _X kRegTypeConflict
163#define _F kRegTypeFloat
164#define _0 kRegTypeZero
165#define _1 kRegTypeOne
166#define _Z kRegTypeBoolean
167#define _b kRegTypePosByte
168#define _B kRegTypeByte
169#define _s kRegTypePosShort
170#define _S kRegTypeShort
171#define _C kRegTypeChar
172#define _I kRegTypeInteger
173#define _J kRegTypeLongLo
174#define _j kRegTypeLongHi
175#define _D kRegTypeDoubleLo
176#define _d kRegTypeDoubleHi
177
178/*
179 * Merge result table for primitive values. The table is symmetric along
180 * the diagonal.
181 *
182 * Note that 32-bit int/float do not merge into 64-bit long/double. This
183 * is a register merge, not a widening conversion. Only the "implicit"
184 * widening within a category, e.g. byte to short, is allowed.
185 *
186 * Because Dalvik does not draw a distinction between int and float, we
187 * have to allow free exchange between 32-bit int/float and 64-bit
188 * long/double.
189 *
190 * Note that Uninit+Uninit=Uninit. This holds true because we only
191 * use this when the RegType value is exactly equal to kRegTypeUninit, which
192 * can only happen for the zeroeth entry in the table.
193 *
194 * "Unknown" never merges with anything known. The only time a register
195 * transitions from "unknown" to "known" is when we're executing code
196 * for the first time, and we handle that with a simple copy.
197 */
198const char gDvmMergeTab[kRegTypeMAX][kRegTypeMAX] =
199{
200 /* chk: _ U X F 0 1 Z b B s S C I J j D d */
201 { /*_*/ __,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X },
202 { /*U*/ _X,_U,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X },
203 { /*X*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X },
204 { /*F*/ _X,_X,_X,_F,_F,_F,_F,_F,_F,_F,_F,_F,_F,_X,_X,_X,_X },
205 { /*0*/ _X,_X,_X,_F,_0,_Z,_Z,_b,_B,_s,_S,_C,_I,_X,_X,_X,_X },
206 { /*1*/ _X,_X,_X,_F,_Z,_1,_Z,_b,_B,_s,_S,_C,_I,_X,_X,_X,_X },
207 { /*Z*/ _X,_X,_X,_F,_Z,_Z,_Z,_b,_B,_s,_S,_C,_I,_X,_X,_X,_X },
208 { /*b*/ _X,_X,_X,_F,_b,_b,_b,_b,_B,_s,_S,_C,_I,_X,_X,_X,_X },
209 { /*B*/ _X,_X,_X,_F,_B,_B,_B,_B,_B,_S,_S,_I,_I,_X,_X,_X,_X },
210 { /*s*/ _X,_X,_X,_F,_s,_s,_s,_s,_S,_s,_S,_C,_I,_X,_X,_X,_X },
211 { /*S*/ _X,_X,_X,_F,_S,_S,_S,_S,_S,_S,_S,_I,_I,_X,_X,_X,_X },
212 { /*C*/ _X,_X,_X,_F,_C,_C,_C,_C,_I,_C,_I,_C,_I,_X,_X,_X,_X },
213 { /*I*/ _X,_X,_X,_F,_I,_I,_I,_I,_I,_I,_I,_I,_I,_X,_X,_X,_X },
214 { /*J*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_J,_X,_J,_X },
215 { /*j*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_j,_X,_j },
216 { /*D*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_J,_X,_D,_X },
217 { /*d*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_j,_X,_d },
218};
219
220#undef __
221#undef _U
222#undef _X
223#undef _F
224#undef _0
225#undef _1
226#undef _Z
227#undef _b
228#undef _B
229#undef _s
230#undef _S
231#undef _C
232#undef _I
233#undef _J
234#undef _j
235#undef _D
236#undef _d
237
238#ifndef NDEBUG
239/*
240 * Verify symmetry in the conversion table.
241 */
242static void checkMergeTab(void)
243{
244 int i, j;
245
246 for (i = 0; i < kRegTypeMAX; i++) {
247 for (j = i; j < kRegTypeMAX; j++) {
248 if (gDvmMergeTab[i][j] != gDvmMergeTab[j][i]) {
249 LOGE("Symmetry violation: %d,%d vs %d,%d\n", i, j, j, i);
250 dvmAbort();
251 }
252 }
253 }
254}
255#endif
256
257/*
258 * Determine whether we can convert "srcType" to "checkType", where
259 * "checkType" is one of the category-1 non-reference types.
260 *
261 * 32-bit int and float are interchangeable.
262 */
263static bool canConvertTo1nr(RegType srcType, RegType checkType)
264{
265 static const char convTab
266 [kRegType1nrEND-kRegType1nrSTART+1][kRegType1nrEND-kRegType1nrSTART+1] =
267 {
268 /* chk: F 0 1 Z b B s S C I */
269 { /*F*/ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
270 { /*0*/ 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
271 { /*1*/ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 },
272 { /*Z*/ 1, 0, 0, 1, 1, 1, 1, 1, 1, 1 },
273 { /*b*/ 1, 0, 0, 0, 1, 1, 1, 1, 1, 1 },
274 { /*B*/ 1, 0, 0, 0, 0, 1, 0, 1, 0, 1 },
275 { /*s*/ 1, 0, 0, 0, 0, 0, 1, 1, 1, 1 },
276 { /*S*/ 1, 0, 0, 0, 0, 0, 0, 1, 0, 1 },
277 { /*C*/ 1, 0, 0, 0, 0, 0, 0, 0, 1, 1 },
278 { /*I*/ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
279 };
280
281 assert(checkType >= kRegType1nrSTART && checkType <= kRegType1nrEND);
282#if 0
283 if (checkType < kRegType1nrSTART || checkType > kRegType1nrEND) {
284 LOG_VFY("Unexpected checkType %d (srcType=%d)\n", checkType, srcType);
285 assert(false);
286 return false;
287 }
288#endif
289
290 //printf("convTab[%d][%d] = %d\n", srcType, checkType,
291 // convTab[srcType-kRegType1nrSTART][checkType-kRegType1nrSTART]);
292 if (srcType >= kRegType1nrSTART && srcType <= kRegType1nrEND)
293 return (bool) convTab[srcType-kRegType1nrSTART][checkType-kRegType1nrSTART];
294
295 return false;
296}
297
298/*
299 * Determine whether the types are compatible. In Dalvik, 64-bit doubles
300 * and longs are interchangeable.
301 */
302static bool canConvertTo2(RegType srcType, RegType checkType)
303{
304 return ((srcType == kRegTypeLongLo || srcType == kRegTypeDoubleLo) &&
305 (checkType == kRegTypeLongLo || checkType == kRegTypeDoubleLo));
306}
307
308/*
309 * Determine whether or not "instrType" and "targetType" are compatible,
310 * for purposes of getting or setting a value in a field or array. The
311 * idea is that an instruction with a category 1nr type (say, aget-short
312 * or iput-boolean) is accessing a static field, instance field, or array
313 * entry, and we want to make sure sure that the operation is legal.
314 *
315 * At a minimum, source and destination must have the same width. We
316 * further refine this to assert that "short" and "char" are not
317 * compatible, because the sign-extension is different on the "get"
318 * operations. As usual, "float" and "int" are interoperable.
319 *
320 * We're not considering the actual contents of the register, so we'll
321 * never get "pseudo-types" like kRegTypeZero or kRegTypePosShort. We
322 * could get kRegTypeUnknown in "targetType" if a field or array class
323 * lookup failed. Category 2 types and references are checked elsewhere.
324 */
325static bool checkFieldArrayStore1nr(RegType instrType, RegType targetType)
326{
327 if (instrType == targetType)
328 return true; /* quick positive; most common case */
329
330 if ((instrType == kRegTypeInteger && targetType == kRegTypeFloat) ||
331 (instrType == kRegTypeFloat && targetType == kRegTypeInteger))
332 {
333 return true;
334 }
335
336 return false;
337}
338
339/*
340 * Convert a VM PrimitiveType enum value to the equivalent RegType value.
341 */
342static RegType primitiveTypeToRegType(PrimitiveType primType)
343{
The Android Open Source Project99409882009-03-18 22:20:24 -0700344 static const struct {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800345 RegType regType; /* type equivalent */
346 PrimitiveType primType; /* verification */
347 } convTab[] = {
348 /* must match order of enum in Object.h */
349 { kRegTypeBoolean, PRIM_BOOLEAN },
350 { kRegTypeChar, PRIM_CHAR },
351 { kRegTypeFloat, PRIM_FLOAT },
352 { kRegTypeDoubleLo, PRIM_DOUBLE },
353 { kRegTypeByte, PRIM_BYTE },
354 { kRegTypeShort, PRIM_SHORT },
355 { kRegTypeInteger, PRIM_INT },
356 { kRegTypeLongLo, PRIM_LONG },
357 // PRIM_VOID
358 };
359
360 if (primType < 0 || primType > (int) (sizeof(convTab) / sizeof(convTab[0])))
361 {
362 assert(false);
363 return kRegTypeUnknown;
364 }
365
366 assert(convTab[primType].primType == primType);
367 return convTab[primType].regType;
368}
369
370/*
Andy McFadden470cbbb2010-11-04 16:31:37 -0700371 * Given a 32-bit constant, return the most-restricted RegType enum entry
372 * that can hold the value.
373 */
374static char determineCat1Const(s4 value)
375{
376 if (value < -32768)
377 return kRegTypeInteger;
378 else if (value < -128)
379 return kRegTypeShort;
380 else if (value < 0)
381 return kRegTypeByte;
382 else if (value == 0)
383 return kRegTypeZero;
384 else if (value == 1)
385 return kRegTypeOne;
386 else if (value < 128)
387 return kRegTypePosByte;
388 else if (value < 32768)
389 return kRegTypePosShort;
390 else if (value < 65536)
391 return kRegTypeChar;
392 else
393 return kRegTypeInteger;
394}
395
396/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800397 * Create a new uninitialized instance map.
398 *
399 * The map is allocated and populated with address entries. The addresses
400 * appear in ascending order to allow binary searching.
401 *
402 * Very few methods have 10 or more new-instance instructions; the
403 * majority have 0 or 1. Occasionally a static initializer will have 200+.
Andy McFadden319a33b2010-11-10 07:55:14 -0800404 *
405 * TODO: merge this into the static pass; want to avoid walking through
406 * the instructions yet again just to set up this table
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800407 */
408UninitInstanceMap* dvmCreateUninitInstanceMap(const Method* meth,
409 const InsnFlags* insnFlags, int newInstanceCount)
410{
411 const int insnsSize = dvmGetMethodInsnsSize(meth);
412 const u2* insns = meth->insns;
413 UninitInstanceMap* uninitMap;
414 bool isInit = false;
415 int idx, addr;
416
417 if (isInitMethod(meth)) {
418 newInstanceCount++;
419 isInit = true;
420 }
421
422 /*
423 * Allocate the header and map as a single unit.
424 *
425 * TODO: consider having a static instance so we can avoid allocations.
426 * I don't think the verifier is guaranteed to be single-threaded when
427 * running in the VM (rather than dexopt), so that must be taken into
428 * account.
429 */
430 int size = offsetof(UninitInstanceMap, map) +
431 newInstanceCount * sizeof(uninitMap->map[0]);
432 uninitMap = calloc(1, size);
433 if (uninitMap == NULL)
434 return NULL;
435 uninitMap->numEntries = newInstanceCount;
436
437 idx = 0;
438 if (isInit) {
439 uninitMap->map[idx++].addr = kUninitThisArgAddr;
440 }
441
442 /*
443 * Run through and find the new-instance instructions.
444 */
445 for (addr = 0; addr < insnsSize; /**/) {
446 int width = dvmInsnGetWidth(insnFlags, addr);
447
448 if ((*insns & 0xff) == OP_NEW_INSTANCE)
449 uninitMap->map[idx++].addr = addr;
450
451 addr += width;
452 insns += width;
453 }
454
455 assert(idx == newInstanceCount);
456 return uninitMap;
457}
458
459/*
460 * Free the map.
461 */
462void dvmFreeUninitInstanceMap(UninitInstanceMap* uninitMap)
463{
464 free(uninitMap);
465}
466
467/*
468 * Set the class object associated with the instruction at "addr".
469 *
470 * Returns the map slot index, or -1 if the address isn't listed in the map
471 * (shouldn't happen) or if a class is already associated with the address
472 * (bad bytecode).
473 *
474 * Entries, once set, do not change -- a given address can only allocate
475 * one type of object.
476 */
477int dvmSetUninitInstance(UninitInstanceMap* uninitMap, int addr,
478 ClassObject* clazz)
479{
480 int idx;
481
482 assert(clazz != NULL);
483
484 /* TODO: binary search when numEntries > 8 */
485 for (idx = uninitMap->numEntries - 1; idx >= 0; idx--) {
486 if (uninitMap->map[idx].addr == addr) {
487 if (uninitMap->map[idx].clazz != NULL &&
488 uninitMap->map[idx].clazz != clazz)
489 {
490 LOG_VFY("VFY: addr %d already set to %p, not setting to %p\n",
491 addr, uninitMap->map[idx].clazz, clazz);
492 return -1; // already set to something else??
493 }
494 uninitMap->map[idx].clazz = clazz;
495 return idx;
496 }
497 }
498
499 LOG_VFY("VFY: addr %d not found in uninit map\n", addr);
500 assert(false); // shouldn't happen
501 return -1;
502}
503
504/*
505 * Get the class object at the specified index.
506 */
507ClassObject* dvmGetUninitInstance(const UninitInstanceMap* uninitMap, int idx)
508{
509 assert(idx >= 0 && idx < uninitMap->numEntries);
510 return uninitMap->map[idx].clazz;
511}
512
513/* determine if "type" is actually an object reference (init/uninit/zero) */
514static inline bool regTypeIsReference(RegType type) {
515 return (type > kRegTypeMAX || type == kRegTypeUninit ||
516 type == kRegTypeZero);
517}
518
519/* determine if "type" is an uninitialized object reference */
520static inline bool regTypeIsUninitReference(RegType type) {
521 return ((type & kRegTypeUninitMask) == kRegTypeUninit);
522}
523
524/* convert the initialized reference "type" to a ClassObject pointer */
525/* (does not expect uninit ref types or "zero") */
526static ClassObject* regTypeInitializedReferenceToClass(RegType type)
527{
528 assert(regTypeIsReference(type) && type != kRegTypeZero);
529 if ((type & 0x01) == 0) {
530 return (ClassObject*) type;
531 } else {
532 //LOG_VFY("VFY: attempted to use uninitialized reference\n");
533 return NULL;
534 }
535}
536
537/* extract the index into the uninitialized instance map table */
538static inline int regTypeToUninitIndex(RegType type) {
539 assert(regTypeIsUninitReference(type));
540 return (type & ~kRegTypeUninitMask) >> kRegTypeUninitShift;
541}
542
543/* convert the reference "type" to a ClassObject pointer */
544static ClassObject* regTypeReferenceToClass(RegType type,
545 const UninitInstanceMap* uninitMap)
546{
547 assert(regTypeIsReference(type) && type != kRegTypeZero);
548 if (regTypeIsUninitReference(type)) {
549 assert(uninitMap != NULL);
550 return dvmGetUninitInstance(uninitMap, regTypeToUninitIndex(type));
551 } else {
552 return (ClassObject*) type;
553 }
554}
555
556/* convert the ClassObject pointer to an (initialized) register type */
557static inline RegType regTypeFromClass(ClassObject* clazz) {
558 return (u4) clazz;
559}
560
561/* return the RegType for the uninitialized reference in slot "uidx" */
562static RegType regTypeFromUninitIndex(int uidx) {
563 return (u4) (kRegTypeUninit | (uidx << kRegTypeUninitShift));
564}
565
566
567/*
568 * ===========================================================================
569 * Signature operations
570 * ===========================================================================
571 */
572
573/*
574 * Is this method a constructor?
575 */
576static bool isInitMethod(const Method* meth)
577{
578 return (*meth->name == '<' && strcmp(meth->name+1, "init>") == 0);
579}
580
581/*
582 * Is this method a class initializer?
583 */
Carl Shapiroe3c01da2010-05-20 22:54:18 -0700584#if 0
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800585static bool isClassInitMethod(const Method* meth)
586{
587 return (*meth->name == '<' && strcmp(meth->name+1, "clinit>") == 0);
588}
Carl Shapiroe3c01da2010-05-20 22:54:18 -0700589#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800590
591/*
592 * Look up a class reference given as a simple string descriptor.
Andy McFadden62a75162009-04-17 17:23:37 -0700593 *
594 * If we can't find it, return a generic substitute when possible.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800595 */
596static ClassObject* lookupClassByDescriptor(const Method* meth,
Andy McFadden62a75162009-04-17 17:23:37 -0700597 const char* pDescriptor, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800598{
599 /*
600 * The javac compiler occasionally puts references to nonexistent
601 * classes in signatures. For example, if you have a non-static
602 * inner class with no constructor, the compiler provides
603 * a private <init> for you. Constructing the class
604 * requires <init>(parent), but the outer class can't call
605 * that because the method is private. So the compiler
606 * generates a package-scope <init>(parent,bogus) method that
607 * just calls the regular <init> (the "bogus" part being necessary
608 * to distinguish the signature of the synthetic method).
609 * Treating the bogus class as an instance of java.lang.Object
610 * allows the verifier to process the class successfully.
611 */
612
613 //LOGI("Looking up '%s'\n", typeStr);
614 ClassObject* clazz;
615 clazz = dvmFindClassNoInit(pDescriptor, meth->clazz->classLoader);
616 if (clazz == NULL) {
617 dvmClearOptException(dvmThreadSelf());
618 if (strchr(pDescriptor, '$') != NULL) {
619 LOGV("VFY: unable to find class referenced in signature (%s)\n",
620 pDescriptor);
621 } else {
622 LOG_VFY("VFY: unable to find class referenced in signature (%s)\n",
623 pDescriptor);
624 }
625
626 if (pDescriptor[0] == '[') {
627 /* We are looking at an array descriptor. */
628
629 /*
630 * There should never be a problem loading primitive arrays.
631 */
632 if (pDescriptor[1] != 'L' && pDescriptor[1] != '[') {
633 LOG_VFY("VFY: invalid char in signature in '%s'\n",
634 pDescriptor);
Andy McFadden62a75162009-04-17 17:23:37 -0700635 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800636 }
637
638 /*
639 * Try to continue with base array type. This will let
640 * us pass basic stuff (e.g. get array len) that wouldn't
641 * fly with an Object. This is NOT correct if the
642 * missing type is a primitive array, but we should never
643 * have a problem loading those. (I'm not convinced this
644 * is correct or even useful. Just use Object here?)
645 */
646 clazz = dvmFindClassNoInit("[Ljava/lang/Object;",
647 meth->clazz->classLoader);
648 } else if (pDescriptor[0] == 'L') {
649 /*
650 * We are looking at a non-array reference descriptor;
651 * try to continue with base reference type.
652 */
653 clazz = gDvm.classJavaLangObject;
654 } else {
655 /* We are looking at a primitive type. */
656 LOG_VFY("VFY: invalid char in signature in '%s'\n", pDescriptor);
Andy McFadden62a75162009-04-17 17:23:37 -0700657 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800658 }
659
660 if (clazz == NULL) {
Andy McFadden62a75162009-04-17 17:23:37 -0700661 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800662 }
663 }
664
665 if (dvmIsPrimitiveClass(clazz)) {
666 LOG_VFY("VFY: invalid use of primitive type '%s'\n", pDescriptor);
Andy McFadden62a75162009-04-17 17:23:37 -0700667 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800668 clazz = NULL;
669 }
670
671 return clazz;
672}
673
674/*
675 * Look up a class reference in a signature. Could be an arg or the
676 * return value.
677 *
678 * Advances "*pSig" to the last character in the signature (that is, to
679 * the ';').
680 *
681 * NOTE: this is also expected to verify the signature.
682 */
683static ClassObject* lookupSignatureClass(const Method* meth, const char** pSig,
Andy McFadden62a75162009-04-17 17:23:37 -0700684 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800685{
686 const char* sig = *pSig;
687 const char* endp = sig;
688
689 assert(sig != NULL && *sig == 'L');
690
691 while (*++endp != ';' && *endp != '\0')
692 ;
693 if (*endp != ';') {
694 LOG_VFY("VFY: bad signature component '%s' (missing ';')\n", sig);
Andy McFadden62a75162009-04-17 17:23:37 -0700695 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800696 return NULL;
697 }
698
699 endp++; /* Advance past the ';'. */
700 int typeLen = endp - sig;
701 char typeStr[typeLen+1]; /* +1 for the '\0' */
702 memcpy(typeStr, sig, typeLen);
703 typeStr[typeLen] = '\0';
704
705 *pSig = endp - 1; /* - 1 so that *pSig points at, not past, the ';' */
706
Andy McFadden62a75162009-04-17 17:23:37 -0700707 return lookupClassByDescriptor(meth, typeStr, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800708}
709
710/*
711 * Look up an array class reference in a signature. Could be an arg or the
712 * return value.
713 *
714 * Advances "*pSig" to the last character in the signature.
715 *
716 * NOTE: this is also expected to verify the signature.
717 */
718static ClassObject* lookupSignatureArrayClass(const Method* meth,
Andy McFadden62a75162009-04-17 17:23:37 -0700719 const char** pSig, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800720{
721 const char* sig = *pSig;
722 const char* endp = sig;
723
724 assert(sig != NULL && *sig == '[');
725
726 /* find the end */
727 while (*++endp == '[' && *endp != '\0')
728 ;
729
730 if (*endp == 'L') {
731 while (*++endp != ';' && *endp != '\0')
732 ;
733 if (*endp != ';') {
734 LOG_VFY("VFY: bad signature component '%s' (missing ';')\n", sig);
Andy McFadden62a75162009-04-17 17:23:37 -0700735 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800736 return NULL;
737 }
738 }
739
740 int typeLen = endp - sig +1;
741 char typeStr[typeLen+1];
742 memcpy(typeStr, sig, typeLen);
743 typeStr[typeLen] = '\0';
744
745 *pSig = endp;
746
Andy McFadden62a75162009-04-17 17:23:37 -0700747 return lookupClassByDescriptor(meth, typeStr, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800748}
749
750/*
751 * Set the register types for the first instruction in the method based on
752 * the method signature.
753 *
754 * This has the side-effect of validating the signature.
755 *
756 * Returns "true" on success.
757 */
758static bool setTypesFromSignature(const Method* meth, RegType* regTypes,
759 UninitInstanceMap* uninitMap)
760{
761 DexParameterIterator iterator;
762 int actualArgs, expectedArgs, argStart;
Andy McFadden62a75162009-04-17 17:23:37 -0700763 VerifyError failure = VERIFY_ERROR_NONE;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800764
765 dexParameterIteratorInit(&iterator, &meth->prototype);
766 argStart = meth->registersSize - meth->insSize;
767 expectedArgs = meth->insSize; /* long/double count as two */
768 actualArgs = 0;
769
770 assert(argStart >= 0); /* should have been verified earlier */
771
772 /*
773 * Include the "this" pointer.
774 */
775 if (!dvmIsStaticMethod(meth)) {
776 /*
777 * If this is a constructor for a class other than java.lang.Object,
778 * mark the first ("this") argument as uninitialized. This restricts
779 * field access until the superclass constructor is called.
780 */
781 if (isInitMethod(meth) && meth->clazz != gDvm.classJavaLangObject) {
782 int uidx = dvmSetUninitInstance(uninitMap, kUninitThisArgAddr,
783 meth->clazz);
784 assert(uidx == 0);
785 regTypes[argStart + actualArgs] = regTypeFromUninitIndex(uidx);
786 } else {
787 regTypes[argStart + actualArgs] = regTypeFromClass(meth->clazz);
788 }
789 actualArgs++;
790 }
791
792 for (;;) {
793 const char* descriptor = dexParameterIteratorNextDescriptor(&iterator);
794
795 if (descriptor == NULL) {
796 break;
797 }
798
799 if (actualArgs >= expectedArgs) {
800 LOG_VFY("VFY: expected %d args, found more (%s)\n",
801 expectedArgs, descriptor);
802 goto bad_sig;
803 }
804
805 switch (*descriptor) {
806 case 'L':
807 case '[':
808 /*
809 * We assume that reference arguments are initialized. The
810 * only way it could be otherwise (assuming the caller was
811 * verified) is if the current method is <init>, but in that
812 * case it's effectively considered initialized the instant
813 * we reach here (in the sense that we can return without
814 * doing anything or call virtual methods).
815 */
816 {
817 ClassObject* clazz =
Andy McFadden62a75162009-04-17 17:23:37 -0700818 lookupClassByDescriptor(meth, descriptor, &failure);
819 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800820 goto bad_sig;
821 regTypes[argStart + actualArgs] = regTypeFromClass(clazz);
822 }
823 actualArgs++;
824 break;
825 case 'Z':
826 regTypes[argStart + actualArgs] = kRegTypeBoolean;
827 actualArgs++;
828 break;
829 case 'C':
830 regTypes[argStart + actualArgs] = kRegTypeChar;
831 actualArgs++;
832 break;
833 case 'B':
834 regTypes[argStart + actualArgs] = kRegTypeByte;
835 actualArgs++;
836 break;
837 case 'I':
838 regTypes[argStart + actualArgs] = kRegTypeInteger;
839 actualArgs++;
840 break;
841 case 'S':
842 regTypes[argStart + actualArgs] = kRegTypeShort;
843 actualArgs++;
844 break;
845 case 'F':
846 regTypes[argStart + actualArgs] = kRegTypeFloat;
847 actualArgs++;
848 break;
849 case 'D':
850 regTypes[argStart + actualArgs] = kRegTypeDoubleLo;
851 regTypes[argStart + actualArgs +1] = kRegTypeDoubleHi;
852 actualArgs += 2;
853 break;
854 case 'J':
855 regTypes[argStart + actualArgs] = kRegTypeLongLo;
856 regTypes[argStart + actualArgs +1] = kRegTypeLongHi;
857 actualArgs += 2;
858 break;
859 default:
860 LOG_VFY("VFY: unexpected signature type char '%c'\n", *descriptor);
861 goto bad_sig;
862 }
863 }
864
865 if (actualArgs != expectedArgs) {
866 LOG_VFY("VFY: expected %d args, found %d\n", expectedArgs, actualArgs);
867 goto bad_sig;
868 }
869
870 const char* descriptor = dexProtoGetReturnType(&meth->prototype);
871
872 /*
873 * Validate return type. We don't do the type lookup; just want to make
874 * sure that it has the right format. Only major difference from the
875 * method argument format is that 'V' is supported.
876 */
877 switch (*descriptor) {
878 case 'I':
879 case 'C':
880 case 'S':
881 case 'B':
882 case 'Z':
883 case 'V':
884 case 'F':
885 case 'D':
886 case 'J':
887 if (*(descriptor+1) != '\0')
888 goto bad_sig;
889 break;
890 case '[':
891 /* single/multi, object/primitive */
892 while (*++descriptor == '[')
893 ;
894 if (*descriptor == 'L') {
895 while (*++descriptor != ';' && *descriptor != '\0')
896 ;
897 if (*descriptor != ';')
898 goto bad_sig;
899 } else {
900 if (*(descriptor+1) != '\0')
901 goto bad_sig;
902 }
903 break;
904 case 'L':
905 /* could be more thorough here, but shouldn't be required */
906 while (*++descriptor != ';' && *descriptor != '\0')
907 ;
908 if (*descriptor != ';')
909 goto bad_sig;
910 break;
911 default:
912 goto bad_sig;
913 }
914
915 return true;
916
917//fail:
918// LOG_VFY_METH(meth, "VFY: bad sig\n");
919// return false;
920
921bad_sig:
922 {
923 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
924 LOG_VFY("VFY: bad signature '%s' for %s.%s\n",
925 desc, meth->clazz->descriptor, meth->name);
926 free(desc);
927 }
928 return false;
929}
930
931/*
932 * Return the register type for the method. We can't just use the
933 * already-computed DalvikJniReturnType, because if it's a reference type
934 * we need to do the class lookup.
935 *
936 * Returned references are assumed to be initialized.
937 *
938 * Returns kRegTypeUnknown for "void".
939 */
940static RegType getMethodReturnType(const Method* meth)
941{
942 RegType type;
943 const char* descriptor = dexProtoGetReturnType(&meth->prototype);
944
945 switch (*descriptor) {
946 case 'I':
947 type = kRegTypeInteger;
948 break;
949 case 'C':
950 type = kRegTypeChar;
951 break;
952 case 'S':
953 type = kRegTypeShort;
954 break;
955 case 'B':
956 type = kRegTypeByte;
957 break;
958 case 'Z':
959 type = kRegTypeBoolean;
960 break;
961 case 'V':
962 type = kRegTypeUnknown;
963 break;
964 case 'F':
965 type = kRegTypeFloat;
966 break;
967 case 'D':
968 type = kRegTypeDoubleLo;
969 break;
970 case 'J':
971 type = kRegTypeLongLo;
972 break;
973 case 'L':
974 case '[':
975 {
Andy McFadden62a75162009-04-17 17:23:37 -0700976 VerifyError failure = VERIFY_ERROR_NONE;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800977 ClassObject* clazz =
Andy McFadden62a75162009-04-17 17:23:37 -0700978 lookupClassByDescriptor(meth, descriptor, &failure);
979 assert(VERIFY_OK(failure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800980 type = regTypeFromClass(clazz);
981 }
982 break;
983 default:
984 /* we verified signature return type earlier, so this is impossible */
985 assert(false);
986 type = kRegTypeConflict;
987 break;
988 }
989
990 return type;
991}
992
993/*
994 * Convert a single-character signature value (i.e. a primitive type) to
995 * the corresponding RegType. This is intended for access to object fields
996 * holding primitive types.
997 *
998 * Returns kRegTypeUnknown for objects, arrays, and void.
999 */
1000static RegType primSigCharToRegType(char sigChar)
1001{
1002 RegType type;
1003
1004 switch (sigChar) {
1005 case 'I':
1006 type = kRegTypeInteger;
1007 break;
1008 case 'C':
1009 type = kRegTypeChar;
1010 break;
1011 case 'S':
1012 type = kRegTypeShort;
1013 break;
1014 case 'B':
1015 type = kRegTypeByte;
1016 break;
1017 case 'Z':
1018 type = kRegTypeBoolean;
1019 break;
1020 case 'F':
1021 type = kRegTypeFloat;
1022 break;
1023 case 'D':
1024 type = kRegTypeDoubleLo;
1025 break;
1026 case 'J':
1027 type = kRegTypeLongLo;
1028 break;
1029 case 'V':
1030 case 'L':
1031 case '[':
1032 type = kRegTypeUnknown;
1033 break;
1034 default:
1035 assert(false);
1036 type = kRegTypeUnknown;
1037 break;
1038 }
1039
1040 return type;
1041}
1042
1043/*
Andy McFadden99a33e72010-10-10 12:59:11 -07001044 * See if the method matches the MethodType.
1045 */
1046static bool isCorrectInvokeKind(MethodType methodType, Method* resMethod)
1047{
1048 switch (methodType) {
1049 case METHOD_DIRECT:
1050 return dvmIsDirectMethod(resMethod);
1051 case METHOD_STATIC:
1052 return dvmIsStaticMethod(resMethod);
1053 case METHOD_VIRTUAL:
1054 case METHOD_INTERFACE:
1055 return !dvmIsDirectMethod(resMethod);
1056 default:
1057 return false;
1058 }
1059}
1060
1061/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001062 * Verify the arguments to a method. We're executing in "method", making
1063 * a call to the method reference in vB.
1064 *
1065 * If this is a "direct" invoke, we allow calls to <init>. For calls to
1066 * <init>, the first argument may be an uninitialized reference. Otherwise,
1067 * calls to anything starting with '<' will be rejected, as will any
1068 * uninitialized reference arguments.
1069 *
1070 * For non-static method calls, this will verify that the method call is
1071 * appropriate for the "this" argument.
1072 *
1073 * The method reference is in vBBBB. The "isRange" parameter determines
1074 * whether we use 0-4 "args" values or a range of registers defined by
1075 * vAA and vCCCC.
1076 *
1077 * Widening conversions on integers and references are allowed, but
1078 * narrowing conversions are not.
1079 *
Andy McFadden62a75162009-04-17 17:23:37 -07001080 * Returns the resolved method on success, NULL on failure (with *pFailure
1081 * set appropriately).
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001082 */
Andy McFadden319a33b2010-11-10 07:55:14 -08001083static Method* verifyInvocationArgs(const Method* meth,
1084 const RegisterLine* registerLine, const int insnRegCount,
1085 const DecodedInstruction* pDecInsn, UninitInstanceMap* uninitMap,
1086 MethodType methodType, bool isRange, bool isSuper, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001087{
1088 Method* resMethod;
1089 char* sigOriginal = NULL;
1090
1091 /*
1092 * Resolve the method. This could be an abstract or concrete method
1093 * depending on what sort of call we're making.
1094 */
1095 if (methodType == METHOD_INTERFACE) {
1096 resMethod = dvmOptResolveInterfaceMethod(meth->clazz, pDecInsn->vB);
1097 } else {
Andy McFadden62a75162009-04-17 17:23:37 -07001098 resMethod = dvmOptResolveMethod(meth->clazz, pDecInsn->vB, methodType,
1099 pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001100 }
1101 if (resMethod == NULL) {
1102 /* failed; print a meaningful failure message */
1103 DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
1104 const DexMethodId* pMethodId;
1105 const char* methodName;
1106 char* methodDesc;
1107 const char* classDescriptor;
1108
1109 pMethodId = dexGetMethodId(pDexFile, pDecInsn->vB);
1110 methodName = dexStringById(pDexFile, pMethodId->nameIdx);
1111 methodDesc = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
1112 classDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
1113
1114 if (!gDvm.optimizing) {
1115 char* dotMissingClass = dvmDescriptorToDot(classDescriptor);
1116 char* dotMethClass = dvmDescriptorToDot(meth->clazz->descriptor);
1117 //char* curMethodDesc =
1118 // dexProtoCopyMethodDescriptor(&meth->prototype);
1119
Andy McFadden99a33e72010-10-10 12:59:11 -07001120 LOGI("Could not find method %s.%s, referenced from method %s.%s\n",
1121 dotMissingClass, methodName/*, methodDesc*/,
1122 dotMethClass, meth->name/*, curMethodDesc*/);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001123
1124 free(dotMissingClass);
1125 free(dotMethClass);
1126 //free(curMethodDesc);
1127 }
1128
1129 LOG_VFY("VFY: unable to resolve %s method %u: %s.%s %s\n",
1130 dvmMethodTypeStr(methodType), pDecInsn->vB,
1131 classDescriptor, methodName, methodDesc);
1132 free(methodDesc);
Andy McFaddenb51ea112009-05-08 16:50:17 -07001133 if (VERIFY_OK(*pFailure)) /* not set for interface resolve */
1134 *pFailure = VERIFY_ERROR_NO_METHOD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001135 goto fail;
1136 }
1137
1138 /*
1139 * Only time you can explicitly call a method starting with '<' is when
1140 * making a "direct" invocation on "<init>". There are additional
1141 * restrictions but we don't enforce them here.
1142 */
1143 if (resMethod->name[0] == '<') {
1144 if (methodType != METHOD_DIRECT || !isInitMethod(resMethod)) {
1145 LOG_VFY("VFY: invalid call to %s.%s\n",
1146 resMethod->clazz->descriptor, resMethod->name);
1147 goto bad_sig;
1148 }
1149 }
1150
1151 /*
Andy McFadden99a33e72010-10-10 12:59:11 -07001152 * See if the method type implied by the invoke instruction matches the
1153 * access flags for the target method.
1154 */
1155 if (!isCorrectInvokeKind(methodType, resMethod)) {
1156 LOG_VFY("VFY: invoke type does not match method type of %s.%s\n",
1157 resMethod->clazz->descriptor, resMethod->name);
1158 goto fail;
1159 }
1160
1161 /*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001162 * If we're using invoke-super(method), make sure that the executing
1163 * method's class' superclass has a vtable entry for the target method.
1164 */
1165 if (isSuper) {
1166 assert(methodType == METHOD_VIRTUAL);
1167 ClassObject* super = meth->clazz->super;
1168 if (super == NULL || resMethod->methodIndex > super->vtableCount) {
1169 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1170 LOG_VFY("VFY: invalid invoke-super from %s.%s to super %s.%s %s\n",
1171 meth->clazz->descriptor, meth->name,
1172 (super == NULL) ? "-" : super->descriptor,
1173 resMethod->name, desc);
1174 free(desc);
Andy McFadden62a75162009-04-17 17:23:37 -07001175 *pFailure = VERIFY_ERROR_NO_METHOD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001176 goto fail;
1177 }
1178 }
1179
1180 /*
1181 * We use vAA as our expected arg count, rather than resMethod->insSize,
1182 * because we need to match the call to the signature. Also, we might
1183 * might be calling through an abstract method definition (which doesn't
1184 * have register count values).
1185 */
1186 sigOriginal = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1187 const char* sig = sigOriginal;
1188 int expectedArgs = pDecInsn->vA;
1189 int actualArgs = 0;
1190
Andy McFaddend3250112010-11-03 14:32:42 -07001191 /* caught by static verifier */
1192 assert(isRange || expectedArgs <= 5);
1193
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001194 if (expectedArgs > meth->outsSize) {
1195 LOG_VFY("VFY: invalid arg count (%d) exceeds outsSize (%d)\n",
1196 expectedArgs, meth->outsSize);
1197 goto fail;
1198 }
1199
1200 if (*sig++ != '(')
1201 goto bad_sig;
1202
1203 /*
1204 * Check the "this" argument, which must be an instance of the class
1205 * that declared the method. For an interface class, we don't do the
1206 * full interface merge, so we can't do a rigorous check here (which
1207 * is okay since we have to do it at runtime).
1208 */
1209 if (!dvmIsStaticMethod(resMethod)) {
1210 ClassObject* actualThisRef;
1211 RegType actualArgType;
1212
Andy McFadden319a33b2010-11-10 07:55:14 -08001213 actualArgType = getInvocationThis(registerLine, pDecInsn, pFailure);
Andy McFadden62a75162009-04-17 17:23:37 -07001214 if (!VERIFY_OK(*pFailure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001215 goto fail;
1216
1217 if (regTypeIsUninitReference(actualArgType) && resMethod->name[0] != '<')
1218 {
1219 LOG_VFY("VFY: 'this' arg must be initialized\n");
1220 goto fail;
1221 }
1222 if (methodType != METHOD_INTERFACE && actualArgType != kRegTypeZero) {
1223 actualThisRef = regTypeReferenceToClass(actualArgType, uninitMap);
1224 if (!dvmInstanceof(actualThisRef, resMethod->clazz)) {
1225 LOG_VFY("VFY: 'this' arg '%s' not instance of '%s'\n",
1226 actualThisRef->descriptor,
1227 resMethod->clazz->descriptor);
1228 goto fail;
1229 }
1230 }
1231 actualArgs++;
1232 }
1233
1234 /*
1235 * Process the target method's signature. This signature may or may not
1236 * have been verified, so we can't assume it's properly formed.
1237 */
1238 while (*sig != '\0' && *sig != ')') {
1239 if (actualArgs >= expectedArgs) {
1240 LOG_VFY("VFY: expected %d args, found more (%c)\n",
1241 expectedArgs, *sig);
1242 goto bad_sig;
1243 }
1244
1245 u4 getReg;
1246 if (isRange)
1247 getReg = pDecInsn->vC + actualArgs;
1248 else
1249 getReg = pDecInsn->arg[actualArgs];
1250
1251 switch (*sig) {
1252 case 'L':
1253 {
Andy McFadden62a75162009-04-17 17:23:37 -07001254 ClassObject* clazz = lookupSignatureClass(meth, &sig, pFailure);
1255 if (!VERIFY_OK(*pFailure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001256 goto bad_sig;
Andy McFadden319a33b2010-11-10 07:55:14 -08001257 verifyRegisterType(registerLine, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001258 regTypeFromClass(clazz), pFailure);
1259 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001260 LOG_VFY("VFY: bad arg %d (into %s)\n",
1261 actualArgs, clazz->descriptor);
1262 goto bad_sig;
1263 }
1264 }
1265 actualArgs++;
1266 break;
1267 case '[':
1268 {
1269 ClassObject* clazz =
Andy McFadden62a75162009-04-17 17:23:37 -07001270 lookupSignatureArrayClass(meth, &sig, pFailure);
1271 if (!VERIFY_OK(*pFailure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001272 goto bad_sig;
Andy McFadden319a33b2010-11-10 07:55:14 -08001273 verifyRegisterType(registerLine, getReg,
Andy McFadden62a75162009-04-17 17:23:37 -07001274 regTypeFromClass(clazz), pFailure);
1275 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001276 LOG_VFY("VFY: bad arg %d (into %s)\n",
1277 actualArgs, clazz->descriptor);
1278 goto bad_sig;
1279 }
1280 }
1281 actualArgs++;
1282 break;
1283 case 'Z':
Andy McFadden319a33b2010-11-10 07:55:14 -08001284 verifyRegisterType(registerLine, getReg, kRegTypeBoolean, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001285 actualArgs++;
1286 break;
1287 case 'C':
Andy McFadden319a33b2010-11-10 07:55:14 -08001288 verifyRegisterType(registerLine, getReg, kRegTypeChar, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001289 actualArgs++;
1290 break;
1291 case 'B':
Andy McFadden319a33b2010-11-10 07:55:14 -08001292 verifyRegisterType(registerLine, getReg, kRegTypeByte, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001293 actualArgs++;
1294 break;
1295 case 'I':
Andy McFadden319a33b2010-11-10 07:55:14 -08001296 verifyRegisterType(registerLine, getReg, kRegTypeInteger, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001297 actualArgs++;
1298 break;
1299 case 'S':
Andy McFadden319a33b2010-11-10 07:55:14 -08001300 verifyRegisterType(registerLine, getReg, kRegTypeShort, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001301 actualArgs++;
1302 break;
1303 case 'F':
Andy McFadden319a33b2010-11-10 07:55:14 -08001304 verifyRegisterType(registerLine, getReg, kRegTypeFloat, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001305 actualArgs++;
1306 break;
1307 case 'D':
Andy McFadden319a33b2010-11-10 07:55:14 -08001308 verifyRegisterType(registerLine, getReg, kRegTypeDoubleLo, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001309 actualArgs += 2;
1310 break;
1311 case 'J':
Andy McFadden319a33b2010-11-10 07:55:14 -08001312 verifyRegisterType(registerLine, getReg, kRegTypeLongLo, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001313 actualArgs += 2;
1314 break;
1315 default:
1316 LOG_VFY("VFY: invocation target: bad signature type char '%c'\n",
1317 *sig);
1318 goto bad_sig;
1319 }
1320
1321 sig++;
1322 }
1323 if (*sig != ')') {
1324 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1325 LOG_VFY("VFY: invocation target: bad signature '%s'\n", desc);
1326 free(desc);
1327 goto bad_sig;
1328 }
1329
1330 if (actualArgs != expectedArgs) {
1331 LOG_VFY("VFY: expected %d args, found %d\n", expectedArgs, actualArgs);
1332 goto bad_sig;
1333 }
1334
1335 free(sigOriginal);
1336 return resMethod;
1337
1338bad_sig:
1339 if (resMethod != NULL) {
1340 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1341 LOG_VFY("VFY: rejecting call to %s.%s %s\n",
Andy McFadden62a75162009-04-17 17:23:37 -07001342 resMethod->clazz->descriptor, resMethod->name, desc);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001343 free(desc);
1344 }
1345
1346fail:
1347 free(sigOriginal);
Andy McFadden62a75162009-04-17 17:23:37 -07001348 if (*pFailure == VERIFY_ERROR_NONE)
1349 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001350 return NULL;
1351}
1352
1353/*
1354 * Get the class object for the type of data stored in a field. This isn't
1355 * stored in the Field struct, so we have to recover it from the signature.
1356 *
1357 * This only works for reference types. Don't call this for primitive types.
1358 *
1359 * If we can't find the class, we return java.lang.Object, so that
1360 * verification can continue if a field is only accessed in trivial ways.
1361 */
1362static ClassObject* getFieldClass(const Method* meth, const Field* field)
1363{
1364 ClassObject* fieldClass;
1365 const char* signature = field->signature;
1366
1367 if ((*signature == 'L') || (*signature == '[')) {
1368 fieldClass = dvmFindClassNoInit(signature,
1369 meth->clazz->classLoader);
1370 } else {
1371 return NULL;
1372 }
1373
1374 if (fieldClass == NULL) {
1375 dvmClearOptException(dvmThreadSelf());
1376 LOGV("VFY: unable to find class '%s' for field %s.%s, trying Object\n",
1377 field->signature, meth->clazz->descriptor, field->name);
1378 fieldClass = gDvm.classJavaLangObject;
1379 } else {
1380 assert(!dvmIsPrimitiveClass(fieldClass));
1381 }
1382 return fieldClass;
1383}
1384
1385
1386/*
1387 * ===========================================================================
1388 * Register operations
1389 * ===========================================================================
1390 */
1391
1392/*
Andy McFaddend3250112010-11-03 14:32:42 -07001393 * Get the type of register N.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001394 *
Andy McFaddend3250112010-11-03 14:32:42 -07001395 * The register index was validated during the static pass, so we don't
1396 * need to check it here.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001397 */
Andy McFadden319a33b2010-11-10 07:55:14 -08001398static inline RegType getRegisterType(const RegisterLine* registerLine, u4 vsrc)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001399{
Andy McFadden319a33b2010-11-10 07:55:14 -08001400 return registerLine->regTypes[vsrc];
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001401}
1402
1403/*
1404 * Get the value from a register, and cast it to a ClassObject. Sets
Andy McFadden62a75162009-04-17 17:23:37 -07001405 * "*pFailure" if something fails.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001406 *
1407 * This fails if the register holds an uninitialized class.
1408 *
1409 * If the register holds kRegTypeZero, this returns a NULL pointer.
1410 */
Andy McFadden319a33b2010-11-10 07:55:14 -08001411static ClassObject* getClassFromRegister(const RegisterLine* registerLine,
Andy McFaddend3250112010-11-03 14:32:42 -07001412 u4 vsrc, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001413{
1414 ClassObject* clazz = NULL;
1415 RegType type;
1416
1417 /* get the element type of the array held in vsrc */
Andy McFadden319a33b2010-11-10 07:55:14 -08001418 type = getRegisterType(registerLine, vsrc);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001419
1420 /* if "always zero", we allow it to fail at runtime */
1421 if (type == kRegTypeZero)
1422 goto bail;
1423
1424 if (!regTypeIsReference(type)) {
1425 LOG_VFY("VFY: tried to get class from non-ref register v%d (type=%d)\n",
1426 vsrc, type);
Andy McFadden62a75162009-04-17 17:23:37 -07001427 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001428 goto bail;
1429 }
1430 if (regTypeIsUninitReference(type)) {
1431 LOG_VFY("VFY: register %u holds uninitialized reference\n", vsrc);
Andy McFadden62a75162009-04-17 17:23:37 -07001432 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001433 goto bail;
1434 }
1435
1436 clazz = regTypeInitializedReferenceToClass(type);
1437
1438bail:
1439 return clazz;
1440}
1441
1442/*
1443 * Get the "this" pointer from a non-static method invocation. This
1444 * returns the RegType so the caller can decide whether it needs the
1445 * reference to be initialized or not. (Can also return kRegTypeZero
1446 * if the reference can only be zero at this point.)
1447 *
1448 * The argument count is in vA, and the first argument is in vC, for both
1449 * "simple" and "range" versions. We just need to make sure vA is >= 1
1450 * and then return vC.
1451 */
Andy McFadden319a33b2010-11-10 07:55:14 -08001452static RegType getInvocationThis(const RegisterLine* registerLine,
Andy McFaddend3250112010-11-03 14:32:42 -07001453 const DecodedInstruction* pDecInsn, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001454{
1455 RegType thisType = kRegTypeUnknown;
1456
1457 if (pDecInsn->vA < 1) {
1458 LOG_VFY("VFY: invoke lacks 'this'\n");
Andy McFadden62a75162009-04-17 17:23:37 -07001459 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001460 goto bail;
1461 }
1462
1463 /* get the element type of the array held in vsrc */
Andy McFadden319a33b2010-11-10 07:55:14 -08001464 thisType = getRegisterType(registerLine, pDecInsn->vC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001465 if (!regTypeIsReference(thisType)) {
1466 LOG_VFY("VFY: tried to get class from non-ref register v%d (type=%d)\n",
1467 pDecInsn->vC, thisType);
Andy McFadden62a75162009-04-17 17:23:37 -07001468 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001469 goto bail;
1470 }
1471
1472bail:
1473 return thisType;
1474}
1475
1476/*
1477 * Set the type of register N, verifying that the register is valid. If
1478 * "newType" is the "Lo" part of a 64-bit value, register N+1 will be
1479 * set to "newType+1".
1480 *
Andy McFaddend3250112010-11-03 14:32:42 -07001481 * The register index was validated during the static pass, so we don't
1482 * need to check it here.
Andy McFadden319a33b2010-11-10 07:55:14 -08001483 *
1484 * TODO: clear mon stack bits
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001485 */
Andy McFadden319a33b2010-11-10 07:55:14 -08001486static void setRegisterType(RegisterLine* registerLine, u4 vdst,
1487 RegType newType)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001488{
Andy McFadden319a33b2010-11-10 07:55:14 -08001489 RegType* insnRegs = registerLine->regTypes;
1490
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001491 switch (newType) {
1492 case kRegTypeUnknown:
1493 case kRegTypeBoolean:
1494 case kRegTypeOne:
1495 case kRegTypeByte:
1496 case kRegTypePosByte:
1497 case kRegTypeShort:
1498 case kRegTypePosShort:
1499 case kRegTypeChar:
1500 case kRegTypeInteger:
1501 case kRegTypeFloat:
1502 case kRegTypeZero:
Andy McFaddend3250112010-11-03 14:32:42 -07001503 case kRegTypeUninit:
1504 insnRegs[vdst] = newType;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001505 break;
1506 case kRegTypeLongLo:
1507 case kRegTypeDoubleLo:
Andy McFaddend3250112010-11-03 14:32:42 -07001508 insnRegs[vdst] = newType;
1509 insnRegs[vdst+1] = newType+1;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001510 break;
1511 case kRegTypeLongHi:
1512 case kRegTypeDoubleHi:
1513 /* should never set these explicitly */
Andy McFaddend3250112010-11-03 14:32:42 -07001514 LOGE("BUG: explicit set of high register type\n");
1515 dvmAbort();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001516 break;
1517
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001518 default:
Andy McFaddend3250112010-11-03 14:32:42 -07001519 /* can't switch for ref types, so we check explicitly */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001520 if (regTypeIsReference(newType)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001521 insnRegs[vdst] = newType;
1522
1523 /*
1524 * In most circumstances we won't see a reference to a primitive
1525 * class here (e.g. "D"), since that would mean the object in the
1526 * register is actually a primitive type. It can happen as the
1527 * result of an assumed-successful check-cast instruction in
1528 * which the second argument refers to a primitive class. (In
1529 * practice, such an instruction will always throw an exception.)
1530 *
1531 * This is not an issue for instructions like const-class, where
1532 * the object in the register is a java.lang.Class instance.
1533 */
1534 break;
1535 }
Andy McFaddend3250112010-11-03 14:32:42 -07001536 /* bad type - fall through */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001537
1538 case kRegTypeConflict: // should only be set during a merge
Andy McFaddend3250112010-11-03 14:32:42 -07001539 LOGE("BUG: set register to unknown type %d\n", newType);
1540 dvmAbort();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001541 break;
1542 }
1543}
1544
1545/*
1546 * Verify that the contents of the specified register have the specified
1547 * type (or can be converted to it through an implicit widening conversion).
1548 *
1549 * In theory we could use this to modify the type of the source register,
1550 * e.g. a generic 32-bit constant, once used as a float, would thereafter
1551 * remain a float. There is no compelling reason to require this though.
1552 *
1553 * If "vsrc" is a reference, both it and the "vsrc" register must be
1554 * initialized ("vsrc" may be Zero). This will verify that the value in
1555 * the register is an instance of checkType, or if checkType is an
1556 * interface, verify that the register implements checkType.
1557 */
Andy McFadden319a33b2010-11-10 07:55:14 -08001558static void verifyRegisterType(const RegisterLine* registerLine, u4 vsrc,
Andy McFaddend3250112010-11-03 14:32:42 -07001559 RegType checkType, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001560{
Andy McFadden319a33b2010-11-10 07:55:14 -08001561 const RegType* insnRegs = registerLine->regTypes;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001562 RegType srcType = insnRegs[vsrc];
1563
1564 //LOGD("check-reg v%u = %d\n", vsrc, checkType);
1565 switch (checkType) {
1566 case kRegTypeFloat:
1567 case kRegTypeBoolean:
1568 case kRegTypePosByte:
1569 case kRegTypeByte:
1570 case kRegTypePosShort:
1571 case kRegTypeShort:
1572 case kRegTypeChar:
1573 case kRegTypeInteger:
1574 if (!canConvertTo1nr(srcType, checkType)) {
1575 LOG_VFY("VFY: register1 v%u type %d, wanted %d\n",
1576 vsrc, srcType, checkType);
Andy McFadden62a75162009-04-17 17:23:37 -07001577 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001578 }
1579 break;
1580 case kRegTypeLongLo:
1581 case kRegTypeDoubleLo:
Andy McFaddend3250112010-11-03 14:32:42 -07001582 if (insnRegs[vsrc+1] != srcType+1) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001583 LOG_VFY("VFY: register2 v%u-%u values %d,%d\n",
1584 vsrc, vsrc+1, insnRegs[vsrc], insnRegs[vsrc+1]);
Andy McFadden62a75162009-04-17 17:23:37 -07001585 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001586 } else if (!canConvertTo2(srcType, checkType)) {
1587 LOG_VFY("VFY: register2 v%u type %d, wanted %d\n",
1588 vsrc, srcType, checkType);
Andy McFadden62a75162009-04-17 17:23:37 -07001589 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001590 }
1591 break;
1592
1593 case kRegTypeLongHi:
1594 case kRegTypeDoubleHi:
1595 case kRegTypeZero:
1596 case kRegTypeOne:
1597 case kRegTypeUnknown:
1598 case kRegTypeConflict:
1599 /* should never be checking for these explicitly */
1600 assert(false);
Andy McFadden62a75162009-04-17 17:23:37 -07001601 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001602 return;
1603 case kRegTypeUninit:
1604 default:
1605 /* make sure checkType is initialized reference */
1606 if (!regTypeIsReference(checkType)) {
1607 LOG_VFY("VFY: unexpected check type %d\n", checkType);
1608 assert(false);
Andy McFadden62a75162009-04-17 17:23:37 -07001609 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001610 break;
1611 }
1612 if (regTypeIsUninitReference(checkType)) {
1613 LOG_VFY("VFY: uninitialized ref not expected as reg check\n");
Andy McFadden62a75162009-04-17 17:23:37 -07001614 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001615 break;
1616 }
1617 /* make sure srcType is initialized reference or always-NULL */
1618 if (!regTypeIsReference(srcType)) {
1619 LOG_VFY("VFY: register1 v%u type %d, wanted ref\n", vsrc, srcType);
Andy McFadden62a75162009-04-17 17:23:37 -07001620 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001621 break;
1622 }
1623 if (regTypeIsUninitReference(srcType)) {
1624 LOG_VFY("VFY: register1 v%u holds uninitialized ref\n", vsrc);
Andy McFadden62a75162009-04-17 17:23:37 -07001625 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001626 break;
1627 }
1628 /* if the register isn't Zero, make sure it's an instance of check */
1629 if (srcType != kRegTypeZero) {
1630 ClassObject* srcClass = regTypeInitializedReferenceToClass(srcType);
1631 ClassObject* checkClass = regTypeInitializedReferenceToClass(checkType);
1632 assert(srcClass != NULL);
1633 assert(checkClass != NULL);
1634
1635 if (dvmIsInterfaceClass(checkClass)) {
1636 /*
1637 * All objects implement all interfaces as far as the
1638 * verifier is concerned. The runtime has to sort it out.
1639 * See comments above findCommonSuperclass.
1640 */
1641 /*
1642 if (srcClass != checkClass &&
1643 !dvmImplements(srcClass, checkClass))
1644 {
1645 LOG_VFY("VFY: %s does not implement %s\n",
1646 srcClass->descriptor, checkClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07001647 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001648 }
1649 */
1650 } else {
1651 if (!dvmInstanceof(srcClass, checkClass)) {
1652 LOG_VFY("VFY: %s is not instance of %s\n",
1653 srcClass->descriptor, checkClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07001654 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001655 }
1656 }
1657 }
1658 break;
1659 }
1660}
1661
1662/*
Andy McFaddend3250112010-11-03 14:32:42 -07001663 * Set the type of the "result" register.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001664 */
Andy McFadden319a33b2010-11-10 07:55:14 -08001665static void setResultRegisterType(RegisterLine* registerLine,
1666 const int insnRegCount, RegType newType)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001667{
Andy McFadden319a33b2010-11-10 07:55:14 -08001668 setRegisterType(registerLine, RESULT_REGISTER(insnRegCount), newType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001669}
1670
1671
1672/*
1673 * Update all registers holding "uninitType" to instead hold the
1674 * corresponding initialized reference type. This is called when an
1675 * appropriate <init> method is invoked -- all copies of the reference
1676 * must be marked as initialized.
1677 */
Andy McFadden319a33b2010-11-10 07:55:14 -08001678static void markRefsAsInitialized(RegisterLine* registerLine, int insnRegCount,
Andy McFadden62a75162009-04-17 17:23:37 -07001679 UninitInstanceMap* uninitMap, RegType uninitType, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001680{
Andy McFadden319a33b2010-11-10 07:55:14 -08001681 RegType* insnRegs = registerLine->regTypes;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001682 ClassObject* clazz;
1683 RegType initType;
1684 int i, changed;
1685
1686 clazz = dvmGetUninitInstance(uninitMap, regTypeToUninitIndex(uninitType));
1687 if (clazz == NULL) {
1688 LOGE("VFY: unable to find type=0x%x (idx=%d)\n",
1689 uninitType, regTypeToUninitIndex(uninitType));
Andy McFadden62a75162009-04-17 17:23:37 -07001690 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001691 return;
1692 }
1693 initType = regTypeFromClass(clazz);
1694
1695 changed = 0;
1696 for (i = 0; i < insnRegCount; i++) {
1697 if (insnRegs[i] == uninitType) {
1698 insnRegs[i] = initType;
1699 changed++;
1700 }
1701 }
1702 //LOGD("VFY: marked %d registers as initialized\n", changed);
1703 assert(changed > 0);
1704
1705 return;
1706}
1707
1708/*
1709 * We're creating a new instance of class C at address A. Any registers
1710 * holding instances previously created at address A must be initialized
1711 * by now. If not, we mark them as "conflict" to prevent them from being
1712 * used (otherwise, markRefsAsInitialized would mark the old ones and the
1713 * new ones at the same time).
Andy McFadden319a33b2010-11-10 07:55:14 -08001714 *
1715 * TODO: clear mon stack bits
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001716 */
Andy McFadden319a33b2010-11-10 07:55:14 -08001717static void markUninitRefsAsInvalid(RegisterLine* registerLine,
1718 int insnRegCount, UninitInstanceMap* uninitMap, RegType uninitType)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001719{
Andy McFadden319a33b2010-11-10 07:55:14 -08001720 RegType* insnRegs = registerLine->regTypes;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001721 int i, changed;
1722
1723 changed = 0;
1724 for (i = 0; i < insnRegCount; i++) {
1725 if (insnRegs[i] == uninitType) {
1726 insnRegs[i] = kRegTypeConflict;
1727 changed++;
1728 }
1729 }
1730
1731 //if (changed)
1732 // LOGD("VFY: marked %d uninitialized registers as invalid\n", changed);
1733}
1734
1735/*
Andy McFadden319a33b2010-11-10 07:55:14 -08001736 * Find the register line for the specified instruction in the current method.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001737 */
Andy McFadden319a33b2010-11-10 07:55:14 -08001738static inline RegisterLine* getRegisterLine(const RegisterTable* regTable,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001739 int insnIdx)
1740{
Andy McFadden319a33b2010-11-10 07:55:14 -08001741 return &regTable->registerLines[insnIdx];
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001742}
1743
1744/*
Andy McFadden319a33b2010-11-10 07:55:14 -08001745 * Copy a register line.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001746 */
Andy McFadden319a33b2010-11-10 07:55:14 -08001747static inline void copyRegisterLine(RegisterLine* dst, const RegisterLine* src,
1748 size_t numRegs)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001749{
Andy McFadden319a33b2010-11-10 07:55:14 -08001750 memcpy(dst->regTypes, src->regTypes, numRegs * sizeof(RegType));
1751
1752 assert((src->monitorEntries == NULL && dst->monitorEntries == NULL) ||
1753 (src->monitorEntries != NULL && dst->monitorEntries != NULL));
1754 if (dst->monitorEntries != NULL) {
1755 assert(dst->monitorStack != NULL);
1756 memcpy(dst->monitorEntries, src->monitorEntries,
1757 numRegs * sizeof(MonitorEntries));
1758 memcpy(dst->monitorStack, src->monitorStack,
1759 kMaxMonitorStackDepth * sizeof(u4));
1760 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001761}
1762
1763/*
Andy McFadden319a33b2010-11-10 07:55:14 -08001764 * Copy a register line into the table.
1765 */
1766static inline void copyLineToTable(RegisterTable* regTable, int insnIdx,
1767 const RegisterLine* src)
1768{
1769 RegisterLine* dst = getRegisterLine(regTable, insnIdx);
1770 assert(dst->regTypes != NULL);
1771 copyRegisterLine(dst, src, regTable->insnRegCountPlus);
1772}
1773
1774/*
1775 * Copy a register line out of the table.
1776 */
1777static inline void copyLineFromTable(RegisterLine* dst,
1778 const RegisterTable* regTable, int insnIdx)
1779{
1780 RegisterLine* src = getRegisterLine(regTable, insnIdx);
1781 assert(src->regTypes != NULL);
1782 copyRegisterLine(dst, src, regTable->insnRegCountPlus);
1783}
1784
1785
1786/*
1787 * Compare two register lines. Returns 0 if they match.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001788 *
Andy McFadden319a33b2010-11-10 07:55:14 -08001789 * Using this for a sort is unwise, since the value can change based on
1790 * machine endianness.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001791 */
Andy McFadden319a33b2010-11-10 07:55:14 -08001792static inline int compareLineToTable(const RegisterTable* regTable,
1793 int insnIdx, const RegisterLine* line2)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001794{
Andy McFadden319a33b2010-11-10 07:55:14 -08001795 const RegisterLine* line1 = getRegisterLine(regTable, insnIdx);
1796 /* TODO: compare mon stack and stack bits */
1797 return memcmp(line1->regTypes, line2->regTypes,
1798 regTable->insnRegCountPlus * sizeof(RegType));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001799}
1800
1801/*
1802 * Register type categories, for type checking.
1803 *
1804 * The spec says category 1 includes boolean, byte, char, short, int, float,
1805 * reference, and returnAddress. Category 2 includes long and double.
1806 *
1807 * We treat object references separately, so we have "category1nr". We
1808 * don't support jsr/ret, so there is no "returnAddress" type.
1809 */
1810typedef enum TypeCategory {
1811 kTypeCategoryUnknown = 0,
Andy McFadden319a33b2010-11-10 07:55:14 -08001812 kTypeCategory1nr, // boolean, byte, char, short, int, float
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001813 kTypeCategory2, // long, double
1814 kTypeCategoryRef, // object reference
1815} TypeCategory;
1816
1817/*
1818 * See if "type" matches "cat". All we're really looking for here is that
1819 * we're not mixing and matching 32-bit and 64-bit quantities, and we're
1820 * not mixing references with numerics. (For example, the arguments to
1821 * "a < b" could be integers of different sizes, but they must both be
1822 * integers. Dalvik is less specific about int vs. float, so we treat them
1823 * as equivalent here.)
1824 *
1825 * For category 2 values, "type" must be the "low" half of the value.
1826 *
Andy McFadden62a75162009-04-17 17:23:37 -07001827 * Sets "*pFailure" if something looks wrong.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001828 */
Andy McFadden62a75162009-04-17 17:23:37 -07001829static void checkTypeCategory(RegType type, TypeCategory cat,
1830 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001831{
1832 switch (cat) {
1833 case kTypeCategory1nr:
1834 switch (type) {
1835 case kRegTypeFloat:
1836 case kRegTypeZero:
1837 case kRegTypeOne:
1838 case kRegTypeBoolean:
1839 case kRegTypePosByte:
1840 case kRegTypeByte:
1841 case kRegTypePosShort:
1842 case kRegTypeShort:
1843 case kRegTypeChar:
1844 case kRegTypeInteger:
1845 break;
1846 default:
Andy McFadden62a75162009-04-17 17:23:37 -07001847 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001848 break;
1849 }
1850 break;
1851
1852 case kTypeCategory2:
1853 switch (type) {
1854 case kRegTypeLongLo:
1855 case kRegTypeDoubleLo:
1856 break;
1857 default:
Andy McFadden62a75162009-04-17 17:23:37 -07001858 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001859 break;
1860 }
1861 break;
1862
1863 case kTypeCategoryRef:
1864 if (type != kRegTypeZero && !regTypeIsReference(type))
Andy McFadden62a75162009-04-17 17:23:37 -07001865 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001866 break;
1867
1868 default:
1869 assert(false);
Andy McFadden62a75162009-04-17 17:23:37 -07001870 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001871 break;
1872 }
1873}
1874
1875/*
1876 * For a category 2 register pair, verify that "typeh" is the appropriate
1877 * high part for "typel".
1878 *
1879 * Does not verify that "typel" is in fact the low part of a 64-bit
1880 * register pair.
1881 */
Andy McFadden62a75162009-04-17 17:23:37 -07001882static void checkWidePair(RegType typel, RegType typeh, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001883{
1884 if ((typeh != typel+1))
Andy McFadden62a75162009-04-17 17:23:37 -07001885 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001886}
1887
1888/*
1889 * Implement category-1 "move" instructions. Copy a 32-bit value from
1890 * "vsrc" to "vdst".
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001891 */
Andy McFadden319a33b2010-11-10 07:55:14 -08001892static void copyRegister1(RegisterLine* registerLine, u4 vdst, u4 vsrc,
Andy McFaddend3250112010-11-03 14:32:42 -07001893 TypeCategory cat, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001894{
Andy McFadden319a33b2010-11-10 07:55:14 -08001895 assert(cat == kTypeCategory1nr || cat == kTypeCategoryRef);
1896 RegType type = getRegisterType(registerLine, vsrc);
Andy McFaddend3250112010-11-03 14:32:42 -07001897 checkTypeCategory(type, cat, pFailure);
Andy McFadden62a75162009-04-17 17:23:37 -07001898 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001899 LOG_VFY("VFY: copy1 v%u<-v%u type=%d cat=%d\n", vdst, vsrc, type, cat);
Andy McFaddend3250112010-11-03 14:32:42 -07001900 } else {
Andy McFadden319a33b2010-11-10 07:55:14 -08001901 setRegisterType(registerLine, vdst, type);
1902 /* TODO copy mon stack bits for Ref; will be cleared for 1nr */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001903 }
1904}
1905
1906/*
1907 * Implement category-2 "move" instructions. Copy a 64-bit value from
1908 * "vsrc" to "vdst". This copies both halves of the register.
1909 */
Andy McFadden319a33b2010-11-10 07:55:14 -08001910static void copyRegister2(RegisterLine* registerLine, u4 vdst, u4 vsrc,
1911 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001912{
Andy McFadden319a33b2010-11-10 07:55:14 -08001913 RegType typel = getRegisterType(registerLine, vsrc);
1914 RegType typeh = getRegisterType(registerLine, vsrc+1);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001915
Andy McFaddend3250112010-11-03 14:32:42 -07001916 checkTypeCategory(typel, kTypeCategory2, pFailure);
1917 checkWidePair(typel, typeh, pFailure);
Andy McFadden62a75162009-04-17 17:23:37 -07001918 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001919 LOG_VFY("VFY: copy2 v%u<-v%u type=%d/%d\n", vdst, vsrc, typel, typeh);
Andy McFaddend3250112010-11-03 14:32:42 -07001920 } else {
Andy McFadden319a33b2010-11-10 07:55:14 -08001921 setRegisterType(registerLine, vdst, typel);
1922 /* target monitor stack bits will be cleared */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001923 }
1924}
1925
1926/*
1927 * Implement "move-result". Copy the category-1 value from the result
1928 * register to another register, and reset the result register.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001929 */
Andy McFadden319a33b2010-11-10 07:55:14 -08001930static void copyResultRegister1(RegisterLine* registerLine,
1931 const int insnRegCount, u4 vdst, TypeCategory cat, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001932{
1933 RegType type;
1934 u4 vsrc;
1935
Andy McFaddend3250112010-11-03 14:32:42 -07001936 assert(vdst < (u4) insnRegCount);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001937
Andy McFaddend3250112010-11-03 14:32:42 -07001938 vsrc = RESULT_REGISTER(insnRegCount);
Andy McFadden319a33b2010-11-10 07:55:14 -08001939 type = getRegisterType(registerLine, vsrc);
Andy McFaddend3250112010-11-03 14:32:42 -07001940 checkTypeCategory(type, cat, pFailure);
Andy McFadden62a75162009-04-17 17:23:37 -07001941 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001942 LOG_VFY("VFY: copyRes1 v%u<-v%u cat=%d type=%d\n",
1943 vdst, vsrc, cat, type);
Andy McFaddend3250112010-11-03 14:32:42 -07001944 } else {
Andy McFadden319a33b2010-11-10 07:55:14 -08001945 setRegisterType(registerLine, vdst, type);
1946 setRegisterType(registerLine, vsrc, kRegTypeUnknown);
1947 /* target monitor stack bits will be cleared */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001948 }
1949}
1950
1951/*
1952 * Implement "move-result-wide". Copy the category-2 value from the result
1953 * register to another register, and reset the result register.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001954 */
Andy McFadden319a33b2010-11-10 07:55:14 -08001955static void copyResultRegister2(RegisterLine* registerLine,
1956 const int insnRegCount, u4 vdst, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001957{
1958 RegType typel, typeh;
1959 u4 vsrc;
1960
Andy McFaddend3250112010-11-03 14:32:42 -07001961 assert(vdst < (u4) insnRegCount);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001962
Andy McFaddend3250112010-11-03 14:32:42 -07001963 vsrc = RESULT_REGISTER(insnRegCount);
Andy McFadden319a33b2010-11-10 07:55:14 -08001964 typel = getRegisterType(registerLine, vsrc);
1965 typeh = getRegisterType(registerLine, vsrc+1);
Andy McFaddend3250112010-11-03 14:32:42 -07001966 checkTypeCategory(typel, kTypeCategory2, pFailure);
1967 checkWidePair(typel, typeh, pFailure);
Andy McFadden62a75162009-04-17 17:23:37 -07001968 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001969 LOG_VFY("VFY: copyRes2 v%u<-v%u type=%d/%d\n",
1970 vdst, vsrc, typel, typeh);
Andy McFaddend3250112010-11-03 14:32:42 -07001971 } else {
Andy McFadden319a33b2010-11-10 07:55:14 -08001972 setRegisterType(registerLine, vdst, typel);
1973 setRegisterType(registerLine, vsrc, kRegTypeUnknown);
1974 setRegisterType(registerLine, vsrc+1, kRegTypeUnknown);
1975 /* target monitor stack bits will be cleared */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001976 }
1977}
1978
1979/*
1980 * Verify types for a simple two-register instruction (e.g. "neg-int").
1981 * "dstType" is stored into vA, and "srcType" is verified against vB.
1982 */
Andy McFadden319a33b2010-11-10 07:55:14 -08001983static void checkUnop(RegisterLine* registerLine, DecodedInstruction* pDecInsn,
Andy McFaddend3250112010-11-03 14:32:42 -07001984 RegType dstType, RegType srcType, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001985{
Andy McFadden319a33b2010-11-10 07:55:14 -08001986 verifyRegisterType(registerLine, pDecInsn->vB, srcType, pFailure);
1987 setRegisterType(registerLine, pDecInsn->vA, dstType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001988}
1989
1990/*
1991 * We're performing an operation like "and-int/2addr" that can be
1992 * performed on booleans as well as integers. We get no indication of
1993 * boolean-ness, but we can infer it from the types of the arguments.
1994 *
1995 * Assumes we've already validated reg1/reg2.
1996 *
Andy McFaddenb5f64bc2009-06-10 14:11:07 -07001997 * TODO: consider generalizing this. The key principle is that the
1998 * result of a bitwise operation can only be as wide as the widest of
1999 * the operands. You can safely AND/OR/XOR two chars together and know
2000 * you still have a char, so it's reasonable for the compiler or "dx"
2001 * to skip the int-to-char instruction. (We need to do this for boolean
2002 * because there is no int-to-boolean operation.)
2003 *
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002004 * Returns true if both args are Boolean, Zero, or One.
2005 */
Andy McFadden319a33b2010-11-10 07:55:14 -08002006static bool upcastBooleanOp(RegisterLine* registerLine, u4 reg1, u4 reg2)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002007{
2008 RegType type1, type2;
2009
Andy McFadden319a33b2010-11-10 07:55:14 -08002010 type1 = getRegisterType(registerLine, reg1);
2011 type2 = getRegisterType(registerLine, reg2);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002012
2013 if ((type1 == kRegTypeBoolean || type1 == kRegTypeZero ||
2014 type1 == kRegTypeOne) &&
2015 (type2 == kRegTypeBoolean || type2 == kRegTypeZero ||
2016 type2 == kRegTypeOne))
2017 {
2018 return true;
2019 }
2020 return false;
2021}
2022
2023/*
2024 * Verify types for A two-register instruction with a literal constant
2025 * (e.g. "add-int/lit8"). "dstType" is stored into vA, and "srcType" is
2026 * verified against vB.
2027 *
2028 * If "checkBooleanOp" is set, we use the constant value in vC.
2029 */
Andy McFadden319a33b2010-11-10 07:55:14 -08002030static void checkLitop(RegisterLine* registerLine, DecodedInstruction* pDecInsn,
Andy McFaddend3250112010-11-03 14:32:42 -07002031 RegType dstType, RegType srcType, bool checkBooleanOp,
2032 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002033{
Andy McFadden319a33b2010-11-10 07:55:14 -08002034 verifyRegisterType(registerLine, pDecInsn->vB, srcType, pFailure);
Andy McFadden62a75162009-04-17 17:23:37 -07002035 if (VERIFY_OK(*pFailure) && checkBooleanOp) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002036 assert(dstType == kRegTypeInteger);
2037 /* check vB with the call, then check the constant manually */
Andy McFadden319a33b2010-11-10 07:55:14 -08002038 if (upcastBooleanOp(registerLine, pDecInsn->vB, pDecInsn->vB)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002039 && (pDecInsn->vC == 0 || pDecInsn->vC == 1))
2040 {
2041 dstType = kRegTypeBoolean;
2042 }
2043 }
Andy McFadden319a33b2010-11-10 07:55:14 -08002044 setRegisterType(registerLine, pDecInsn->vA, dstType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002045}
2046
2047/*
2048 * Verify types for a simple three-register instruction (e.g. "add-int").
2049 * "dstType" is stored into vA, and "srcType1"/"srcType2" are verified
2050 * against vB/vC.
2051 */
Andy McFadden319a33b2010-11-10 07:55:14 -08002052static void checkBinop(RegisterLine* registerLine, DecodedInstruction* pDecInsn,
Andy McFaddend3250112010-11-03 14:32:42 -07002053 RegType dstType, RegType srcType1, RegType srcType2, bool checkBooleanOp,
2054 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002055{
Andy McFadden319a33b2010-11-10 07:55:14 -08002056 verifyRegisterType(registerLine, pDecInsn->vB, srcType1, pFailure);
2057 verifyRegisterType(registerLine, pDecInsn->vC, srcType2, pFailure);
Andy McFadden62a75162009-04-17 17:23:37 -07002058 if (VERIFY_OK(*pFailure) && checkBooleanOp) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002059 assert(dstType == kRegTypeInteger);
Andy McFadden319a33b2010-11-10 07:55:14 -08002060 if (upcastBooleanOp(registerLine, pDecInsn->vB, pDecInsn->vC))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002061 dstType = kRegTypeBoolean;
2062 }
Andy McFadden319a33b2010-11-10 07:55:14 -08002063 setRegisterType(registerLine, pDecInsn->vA, dstType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002064}
2065
2066/*
2067 * Verify types for a binary "2addr" operation. "srcType1"/"srcType2"
2068 * are verified against vA/vB, then "dstType" is stored into vA.
2069 */
Andy McFadden319a33b2010-11-10 07:55:14 -08002070static void checkBinop2addr(RegisterLine* registerLine,
2071 DecodedInstruction* pDecInsn, RegType dstType, RegType srcType1,
2072 RegType srcType2, bool checkBooleanOp, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002073{
Andy McFadden319a33b2010-11-10 07:55:14 -08002074 verifyRegisterType(registerLine, pDecInsn->vA, srcType1, pFailure);
2075 verifyRegisterType(registerLine, pDecInsn->vB, srcType2, pFailure);
Andy McFadden62a75162009-04-17 17:23:37 -07002076 if (VERIFY_OK(*pFailure) && checkBooleanOp) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002077 assert(dstType == kRegTypeInteger);
Andy McFadden319a33b2010-11-10 07:55:14 -08002078 if (upcastBooleanOp(registerLine, pDecInsn->vA, pDecInsn->vB))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002079 dstType = kRegTypeBoolean;
2080 }
Andy McFadden319a33b2010-11-10 07:55:14 -08002081 setRegisterType(registerLine, pDecInsn->vA, dstType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002082}
2083
Andy McFadden80d25ea2009-06-12 07:26:17 -07002084/*
2085 * Treat right-shifting as a narrowing conversion when possible.
2086 *
2087 * For example, right-shifting an int 24 times results in a value that can
2088 * be treated as a byte.
2089 *
2090 * Things get interesting when contemplating sign extension. Right-
2091 * shifting an integer by 16 yields a value that can be represented in a
2092 * "short" but not a "char", but an unsigned right shift by 16 yields a
2093 * value that belongs in a char rather than a short. (Consider what would
2094 * happen if the result of the shift were cast to a char or short and then
2095 * cast back to an int. If sign extension, or the lack thereof, causes
2096 * a change in the 32-bit representation, then the conversion was lossy.)
2097 *
2098 * A signed right shift by 17 on an integer results in a short. An unsigned
2099 * right shfit by 17 on an integer results in a posshort, which can be
2100 * assigned to a short or a char.
2101 *
2102 * An unsigned right shift on a short can actually expand the result into
2103 * a 32-bit integer. For example, 0xfffff123 >>> 8 becomes 0x00fffff1,
2104 * which can't be represented in anything smaller than an int.
2105 *
2106 * javac does not generate code that takes advantage of this, but some
2107 * of the code optimizers do. It's generally a peephole optimization
2108 * that replaces a particular sequence, e.g. (bipush 24, ishr, i2b) is
2109 * replaced by (bipush 24, ishr). Knowing that shifting a short 8 times
2110 * to the right yields a byte is really more than we need to handle the
2111 * code that's out there, but support is not much more complex than just
2112 * handling integer.
2113 *
2114 * Right-shifting never yields a boolean value.
2115 *
2116 * Returns the new register type.
2117 */
Andy McFadden319a33b2010-11-10 07:55:14 -08002118static RegType adjustForRightShift(RegisterLine* registerLine, int reg,
Andy McFaddend3250112010-11-03 14:32:42 -07002119 unsigned int shiftCount, bool isUnsignedShift, VerifyError* pFailure)
Andy McFadden80d25ea2009-06-12 07:26:17 -07002120{
Andy McFadden319a33b2010-11-10 07:55:14 -08002121 RegType srcType = getRegisterType(registerLine, reg);
Andy McFadden80d25ea2009-06-12 07:26:17 -07002122 RegType newType;
2123
2124 /* no-op */
2125 if (shiftCount == 0)
2126 return srcType;
2127
2128 /* safe defaults */
2129 if (isUnsignedShift)
2130 newType = kRegTypeInteger;
2131 else
2132 newType = srcType;
2133
2134 if (shiftCount >= 32) {
2135 LOG_VFY("Got unexpectedly large shift count %u\n", shiftCount);
2136 /* fail? */
2137 return newType;
2138 }
2139
2140 switch (srcType) {
2141 case kRegTypeInteger: /* 32-bit signed value */
2142 case kRegTypeFloat: /* (allowed; treat same as int) */
2143 if (isUnsignedShift) {
2144 if (shiftCount > 24)
2145 newType = kRegTypePosByte;
2146 else if (shiftCount >= 16)
2147 newType = kRegTypeChar;
2148 } else {
2149 if (shiftCount >= 24)
2150 newType = kRegTypeByte;
2151 else if (shiftCount >= 16)
2152 newType = kRegTypeShort;
2153 }
2154 break;
2155 case kRegTypeShort: /* 16-bit signed value */
2156 if (isUnsignedShift) {
2157 /* default (kRegTypeInteger) is correct */
2158 } else {
2159 if (shiftCount >= 8)
2160 newType = kRegTypeByte;
2161 }
2162 break;
2163 case kRegTypePosShort: /* 15-bit unsigned value */
2164 if (shiftCount >= 8)
2165 newType = kRegTypePosByte;
2166 break;
2167 case kRegTypeChar: /* 16-bit unsigned value */
2168 if (shiftCount > 8)
2169 newType = kRegTypePosByte;
2170 break;
2171 case kRegTypeByte: /* 8-bit signed value */
2172 /* defaults (u=kRegTypeInteger / s=srcType) are correct */
2173 break;
2174 case kRegTypePosByte: /* 7-bit unsigned value */
2175 /* always use newType=srcType */
2176 newType = srcType;
2177 break;
2178 case kRegTypeZero: /* 1-bit unsigned value */
2179 case kRegTypeOne:
2180 case kRegTypeBoolean:
2181 /* unnecessary? */
2182 newType = kRegTypeZero;
2183 break;
2184 default:
2185 /* long, double, references; shouldn't be here! */
2186 assert(false);
2187 break;
2188 }
2189
2190 if (newType != srcType) {
2191 LOGVV("narrowing: %d(%d) --> %d to %d\n",
2192 shiftCount, isUnsignedShift, srcType, newType);
2193 } else {
2194 LOGVV("not narrowed: %d(%d) --> %d\n",
2195 shiftCount, isUnsignedShift, srcType);
2196 }
2197 return newType;
2198}
2199
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002200
2201/*
2202 * ===========================================================================
2203 * Register merge
2204 * ===========================================================================
2205 */
2206
2207/*
2208 * Compute the "class depth" of a class. This is the distance from the
2209 * class to the top of the tree, chasing superclass links. java.lang.Object
2210 * has a class depth of 0.
2211 */
2212static int getClassDepth(ClassObject* clazz)
2213{
2214 int depth = 0;
2215
2216 while (clazz->super != NULL) {
2217 clazz = clazz->super;
2218 depth++;
2219 }
2220 return depth;
2221}
2222
2223/*
2224 * Given two classes, walk up the superclass tree to find a common
2225 * ancestor. (Called from findCommonSuperclass().)
2226 *
2227 * TODO: consider caching the class depth in the class object so we don't
2228 * have to search for it here.
2229 */
2230static ClassObject* digForSuperclass(ClassObject* c1, ClassObject* c2)
2231{
2232 int depth1, depth2;
2233
2234 depth1 = getClassDepth(c1);
2235 depth2 = getClassDepth(c2);
2236
2237 if (gDebugVerbose) {
2238 LOGVV("COMMON: %s(%d) + %s(%d)\n",
2239 c1->descriptor, depth1, c2->descriptor, depth2);
2240 }
2241
2242 /* pull the deepest one up */
2243 if (depth1 > depth2) {
2244 while (depth1 > depth2) {
2245 c1 = c1->super;
2246 depth1--;
2247 }
2248 } else {
2249 while (depth2 > depth1) {
2250 c2 = c2->super;
2251 depth2--;
2252 }
2253 }
2254
2255 /* walk up in lock-step */
2256 while (c1 != c2) {
2257 c1 = c1->super;
2258 c2 = c2->super;
2259
2260 assert(c1 != NULL && c2 != NULL);
2261 }
2262
2263 if (gDebugVerbose) {
2264 LOGVV(" : --> %s\n", c1->descriptor);
2265 }
2266 return c1;
2267}
2268
2269/*
2270 * Merge two array classes. We can't use the general "walk up to the
2271 * superclass" merge because the superclass of an array is always Object.
2272 * We want String[] + Integer[] = Object[]. This works for higher dimensions
2273 * as well, e.g. String[][] + Integer[][] = Object[][].
2274 *
2275 * If Foo1 and Foo2 are subclasses of Foo, Foo1[] + Foo2[] = Foo[].
2276 *
2277 * If Class implements Type, Class[] + Type[] = Type[].
2278 *
2279 * If the dimensions don't match, we want to convert to an array of Object
2280 * with the least dimension, e.g. String[][] + String[][][][] = Object[][].
2281 *
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002282 * Arrays of primitive types effectively have one less dimension when
2283 * merging. int[] + float[] = Object, int[] + String[] = Object,
2284 * int[][] + float[][] = Object[], int[][] + String[] = Object[]. (The
2285 * only time this function doesn't return an array class is when one of
2286 * the arguments is a 1-dimensional primitive array.)
2287 *
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002288 * This gets a little awkward because we may have to ask the VM to create
2289 * a new array type with the appropriate element and dimensions. However, we
2290 * shouldn't be doing this often.
2291 */
2292static ClassObject* findCommonArraySuperclass(ClassObject* c1, ClassObject* c2)
2293{
2294 ClassObject* arrayClass = NULL;
2295 ClassObject* commonElem;
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002296 int arrayDim1, arrayDim2;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002297 int i, numDims;
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002298 bool hasPrimitive = false;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002299
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002300 arrayDim1 = c1->arrayDim;
2301 arrayDim2 = c2->arrayDim;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002302 assert(c1->arrayDim > 0);
2303 assert(c2->arrayDim > 0);
2304
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002305 if (dvmIsPrimitiveClass(c1->elementClass)) {
2306 arrayDim1--;
2307 hasPrimitive = true;
2308 }
2309 if (dvmIsPrimitiveClass(c2->elementClass)) {
2310 arrayDim2--;
2311 hasPrimitive = true;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002312 }
2313
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002314 if (!hasPrimitive && arrayDim1 == arrayDim2) {
2315 /*
2316 * Two arrays of reference types with equal dimensions. Try to
2317 * find a good match.
2318 */
2319 commonElem = findCommonSuperclass(c1->elementClass, c2->elementClass);
2320 numDims = arrayDim1;
2321 } else {
2322 /*
2323 * Mismatched array depths and/or array(s) of primitives. We want
2324 * Object, or an Object array with appropriate dimensions.
2325 *
2326 * We initialize arrayClass to Object here, because it's possible
2327 * for us to set numDims=0.
2328 */
2329 if (arrayDim1 < arrayDim2)
2330 numDims = arrayDim1;
2331 else
2332 numDims = arrayDim2;
2333 arrayClass = commonElem = c1->super; // == java.lang.Object
2334 }
2335
2336 /*
2337 * Find an appropriately-dimensioned array class. This is easiest
2338 * to do iteratively, using the array class found by the current round
2339 * as the element type for the next round.
2340 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002341 for (i = 0; i < numDims; i++) {
2342 arrayClass = dvmFindArrayClassForElement(commonElem);
2343 commonElem = arrayClass;
2344 }
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002345 assert(arrayClass != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002346
2347 LOGVV("ArrayMerge '%s' + '%s' --> '%s'\n",
2348 c1->descriptor, c2->descriptor, arrayClass->descriptor);
2349 return arrayClass;
2350}
2351
2352/*
2353 * Find the first common superclass of the two classes. We're not
2354 * interested in common interfaces.
2355 *
2356 * The easiest way to do this for concrete classes is to compute the "class
2357 * depth" of each, move up toward the root of the deepest one until they're
2358 * at the same depth, then walk both up to the root until they match.
2359 *
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002360 * If both classes are arrays, we need to merge based on array depth and
2361 * element type.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002362 *
2363 * If one class is an interface, we check to see if the other class/interface
2364 * (or one of its predecessors) implements the interface. If so, we return
2365 * the interface; otherwise, we return Object.
2366 *
2367 * NOTE: we continue the tradition of "lazy interface handling". To wit,
2368 * suppose we have three classes:
2369 * One implements Fancy, Free
2370 * Two implements Fancy, Free
2371 * Three implements Free
2372 * where Fancy and Free are unrelated interfaces. The code requires us
2373 * to merge One into Two. Ideally we'd use a common interface, which
2374 * gives us a choice between Fancy and Free, and no guidance on which to
2375 * use. If we use Free, we'll be okay when Three gets merged in, but if
2376 * we choose Fancy, we're hosed. The "ideal" solution is to create a
2377 * set of common interfaces and carry that around, merging further references
2378 * into it. This is a pain. The easy solution is to simply boil them
2379 * down to Objects and let the runtime invokeinterface call fail, which
2380 * is what we do.
2381 */
2382static ClassObject* findCommonSuperclass(ClassObject* c1, ClassObject* c2)
2383{
2384 assert(!dvmIsPrimitiveClass(c1) && !dvmIsPrimitiveClass(c2));
2385
2386 if (c1 == c2)
2387 return c1;
2388
2389 if (dvmIsInterfaceClass(c1) && dvmImplements(c2, c1)) {
2390 if (gDebugVerbose)
2391 LOGVV("COMMON/I1: %s + %s --> %s\n",
2392 c1->descriptor, c2->descriptor, c1->descriptor);
2393 return c1;
2394 }
2395 if (dvmIsInterfaceClass(c2) && dvmImplements(c1, c2)) {
2396 if (gDebugVerbose)
2397 LOGVV("COMMON/I2: %s + %s --> %s\n",
2398 c1->descriptor, c2->descriptor, c2->descriptor);
2399 return c2;
2400 }
2401
Andy McFaddenc2d74dd2010-10-25 16:13:46 -07002402 if (dvmIsArrayClass(c1) && dvmIsArrayClass(c2)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002403 return findCommonArraySuperclass(c1, c2);
2404 }
2405
2406 return digForSuperclass(c1, c2);
2407}
2408
2409/*
2410 * Merge two RegType values.
2411 *
2412 * Sets "*pChanged" to "true" if the result doesn't match "type1".
2413 */
2414static RegType mergeTypes(RegType type1, RegType type2, bool* pChanged)
2415{
2416 RegType result;
2417
2418 /*
2419 * Check for trivial case so we don't have to hit memory.
2420 */
2421 if (type1 == type2)
2422 return type1;
2423
2424 /*
2425 * Use the table if we can, and reject any attempts to merge something
2426 * from the table with a reference type.
2427 *
Andy McFadden470cbbb2010-11-04 16:31:37 -07002428 * Uninitialized references are composed of the enum ORed with an
2429 * index value. The uninitialized table entry at index zero *will*
2430 * show up as a simple kRegTypeUninit value. Since this cannot be
2431 * merged with anything but itself, the rules do the right thing.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002432 */
2433 if (type1 < kRegTypeMAX) {
2434 if (type2 < kRegTypeMAX) {
2435 result = gDvmMergeTab[type1][type2];
2436 } else {
2437 /* simple + reference == conflict, usually */
2438 if (type1 == kRegTypeZero)
2439 result = type2;
2440 else
2441 result = kRegTypeConflict;
2442 }
2443 } else {
2444 if (type2 < kRegTypeMAX) {
2445 /* reference + simple == conflict, usually */
2446 if (type2 == kRegTypeZero)
2447 result = type1;
2448 else
2449 result = kRegTypeConflict;
2450 } else {
2451 /* merging two references */
2452 if (regTypeIsUninitReference(type1) ||
2453 regTypeIsUninitReference(type2))
2454 {
2455 /* can't merge uninit with anything but self */
2456 result = kRegTypeConflict;
2457 } else {
2458 ClassObject* clazz1 = regTypeInitializedReferenceToClass(type1);
2459 ClassObject* clazz2 = regTypeInitializedReferenceToClass(type2);
2460 ClassObject* mergedClass;
2461
2462 mergedClass = findCommonSuperclass(clazz1, clazz2);
2463 assert(mergedClass != NULL);
2464 result = regTypeFromClass(mergedClass);
2465 }
2466 }
2467 }
2468
2469 if (result != type1)
2470 *pChanged = true;
2471 return result;
2472}
2473
2474/*
2475 * Control can transfer to "nextInsn".
2476 *
Andy McFadden319a33b2010-11-10 07:55:14 -08002477 * Merge the registers from "workLine" into "regTable" at "nextInsn", and
2478 * set the "changed" flag on the target address if any of the registers
2479 * has changed.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002480 */
2481static void updateRegisters(const Method* meth, InsnFlags* insnFlags,
Andy McFadden319a33b2010-11-10 07:55:14 -08002482 RegisterTable* regTable, int nextInsn, const RegisterLine* workLine)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002483{
Andy McFadden319a33b2010-11-10 07:55:14 -08002484 const size_t insnRegCountPlus = regTable->insnRegCountPlus;
2485 assert(workLine != NULL);
2486 const RegType* workRegs = workLine->regTypes;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002487
2488 if (!dvmInsnIsVisitedOrChanged(insnFlags, nextInsn)) {
2489 /*
2490 * We haven't processed this instruction before, and we haven't
2491 * touched the registers here, so there's nothing to "merge". Copy
2492 * the registers over and mark it as changed. (This is the only
2493 * way a register can transition out of "unknown", so this is not
2494 * just an optimization.)
2495 */
2496 LOGVV("COPY into 0x%04x\n", nextInsn);
Andy McFadden319a33b2010-11-10 07:55:14 -08002497 copyLineToTable(regTable, nextInsn, workLine);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002498 dvmInsnSetChanged(insnFlags, nextInsn, true);
Andy McFadden470cbbb2010-11-04 16:31:37 -07002499#ifdef VERIFIER_STATS
2500 gDvm.verifierStats.copyRegCount++;
2501#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002502 } else {
2503 if (gDebugVerbose) {
2504 LOGVV("MERGE into 0x%04x\n", nextInsn);
2505 //dumpRegTypes(meth, insnFlags, targetRegs, 0, "targ", NULL, 0);
2506 //dumpRegTypes(meth, insnFlags, workRegs, 0, "work", NULL, 0);
2507 }
2508 /* merge registers, set Changed only if different */
Andy McFadden319a33b2010-11-10 07:55:14 -08002509 RegisterLine* targetLine = getRegisterLine(regTable, nextInsn);
2510 RegType* targetRegs = targetLine->regTypes;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002511 bool changed = false;
Andy McFadden319a33b2010-11-10 07:55:14 -08002512 unsigned int idx;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002513
Andy McFadden319a33b2010-11-10 07:55:14 -08002514 assert(targetRegs != NULL);
2515
2516 /* TODO: check mon stacks are the same; if different, fail somehow */
2517 for (idx = 0; idx < insnRegCountPlus; idx++) {
2518 targetRegs[idx] =
2519 mergeTypes(targetRegs[idx], workRegs[idx], &changed);
2520 /* TODO merge monitorEntries */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002521 }
2522
2523 if (gDebugVerbose) {
2524 //LOGI(" RESULT (changed=%d)\n", changed);
2525 //dumpRegTypes(meth, insnFlags, targetRegs, 0, "rslt", NULL, 0);
2526 }
Andy McFadden470cbbb2010-11-04 16:31:37 -07002527#ifdef VERIFIER_STATS
2528 gDvm.verifierStats.mergeRegCount++;
2529 if (changed)
2530 gDvm.verifierStats.mergeRegChanged++;
2531#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002532
2533 if (changed)
2534 dvmInsnSetChanged(insnFlags, nextInsn, true);
2535 }
2536}
2537
2538
2539/*
2540 * ===========================================================================
2541 * Utility functions
2542 * ===========================================================================
2543 */
2544
2545/*
2546 * Look up an instance field, specified by "fieldIdx", that is going to be
2547 * accessed in object "objType". This resolves the field and then verifies
2548 * that the class containing the field is an instance of the reference in
2549 * "objType".
2550 *
2551 * It is possible for "objType" to be kRegTypeZero, meaning that we might
2552 * have a null reference. This is a runtime problem, so we allow it,
2553 * skipping some of the type checks.
2554 *
2555 * In general, "objType" must be an initialized reference. However, we
2556 * allow it to be uninitialized if this is an "<init>" method and the field
2557 * is declared within the "objType" class.
2558 *
Andy McFadden62a75162009-04-17 17:23:37 -07002559 * Returns an InstField on success, returns NULL and sets "*pFailure"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002560 * on failure.
2561 */
2562static InstField* getInstField(const Method* meth,
2563 const UninitInstanceMap* uninitMap, RegType objType, int fieldIdx,
Andy McFadden62a75162009-04-17 17:23:37 -07002564 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002565{
2566 InstField* instField = NULL;
2567 ClassObject* objClass;
2568 bool mustBeLocal = false;
2569
2570 if (!regTypeIsReference(objType)) {
Andy McFadden62a75162009-04-17 17:23:37 -07002571 LOG_VFY("VFY: attempt to access field in non-reference type %d\n",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002572 objType);
Andy McFadden62a75162009-04-17 17:23:37 -07002573 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002574 goto bail;
2575 }
2576
Andy McFadden62a75162009-04-17 17:23:37 -07002577 instField = dvmOptResolveInstField(meth->clazz, fieldIdx, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002578 if (instField == NULL) {
2579 LOG_VFY("VFY: unable to resolve instance field %u\n", fieldIdx);
Andy McFadden62a75162009-04-17 17:23:37 -07002580 assert(!VERIFY_OK(*pFailure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002581 goto bail;
2582 }
2583
2584 if (objType == kRegTypeZero)
2585 goto bail;
2586
2587 /*
2588 * Access to fields in uninitialized objects is allowed if this is
2589 * the <init> method for the object and the field in question is
2590 * declared by this class.
2591 */
2592 objClass = regTypeReferenceToClass(objType, uninitMap);
2593 assert(objClass != NULL);
2594 if (regTypeIsUninitReference(objType)) {
2595 if (!isInitMethod(meth) || meth->clazz != objClass) {
2596 LOG_VFY("VFY: attempt to access field via uninitialized ref\n");
Andy McFadden62a75162009-04-17 17:23:37 -07002597 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002598 goto bail;
2599 }
2600 mustBeLocal = true;
2601 }
2602
2603 if (!dvmInstanceof(objClass, instField->field.clazz)) {
2604 LOG_VFY("VFY: invalid field access (field %s.%s, through %s ref)\n",
2605 instField->field.clazz->descriptor, instField->field.name,
2606 objClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07002607 *pFailure = VERIFY_ERROR_NO_FIELD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002608 goto bail;
2609 }
2610
2611 if (mustBeLocal) {
2612 /* for uninit ref, make sure it's defined by this class, not super */
2613 if (instField < objClass->ifields ||
2614 instField >= objClass->ifields + objClass->ifieldCount)
2615 {
2616 LOG_VFY("VFY: invalid constructor field access (field %s in %s)\n",
2617 instField->field.name, objClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07002618 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002619 goto bail;
2620 }
2621 }
2622
2623bail:
2624 return instField;
2625}
2626
2627/*
2628 * Look up a static field.
2629 *
Andy McFadden62a75162009-04-17 17:23:37 -07002630 * Returns a StaticField on success, returns NULL and sets "*pFailure"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002631 * on failure.
2632 */
2633static StaticField* getStaticField(const Method* meth, int fieldIdx,
Andy McFadden62a75162009-04-17 17:23:37 -07002634 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002635{
2636 StaticField* staticField;
2637
Andy McFadden62a75162009-04-17 17:23:37 -07002638 staticField = dvmOptResolveStaticField(meth->clazz, fieldIdx, pFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002639 if (staticField == NULL) {
2640 DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
2641 const DexFieldId* pFieldId;
2642
2643 pFieldId = dexGetFieldId(pDexFile, fieldIdx);
2644
2645 LOG_VFY("VFY: unable to resolve static field %u (%s) in %s\n", fieldIdx,
2646 dexStringById(pDexFile, pFieldId->nameIdx),
2647 dexStringByTypeIdx(pDexFile, pFieldId->classIdx));
Andy McFadden62a75162009-04-17 17:23:37 -07002648 assert(!VERIFY_OK(*pFailure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002649 goto bail;
2650 }
2651
2652bail:
2653 return staticField;
2654}
2655
2656/*
2657 * If "field" is marked "final", make sure this is the either <clinit>
2658 * or <init> as appropriate.
2659 *
Andy McFadden62a75162009-04-17 17:23:37 -07002660 * Sets "*pFailure" on failure.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002661 */
2662static void checkFinalFieldAccess(const Method* meth, const Field* field,
Andy McFadden62a75162009-04-17 17:23:37 -07002663 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002664{
2665 if (!dvmIsFinalField(field))
2666 return;
2667
2668 /* make sure we're in the same class */
2669 if (meth->clazz != field->clazz) {
2670 LOG_VFY_METH(meth, "VFY: can't modify final field %s.%s\n",
2671 field->clazz->descriptor, field->name);
Andy McFaddenb51ea112009-05-08 16:50:17 -07002672 *pFailure = VERIFY_ERROR_ACCESS_FIELD;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002673 return;
2674 }
2675
2676 /*
Andy McFadden62a75162009-04-17 17:23:37 -07002677 * The VM spec descriptions of putfield and putstatic say that
2678 * IllegalAccessError is only thrown when the instructions appear
2679 * outside the declaring class. Our earlier attempts to restrict
2680 * final field modification to constructors are, therefore, wrong.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002681 */
2682#if 0
2683 /* make sure we're in the right kind of constructor */
2684 if (dvmIsStaticField(field)) {
2685 if (!isClassInitMethod(meth)) {
2686 LOG_VFY_METH(meth,
2687 "VFY: can't modify final static field outside <clinit>\n");
Andy McFadden62a75162009-04-17 17:23:37 -07002688 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002689 }
2690 } else {
2691 if (!isInitMethod(meth)) {
2692 LOG_VFY_METH(meth,
2693 "VFY: can't modify final field outside <init>\n");
Andy McFadden62a75162009-04-17 17:23:37 -07002694 *pFailure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002695 }
2696 }
2697#endif
2698}
2699
2700/*
2701 * Make sure that the register type is suitable for use as an array index.
2702 *
Andy McFadden62a75162009-04-17 17:23:37 -07002703 * Sets "*pFailure" if not.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002704 */
2705static void checkArrayIndexType(const Method* meth, RegType regType,
Andy McFadden62a75162009-04-17 17:23:37 -07002706 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002707{
Andy McFadden62a75162009-04-17 17:23:37 -07002708 if (VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002709 /*
2710 * The 1nr types are interchangeable at this level. We could
2711 * do something special if we can definitively identify it as a
2712 * float, but there's no real value in doing so.
2713 */
Andy McFadden62a75162009-04-17 17:23:37 -07002714 checkTypeCategory(regType, kTypeCategory1nr, pFailure);
2715 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002716 LOG_VFY_METH(meth, "Invalid reg type for array index (%d)\n",
2717 regType);
2718 }
2719 }
2720}
2721
2722/*
2723 * Check constraints on constructor return. Specifically, make sure that
2724 * the "this" argument got initialized.
2725 *
2726 * The "this" argument to <init> uses code offset kUninitThisArgAddr, which
2727 * puts it at the start of the list in slot 0. If we see a register with
2728 * an uninitialized slot 0 reference, we know it somehow didn't get
2729 * initialized.
2730 *
2731 * Returns "true" if all is well.
2732 */
Andy McFadden319a33b2010-11-10 07:55:14 -08002733static bool checkConstructorReturn(const Method* meth,
2734 const RegisterLine* registerLine, const int insnRegCount)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002735{
Andy McFadden319a33b2010-11-10 07:55:14 -08002736 const RegType* insnRegs = registerLine->regTypes;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002737 int i;
2738
2739 if (!isInitMethod(meth))
2740 return true;
2741
2742 RegType uninitThis = regTypeFromUninitIndex(kUninitThisArgSlot);
2743
2744 for (i = 0; i < insnRegCount; i++) {
2745 if (insnRegs[i] == uninitThis) {
2746 LOG_VFY("VFY: <init> returning without calling superclass init\n");
2747 return false;
2748 }
2749 }
2750 return true;
2751}
2752
2753/*
2754 * Verify that the target instruction is not "move-exception". It's important
2755 * that the only way to execute a move-exception is as the first instruction
2756 * of an exception handler.
2757 *
2758 * Returns "true" if all is well, "false" if the target instruction is
2759 * move-exception.
2760 */
2761static bool checkMoveException(const Method* meth, int insnIdx,
2762 const char* logNote)
2763{
2764 assert(insnIdx >= 0 && insnIdx < (int)dvmGetMethodInsnsSize(meth));
2765
2766 if ((meth->insns[insnIdx] & 0xff) == OP_MOVE_EXCEPTION) {
2767 LOG_VFY("VFY: invalid use of move-exception\n");
2768 return false;
2769 }
2770 return true;
2771}
2772
2773/*
2774 * For the "move-exception" instruction at "insnIdx", which must be at an
2775 * exception handler address, determine the first common superclass of
2776 * all exceptions that can land here. (For javac output, we're probably
2777 * looking at multiple spans of bytecode covered by one "try" that lands
2778 * at an exception-specific "catch", but in general the handler could be
2779 * shared for multiple exceptions.)
2780 *
2781 * Returns NULL if no matching exception handler can be found, or if the
2782 * exception is not a subclass of Throwable.
2783 */
Andy McFadden62a75162009-04-17 17:23:37 -07002784static ClassObject* getCaughtExceptionType(const Method* meth, int insnIdx,
2785 VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002786{
Andy McFadden62a75162009-04-17 17:23:37 -07002787 VerifyError localFailure;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002788 const DexCode* pCode;
2789 DexFile* pDexFile;
2790 ClassObject* commonSuper = NULL;
Andy McFadden62a75162009-04-17 17:23:37 -07002791 bool foundPossibleHandler = false;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002792 u4 handlersSize;
2793 u4 offset;
2794 u4 i;
2795
2796 pDexFile = meth->clazz->pDvmDex->pDexFile;
2797 pCode = dvmGetMethodCode(meth);
2798
2799 if (pCode->triesSize != 0) {
2800 handlersSize = dexGetHandlersSize(pCode);
2801 offset = dexGetFirstHandlerOffset(pCode);
2802 } else {
2803 handlersSize = 0;
2804 offset = 0;
2805 }
2806
2807 for (i = 0; i < handlersSize; i++) {
2808 DexCatchIterator iterator;
2809 dexCatchIteratorInit(&iterator, pCode, offset);
2810
2811 for (;;) {
2812 const DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
2813
2814 if (handler == NULL) {
2815 break;
2816 }
2817
2818 if (handler->address == (u4) insnIdx) {
2819 ClassObject* clazz;
Andy McFadden62a75162009-04-17 17:23:37 -07002820 foundPossibleHandler = true;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002821
2822 if (handler->typeIdx == kDexNoIndex)
2823 clazz = gDvm.classJavaLangThrowable;
2824 else
Andy McFadden62a75162009-04-17 17:23:37 -07002825 clazz = dvmOptResolveClass(meth->clazz, handler->typeIdx,
2826 &localFailure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002827
2828 if (clazz == NULL) {
2829 LOG_VFY("VFY: unable to resolve exception class %u (%s)\n",
2830 handler->typeIdx,
2831 dexStringByTypeIdx(pDexFile, handler->typeIdx));
Andy McFadden62a75162009-04-17 17:23:37 -07002832 /* TODO: do we want to keep going? If we don't fail
2833 * this we run the risk of having a non-Throwable
2834 * introduced at runtime. However, that won't pass
2835 * an instanceof test, so is essentially harmless. */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002836 } else {
2837 if (commonSuper == NULL)
2838 commonSuper = clazz;
2839 else
2840 commonSuper = findCommonSuperclass(clazz, commonSuper);
2841 }
2842 }
2843 }
2844
2845 offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
2846 }
2847
2848 if (commonSuper == NULL) {
Andy McFadden62a75162009-04-17 17:23:37 -07002849 /* no catch blocks, or no catches with classes we can find */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002850 LOG_VFY_METH(meth,
2851 "VFY: unable to find exception handler at addr 0x%x\n", insnIdx);
Andy McFadden62a75162009-04-17 17:23:37 -07002852 *pFailure = VERIFY_ERROR_GENERIC;
2853 } else {
2854 // TODO: verify the class is an instance of Throwable?
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002855 }
2856
2857 return commonSuper;
2858}
2859
2860/*
2861 * Initialize the RegisterTable.
2862 *
2863 * Every instruction address can have a different set of information about
2864 * what's in which register, but for verification purposes we only need to
2865 * store it at branch target addresses (because we merge into that).
2866 *
2867 * By zeroing out the storage we are effectively initializing the register
2868 * information to kRegTypeUnknown.
Andy McFadden319a33b2010-11-10 07:55:14 -08002869 *
2870 * We jump through some hoops here to minimize the total number of
2871 * allocations we have to perform per method verified.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002872 */
2873static bool initRegisterTable(const Method* meth, const InsnFlags* insnFlags,
2874 RegisterTable* regTable, RegisterTrackingMode trackRegsFor)
2875{
2876 const int insnsSize = dvmGetMethodInsnsSize(meth);
Andy McFadden319a33b2010-11-10 07:55:14 -08002877 const int kExtraLines = 2; /* workLine, savedLine */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002878 int i;
2879
2880 regTable->insnRegCountPlus = meth->registersSize + kExtraRegs;
Andy McFadden319a33b2010-11-10 07:55:14 -08002881 regTable->registerLines =
2882 (RegisterLine*) calloc(insnsSize, sizeof(RegisterLine));
2883 if (regTable->registerLines == NULL)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002884 return false;
2885
2886 assert(insnsSize > 0);
2887
2888 /*
Andy McFadden319a33b2010-11-10 07:55:14 -08002889 * Count up the number of "interesting" instructions.
2890 *
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002891 * "All" means "every address that holds the start of an instruction".
2892 * "Branches" and "GcPoints" mean just those addresses.
2893 *
2894 * "GcPoints" fills about half the addresses, "Branches" about 15%.
2895 */
Andy McFadden319a33b2010-11-10 07:55:14 -08002896 int interestingCount = kExtraLines;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002897
2898 for (i = 0; i < insnsSize; i++) {
2899 bool interesting;
2900
2901 switch (trackRegsFor) {
2902 case kTrackRegsAll:
2903 interesting = dvmInsnIsOpcode(insnFlags, i);
2904 break;
2905 case kTrackRegsGcPoints:
2906 interesting = dvmInsnIsGcPoint(insnFlags, i) ||
2907 dvmInsnIsBranchTarget(insnFlags, i);
2908 break;
2909 case kTrackRegsBranches:
2910 interesting = dvmInsnIsBranchTarget(insnFlags, i);
2911 break;
2912 default:
2913 dvmAbort();
2914 return false;
2915 }
2916
2917 if (interesting)
2918 interestingCount++;
2919
2920 /* count instructions, for display only */
2921 //if (dvmInsnIsOpcode(insnFlags, i))
2922 // insnCount++;
2923 }
2924
Andy McFadden319a33b2010-11-10 07:55:14 -08002925 /*
2926 * Allocate storage for the register type arrays.
2927 * TODO: also allocate and assign storage for monitor tracking
2928 */
2929 regTable->lineAlloc =
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002930 calloc(regTable->insnRegCountPlus * interestingCount, sizeof(RegType));
Andy McFadden319a33b2010-11-10 07:55:14 -08002931 if (regTable->lineAlloc == NULL)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002932 return false;
2933
Andy McFadden319a33b2010-11-10 07:55:14 -08002934 /*
2935 * Populate the sparse register line table.
2936 */
2937 RegType* regPtr = regTable->lineAlloc;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002938 for (i = 0; i < insnsSize; i++) {
2939 bool interesting;
2940
2941 switch (trackRegsFor) {
2942 case kTrackRegsAll:
2943 interesting = dvmInsnIsOpcode(insnFlags, i);
2944 break;
2945 case kTrackRegsGcPoints:
2946 interesting = dvmInsnIsGcPoint(insnFlags, i) ||
2947 dvmInsnIsBranchTarget(insnFlags, i);
2948 break;
2949 case kTrackRegsBranches:
2950 interesting = dvmInsnIsBranchTarget(insnFlags, i);
2951 break;
2952 default:
2953 dvmAbort();
2954 return false;
2955 }
2956
2957 if (interesting) {
Andy McFadden319a33b2010-11-10 07:55:14 -08002958 regTable->registerLines[i].regTypes = regPtr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002959 regPtr += regTable->insnRegCountPlus;
2960 }
2961 }
2962
Andy McFadden319a33b2010-11-10 07:55:14 -08002963 /*
2964 * Grab storage for our "temporary" register lines.
2965 */
2966 regTable->workLine.regTypes = regPtr;
2967 regPtr += regTable->insnRegCountPlus;
2968 regTable->savedLine.regTypes = regPtr;
2969 regPtr += regTable->insnRegCountPlus;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002970
Andy McFadden319a33b2010-11-10 07:55:14 -08002971 //LOGD("Tracking registers for [%d], total %d in %d units\n",
2972 // trackRegsFor, interestingCount-kExtraLines, insnsSize);
2973
2974 assert(regPtr - (RegType*)regTable->lineAlloc ==
2975 (int) (regTable->insnRegCountPlus * interestingCount));
2976 assert(regTable->registerLines[0].regTypes != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002977 return true;
2978}
2979
2980
2981/*
2982 * Verify that the arguments in a filled-new-array instruction are valid.
2983 *
2984 * "resClass" is the class refered to by pDecInsn->vB.
2985 */
2986static void verifyFilledNewArrayRegs(const Method* meth,
Andy McFadden319a33b2010-11-10 07:55:14 -08002987 const RegisterLine* registerLine, const DecodedInstruction* pDecInsn,
Andy McFaddend3250112010-11-03 14:32:42 -07002988 ClassObject* resClass, bool isRange, VerifyError* pFailure)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002989{
2990 u4 argCount = pDecInsn->vA;
2991 RegType expectedType;
2992 PrimitiveType elemType;
2993 unsigned int ui;
2994
2995 assert(dvmIsArrayClass(resClass));
2996 elemType = resClass->elementClass->primitiveType;
2997 if (elemType == PRIM_NOT) {
2998 expectedType = regTypeFromClass(resClass->elementClass);
2999 } else {
3000 expectedType = primitiveTypeToRegType(elemType);
3001 }
3002 //LOGI("filled-new-array: %s -> %d\n", resClass->descriptor, expectedType);
3003
3004 /*
3005 * Verify each register. If "argCount" is bad, verifyRegisterType()
3006 * will run off the end of the list and fail. It's legal, if silly,
3007 * for argCount to be zero.
3008 */
3009 for (ui = 0; ui < argCount; ui++) {
3010 u4 getReg;
3011
3012 if (isRange)
3013 getReg = pDecInsn->vC + ui;
3014 else
3015 getReg = pDecInsn->arg[ui];
3016
Andy McFadden319a33b2010-11-10 07:55:14 -08003017 verifyRegisterType(registerLine, getReg, expectedType, pFailure);
Andy McFadden62a75162009-04-17 17:23:37 -07003018 if (!VERIFY_OK(*pFailure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003019 LOG_VFY("VFY: filled-new-array arg %u(%u) not valid\n", ui, getReg);
3020 return;
3021 }
3022 }
3023}
3024
3025
3026/*
Andy McFaddenb51ea112009-05-08 16:50:17 -07003027 * Replace an instruction with "throw-verification-error". This allows us to
3028 * defer error reporting until the code path is first used.
3029 *
Andy McFadden861b3382010-03-05 15:58:31 -08003030 * This is expected to be called during "just in time" verification, not
3031 * from within dexopt. (Verification failures in dexopt will result in
3032 * postponement of verification to first use of the class.)
3033 *
Andy McFaddenb51ea112009-05-08 16:50:17 -07003034 * The throw-verification-error instruction requires two code units. Some
3035 * of the replaced instructions require three; the third code unit will
3036 * receive a "nop". The instruction's length will be left unchanged
3037 * in "insnFlags".
3038 *
Andy McFadden319a33b2010-11-10 07:55:14 -08003039 * The VM postpones setting of debugger breakpoints in unverified classes,
3040 * so there should be no clashes with the debugger.
Andy McFadden96516932009-10-28 17:39:02 -07003041 *
Andy McFaddenb51ea112009-05-08 16:50:17 -07003042 * Returns "true" on success.
3043 */
Andy McFadden228a6b02010-05-04 15:02:32 -07003044static bool replaceFailingInstruction(const Method* meth, InsnFlags* insnFlags,
Andy McFaddenb51ea112009-05-08 16:50:17 -07003045 int insnIdx, VerifyError failure)
3046{
Andy McFaddenaf0e8382009-08-28 10:38:37 -07003047 VerifyErrorRefType refType;
Andy McFaddenb51ea112009-05-08 16:50:17 -07003048 const u2* oldInsns = meth->insns + insnIdx;
3049 u2 oldInsn = *oldInsns;
3050 bool result = false;
3051
Andy McFaddenfb119e62010-06-28 16:21:20 -07003052 if (gDvm.optimizing)
3053 LOGD("Weird: RFI during dexopt?");
3054
Andy McFaddenb51ea112009-05-08 16:50:17 -07003055 //LOGD(" was 0x%04x\n", oldInsn);
3056 u2* newInsns = (u2*) meth->insns + insnIdx;
3057
3058 /*
3059 * Generate the new instruction out of the old.
3060 *
3061 * First, make sure this is an instruction we're expecting to stomp on.
3062 */
3063 switch (oldInsn & 0xff) {
3064 case OP_CONST_CLASS: // insn[1] == class ref, 2 bytes
3065 case OP_CHECK_CAST:
3066 case OP_INSTANCE_OF:
3067 case OP_NEW_INSTANCE:
3068 case OP_NEW_ARRAY:
Andy McFaddenb51ea112009-05-08 16:50:17 -07003069 case OP_FILLED_NEW_ARRAY: // insn[1] == class ref, 3 bytes
3070 case OP_FILLED_NEW_ARRAY_RANGE:
Andy McFaddenaf0e8382009-08-28 10:38:37 -07003071 refType = VERIFY_ERROR_REF_CLASS;
3072 break;
Andy McFaddenb51ea112009-05-08 16:50:17 -07003073
3074 case OP_IGET: // insn[1] == field ref, 2 bytes
3075 case OP_IGET_BOOLEAN:
3076 case OP_IGET_BYTE:
3077 case OP_IGET_CHAR:
3078 case OP_IGET_SHORT:
3079 case OP_IGET_WIDE:
3080 case OP_IGET_OBJECT:
3081 case OP_IPUT:
3082 case OP_IPUT_BOOLEAN:
3083 case OP_IPUT_BYTE:
3084 case OP_IPUT_CHAR:
3085 case OP_IPUT_SHORT:
3086 case OP_IPUT_WIDE:
3087 case OP_IPUT_OBJECT:
3088 case OP_SGET:
3089 case OP_SGET_BOOLEAN:
3090 case OP_SGET_BYTE:
3091 case OP_SGET_CHAR:
3092 case OP_SGET_SHORT:
3093 case OP_SGET_WIDE:
3094 case OP_SGET_OBJECT:
3095 case OP_SPUT:
3096 case OP_SPUT_BOOLEAN:
3097 case OP_SPUT_BYTE:
3098 case OP_SPUT_CHAR:
3099 case OP_SPUT_SHORT:
3100 case OP_SPUT_WIDE:
3101 case OP_SPUT_OBJECT:
Andy McFaddenaf0e8382009-08-28 10:38:37 -07003102 refType = VERIFY_ERROR_REF_FIELD;
3103 break;
Andy McFaddenb51ea112009-05-08 16:50:17 -07003104
3105 case OP_INVOKE_VIRTUAL: // insn[1] == method ref, 3 bytes
3106 case OP_INVOKE_VIRTUAL_RANGE:
3107 case OP_INVOKE_SUPER:
3108 case OP_INVOKE_SUPER_RANGE:
3109 case OP_INVOKE_DIRECT:
3110 case OP_INVOKE_DIRECT_RANGE:
3111 case OP_INVOKE_STATIC:
3112 case OP_INVOKE_STATIC_RANGE:
3113 case OP_INVOKE_INTERFACE:
3114 case OP_INVOKE_INTERFACE_RANGE:
Andy McFaddenaf0e8382009-08-28 10:38:37 -07003115 refType = VERIFY_ERROR_REF_METHOD;
Andy McFaddenb51ea112009-05-08 16:50:17 -07003116 break;
Andy McFaddenaf0e8382009-08-28 10:38:37 -07003117
Andy McFaddenb51ea112009-05-08 16:50:17 -07003118 default:
3119 /* could handle this in a generic way, but this is probably safer */
3120 LOG_VFY("GLITCH: verifier asked to replace opcode 0x%02x\n",
3121 oldInsn & 0xff);
3122 goto bail;
3123 }
3124
3125 /* write a NOP over the third code unit, if necessary */
3126 int width = dvmInsnGetWidth(insnFlags, insnIdx);
3127 switch (width) {
3128 case 2:
3129 /* nothing to do */
3130 break;
3131 case 3:
Andy McFadden96516932009-10-28 17:39:02 -07003132 dvmDexChangeDex2(meth->clazz->pDvmDex, newInsns+2, OP_NOP);
3133 //newInsns[2] = OP_NOP;
Andy McFaddenb51ea112009-05-08 16:50:17 -07003134 break;
3135 default:
3136 /* whoops */
3137 LOGE("ERROR: stomped a %d-unit instruction with a verifier error\n",
3138 width);
3139 dvmAbort();
3140 }
3141
3142 /* encode the opcode, with the failure code in the high byte */
Andy McFadden96516932009-10-28 17:39:02 -07003143 u2 newVal = OP_THROW_VERIFICATION_ERROR |
Andy McFaddenaf0e8382009-08-28 10:38:37 -07003144 (failure << 8) | (refType << (8 + kVerifyErrorRefTypeShift));
Andy McFadden96516932009-10-28 17:39:02 -07003145 //newInsns[0] = newVal;
3146 dvmDexChangeDex2(meth->clazz->pDvmDex, newInsns, newVal);
Andy McFaddenb51ea112009-05-08 16:50:17 -07003147
3148 result = true;
3149
3150bail:
Andy McFaddenb51ea112009-05-08 16:50:17 -07003151 return result;
3152}
3153
3154
3155/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003156 * ===========================================================================
3157 * Entry point and driver loop
3158 * ===========================================================================
3159 */
3160
3161/*
Andy McFadden319a33b2010-11-10 07:55:14 -08003162 * One-time preparation.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003163 */
Andy McFadden319a33b2010-11-10 07:55:14 -08003164static void verifyPrep(void)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003165{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003166#ifndef NDEBUG
Andy McFadden319a33b2010-11-10 07:55:14 -08003167 /* only need to do this if the table was updated */
3168 checkMergeTab();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003169#endif
3170
3171 /*
3172 * We rely on these for verification of const-class, const-string,
Andy McFadden319a33b2010-11-10 07:55:14 -08003173 * and throw instructions. Make sure we have them loaded.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003174 */
3175 if (gDvm.classJavaLangClass == NULL)
3176 gDvm.classJavaLangClass =
3177 dvmFindSystemClassNoInit("Ljava/lang/Class;");
3178 if (gDvm.classJavaLangString == NULL)
3179 gDvm.classJavaLangString =
3180 dvmFindSystemClassNoInit("Ljava/lang/String;");
Andy McFadden686e1e22009-05-26 16:56:30 -07003181 if (gDvm.classJavaLangThrowable == NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003182 gDvm.classJavaLangThrowable =
3183 dvmFindSystemClassNoInit("Ljava/lang/Throwable;");
Andy McFadden686e1e22009-05-26 16:56:30 -07003184 gDvm.offJavaLangThrowable_cause =
3185 dvmFindFieldOffset(gDvm.classJavaLangThrowable,
3186 "cause", "Ljava/lang/Throwable;");
3187 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003188 if (gDvm.classJavaLangObject == NULL)
3189 gDvm.classJavaLangObject =
3190 dvmFindSystemClassNoInit("Ljava/lang/Object;");
Andy McFadden319a33b2010-11-10 07:55:14 -08003191}
3192
3193/*
3194 * Entry point for the detailed code-flow analysis of a single method.
3195 */
3196bool dvmVerifyCodeFlow(VerifierData* vdata)
3197{
3198 bool result = false;
3199 const Method* meth = vdata->method;
3200 const int insnsSize = vdata->insnsSize;
3201 const bool generateRegisterMap = gDvm.generateRegisterMaps;
3202 RegisterTable regTable;
3203
3204 memset(&regTable, 0, sizeof(regTable));
3205
3206#ifdef VERIFIER_STATS
3207 gDvm.verifierStats.methodsExamined++;
3208#endif
3209
3210 /* TODO: move this elsewhere -- we don't need to do this for every method */
3211 verifyPrep();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003212
Andy McFadden6be954f2010-06-14 13:37:49 -07003213 if (meth->registersSize * insnsSize > 4*1024*1024) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003214 LOG_VFY_METH(meth,
Andy McFadden34e314a2010-09-28 13:58:16 -07003215 "VFY: warning: method is huge (regs=%d insnsSize=%d)\n",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003216 meth->registersSize, insnsSize);
Andy McFadden34e314a2010-09-28 13:58:16 -07003217 /* might be bogus data, might be some huge generated method */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003218 }
3219
3220 /*
3221 * Create register lists, and initialize them to "Unknown". If we're
3222 * also going to create the register map, we need to retain the
3223 * register lists for a larger set of addresses.
3224 */
Andy McFadden228a6b02010-05-04 15:02:32 -07003225 if (!initRegisterTable(meth, vdata->insnFlags, &regTable,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003226 generateRegisterMap ? kTrackRegsGcPoints : kTrackRegsBranches))
3227 goto bail;
3228
Andy McFadden319a33b2010-11-10 07:55:14 -08003229 vdata->registerLines = NULL; /* don't set this until we need it */
Andy McFadden228a6b02010-05-04 15:02:32 -07003230
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003231 /*
3232 * Initialize the types of the registers that correspond to the
3233 * method arguments. We can determine this from the method signature.
3234 */
Andy McFadden319a33b2010-11-10 07:55:14 -08003235 if (!setTypesFromSignature(meth, regTable.registerLines[0].regTypes,
3236 vdata->uninitMap))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003237 goto bail;
3238
3239 /*
3240 * Run the verifier.
3241 */
Andy McFadden319a33b2010-11-10 07:55:14 -08003242 if (!doCodeVerification(meth, vdata->insnFlags, &regTable,
3243 vdata->uninitMap))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003244 goto bail;
3245
3246 /*
3247 * Generate a register map.
3248 */
3249 if (generateRegisterMap) {
Andy McFadden319a33b2010-11-10 07:55:14 -08003250 vdata->registerLines = regTable.registerLines;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003251
Andy McFadden228a6b02010-05-04 15:02:32 -07003252 RegisterMap* pMap = dvmGenerateRegisterMapV(vdata);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003253 if (pMap != NULL) {
3254 /*
3255 * Tuck it into the Method struct. It will either get used
3256 * directly or, if we're in dexopt, will be packed up and
3257 * appended to the DEX file.
3258 */
3259 dvmSetRegisterMap((Method*)meth, pMap);
3260 }
3261 }
3262
3263 /*
3264 * Success.
3265 */
3266 result = true;
3267
3268bail:
Andy McFadden319a33b2010-11-10 07:55:14 -08003269 free(regTable.registerLines);
3270 free(regTable.lineAlloc);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003271 return result;
3272}
3273
3274/*
3275 * Grind through the instructions.
3276 *
3277 * The basic strategy is as outlined in v3 4.11.1.2: set the "changed" bit
3278 * on the first instruction, process it (setting additional "changed" bits),
3279 * and repeat until there are no more.
3280 *
3281 * v3 4.11.1.1
3282 * - (N/A) operand stack is always the same size
3283 * - operand stack [registers] contain the correct types of values
3284 * - local variables [registers] contain the correct types of values
3285 * - methods are invoked with the appropriate arguments
3286 * - fields are assigned using values of appropriate types
3287 * - opcodes have the correct type values in operand registers
3288 * - there is never an uninitialized class instance in a local variable in
3289 * code protected by an exception handler (operand stack is okay, because
3290 * the operand stack is discarded when an exception is thrown) [can't
3291 * know what's a local var w/o the debug info -- should fall out of
3292 * register typing]
3293 *
3294 * v3 4.11.1.2
3295 * - execution cannot fall off the end of the code
3296 *
3297 * (We also do many of the items described in the "static checks" sections,
3298 * because it's easier to do them here.)
3299 *
3300 * We need an array of RegType values, one per register, for every
Andy McFadden319a33b2010-11-10 07:55:14 -08003301 * instruction. If the method uses monitor-enter, we need extra data
3302 * for every register, and a stack for every "interesting" instruction.
3303 * In theory this could become quite large -- up to several megabytes for
3304 * a monster function.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003305 *
Andy McFadden319a33b2010-11-10 07:55:14 -08003306 * NOTE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003307 * The spec forbids backward branches when there's an uninitialized reference
3308 * in a register. The idea is to prevent something like this:
3309 * loop:
3310 * move r1, r0
3311 * new-instance r0, MyClass
3312 * ...
3313 * if-eq rN, loop // once
3314 * initialize r0
3315 *
3316 * This leaves us with two different instances, both allocated by the
3317 * same instruction, but only one is initialized. The scheme outlined in
3318 * v3 4.11.1.4 wouldn't catch this, so they work around it by preventing
3319 * backward branches. We achieve identical results without restricting
3320 * code reordering by specifying that you can't execute the new-instance
3321 * instruction if a register contains an uninitialized instance created
3322 * by that same instrutcion.
3323 */
Andy McFadden228a6b02010-05-04 15:02:32 -07003324static bool doCodeVerification(const Method* meth, InsnFlags* insnFlags,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003325 RegisterTable* regTable, UninitInstanceMap* uninitMap)
3326{
3327 const int insnsSize = dvmGetMethodInsnsSize(meth);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003328 bool result = false;
3329 bool debugVerbose = false;
Carl Shapiroe3c01da2010-05-20 22:54:18 -07003330 int insnIdx, startGuess;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003331
3332 /*
3333 * Begin by marking the first instruction as "changed".
3334 */
3335 dvmInsnSetChanged(insnFlags, 0, true);
3336
3337 if (doVerboseLogging(meth)) {
3338 IF_LOGI() {
3339 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
3340 LOGI("Now verifying: %s.%s %s (ins=%d regs=%d)\n",
3341 meth->clazz->descriptor, meth->name, desc,
3342 meth->insSize, meth->registersSize);
3343 LOGI(" ------ [0 4 8 12 16 20 24 28 32 36\n");
3344 free(desc);
3345 }
3346 debugVerbose = true;
3347 gDebugVerbose = true;
3348 } else {
3349 gDebugVerbose = false;
3350 }
3351
3352 startGuess = 0;
3353
3354 /*
3355 * Continue until no instructions are marked "changed".
3356 */
3357 while (true) {
3358 /*
3359 * Find the first marked one. Use "startGuess" as a way to find
3360 * one quickly.
3361 */
3362 for (insnIdx = startGuess; insnIdx < insnsSize; insnIdx++) {
3363 if (dvmInsnIsChanged(insnFlags, insnIdx))
3364 break;
3365 }
3366
3367 if (insnIdx == insnsSize) {
3368 if (startGuess != 0) {
3369 /* try again, starting from the top */
3370 startGuess = 0;
3371 continue;
3372 } else {
3373 /* all flags are clear */
3374 break;
3375 }
3376 }
3377
3378 /*
3379 * We carry the working set of registers from instruction to
3380 * instruction. If this address can be the target of a branch
3381 * (or throw) instruction, or if we're skipping around chasing
3382 * "changed" flags, we need to load the set of registers from
3383 * the table.
3384 *
3385 * Because we always prefer to continue on to the next instruction,
3386 * we should never have a situation where we have a stray
3387 * "changed" flag set on an instruction that isn't a branch target.
3388 */
3389 if (dvmInsnIsBranchTarget(insnFlags, insnIdx)) {
Andy McFadden319a33b2010-11-10 07:55:14 -08003390 RegisterLine* workLine = &regTable->workLine;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003391
Andy McFadden319a33b2010-11-10 07:55:14 -08003392 copyLineFromTable(workLine, regTable, insnIdx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003393 } else {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003394#ifndef NDEBUG
3395 /*
3396 * Sanity check: retrieve the stored register line (assuming
3397 * a full table) and make sure it actually matches.
3398 */
Andy McFadden319a33b2010-11-10 07:55:14 -08003399 RegisterLine* registerLine = getRegisterLine(regTable, insnIdx);
3400 if (registerLine->regTypes != NULL &&
3401 compareLineToTable(regTable, insnIdx, &regTable->workLine) != 0)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003402 {
3403 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
Andy McFadden319a33b2010-11-10 07:55:14 -08003404 LOG_VFY("HUH? workLine diverged in %s.%s %s\n",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003405 meth->clazz->descriptor, meth->name, desc);
3406 free(desc);
Andy McFadden319a33b2010-11-10 07:55:14 -08003407 dumpRegTypes(meth, insnFlags, registerLine, 0, "work",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003408 uninitMap, DRT_SHOW_REF_TYPES | DRT_SHOW_LOCALS);
Andy McFadden319a33b2010-11-10 07:55:14 -08003409 dumpRegTypes(meth, insnFlags, registerLine, 0, "insn",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003410 uninitMap, DRT_SHOW_REF_TYPES | DRT_SHOW_LOCALS);
3411 }
3412#endif
3413 }
Andy McFadden319a33b2010-11-10 07:55:14 -08003414 if (debugVerbose) {
3415 dumpRegTypes(meth, insnFlags, &regTable->workLine, insnIdx,
3416 NULL, uninitMap, SHOW_REG_DETAILS);
3417 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003418
3419 //LOGI("process %s.%s %s %d\n",
3420 // meth->clazz->descriptor, meth->name, meth->descriptor, insnIdx);
Andy McFadden319a33b2010-11-10 07:55:14 -08003421 if (!verifyInstruction(meth, insnFlags, regTable, insnIdx,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003422 uninitMap, &startGuess))
3423 {
3424 //LOGD("+++ %s bailing at %d\n", meth->name, insnIdx);
3425 goto bail;
3426 }
3427
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003428 /*
3429 * Clear "changed" and mark as visited.
3430 */
3431 dvmInsnSetVisited(insnFlags, insnIdx, true);
3432 dvmInsnSetChanged(insnFlags, insnIdx, false);
3433 }
3434
Andy McFaddenb51ea112009-05-08 16:50:17 -07003435 if (DEAD_CODE_SCAN && !IS_METHOD_FLAG_SET(meth, METHOD_ISWRITABLE)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003436 /*
Andy McFaddenb51ea112009-05-08 16:50:17 -07003437 * Scan for dead code. There's nothing "evil" about dead code
3438 * (besides the wasted space), but it indicates a flaw somewhere
3439 * down the line, possibly in the verifier.
3440 *
Andy McFadden319a33b2010-11-10 07:55:14 -08003441 * If we've substituted "always throw" instructions into the stream,
Andy McFaddenb51ea112009-05-08 16:50:17 -07003442 * we are almost certainly going to have some dead code.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003443 */
3444 int deadStart = -1;
3445 for (insnIdx = 0; insnIdx < insnsSize;
3446 insnIdx += dvmInsnGetWidth(insnFlags, insnIdx))
3447 {
3448 /*
3449 * Switch-statement data doesn't get "visited" by scanner. It
Andy McFadden319a33b2010-11-10 07:55:14 -08003450 * may or may not be preceded by a padding NOP (for alignment).
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003451 */
3452 int instr = meth->insns[insnIdx];
3453 if (instr == kPackedSwitchSignature ||
3454 instr == kSparseSwitchSignature ||
3455 instr == kArrayDataSignature ||
3456 (instr == OP_NOP &&
3457 (meth->insns[insnIdx+1] == kPackedSwitchSignature ||
3458 meth->insns[insnIdx+1] == kSparseSwitchSignature ||
3459 meth->insns[insnIdx+1] == kArrayDataSignature)))
3460 {
3461 dvmInsnSetVisited(insnFlags, insnIdx, true);
3462 }
3463
3464 if (!dvmInsnIsVisited(insnFlags, insnIdx)) {
3465 if (deadStart < 0)
3466 deadStart = insnIdx;
3467 } else if (deadStart >= 0) {
3468 IF_LOGD() {
3469 char* desc =
3470 dexProtoCopyMethodDescriptor(&meth->prototype);
3471 LOGD("VFY: dead code 0x%04x-%04x in %s.%s %s\n",
3472 deadStart, insnIdx-1,
3473 meth->clazz->descriptor, meth->name, desc);
3474 free(desc);
3475 }
3476
3477 deadStart = -1;
3478 }
3479 }
3480 if (deadStart >= 0) {
3481 IF_LOGD() {
3482 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
3483 LOGD("VFY: dead code 0x%04x-%04x in %s.%s %s\n",
3484 deadStart, insnIdx-1,
3485 meth->clazz->descriptor, meth->name, desc);
3486 free(desc);
3487 }
3488 }
3489 }
3490
3491 result = true;
3492
3493bail:
3494 return result;
3495}
3496
3497
3498/*
3499 * Perform verification for a single instruction.
3500 *
3501 * This requires fully decoding the instruction to determine the effect
3502 * it has on registers.
3503 *
3504 * Finds zero or more following instructions and sets the "changed" flag
3505 * if execution at that point needs to be (re-)evaluated. Register changes
3506 * are merged into "regTypes" at the target addresses. Does not set or
3507 * clear any other flags in "insnFlags".
Andy McFaddenb51ea112009-05-08 16:50:17 -07003508 *
3509 * This may alter meth->insns if we need to replace an instruction with
3510 * throw-verification-error.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003511 */
Andy McFadden228a6b02010-05-04 15:02:32 -07003512static bool verifyInstruction(const Method* meth, InsnFlags* insnFlags,
Andy McFadden319a33b2010-11-10 07:55:14 -08003513 RegisterTable* regTable, int insnIdx, UninitInstanceMap* uninitMap,
3514 int* pStartGuess)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003515{
3516 const int insnsSize = dvmGetMethodInsnsSize(meth);
3517 const u2* insns = meth->insns + insnIdx;
3518 bool result = false;
3519
Andy McFadden470cbbb2010-11-04 16:31:37 -07003520#ifdef VERIFIER_STATS
3521 if (dvmInsnIsVisited(insnFlags, insnIdx)) {
3522 gDvm.verifierStats.instrsReexamined++;
3523 } else {
3524 gDvm.verifierStats.instrsExamined++;
3525 }
3526#endif
3527
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003528 /*
3529 * Once we finish decoding the instruction, we need to figure out where
3530 * we can go from here. There are three possible ways to transfer
3531 * control to another statement:
3532 *
3533 * (1) Continue to the next instruction. Applies to all but
3534 * unconditional branches, method returns, and exception throws.
3535 * (2) Branch to one or more possible locations. Applies to branches
3536 * and switch statements.
3537 * (3) Exception handlers. Applies to any instruction that can
3538 * throw an exception that is handled by an encompassing "try"
Andy McFadden228a6b02010-05-04 15:02:32 -07003539 * block.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003540 *
3541 * We can also return, in which case there is no successor instruction
3542 * from this point.
3543 *
Andy McFadden228a6b02010-05-04 15:02:32 -07003544 * The behavior can be determined from the InstructionFlags.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003545 */
3546
Andy McFadden319a33b2010-11-10 07:55:14 -08003547 RegisterLine* workLine = &regTable->workLine;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003548 const DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003549 ClassObject* resClass;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003550 int branchTarget = 0;
3551 const int insnRegCount = meth->registersSize;
3552 RegType tmpType;
3553 DecodedInstruction decInsn;
3554 bool justSetResult = false;
Andy McFadden62a75162009-04-17 17:23:37 -07003555 VerifyError failure = VERIFY_ERROR_NONE;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003556
3557#ifndef NDEBUG
3558 memset(&decInsn, 0x81, sizeof(decInsn));
3559#endif
Dan Bornstein44a38f42010-11-10 17:34:32 -08003560 dexDecodeInstruction(&gDvm.instrInfo, insns, &decInsn);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003561
Dan Bornstein44a38f42010-11-10 17:34:32 -08003562 int nextFlags = dexGetInstrFlags(gDvm.instrInfo.flags, decInsn.opCode);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003563
3564 /*
3565 * Make a copy of the previous register state. If the instruction
Andy McFadden319a33b2010-11-10 07:55:14 -08003566 * can throw an exception, we will copy/merge this into the "catch"
3567 * address rather than workLine, because we don't want the result
3568 * from the "successful" code path (e.g. a check-cast that "improves"
3569 * a type) to be visible to the exception handler.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003570 */
3571 if ((nextFlags & kInstrCanThrow) != 0 && dvmInsnIsInTry(insnFlags, insnIdx))
3572 {
Andy McFadden319a33b2010-11-10 07:55:14 -08003573 copyRegisterLine(&regTable->savedLine, workLine,
3574 regTable->insnRegCountPlus);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003575 } else {
3576#ifndef NDEBUG
Andy McFadden319a33b2010-11-10 07:55:14 -08003577 memset(regTable->savedLine.regTypes, 0xdd,
3578 regTable->insnRegCountPlus * sizeof(RegType));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003579#endif
3580 }
3581
3582 switch (decInsn.opCode) {
3583 case OP_NOP:
3584 /*
3585 * A "pure" NOP has no effect on anything. Data tables start with
3586 * a signature that looks like a NOP; if we see one of these in
3587 * the course of executing code then we have a problem.
3588 */
3589 if (decInsn.vA != 0) {
3590 LOG_VFY("VFY: encountered data table in instruction stream\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003591 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003592 }
3593 break;
3594
3595 case OP_MOVE:
3596 case OP_MOVE_FROM16:
3597 case OP_MOVE_16:
Andy McFadden319a33b2010-11-10 07:55:14 -08003598 copyRegister1(workLine, decInsn.vA, decInsn.vB, kTypeCategory1nr,
Andy McFaddend3250112010-11-03 14:32:42 -07003599 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003600 break;
3601 case OP_MOVE_WIDE:
3602 case OP_MOVE_WIDE_FROM16:
3603 case OP_MOVE_WIDE_16:
Andy McFadden319a33b2010-11-10 07:55:14 -08003604 copyRegister2(workLine, decInsn.vA, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003605 break;
3606 case OP_MOVE_OBJECT:
3607 case OP_MOVE_OBJECT_FROM16:
3608 case OP_MOVE_OBJECT_16:
Andy McFadden319a33b2010-11-10 07:55:14 -08003609 copyRegister1(workLine, decInsn.vA, decInsn.vB, kTypeCategoryRef,
Andy McFaddend3250112010-11-03 14:32:42 -07003610 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003611 break;
3612
3613 /*
3614 * The move-result instructions copy data out of a "pseudo-register"
3615 * with the results from the last method invocation. In practice we
3616 * might want to hold the result in an actual CPU register, so the
3617 * Dalvik spec requires that these only appear immediately after an
3618 * invoke or filled-new-array.
3619 *
3620 * These calls invalidate the "result" register. (This is now
3621 * redundant with the reset done below, but it can make the debug info
3622 * easier to read in some cases.)
3623 */
3624 case OP_MOVE_RESULT:
Andy McFadden319a33b2010-11-10 07:55:14 -08003625 copyResultRegister1(workLine, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003626 kTypeCategory1nr, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003627 break;
3628 case OP_MOVE_RESULT_WIDE:
Andy McFadden319a33b2010-11-10 07:55:14 -08003629 copyResultRegister2(workLine, insnRegCount, decInsn.vA, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003630 break;
3631 case OP_MOVE_RESULT_OBJECT:
Andy McFadden319a33b2010-11-10 07:55:14 -08003632 copyResultRegister1(workLine, insnRegCount, decInsn.vA,
Andy McFadden62a75162009-04-17 17:23:37 -07003633 kTypeCategoryRef, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003634 break;
3635
3636 case OP_MOVE_EXCEPTION:
3637 /*
3638 * This statement can only appear as the first instruction in an
3639 * exception handler (though not all exception handlers need to
3640 * have one of these). We verify that as part of extracting the
3641 * exception type from the catch block list.
3642 *
3643 * "resClass" will hold the closest common superclass of all
3644 * exceptions that can be handled here.
3645 */
Andy McFadden62a75162009-04-17 17:23:37 -07003646 resClass = getCaughtExceptionType(meth, insnIdx, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003647 if (resClass == NULL) {
Andy McFadden62a75162009-04-17 17:23:37 -07003648 assert(!VERIFY_OK(failure));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003649 } else {
Andy McFadden319a33b2010-11-10 07:55:14 -08003650 setRegisterType(workLine, decInsn.vA, regTypeFromClass(resClass));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003651 }
3652 break;
3653
3654 case OP_RETURN_VOID:
Andy McFadden319a33b2010-11-10 07:55:14 -08003655 if (!checkConstructorReturn(meth, workLine, insnRegCount)) {
Andy McFadden62a75162009-04-17 17:23:37 -07003656 failure = VERIFY_ERROR_GENERIC;
3657 } else if (getMethodReturnType(meth) != kRegTypeUnknown) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003658 LOG_VFY("VFY: return-void not expected\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003659 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003660 }
3661 break;
3662 case OP_RETURN:
Andy McFadden319a33b2010-11-10 07:55:14 -08003663 if (!checkConstructorReturn(meth, workLine, insnRegCount)) {
Andy McFadden62a75162009-04-17 17:23:37 -07003664 failure = VERIFY_ERROR_GENERIC;
3665 } else {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003666 /* check the method signature */
3667 RegType returnType = getMethodReturnType(meth);
Andy McFadden62a75162009-04-17 17:23:37 -07003668 checkTypeCategory(returnType, kTypeCategory1nr, &failure);
3669 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003670 LOG_VFY("VFY: return-32 not expected\n");
3671
3672 /* check the register contents */
Andy McFadden319a33b2010-11-10 07:55:14 -08003673 returnType = getRegisterType(workLine, decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07003674 checkTypeCategory(returnType, kTypeCategory1nr, &failure);
3675 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003676 LOG_VFY("VFY: return-32 on invalid register v%d\n", decInsn.vA);
3677 }
3678 break;
3679 case OP_RETURN_WIDE:
Andy McFadden319a33b2010-11-10 07:55:14 -08003680 if (!checkConstructorReturn(meth, workLine, insnRegCount)) {
Andy McFadden62a75162009-04-17 17:23:37 -07003681 failure = VERIFY_ERROR_GENERIC;
3682 } else {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003683 RegType returnType, returnTypeHi;
3684
3685 /* check the method signature */
3686 returnType = getMethodReturnType(meth);
Andy McFadden62a75162009-04-17 17:23:37 -07003687 checkTypeCategory(returnType, kTypeCategory2, &failure);
3688 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003689 LOG_VFY("VFY: return-wide not expected\n");
3690
3691 /* check the register contents */
Andy McFadden319a33b2010-11-10 07:55:14 -08003692 returnType = getRegisterType(workLine, decInsn.vA);
3693 returnTypeHi = getRegisterType(workLine, decInsn.vA +1);
Andy McFaddend3250112010-11-03 14:32:42 -07003694 checkTypeCategory(returnType, kTypeCategory2, &failure);
3695 checkWidePair(returnType, returnTypeHi, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07003696 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003697 LOG_VFY("VFY: return-wide on invalid register pair v%d\n",
3698 decInsn.vA);
3699 }
3700 }
3701 break;
3702 case OP_RETURN_OBJECT:
Andy McFadden319a33b2010-11-10 07:55:14 -08003703 if (!checkConstructorReturn(meth, workLine, insnRegCount)) {
Andy McFadden62a75162009-04-17 17:23:37 -07003704 failure = VERIFY_ERROR_GENERIC;
3705 } else {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003706 RegType returnType = getMethodReturnType(meth);
Andy McFadden62a75162009-04-17 17:23:37 -07003707 checkTypeCategory(returnType, kTypeCategoryRef, &failure);
3708 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003709 LOG_VFY("VFY: return-object not expected\n");
3710 break;
3711 }
3712
3713 /* returnType is the *expected* return type, not register value */
3714 assert(returnType != kRegTypeZero);
3715 assert(!regTypeIsUninitReference(returnType));
3716
3717 /*
3718 * Verify that the reference in vAA is an instance of the type
3719 * in "returnType". The Zero type is allowed here. If the
3720 * method is declared to return an interface, then any
3721 * initialized reference is acceptable.
3722 *
3723 * Note getClassFromRegister fails if the register holds an
3724 * uninitialized reference, so we do not allow them to be
3725 * returned.
3726 */
3727 ClassObject* declClass;
3728
3729 declClass = regTypeInitializedReferenceToClass(returnType);
Andy McFadden319a33b2010-11-10 07:55:14 -08003730 resClass = getClassFromRegister(workLine, decInsn.vA, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07003731 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003732 break;
3733 if (resClass != NULL) {
3734 if (!dvmIsInterfaceClass(declClass) &&
3735 !dvmInstanceof(resClass, declClass))
3736 {
Andy McFadden86c86432009-05-27 14:40:12 -07003737 LOG_VFY("VFY: returning %s (cl=%p), declared %s (cl=%p)\n",
3738 resClass->descriptor, resClass->classLoader,
3739 declClass->descriptor, declClass->classLoader);
Andy McFadden62a75162009-04-17 17:23:37 -07003740 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003741 break;
3742 }
3743 }
3744 }
3745 break;
3746
3747 case OP_CONST_4:
3748 case OP_CONST_16:
3749 case OP_CONST:
3750 /* could be boolean, int, float, or a null reference */
Andy McFadden319a33b2010-11-10 07:55:14 -08003751 setRegisterType(workLine, decInsn.vA,
Andy McFadden470cbbb2010-11-04 16:31:37 -07003752 determineCat1Const((s4)decInsn.vB));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003753 break;
3754 case OP_CONST_HIGH16:
3755 /* could be boolean, int, float, or a null reference */
Andy McFadden319a33b2010-11-10 07:55:14 -08003756 setRegisterType(workLine, decInsn.vA,
Andy McFadden470cbbb2010-11-04 16:31:37 -07003757 determineCat1Const((s4) decInsn.vB << 16));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003758 break;
3759 case OP_CONST_WIDE_16:
3760 case OP_CONST_WIDE_32:
3761 case OP_CONST_WIDE:
3762 case OP_CONST_WIDE_HIGH16:
3763 /* could be long or double; default to long and allow conversion */
Andy McFadden319a33b2010-11-10 07:55:14 -08003764 setRegisterType(workLine, decInsn.vA, kRegTypeLongLo);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003765 break;
3766 case OP_CONST_STRING:
3767 case OP_CONST_STRING_JUMBO:
3768 assert(gDvm.classJavaLangString != NULL);
Andy McFadden319a33b2010-11-10 07:55:14 -08003769 setRegisterType(workLine, decInsn.vA,
Andy McFaddend3250112010-11-03 14:32:42 -07003770 regTypeFromClass(gDvm.classJavaLangString));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003771 break;
3772 case OP_CONST_CLASS:
3773 assert(gDvm.classJavaLangClass != NULL);
3774 /* make sure we can resolve the class; access check is important */
Andy McFadden62a75162009-04-17 17:23:37 -07003775 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003776 if (resClass == NULL) {
3777 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3778 dvmLogUnableToResolveClass(badClassDesc, meth);
3779 LOG_VFY("VFY: unable to resolve const-class %d (%s) in %s\n",
3780 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003781 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003782 } else {
Andy McFadden319a33b2010-11-10 07:55:14 -08003783 setRegisterType(workLine, decInsn.vA,
Andy McFaddend3250112010-11-03 14:32:42 -07003784 regTypeFromClass(gDvm.classJavaLangClass));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003785 }
3786 break;
3787
3788 case OP_MONITOR_ENTER:
3789 case OP_MONITOR_EXIT:
Andy McFadden319a33b2010-11-10 07:55:14 -08003790 tmpType = getRegisterType(workLine, decInsn.vA);
Andy McFaddend3250112010-11-03 14:32:42 -07003791 if (!regTypeIsReference(tmpType)) {
3792 LOG_VFY("VFY: monitor op on non-object\n");
3793 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003794 }
3795 break;
3796
3797 case OP_CHECK_CAST:
3798 /*
3799 * If this instruction succeeds, we will promote register vA to
3800 * the type in vB. (This could be a demotion -- not expected, so
3801 * we don't try to address it.)
3802 *
3803 * If it fails, an exception is thrown, which we deal with later
3804 * by ignoring the update to decInsn.vA when branching to a handler.
3805 */
Andy McFadden62a75162009-04-17 17:23:37 -07003806 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003807 if (resClass == NULL) {
3808 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3809 dvmLogUnableToResolveClass(badClassDesc, meth);
3810 LOG_VFY("VFY: unable to resolve check-cast %d (%s) in %s\n",
3811 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003812 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003813 } else {
3814 RegType origType;
3815
Andy McFadden319a33b2010-11-10 07:55:14 -08003816 origType = getRegisterType(workLine, decInsn.vA);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003817 if (!regTypeIsReference(origType)) {
3818 LOG_VFY("VFY: check-cast on non-reference in v%u\n",decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07003819 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003820 break;
3821 }
Andy McFadden319a33b2010-11-10 07:55:14 -08003822 setRegisterType(workLine, decInsn.vA, regTypeFromClass(resClass));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003823 }
3824 break;
3825 case OP_INSTANCE_OF:
3826 /* make sure we're checking a reference type */
Andy McFadden319a33b2010-11-10 07:55:14 -08003827 tmpType = getRegisterType(workLine, decInsn.vB);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003828 if (!regTypeIsReference(tmpType)) {
3829 LOG_VFY("VFY: vB not a reference (%d)\n", tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07003830 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003831 break;
3832 }
3833
3834 /* make sure we can resolve the class; access check is important */
Andy McFadden62a75162009-04-17 17:23:37 -07003835 resClass = dvmOptResolveClass(meth->clazz, decInsn.vC, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003836 if (resClass == NULL) {
3837 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vC);
3838 dvmLogUnableToResolveClass(badClassDesc, meth);
3839 LOG_VFY("VFY: unable to resolve instanceof %d (%s) in %s\n",
3840 decInsn.vC, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003841 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003842 } else {
3843 /* result is boolean */
Andy McFadden319a33b2010-11-10 07:55:14 -08003844 setRegisterType(workLine, decInsn.vA, kRegTypeBoolean);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003845 }
3846 break;
3847
3848 case OP_ARRAY_LENGTH:
Andy McFadden319a33b2010-11-10 07:55:14 -08003849 resClass = getClassFromRegister(workLine, decInsn.vB, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07003850 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003851 break;
3852 if (resClass != NULL && !dvmIsArrayClass(resClass)) {
3853 LOG_VFY("VFY: array-length on non-array\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003854 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003855 break;
3856 }
Andy McFadden319a33b2010-11-10 07:55:14 -08003857 setRegisterType(workLine, decInsn.vA, kRegTypeInteger);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003858 break;
3859
3860 case OP_NEW_INSTANCE:
Andy McFadden62a75162009-04-17 17:23:37 -07003861 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003862 if (resClass == NULL) {
3863 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3864 dvmLogUnableToResolveClass(badClassDesc, meth);
3865 LOG_VFY("VFY: unable to resolve new-instance %d (%s) in %s\n",
3866 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003867 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003868 } else {
3869 RegType uninitType;
3870
Andy McFaddenb51ea112009-05-08 16:50:17 -07003871 /* can't create an instance of an interface or abstract class */
3872 if (dvmIsAbstractClass(resClass) || dvmIsInterfaceClass(resClass)) {
3873 LOG_VFY("VFY: new-instance on interface or abstract class %s\n",
3874 resClass->descriptor);
3875 failure = VERIFY_ERROR_INSTANTIATION;
3876 break;
3877 }
3878
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003879 /* add resolved class to uninit map if not already there */
3880 int uidx = dvmSetUninitInstance(uninitMap, insnIdx, resClass);
3881 assert(uidx >= 0);
3882 uninitType = regTypeFromUninitIndex(uidx);
3883
3884 /*
3885 * Any registers holding previous allocations from this address
3886 * that have not yet been initialized must be marked invalid.
3887 */
Andy McFadden319a33b2010-11-10 07:55:14 -08003888 markUninitRefsAsInvalid(workLine, insnRegCount, uninitMap,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003889 uninitType);
3890
3891 /* add the new uninitialized reference to the register ste */
Andy McFadden319a33b2010-11-10 07:55:14 -08003892 setRegisterType(workLine, decInsn.vA, uninitType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003893 }
3894 break;
3895 case OP_NEW_ARRAY:
Andy McFadden62a75162009-04-17 17:23:37 -07003896 resClass = dvmOptResolveClass(meth->clazz, decInsn.vC, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003897 if (resClass == NULL) {
3898 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vC);
3899 dvmLogUnableToResolveClass(badClassDesc, meth);
3900 LOG_VFY("VFY: unable to resolve new-array %d (%s) in %s\n",
3901 decInsn.vC, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003902 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003903 } else if (!dvmIsArrayClass(resClass)) {
3904 LOG_VFY("VFY: new-array on non-array class\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003905 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003906 } else {
3907 /* make sure "size" register is valid type */
Andy McFadden319a33b2010-11-10 07:55:14 -08003908 verifyRegisterType(workLine, decInsn.vB, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003909 /* set register type to array class */
Andy McFadden319a33b2010-11-10 07:55:14 -08003910 setRegisterType(workLine, decInsn.vA, regTypeFromClass(resClass));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003911 }
3912 break;
3913 case OP_FILLED_NEW_ARRAY:
3914 case OP_FILLED_NEW_ARRAY_RANGE:
Andy McFadden62a75162009-04-17 17:23:37 -07003915 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003916 if (resClass == NULL) {
3917 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3918 dvmLogUnableToResolveClass(badClassDesc, meth);
3919 LOG_VFY("VFY: unable to resolve filled-array %d (%s) in %s\n",
3920 decInsn.vB, badClassDesc, meth->clazz->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003921 assert(failure != VERIFY_ERROR_GENERIC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003922 } else if (!dvmIsArrayClass(resClass)) {
3923 LOG_VFY("VFY: filled-new-array on non-array class\n");
Andy McFadden62a75162009-04-17 17:23:37 -07003924 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003925 } else {
3926 bool isRange = (decInsn.opCode == OP_FILLED_NEW_ARRAY_RANGE);
3927
3928 /* check the arguments to the instruction */
Andy McFadden319a33b2010-11-10 07:55:14 -08003929 verifyFilledNewArrayRegs(meth, workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07003930 resClass, isRange, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003931 /* filled-array result goes into "result" register */
Andy McFadden319a33b2010-11-10 07:55:14 -08003932 setResultRegisterType(workLine, insnRegCount,
Andy McFaddend3250112010-11-03 14:32:42 -07003933 regTypeFromClass(resClass));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003934 justSetResult = true;
3935 }
3936 break;
3937
3938 case OP_CMPL_FLOAT:
3939 case OP_CMPG_FLOAT:
Andy McFadden319a33b2010-11-10 07:55:14 -08003940 verifyRegisterType(workLine, decInsn.vB, kRegTypeFloat, &failure);
3941 verifyRegisterType(workLine, decInsn.vC, kRegTypeFloat, &failure);
3942 setRegisterType(workLine, decInsn.vA, kRegTypeBoolean);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003943 break;
3944 case OP_CMPL_DOUBLE:
3945 case OP_CMPG_DOUBLE:
Andy McFadden319a33b2010-11-10 07:55:14 -08003946 verifyRegisterType(workLine, decInsn.vB, kRegTypeDoubleLo, &failure);
3947 verifyRegisterType(workLine, decInsn.vC, kRegTypeDoubleLo, &failure);
3948 setRegisterType(workLine, decInsn.vA, kRegTypeBoolean);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003949 break;
3950 case OP_CMP_LONG:
Andy McFadden319a33b2010-11-10 07:55:14 -08003951 verifyRegisterType(workLine, decInsn.vB, kRegTypeLongLo, &failure);
3952 verifyRegisterType(workLine, decInsn.vC, kRegTypeLongLo, &failure);
3953 setRegisterType(workLine, decInsn.vA, kRegTypeBoolean);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003954 break;
3955
3956 case OP_THROW:
Andy McFadden319a33b2010-11-10 07:55:14 -08003957 resClass = getClassFromRegister(workLine, decInsn.vA, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07003958 if (VERIFY_OK(failure) && resClass != NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003959 if (!dvmInstanceof(resClass, gDvm.classJavaLangThrowable)) {
3960 LOG_VFY("VFY: thrown class %s not instanceof Throwable\n",
3961 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07003962 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003963 }
3964 }
3965 break;
3966
3967 case OP_GOTO:
3968 case OP_GOTO_16:
3969 case OP_GOTO_32:
3970 /* no effect on or use of registers */
3971 break;
3972
3973 case OP_PACKED_SWITCH:
3974 case OP_SPARSE_SWITCH:
3975 /* verify that vAA is an integer, or can be converted to one */
Andy McFadden319a33b2010-11-10 07:55:14 -08003976 verifyRegisterType(workLine, decInsn.vA, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003977 break;
3978
3979 case OP_FILL_ARRAY_DATA:
3980 {
3981 RegType valueType;
3982 const u2 *arrayData;
3983 u2 elemWidth;
3984
3985 /* Similar to the verification done for APUT */
Andy McFadden319a33b2010-11-10 07:55:14 -08003986 resClass = getClassFromRegister(workLine, decInsn.vA, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07003987 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08003988 break;
3989
3990 /* resClass can be null if the reg type is Zero */
3991 if (resClass == NULL)
3992 break;
3993
3994 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
3995 resClass->elementClass->primitiveType == PRIM_NOT ||
3996 resClass->elementClass->primitiveType == PRIM_VOID)
3997 {
3998 LOG_VFY("VFY: invalid fill-array-data on %s\n",
3999 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004000 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004001 break;
4002 }
4003
4004 valueType = primitiveTypeToRegType(
4005 resClass->elementClass->primitiveType);
4006 assert(valueType != kRegTypeUnknown);
4007
4008 /*
4009 * Now verify if the element width in the table matches the element
4010 * width declared in the array
4011 */
4012 arrayData = insns + (insns[1] | (((s4)insns[2]) << 16));
4013 if (arrayData[0] != kArrayDataSignature) {
4014 LOG_VFY("VFY: invalid magic for array-data\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004015 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004016 break;
4017 }
4018
4019 switch (resClass->elementClass->primitiveType) {
4020 case PRIM_BOOLEAN:
4021 case PRIM_BYTE:
4022 elemWidth = 1;
4023 break;
4024 case PRIM_CHAR:
4025 case PRIM_SHORT:
4026 elemWidth = 2;
4027 break;
4028 case PRIM_FLOAT:
4029 case PRIM_INT:
4030 elemWidth = 4;
4031 break;
4032 case PRIM_DOUBLE:
4033 case PRIM_LONG:
4034 elemWidth = 8;
4035 break;
4036 default:
4037 elemWidth = 0;
4038 break;
4039 }
4040
4041 /*
4042 * Since we don't compress the data in Dex, expect to see equal
4043 * width of data stored in the table and expected from the array
4044 * class.
4045 */
4046 if (arrayData[1] != elemWidth) {
4047 LOG_VFY("VFY: array-data size mismatch (%d vs %d)\n",
4048 arrayData[1], elemWidth);
Andy McFadden62a75162009-04-17 17:23:37 -07004049 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004050 }
4051 }
4052 break;
4053
4054 case OP_IF_EQ:
4055 case OP_IF_NE:
4056 {
4057 RegType type1, type2;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004058
Andy McFadden319a33b2010-11-10 07:55:14 -08004059 type1 = getRegisterType(workLine, decInsn.vA);
4060 type2 = getRegisterType(workLine, decInsn.vB);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004061
4062 /* both references? */
4063 if (regTypeIsReference(type1) && regTypeIsReference(type2))
4064 break;
4065
4066 /* both category-1nr? */
Andy McFadden62a75162009-04-17 17:23:37 -07004067 checkTypeCategory(type1, kTypeCategory1nr, &failure);
4068 checkTypeCategory(type2, kTypeCategory1nr, &failure);
4069 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004070 LOG_VFY("VFY: args to if-eq/if-ne must both be refs or cat1\n");
4071 break;
4072 }
4073 }
4074 break;
4075 case OP_IF_LT:
4076 case OP_IF_GE:
4077 case OP_IF_GT:
4078 case OP_IF_LE:
Andy McFadden319a33b2010-11-10 07:55:14 -08004079 tmpType = getRegisterType(workLine, decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07004080 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
4081 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004082 LOG_VFY("VFY: args to 'if' must be cat-1nr\n");
4083 break;
4084 }
Andy McFadden319a33b2010-11-10 07:55:14 -08004085 tmpType = getRegisterType(workLine, decInsn.vB);
Andy McFadden62a75162009-04-17 17:23:37 -07004086 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
4087 if (!VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004088 LOG_VFY("VFY: args to 'if' must be cat-1nr\n");
4089 break;
4090 }
4091 break;
4092 case OP_IF_EQZ:
4093 case OP_IF_NEZ:
Andy McFadden319a33b2010-11-10 07:55:14 -08004094 tmpType = getRegisterType(workLine, decInsn.vA);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004095 if (regTypeIsReference(tmpType))
4096 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004097 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
4098 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004099 LOG_VFY("VFY: expected cat-1 arg to if\n");
4100 break;
4101 case OP_IF_LTZ:
4102 case OP_IF_GEZ:
4103 case OP_IF_GTZ:
4104 case OP_IF_LEZ:
Andy McFadden319a33b2010-11-10 07:55:14 -08004105 tmpType = getRegisterType(workLine, decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07004106 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
4107 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004108 LOG_VFY("VFY: expected cat-1 arg to if\n");
4109 break;
4110
4111 case OP_AGET:
4112 tmpType = kRegTypeInteger;
4113 goto aget_1nr_common;
4114 case OP_AGET_BOOLEAN:
4115 tmpType = kRegTypeBoolean;
4116 goto aget_1nr_common;
4117 case OP_AGET_BYTE:
4118 tmpType = kRegTypeByte;
4119 goto aget_1nr_common;
4120 case OP_AGET_CHAR:
4121 tmpType = kRegTypeChar;
4122 goto aget_1nr_common;
4123 case OP_AGET_SHORT:
4124 tmpType = kRegTypeShort;
4125 goto aget_1nr_common;
4126aget_1nr_common:
4127 {
4128 RegType srcType, indexType;
4129
Andy McFadden319a33b2010-11-10 07:55:14 -08004130 indexType = getRegisterType(workLine, decInsn.vC);
Andy McFadden62a75162009-04-17 17:23:37 -07004131 checkArrayIndexType(meth, indexType, &failure);
4132 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004133 break;
4134
Andy McFadden319a33b2010-11-10 07:55:14 -08004135 resClass = getClassFromRegister(workLine, decInsn.vB, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07004136 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004137 break;
4138 if (resClass != NULL) {
4139 /* verify the class */
4140 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4141 resClass->elementClass->primitiveType == PRIM_NOT)
4142 {
4143 LOG_VFY("VFY: invalid aget-1nr target %s\n",
4144 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004145 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004146 break;
4147 }
4148
4149 /* make sure array type matches instruction */
4150 srcType = primitiveTypeToRegType(
4151 resClass->elementClass->primitiveType);
4152
4153 if (!checkFieldArrayStore1nr(tmpType, srcType)) {
4154 LOG_VFY("VFY: invalid aget-1nr, array type=%d with"
4155 " inst type=%d (on %s)\n",
4156 srcType, tmpType, resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004157 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004158 break;
4159 }
4160
4161 }
Andy McFadden319a33b2010-11-10 07:55:14 -08004162 setRegisterType(workLine, decInsn.vA, tmpType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004163 }
4164 break;
4165
4166 case OP_AGET_WIDE:
4167 {
4168 RegType dstType, indexType;
4169
Andy McFadden319a33b2010-11-10 07:55:14 -08004170 indexType = getRegisterType(workLine, decInsn.vC);
Andy McFadden62a75162009-04-17 17:23:37 -07004171 checkArrayIndexType(meth, indexType, &failure);
4172 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004173 break;
4174
Andy McFadden319a33b2010-11-10 07:55:14 -08004175 resClass = getClassFromRegister(workLine, decInsn.vB, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07004176 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004177 break;
4178 if (resClass != NULL) {
4179 /* verify the class */
4180 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4181 resClass->elementClass->primitiveType == PRIM_NOT)
4182 {
4183 LOG_VFY("VFY: invalid aget-wide target %s\n",
4184 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004185 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004186 break;
4187 }
4188
4189 /* try to refine "dstType" */
4190 switch (resClass->elementClass->primitiveType) {
4191 case PRIM_LONG:
4192 dstType = kRegTypeLongLo;
4193 break;
4194 case PRIM_DOUBLE:
4195 dstType = kRegTypeDoubleLo;
4196 break;
4197 default:
4198 LOG_VFY("VFY: invalid aget-wide on %s\n",
4199 resClass->descriptor);
4200 dstType = kRegTypeUnknown;
Andy McFadden62a75162009-04-17 17:23:37 -07004201 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004202 break;
4203 }
4204 } else {
4205 /*
4206 * Null array ref; this code path will fail at runtime. We
4207 * know this is either long or double, and we don't really
4208 * discriminate between those during verification, so we
4209 * call it a long.
4210 */
4211 dstType = kRegTypeLongLo;
4212 }
Andy McFadden319a33b2010-11-10 07:55:14 -08004213 setRegisterType(workLine, decInsn.vA, dstType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004214 }
4215 break;
4216
4217 case OP_AGET_OBJECT:
4218 {
4219 RegType dstType, indexType;
4220
Andy McFadden319a33b2010-11-10 07:55:14 -08004221 indexType = getRegisterType(workLine, decInsn.vC);
Andy McFadden62a75162009-04-17 17:23:37 -07004222 checkArrayIndexType(meth, indexType, &failure);
4223 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004224 break;
4225
4226 /* get the class of the array we're pulling an object from */
Andy McFadden319a33b2010-11-10 07:55:14 -08004227 resClass = getClassFromRegister(workLine, decInsn.vB, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07004228 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004229 break;
4230 if (resClass != NULL) {
4231 ClassObject* elementClass;
4232
4233 assert(resClass != NULL);
4234 if (!dvmIsArrayClass(resClass)) {
4235 LOG_VFY("VFY: aget-object on non-array class\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004236 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004237 break;
4238 }
4239 assert(resClass->elementClass != NULL);
4240
4241 /*
4242 * Find the element class. resClass->elementClass indicates
4243 * the basic type, which won't be what we want for a
4244 * multi-dimensional array.
4245 */
4246 if (resClass->descriptor[1] == '[') {
4247 assert(resClass->arrayDim > 1);
4248 elementClass = dvmFindArrayClass(&resClass->descriptor[1],
4249 resClass->classLoader);
4250 } else if (resClass->descriptor[1] == 'L') {
4251 assert(resClass->arrayDim == 1);
4252 elementClass = resClass->elementClass;
4253 } else {
4254 LOG_VFY("VFY: aget-object on non-ref array class (%s)\n",
4255 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004256 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004257 break;
4258 }
4259
4260 dstType = regTypeFromClass(elementClass);
4261 } else {
4262 /*
4263 * The array reference is NULL, so the current code path will
4264 * throw an exception. For proper merging with later code
4265 * paths, and correct handling of "if-eqz" tests on the
4266 * result of the array get, we want to treat this as a null
4267 * reference.
4268 */
4269 dstType = kRegTypeZero;
4270 }
Andy McFadden319a33b2010-11-10 07:55:14 -08004271 setRegisterType(workLine, decInsn.vA, dstType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004272 }
4273 break;
4274 case OP_APUT:
4275 tmpType = kRegTypeInteger;
4276 goto aput_1nr_common;
4277 case OP_APUT_BOOLEAN:
4278 tmpType = kRegTypeBoolean;
4279 goto aput_1nr_common;
4280 case OP_APUT_BYTE:
4281 tmpType = kRegTypeByte;
4282 goto aput_1nr_common;
4283 case OP_APUT_CHAR:
4284 tmpType = kRegTypeChar;
4285 goto aput_1nr_common;
4286 case OP_APUT_SHORT:
4287 tmpType = kRegTypeShort;
4288 goto aput_1nr_common;
4289aput_1nr_common:
4290 {
4291 RegType srcType, dstType, indexType;
4292
Andy McFadden319a33b2010-11-10 07:55:14 -08004293 indexType = getRegisterType(workLine, decInsn.vC);
Andy McFadden62a75162009-04-17 17:23:37 -07004294 checkArrayIndexType(meth, indexType, &failure);
4295 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004296 break;
4297
4298 /* make sure the source register has the correct type */
Andy McFadden319a33b2010-11-10 07:55:14 -08004299 srcType = getRegisterType(workLine, decInsn.vA);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004300 if (!canConvertTo1nr(srcType, tmpType)) {
4301 LOG_VFY("VFY: invalid reg type %d on aput instr (need %d)\n",
4302 srcType, tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07004303 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004304 break;
4305 }
4306
Andy McFadden319a33b2010-11-10 07:55:14 -08004307 resClass = getClassFromRegister(workLine, decInsn.vB, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07004308 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004309 break;
4310
4311 /* resClass can be null if the reg type is Zero */
4312 if (resClass == NULL)
4313 break;
4314
4315 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4316 resClass->elementClass->primitiveType == PRIM_NOT)
4317 {
4318 LOG_VFY("VFY: invalid aput-1nr on %s\n", resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004319 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004320 break;
4321 }
4322
4323 /* verify that instruction matches array */
4324 dstType = primitiveTypeToRegType(
4325 resClass->elementClass->primitiveType);
4326 assert(dstType != kRegTypeUnknown);
4327
4328 if (!checkFieldArrayStore1nr(tmpType, dstType)) {
4329 LOG_VFY("VFY: invalid aput-1nr on %s (inst=%d dst=%d)\n",
4330 resClass->descriptor, tmpType, dstType);
Andy McFadden62a75162009-04-17 17:23:37 -07004331 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004332 break;
4333 }
4334 }
4335 break;
4336 case OP_APUT_WIDE:
Andy McFadden319a33b2010-11-10 07:55:14 -08004337 tmpType = getRegisterType(workLine, decInsn.vC);
Andy McFadden62a75162009-04-17 17:23:37 -07004338 checkArrayIndexType(meth, tmpType, &failure);
4339 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004340 break;
4341
Andy McFadden319a33b2010-11-10 07:55:14 -08004342 tmpType = getRegisterType(workLine, decInsn.vA);
Andy McFaddend3250112010-11-03 14:32:42 -07004343 {
Andy McFadden319a33b2010-11-10 07:55:14 -08004344 RegType typeHi = getRegisterType(workLine, decInsn.vA+1);
Andy McFadden62a75162009-04-17 17:23:37 -07004345 checkTypeCategory(tmpType, kTypeCategory2, &failure);
4346 checkWidePair(tmpType, typeHi, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004347 }
Andy McFadden62a75162009-04-17 17:23:37 -07004348 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004349 break;
4350
Andy McFadden319a33b2010-11-10 07:55:14 -08004351 resClass = getClassFromRegister(workLine, decInsn.vB, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07004352 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004353 break;
4354 if (resClass != NULL) {
4355 /* verify the class and try to refine "dstType" */
4356 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4357 resClass->elementClass->primitiveType == PRIM_NOT)
4358 {
4359 LOG_VFY("VFY: invalid aput-wide on %s\n",
4360 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004361 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004362 break;
4363 }
4364
4365 switch (resClass->elementClass->primitiveType) {
4366 case PRIM_LONG:
4367 case PRIM_DOUBLE:
4368 /* these are okay */
4369 break;
4370 default:
4371 LOG_VFY("VFY: invalid aput-wide on %s\n",
4372 resClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004373 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004374 break;
4375 }
4376 }
4377 break;
4378 case OP_APUT_OBJECT:
Andy McFadden319a33b2010-11-10 07:55:14 -08004379 tmpType = getRegisterType(workLine, decInsn.vC);
Andy McFadden62a75162009-04-17 17:23:37 -07004380 checkArrayIndexType(meth, tmpType, &failure);
4381 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004382 break;
4383
4384 /* get the ref we're storing; Zero is okay, Uninit is not */
Andy McFadden319a33b2010-11-10 07:55:14 -08004385 resClass = getClassFromRegister(workLine, decInsn.vA, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07004386 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004387 break;
4388 if (resClass != NULL) {
4389 ClassObject* arrayClass;
4390 ClassObject* elementClass;
4391
4392 /*
4393 * Get the array class. If the array ref is null, we won't
4394 * have type information (and we'll crash at runtime with a
4395 * null pointer exception).
4396 */
Andy McFadden319a33b2010-11-10 07:55:14 -08004397 arrayClass = getClassFromRegister(workLine, decInsn.vB, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004398
4399 if (arrayClass != NULL) {
4400 /* see if the array holds a compatible type */
4401 if (!dvmIsArrayClass(arrayClass)) {
4402 LOG_VFY("VFY: invalid aput-object on %s\n",
4403 arrayClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004404 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004405 break;
4406 }
4407
4408 /*
4409 * Find the element class. resClass->elementClass indicates
4410 * the basic type, which won't be what we want for a
4411 * multi-dimensional array.
4412 *
4413 * All we want to check here is that the element type is a
4414 * reference class. We *don't* check instanceof here, because
4415 * you can still put a String into a String[] after the latter
4416 * has been cast to an Object[].
4417 */
4418 if (arrayClass->descriptor[1] == '[') {
4419 assert(arrayClass->arrayDim > 1);
4420 elementClass = dvmFindArrayClass(&arrayClass->descriptor[1],
4421 arrayClass->classLoader);
4422 } else {
4423 assert(arrayClass->arrayDim == 1);
4424 elementClass = arrayClass->elementClass;
4425 }
4426 if (elementClass->primitiveType != PRIM_NOT) {
4427 LOG_VFY("VFY: invalid aput-object of %s into %s\n",
4428 resClass->descriptor, 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 break;
4435
4436 case OP_IGET:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004437 case OP_IGET_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004438 tmpType = kRegTypeInteger;
4439 goto iget_1nr_common;
4440 case OP_IGET_BOOLEAN:
4441 tmpType = kRegTypeBoolean;
4442 goto iget_1nr_common;
4443 case OP_IGET_BYTE:
4444 tmpType = kRegTypeByte;
4445 goto iget_1nr_common;
4446 case OP_IGET_CHAR:
4447 tmpType = kRegTypeChar;
4448 goto iget_1nr_common;
4449 case OP_IGET_SHORT:
4450 tmpType = kRegTypeShort;
4451 goto iget_1nr_common;
4452iget_1nr_common:
4453 {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004454 InstField* instField;
4455 RegType objType, fieldType;
4456
Andy McFadden319a33b2010-11-10 07:55:14 -08004457 objType = getRegisterType(workLine, decInsn.vB);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004458 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004459 &failure);
4460 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004461 break;
4462
4463 /* make sure the field's type is compatible with expectation */
4464 fieldType = primSigCharToRegType(instField->field.signature[0]);
4465 if (fieldType == kRegTypeUnknown ||
4466 !checkFieldArrayStore1nr(tmpType, fieldType))
4467 {
4468 LOG_VFY("VFY: invalid iget-1nr of %s.%s (inst=%d field=%d)\n",
4469 instField->field.clazz->descriptor,
4470 instField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004471 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004472 break;
4473 }
4474
Andy McFadden319a33b2010-11-10 07:55:14 -08004475 setRegisterType(workLine, decInsn.vA, tmpType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004476 }
4477 break;
4478 case OP_IGET_WIDE:
Andy McFadden861b3382010-03-05 15:58:31 -08004479 case OP_IGET_WIDE_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004480 {
4481 RegType dstType;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004482 InstField* instField;
4483 RegType objType;
4484
Andy McFadden319a33b2010-11-10 07:55:14 -08004485 objType = getRegisterType(workLine, decInsn.vB);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004486 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004487 &failure);
4488 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004489 break;
4490 /* check the type, which should be prim */
4491 switch (instField->field.signature[0]) {
4492 case 'D':
4493 dstType = kRegTypeDoubleLo;
4494 break;
4495 case 'J':
4496 dstType = kRegTypeLongLo;
4497 break;
4498 default:
4499 LOG_VFY("VFY: invalid iget-wide of %s.%s\n",
4500 instField->field.clazz->descriptor,
4501 instField->field.name);
4502 dstType = kRegTypeUnknown;
Andy McFadden62a75162009-04-17 17:23:37 -07004503 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004504 break;
4505 }
Andy McFadden62a75162009-04-17 17:23:37 -07004506 if (VERIFY_OK(failure)) {
Andy McFadden319a33b2010-11-10 07:55:14 -08004507 setRegisterType(workLine, decInsn.vA, dstType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004508 }
4509 }
4510 break;
4511 case OP_IGET_OBJECT:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004512 case OP_IGET_OBJECT_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004513 {
4514 ClassObject* fieldClass;
4515 InstField* instField;
4516 RegType objType;
4517
Andy McFadden319a33b2010-11-10 07:55:14 -08004518 objType = getRegisterType(workLine, decInsn.vB);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004519 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004520 &failure);
4521 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004522 break;
4523 fieldClass = getFieldClass(meth, &instField->field);
4524 if (fieldClass == NULL) {
4525 /* class not found or primitive type */
4526 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4527 instField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004528 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004529 break;
4530 }
Andy McFadden62a75162009-04-17 17:23:37 -07004531 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004532 assert(!dvmIsPrimitiveClass(fieldClass));
Andy McFadden319a33b2010-11-10 07:55:14 -08004533 setRegisterType(workLine, decInsn.vA,
Andy McFaddend3250112010-11-03 14:32:42 -07004534 regTypeFromClass(fieldClass));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004535 }
4536 }
4537 break;
4538 case OP_IPUT:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004539 case OP_IPUT_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004540 tmpType = kRegTypeInteger;
4541 goto iput_1nr_common;
4542 case OP_IPUT_BOOLEAN:
4543 tmpType = kRegTypeBoolean;
4544 goto iput_1nr_common;
4545 case OP_IPUT_BYTE:
4546 tmpType = kRegTypeByte;
4547 goto iput_1nr_common;
4548 case OP_IPUT_CHAR:
4549 tmpType = kRegTypeChar;
4550 goto iput_1nr_common;
4551 case OP_IPUT_SHORT:
4552 tmpType = kRegTypeShort;
4553 goto iput_1nr_common;
4554iput_1nr_common:
4555 {
4556 RegType srcType, fieldType, objType;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004557 InstField* instField;
4558
Andy McFadden319a33b2010-11-10 07:55:14 -08004559 srcType = getRegisterType(workLine, decInsn.vA);
Andy McFaddenb5f64bc2009-06-10 14:11:07 -07004560
4561 /*
4562 * javac generates synthetic functions that write byte values
4563 * into boolean fields.
4564 */
4565 if (tmpType == kRegTypeBoolean && srcType == kRegTypeByte)
4566 srcType = kRegTypeBoolean;
4567
4568 /* make sure the source register has the correct type */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004569 if (!canConvertTo1nr(srcType, tmpType)) {
4570 LOG_VFY("VFY: invalid reg type %d on iput instr (need %d)\n",
4571 srcType, tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07004572 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004573 break;
4574 }
4575
Andy McFadden319a33b2010-11-10 07:55:14 -08004576 objType = getRegisterType(workLine, decInsn.vB);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004577 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004578 &failure);
4579 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004580 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004581 checkFinalFieldAccess(meth, &instField->field, &failure);
4582 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004583 break;
4584
4585 /* get type of field we're storing into */
4586 fieldType = primSigCharToRegType(instField->field.signature[0]);
4587 if (fieldType == kRegTypeUnknown ||
4588 !checkFieldArrayStore1nr(tmpType, fieldType))
4589 {
4590 LOG_VFY("VFY: invalid iput-1nr of %s.%s (inst=%d field=%d)\n",
4591 instField->field.clazz->descriptor,
4592 instField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004593 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004594 break;
4595 }
4596 }
4597 break;
4598 case OP_IPUT_WIDE:
Andy McFadden861b3382010-03-05 15:58:31 -08004599 case OP_IPUT_WIDE_VOLATILE:
Andy McFadden319a33b2010-11-10 07:55:14 -08004600 tmpType = getRegisterType(workLine, decInsn.vA);
Andy McFaddend3250112010-11-03 14:32:42 -07004601 {
Andy McFadden319a33b2010-11-10 07:55:14 -08004602 RegType typeHi = getRegisterType(workLine, decInsn.vA+1);
Andy McFadden62a75162009-04-17 17:23:37 -07004603 checkTypeCategory(tmpType, kTypeCategory2, &failure);
4604 checkWidePair(tmpType, typeHi, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004605 }
Andy McFadden62a75162009-04-17 17:23:37 -07004606 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004607 InstField* instField;
4608 RegType objType;
4609
Andy McFadden319a33b2010-11-10 07:55:14 -08004610 objType = getRegisterType(workLine, decInsn.vB);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004611 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004612 &failure);
4613 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004614 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004615 checkFinalFieldAccess(meth, &instField->field, &failure);
4616 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004617 break;
4618
4619 /* check the type, which should be prim */
4620 switch (instField->field.signature[0]) {
4621 case 'D':
4622 case 'J':
4623 /* these are okay (and interchangeable) */
4624 break;
4625 default:
4626 LOG_VFY("VFY: invalid iput-wide of %s.%s\n",
4627 instField->field.clazz->descriptor,
4628 instField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07004629 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004630 break;
4631 }
4632 }
4633 break;
4634 case OP_IPUT_OBJECT:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004635 case OP_IPUT_OBJECT_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004636 {
4637 ClassObject* fieldClass;
4638 ClassObject* valueClass;
4639 InstField* instField;
4640 RegType objType, valueType;
4641
Andy McFadden319a33b2010-11-10 07:55:14 -08004642 objType = getRegisterType(workLine, decInsn.vB);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004643 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
Andy McFadden62a75162009-04-17 17:23:37 -07004644 &failure);
4645 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004646 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004647 checkFinalFieldAccess(meth, &instField->field, &failure);
4648 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004649 break;
4650
4651 fieldClass = getFieldClass(meth, &instField->field);
4652 if (fieldClass == NULL) {
4653 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4654 instField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004655 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004656 break;
4657 }
4658
Andy McFadden319a33b2010-11-10 07:55:14 -08004659 valueType = getRegisterType(workLine, decInsn.vA);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004660 if (!regTypeIsReference(valueType)) {
4661 LOG_VFY("VFY: storing non-ref v%d into ref field '%s' (%s)\n",
4662 decInsn.vA, instField->field.name,
4663 fieldClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004664 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004665 break;
4666 }
4667 if (valueType != kRegTypeZero) {
4668 valueClass = regTypeInitializedReferenceToClass(valueType);
4669 if (valueClass == NULL) {
4670 LOG_VFY("VFY: storing uninit ref v%d into ref field\n",
4671 decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07004672 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004673 break;
4674 }
4675 /* allow if field is any interface or field is base class */
4676 if (!dvmIsInterfaceClass(fieldClass) &&
4677 !dvmInstanceof(valueClass, fieldClass))
4678 {
4679 LOG_VFY("VFY: storing type '%s' into field type '%s' (%s.%s)\n",
4680 valueClass->descriptor, fieldClass->descriptor,
4681 instField->field.clazz->descriptor,
4682 instField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07004683 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004684 break;
4685 }
4686 }
4687 }
4688 break;
4689
4690 case OP_SGET:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004691 case OP_SGET_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004692 tmpType = kRegTypeInteger;
4693 goto sget_1nr_common;
4694 case OP_SGET_BOOLEAN:
4695 tmpType = kRegTypeBoolean;
4696 goto sget_1nr_common;
4697 case OP_SGET_BYTE:
4698 tmpType = kRegTypeByte;
4699 goto sget_1nr_common;
4700 case OP_SGET_CHAR:
4701 tmpType = kRegTypeChar;
4702 goto sget_1nr_common;
4703 case OP_SGET_SHORT:
4704 tmpType = kRegTypeShort;
4705 goto sget_1nr_common;
4706sget_1nr_common:
4707 {
4708 StaticField* staticField;
4709 RegType fieldType;
4710
Andy McFadden62a75162009-04-17 17:23:37 -07004711 staticField = getStaticField(meth, decInsn.vB, &failure);
4712 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004713 break;
4714
4715 /*
4716 * Make sure the field's type is compatible with expectation.
4717 * We can get ourselves into trouble if we mix & match loads
4718 * and stores with different widths, so rather than just checking
4719 * "canConvertTo1nr" we require that the field types have equal
4720 * widths. (We can't generally require an exact type match,
4721 * because e.g. "int" and "float" are interchangeable.)
4722 */
4723 fieldType = primSigCharToRegType(staticField->field.signature[0]);
4724 if (!checkFieldArrayStore1nr(tmpType, fieldType)) {
4725 LOG_VFY("VFY: invalid sget-1nr of %s.%s (inst=%d actual=%d)\n",
4726 staticField->field.clazz->descriptor,
4727 staticField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004728 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004729 break;
4730 }
4731
Andy McFadden319a33b2010-11-10 07:55:14 -08004732 setRegisterType(workLine, decInsn.vA, tmpType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004733 }
4734 break;
4735 case OP_SGET_WIDE:
Andy McFadden861b3382010-03-05 15:58:31 -08004736 case OP_SGET_WIDE_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004737 {
4738 StaticField* staticField;
4739 RegType dstType;
4740
Andy McFadden62a75162009-04-17 17:23:37 -07004741 staticField = getStaticField(meth, decInsn.vB, &failure);
4742 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004743 break;
4744 /* check the type, which should be prim */
4745 switch (staticField->field.signature[0]) {
4746 case 'D':
4747 dstType = kRegTypeDoubleLo;
4748 break;
4749 case 'J':
4750 dstType = kRegTypeLongLo;
4751 break;
4752 default:
4753 LOG_VFY("VFY: invalid sget-wide of %s.%s\n",
4754 staticField->field.clazz->descriptor,
4755 staticField->field.name);
4756 dstType = kRegTypeUnknown;
Andy McFadden62a75162009-04-17 17:23:37 -07004757 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004758 break;
4759 }
Andy McFadden62a75162009-04-17 17:23:37 -07004760 if (VERIFY_OK(failure)) {
Andy McFadden319a33b2010-11-10 07:55:14 -08004761 setRegisterType(workLine, decInsn.vA, dstType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004762 }
4763 }
4764 break;
4765 case OP_SGET_OBJECT:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004766 case OP_SGET_OBJECT_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004767 {
4768 StaticField* staticField;
4769 ClassObject* fieldClass;
4770
Andy McFadden62a75162009-04-17 17:23:37 -07004771 staticField = getStaticField(meth, decInsn.vB, &failure);
4772 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004773 break;
4774 fieldClass = getFieldClass(meth, &staticField->field);
4775 if (fieldClass == NULL) {
4776 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4777 staticField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004778 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004779 break;
4780 }
4781 if (dvmIsPrimitiveClass(fieldClass)) {
4782 LOG_VFY("VFY: attempt to get prim field with sget-object\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004783 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004784 break;
4785 }
Andy McFadden319a33b2010-11-10 07:55:14 -08004786 setRegisterType(workLine, decInsn.vA, regTypeFromClass(fieldClass));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004787 }
4788 break;
4789 case OP_SPUT:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004790 case OP_SPUT_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004791 tmpType = kRegTypeInteger;
4792 goto sput_1nr_common;
4793 case OP_SPUT_BOOLEAN:
4794 tmpType = kRegTypeBoolean;
4795 goto sput_1nr_common;
4796 case OP_SPUT_BYTE:
4797 tmpType = kRegTypeByte;
4798 goto sput_1nr_common;
4799 case OP_SPUT_CHAR:
4800 tmpType = kRegTypeChar;
4801 goto sput_1nr_common;
4802 case OP_SPUT_SHORT:
4803 tmpType = kRegTypeShort;
4804 goto sput_1nr_common;
4805sput_1nr_common:
4806 {
4807 RegType srcType, fieldType;
4808 StaticField* staticField;
4809
Andy McFadden319a33b2010-11-10 07:55:14 -08004810 srcType = getRegisterType(workLine, decInsn.vA);
Andy McFaddenb5f64bc2009-06-10 14:11:07 -07004811
4812 /*
4813 * javac generates synthetic functions that write byte values
4814 * into boolean fields.
4815 */
4816 if (tmpType == kRegTypeBoolean && srcType == kRegTypeByte)
4817 srcType = kRegTypeBoolean;
4818
4819 /* make sure the source register has the correct type */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004820 if (!canConvertTo1nr(srcType, tmpType)) {
Andy McFaddenb5f64bc2009-06-10 14:11:07 -07004821 LOG_VFY("VFY: invalid reg type %d on sput instr (need %d)\n",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004822 srcType, tmpType);
Andy McFadden62a75162009-04-17 17:23:37 -07004823 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004824 break;
4825 }
4826
Andy McFadden62a75162009-04-17 17:23:37 -07004827 staticField = getStaticField(meth, decInsn.vB, &failure);
4828 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004829 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004830 checkFinalFieldAccess(meth, &staticField->field, &failure);
4831 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004832 break;
4833
4834 /*
4835 * Get type of field we're storing into. We know that the
4836 * contents of the register match the instruction, but we also
4837 * need to ensure that the instruction matches the field type.
4838 * Using e.g. sput-short to write into a 32-bit integer field
4839 * can lead to trouble if we do 16-bit writes.
4840 */
4841 fieldType = primSigCharToRegType(staticField->field.signature[0]);
4842 if (!checkFieldArrayStore1nr(tmpType, fieldType)) {
4843 LOG_VFY("VFY: invalid sput-1nr of %s.%s (inst=%d actual=%d)\n",
4844 staticField->field.clazz->descriptor,
4845 staticField->field.name, tmpType, fieldType);
Andy McFadden62a75162009-04-17 17:23:37 -07004846 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004847 break;
4848 }
4849 }
4850 break;
4851 case OP_SPUT_WIDE:
Andy McFadden861b3382010-03-05 15:58:31 -08004852 case OP_SPUT_WIDE_VOLATILE:
Andy McFadden319a33b2010-11-10 07:55:14 -08004853 tmpType = getRegisterType(workLine, decInsn.vA);
Andy McFaddend3250112010-11-03 14:32:42 -07004854 {
Andy McFadden319a33b2010-11-10 07:55:14 -08004855 RegType typeHi = getRegisterType(workLine, decInsn.vA+1);
Andy McFadden62a75162009-04-17 17:23:37 -07004856 checkTypeCategory(tmpType, kTypeCategory2, &failure);
4857 checkWidePair(tmpType, typeHi, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004858 }
Andy McFadden62a75162009-04-17 17:23:37 -07004859 if (VERIFY_OK(failure)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004860 StaticField* staticField;
4861
Andy McFadden62a75162009-04-17 17:23:37 -07004862 staticField = getStaticField(meth, decInsn.vB, &failure);
4863 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004864 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004865 checkFinalFieldAccess(meth, &staticField->field, &failure);
4866 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004867 break;
4868
4869 /* check the type, which should be prim */
4870 switch (staticField->field.signature[0]) {
4871 case 'D':
4872 case 'J':
4873 /* these are okay */
4874 break;
4875 default:
4876 LOG_VFY("VFY: invalid sput-wide of %s.%s\n",
4877 staticField->field.clazz->descriptor,
4878 staticField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07004879 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004880 break;
4881 }
4882 }
4883 break;
4884 case OP_SPUT_OBJECT:
Andy McFaddenc35a2ef2010-06-17 12:36:00 -07004885 case OP_SPUT_OBJECT_VOLATILE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004886 {
4887 ClassObject* fieldClass;
4888 ClassObject* valueClass;
4889 StaticField* staticField;
4890 RegType valueType;
4891
Andy McFadden62a75162009-04-17 17:23:37 -07004892 staticField = getStaticField(meth, decInsn.vB, &failure);
4893 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004894 break;
Andy McFadden62a75162009-04-17 17:23:37 -07004895 checkFinalFieldAccess(meth, &staticField->field, &failure);
4896 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004897 break;
4898
4899 fieldClass = getFieldClass(meth, &staticField->field);
4900 if (fieldClass == NULL) {
4901 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4902 staticField->field.signature);
Andy McFadden62a75162009-04-17 17:23:37 -07004903 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004904 break;
4905 }
4906
Andy McFadden319a33b2010-11-10 07:55:14 -08004907 valueType = getRegisterType(workLine, decInsn.vA);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004908 if (!regTypeIsReference(valueType)) {
4909 LOG_VFY("VFY: storing non-ref v%d into ref field '%s' (%s)\n",
4910 decInsn.vA, staticField->field.name,
4911 fieldClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07004912 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004913 break;
4914 }
4915 if (valueType != kRegTypeZero) {
4916 valueClass = regTypeInitializedReferenceToClass(valueType);
4917 if (valueClass == NULL) {
4918 LOG_VFY("VFY: storing uninit ref v%d into ref field\n",
4919 decInsn.vA);
Andy McFadden62a75162009-04-17 17:23:37 -07004920 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004921 break;
4922 }
4923 /* allow if field is any interface or field is base class */
4924 if (!dvmIsInterfaceClass(fieldClass) &&
4925 !dvmInstanceof(valueClass, fieldClass))
4926 {
4927 LOG_VFY("VFY: storing type '%s' into field type '%s' (%s.%s)\n",
4928 valueClass->descriptor, fieldClass->descriptor,
4929 staticField->field.clazz->descriptor,
4930 staticField->field.name);
Andy McFadden62a75162009-04-17 17:23:37 -07004931 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004932 break;
4933 }
4934 }
4935 }
4936 break;
4937
4938 case OP_INVOKE_VIRTUAL:
4939 case OP_INVOKE_VIRTUAL_RANGE:
4940 case OP_INVOKE_SUPER:
4941 case OP_INVOKE_SUPER_RANGE:
4942 {
4943 Method* calledMethod;
4944 RegType returnType;
4945 bool isRange;
4946 bool isSuper;
4947
4948 isRange = (decInsn.opCode == OP_INVOKE_VIRTUAL_RANGE ||
4949 decInsn.opCode == OP_INVOKE_SUPER_RANGE);
4950 isSuper = (decInsn.opCode == OP_INVOKE_SUPER ||
4951 decInsn.opCode == OP_INVOKE_SUPER_RANGE);
4952
Andy McFadden319a33b2010-11-10 07:55:14 -08004953 calledMethod = verifyInvocationArgs(meth, workLine, insnRegCount,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004954 &decInsn, uninitMap, METHOD_VIRTUAL, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07004955 isSuper, &failure);
4956 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004957 break;
4958 returnType = getMethodReturnType(calledMethod);
Andy McFadden319a33b2010-11-10 07:55:14 -08004959 setResultRegisterType(workLine, insnRegCount, returnType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004960 justSetResult = true;
4961 }
4962 break;
4963 case OP_INVOKE_DIRECT:
4964 case OP_INVOKE_DIRECT_RANGE:
4965 {
4966 RegType returnType;
4967 Method* calledMethod;
4968 bool isRange;
4969
4970 isRange = (decInsn.opCode == OP_INVOKE_DIRECT_RANGE);
Andy McFadden319a33b2010-11-10 07:55:14 -08004971 calledMethod = verifyInvocationArgs(meth, workLine, insnRegCount,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004972 &decInsn, uninitMap, METHOD_DIRECT, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07004973 false, &failure);
4974 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004975 break;
4976
4977 /*
4978 * Some additional checks when calling <init>. We know from
4979 * the invocation arg check that the "this" argument is an
4980 * instance of calledMethod->clazz. Now we further restrict
4981 * that to require that calledMethod->clazz is the same as
4982 * this->clazz or this->super, allowing the latter only if
4983 * the "this" argument is the same as the "this" argument to
4984 * this method (which implies that we're in <init> ourselves).
4985 */
4986 if (isInitMethod(calledMethod)) {
4987 RegType thisType;
Andy McFadden319a33b2010-11-10 07:55:14 -08004988 thisType = getInvocationThis(workLine, &decInsn, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07004989 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004990 break;
4991
4992 /* no null refs allowed (?) */
4993 if (thisType == kRegTypeZero) {
4994 LOG_VFY("VFY: unable to initialize null ref\n");
Andy McFadden62a75162009-04-17 17:23:37 -07004995 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08004996 break;
4997 }
4998
4999 ClassObject* thisClass;
5000
5001 thisClass = regTypeReferenceToClass(thisType, uninitMap);
5002 assert(thisClass != NULL);
5003
5004 /* must be in same class or in superclass */
5005 if (calledMethod->clazz == thisClass->super) {
5006 if (thisClass != meth->clazz) {
5007 LOG_VFY("VFY: invoke-direct <init> on super only "
5008 "allowed for 'this' in <init>");
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 } else if (calledMethod->clazz != thisClass) {
5013 LOG_VFY("VFY: invoke-direct <init> must be on current "
5014 "class or super\n");
Andy McFadden62a75162009-04-17 17:23:37 -07005015 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005016 break;
5017 }
5018
5019 /* arg must be an uninitialized reference */
5020 if (!regTypeIsUninitReference(thisType)) {
5021 LOG_VFY("VFY: can only initialize the uninitialized\n");
Andy McFadden62a75162009-04-17 17:23:37 -07005022 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005023 break;
5024 }
5025
5026 /*
5027 * Replace the uninitialized reference with an initialized
5028 * one, and clear the entry in the uninit map. We need to
5029 * do this for all registers that have the same object
5030 * instance in them, not just the "this" register.
5031 */
Andy McFadden319a33b2010-11-10 07:55:14 -08005032 markRefsAsInitialized(workLine, insnRegCount, uninitMap,
Andy McFadden62a75162009-04-17 17:23:37 -07005033 thisType, &failure);
5034 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005035 break;
5036 }
5037 returnType = getMethodReturnType(calledMethod);
Andy McFadden319a33b2010-11-10 07:55:14 -08005038 setResultRegisterType(workLine, insnRegCount, returnType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005039 justSetResult = true;
5040 }
5041 break;
5042 case OP_INVOKE_STATIC:
5043 case OP_INVOKE_STATIC_RANGE:
5044 {
5045 RegType returnType;
5046 Method* calledMethod;
5047 bool isRange;
5048
5049 isRange = (decInsn.opCode == OP_INVOKE_STATIC_RANGE);
Andy McFadden319a33b2010-11-10 07:55:14 -08005050 calledMethod = verifyInvocationArgs(meth, workLine, insnRegCount,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005051 &decInsn, uninitMap, METHOD_STATIC, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07005052 false, &failure);
5053 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005054 break;
5055
5056 returnType = getMethodReturnType(calledMethod);
Andy McFadden319a33b2010-11-10 07:55:14 -08005057 setResultRegisterType(workLine, insnRegCount, returnType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005058 justSetResult = true;
5059 }
5060 break;
5061 case OP_INVOKE_INTERFACE:
5062 case OP_INVOKE_INTERFACE_RANGE:
5063 {
5064 RegType /*thisType,*/ returnType;
5065 Method* absMethod;
5066 bool isRange;
5067
5068 isRange = (decInsn.opCode == OP_INVOKE_INTERFACE_RANGE);
Andy McFadden319a33b2010-11-10 07:55:14 -08005069 absMethod = verifyInvocationArgs(meth, workLine, insnRegCount,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005070 &decInsn, uninitMap, METHOD_INTERFACE, isRange,
Andy McFadden62a75162009-04-17 17:23:37 -07005071 false, &failure);
5072 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005073 break;
5074
5075#if 0 /* can't do this here, fails on dalvik test 052-verifier-fun */
5076 /*
5077 * Get the type of the "this" arg, which should always be an
5078 * interface class. Because we don't do a full merge on
5079 * interface classes, this might have reduced to Object.
5080 */
Andy McFadden319a33b2010-11-10 07:55:14 -08005081 thisType = getInvocationThis(workLine, &decInsn, &failure);
Andy McFadden62a75162009-04-17 17:23:37 -07005082 if (!VERIFY_OK(failure))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005083 break;
5084
5085 if (thisType == kRegTypeZero) {
5086 /* null pointer always passes (and always fails at runtime) */
5087 } else {
5088 ClassObject* thisClass;
5089
5090 thisClass = regTypeInitializedReferenceToClass(thisType);
5091 if (thisClass == NULL) {
5092 LOG_VFY("VFY: interface call on uninitialized\n");
Andy McFadden62a75162009-04-17 17:23:37 -07005093 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005094 break;
5095 }
5096
5097 /*
5098 * Either "thisClass" needs to be the interface class that
5099 * defined absMethod, or absMethod's class needs to be one
5100 * of the interfaces implemented by "thisClass". (Or, if
5101 * we couldn't complete the merge, this will be Object.)
5102 */
5103 if (thisClass != absMethod->clazz &&
5104 thisClass != gDvm.classJavaLangObject &&
5105 !dvmImplements(thisClass, absMethod->clazz))
5106 {
5107 LOG_VFY("VFY: unable to match absMethod '%s' with %s interfaces\n",
5108 absMethod->name, thisClass->descriptor);
Andy McFadden62a75162009-04-17 17:23:37 -07005109 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005110 break;
5111 }
5112 }
5113#endif
5114
5115 /*
5116 * We don't have an object instance, so we can't find the
5117 * concrete method. However, all of the type information is
5118 * in the abstract method, so we're good.
5119 */
5120 returnType = getMethodReturnType(absMethod);
Andy McFadden319a33b2010-11-10 07:55:14 -08005121 setResultRegisterType(workLine, insnRegCount, returnType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005122 justSetResult = true;
5123 }
5124 break;
5125
5126 case OP_NEG_INT:
5127 case OP_NOT_INT:
Andy McFadden319a33b2010-11-10 07:55:14 -08005128 checkUnop(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005129 kRegTypeInteger, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005130 break;
5131 case OP_NEG_LONG:
5132 case OP_NOT_LONG:
Andy McFadden319a33b2010-11-10 07:55:14 -08005133 checkUnop(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005134 kRegTypeLongLo, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005135 break;
5136 case OP_NEG_FLOAT:
Andy McFadden319a33b2010-11-10 07:55:14 -08005137 checkUnop(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005138 kRegTypeFloat, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005139 break;
5140 case OP_NEG_DOUBLE:
Andy McFadden319a33b2010-11-10 07:55:14 -08005141 checkUnop(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005142 kRegTypeDoubleLo, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005143 break;
5144 case OP_INT_TO_LONG:
Andy McFadden319a33b2010-11-10 07:55:14 -08005145 checkUnop(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005146 kRegTypeLongLo, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005147 break;
5148 case OP_INT_TO_FLOAT:
Andy McFadden319a33b2010-11-10 07:55:14 -08005149 checkUnop(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005150 kRegTypeFloat, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005151 break;
5152 case OP_INT_TO_DOUBLE:
Andy McFadden319a33b2010-11-10 07:55:14 -08005153 checkUnop(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005154 kRegTypeDoubleLo, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005155 break;
5156 case OP_LONG_TO_INT:
Andy McFadden319a33b2010-11-10 07:55:14 -08005157 checkUnop(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005158 kRegTypeInteger, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005159 break;
5160 case OP_LONG_TO_FLOAT:
Andy McFadden319a33b2010-11-10 07:55:14 -08005161 checkUnop(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005162 kRegTypeFloat, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005163 break;
5164 case OP_LONG_TO_DOUBLE:
Andy McFadden319a33b2010-11-10 07:55:14 -08005165 checkUnop(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005166 kRegTypeDoubleLo, kRegTypeLongLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005167 break;
5168 case OP_FLOAT_TO_INT:
Andy McFadden319a33b2010-11-10 07:55:14 -08005169 checkUnop(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005170 kRegTypeInteger, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005171 break;
5172 case OP_FLOAT_TO_LONG:
Andy McFadden319a33b2010-11-10 07:55:14 -08005173 checkUnop(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005174 kRegTypeLongLo, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005175 break;
5176 case OP_FLOAT_TO_DOUBLE:
Andy McFadden319a33b2010-11-10 07:55:14 -08005177 checkUnop(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005178 kRegTypeDoubleLo, kRegTypeFloat, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005179 break;
5180 case OP_DOUBLE_TO_INT:
Andy McFadden319a33b2010-11-10 07:55:14 -08005181 checkUnop(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005182 kRegTypeInteger, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005183 break;
5184 case OP_DOUBLE_TO_LONG:
Andy McFadden319a33b2010-11-10 07:55:14 -08005185 checkUnop(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005186 kRegTypeLongLo, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005187 break;
5188 case OP_DOUBLE_TO_FLOAT:
Andy McFadden319a33b2010-11-10 07:55:14 -08005189 checkUnop(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005190 kRegTypeFloat, kRegTypeDoubleLo, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005191 break;
5192 case OP_INT_TO_BYTE:
Andy McFadden319a33b2010-11-10 07:55:14 -08005193 checkUnop(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005194 kRegTypeByte, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005195 break;
5196 case OP_INT_TO_CHAR:
Andy McFadden319a33b2010-11-10 07:55:14 -08005197 checkUnop(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005198 kRegTypeChar, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005199 break;
5200 case OP_INT_TO_SHORT:
Andy McFadden319a33b2010-11-10 07:55:14 -08005201 checkUnop(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005202 kRegTypeShort, kRegTypeInteger, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005203 break;
5204
5205 case OP_ADD_INT:
5206 case OP_SUB_INT:
5207 case OP_MUL_INT:
5208 case OP_REM_INT:
5209 case OP_DIV_INT:
5210 case OP_SHL_INT:
5211 case OP_SHR_INT:
5212 case OP_USHR_INT:
Andy McFadden319a33b2010-11-10 07:55:14 -08005213 checkBinop(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005214 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005215 break;
5216 case OP_AND_INT:
5217 case OP_OR_INT:
5218 case OP_XOR_INT:
Andy McFadden319a33b2010-11-10 07:55:14 -08005219 checkBinop(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005220 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005221 break;
5222 case OP_ADD_LONG:
5223 case OP_SUB_LONG:
5224 case OP_MUL_LONG:
5225 case OP_DIV_LONG:
5226 case OP_REM_LONG:
5227 case OP_AND_LONG:
5228 case OP_OR_LONG:
5229 case OP_XOR_LONG:
Andy McFadden319a33b2010-11-10 07:55:14 -08005230 checkBinop(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005231 kRegTypeLongLo, kRegTypeLongLo, kRegTypeLongLo, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005232 break;
5233 case OP_SHL_LONG:
5234 case OP_SHR_LONG:
5235 case OP_USHR_LONG:
5236 /* shift distance is Int, making these different from other binops */
Andy McFadden319a33b2010-11-10 07:55:14 -08005237 checkBinop(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005238 kRegTypeLongLo, kRegTypeLongLo, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005239 break;
5240 case OP_ADD_FLOAT:
5241 case OP_SUB_FLOAT:
5242 case OP_MUL_FLOAT:
5243 case OP_DIV_FLOAT:
5244 case OP_REM_FLOAT:
Andy McFadden319a33b2010-11-10 07:55:14 -08005245 checkBinop(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005246 kRegTypeFloat, kRegTypeFloat, kRegTypeFloat, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005247 break;
5248 case OP_ADD_DOUBLE:
5249 case OP_SUB_DOUBLE:
5250 case OP_MUL_DOUBLE:
5251 case OP_DIV_DOUBLE:
5252 case OP_REM_DOUBLE:
Andy McFadden319a33b2010-11-10 07:55:14 -08005253 checkBinop(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005254 kRegTypeDoubleLo, kRegTypeDoubleLo, kRegTypeDoubleLo, false,
5255 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005256 break;
5257 case OP_ADD_INT_2ADDR:
5258 case OP_SUB_INT_2ADDR:
5259 case OP_MUL_INT_2ADDR:
5260 case OP_REM_INT_2ADDR:
5261 case OP_SHL_INT_2ADDR:
5262 case OP_SHR_INT_2ADDR:
5263 case OP_USHR_INT_2ADDR:
Andy McFadden319a33b2010-11-10 07:55:14 -08005264 checkBinop2addr(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005265 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005266 break;
5267 case OP_AND_INT_2ADDR:
5268 case OP_OR_INT_2ADDR:
5269 case OP_XOR_INT_2ADDR:
Andy McFadden319a33b2010-11-10 07:55:14 -08005270 checkBinop2addr(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005271 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005272 break;
5273 case OP_DIV_INT_2ADDR:
Andy McFadden319a33b2010-11-10 07:55:14 -08005274 checkBinop2addr(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005275 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005276 break;
5277 case OP_ADD_LONG_2ADDR:
5278 case OP_SUB_LONG_2ADDR:
5279 case OP_MUL_LONG_2ADDR:
5280 case OP_DIV_LONG_2ADDR:
5281 case OP_REM_LONG_2ADDR:
5282 case OP_AND_LONG_2ADDR:
5283 case OP_OR_LONG_2ADDR:
5284 case OP_XOR_LONG_2ADDR:
Andy McFadden319a33b2010-11-10 07:55:14 -08005285 checkBinop2addr(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005286 kRegTypeLongLo, kRegTypeLongLo, kRegTypeLongLo, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005287 break;
5288 case OP_SHL_LONG_2ADDR:
5289 case OP_SHR_LONG_2ADDR:
5290 case OP_USHR_LONG_2ADDR:
Andy McFadden319a33b2010-11-10 07:55:14 -08005291 checkBinop2addr(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005292 kRegTypeLongLo, kRegTypeLongLo, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005293 break;
5294 case OP_ADD_FLOAT_2ADDR:
5295 case OP_SUB_FLOAT_2ADDR:
5296 case OP_MUL_FLOAT_2ADDR:
5297 case OP_DIV_FLOAT_2ADDR:
5298 case OP_REM_FLOAT_2ADDR:
Andy McFadden319a33b2010-11-10 07:55:14 -08005299 checkBinop2addr(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005300 kRegTypeFloat, kRegTypeFloat, kRegTypeFloat, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005301 break;
5302 case OP_ADD_DOUBLE_2ADDR:
5303 case OP_SUB_DOUBLE_2ADDR:
5304 case OP_MUL_DOUBLE_2ADDR:
5305 case OP_DIV_DOUBLE_2ADDR:
5306 case OP_REM_DOUBLE_2ADDR:
Andy McFadden319a33b2010-11-10 07:55:14 -08005307 checkBinop2addr(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005308 kRegTypeDoubleLo, kRegTypeDoubleLo, kRegTypeDoubleLo, false,
5309 &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005310 break;
5311 case OP_ADD_INT_LIT16:
5312 case OP_RSUB_INT:
5313 case OP_MUL_INT_LIT16:
5314 case OP_DIV_INT_LIT16:
5315 case OP_REM_INT_LIT16:
Andy McFadden319a33b2010-11-10 07:55:14 -08005316 checkLitop(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005317 kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005318 break;
5319 case OP_AND_INT_LIT16:
5320 case OP_OR_INT_LIT16:
5321 case OP_XOR_INT_LIT16:
Andy McFadden319a33b2010-11-10 07:55:14 -08005322 checkLitop(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005323 kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005324 break;
5325 case OP_ADD_INT_LIT8:
5326 case OP_RSUB_INT_LIT8:
5327 case OP_MUL_INT_LIT8:
5328 case OP_DIV_INT_LIT8:
5329 case OP_REM_INT_LIT8:
5330 case OP_SHL_INT_LIT8:
Andy McFadden319a33b2010-11-10 07:55:14 -08005331 checkLitop(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005332 kRegTypeInteger, kRegTypeInteger, false, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005333 break;
Andy McFadden80d25ea2009-06-12 07:26:17 -07005334 case OP_SHR_INT_LIT8:
Andy McFadden319a33b2010-11-10 07:55:14 -08005335 tmpType = adjustForRightShift(workLine,
Andy McFadden80d25ea2009-06-12 07:26:17 -07005336 decInsn.vB, decInsn.vC, false, &failure);
Andy McFadden319a33b2010-11-10 07:55:14 -08005337 checkLitop(workLine, &decInsn,
Andy McFadden80d25ea2009-06-12 07:26:17 -07005338 tmpType, kRegTypeInteger, false, &failure);
5339 break;
5340 case OP_USHR_INT_LIT8:
Andy McFadden319a33b2010-11-10 07:55:14 -08005341 tmpType = adjustForRightShift(workLine,
Andy McFadden80d25ea2009-06-12 07:26:17 -07005342 decInsn.vB, decInsn.vC, true, &failure);
Andy McFadden319a33b2010-11-10 07:55:14 -08005343 checkLitop(workLine, &decInsn,
Andy McFadden80d25ea2009-06-12 07:26:17 -07005344 tmpType, kRegTypeInteger, false, &failure);
5345 break;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005346 case OP_AND_INT_LIT8:
5347 case OP_OR_INT_LIT8:
5348 case OP_XOR_INT_LIT8:
Andy McFadden319a33b2010-11-10 07:55:14 -08005349 checkLitop(workLine, &decInsn,
Andy McFadden62a75162009-04-17 17:23:37 -07005350 kRegTypeInteger, kRegTypeInteger, true, &failure);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005351 break;
5352
Andy McFaddenb51ea112009-05-08 16:50:17 -07005353 /*
5354 * This falls into the general category of "optimized" instructions,
5355 * which don't generally appear during verification. Because it's
5356 * inserted in the course of verification, we can expect to see it here.
5357 */
5358 case OP_THROW_VERIFICATION_ERROR:
5359 break;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005360
5361 /*
5362 * Verifying "quickened" instructions is tricky, because we have
5363 * discarded the original field/method information. The byte offsets
5364 * and vtable indices only have meaning in the context of an object
5365 * instance.
5366 *
5367 * If a piece of code declares a local reference variable, assigns
5368 * null to it, and then issues a virtual method call on it, we
5369 * cannot evaluate the method call during verification. This situation
5370 * isn't hard to handle, since we know the call will always result in an
5371 * NPE, and the arguments and return value don't matter. Any code that
5372 * depends on the result of the method call is inaccessible, so the
5373 * fact that we can't fully verify anything that comes after the bad
5374 * call is not a problem.
5375 *
5376 * We must also consider the case of multiple code paths, only some of
5377 * which involve a null reference. We can completely verify the method
5378 * if we sidestep the results of executing with a null reference.
5379 * For example, if on the first pass through the code we try to do a
5380 * virtual method invocation through a null ref, we have to skip the
5381 * method checks and have the method return a "wildcard" type (which
5382 * merges with anything to become that other thing). The move-result
5383 * will tell us if it's a reference, single-word numeric, or double-word
5384 * value. We continue to perform the verification, and at the end of
5385 * the function any invocations that were never fully exercised are
5386 * marked as null-only.
5387 *
5388 * We would do something similar for the field accesses. The field's
5389 * type, once known, can be used to recover the width of short integers.
5390 * If the object reference was null, the field-get returns the "wildcard"
5391 * type, which is acceptable for any operation.
5392 */
5393 case OP_EXECUTE_INLINE:
Andy McFaddenb0a05412009-11-19 10:23:41 -08005394 case OP_EXECUTE_INLINE_RANGE:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005395 case OP_INVOKE_DIRECT_EMPTY:
5396 case OP_IGET_QUICK:
5397 case OP_IGET_WIDE_QUICK:
5398 case OP_IGET_OBJECT_QUICK:
5399 case OP_IPUT_QUICK:
5400 case OP_IPUT_WIDE_QUICK:
5401 case OP_IPUT_OBJECT_QUICK:
5402 case OP_INVOKE_VIRTUAL_QUICK:
5403 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
5404 case OP_INVOKE_SUPER_QUICK:
5405 case OP_INVOKE_SUPER_QUICK_RANGE:
Andy McFadden291758c2010-09-10 08:04:52 -07005406 case OP_RETURN_VOID_BARRIER:
Andy McFadden62a75162009-04-17 17:23:37 -07005407 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005408 break;
5409
Andy McFadden96516932009-10-28 17:39:02 -07005410 /* these should never appear during verification */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005411 case OP_UNUSED_3E:
5412 case OP_UNUSED_3F:
5413 case OP_UNUSED_40:
5414 case OP_UNUSED_41:
5415 case OP_UNUSED_42:
5416 case OP_UNUSED_43:
5417 case OP_UNUSED_73:
5418 case OP_UNUSED_79:
5419 case OP_UNUSED_7A:
Andy McFadden96516932009-10-28 17:39:02 -07005420 case OP_BREAKPOINT:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005421 case OP_UNUSED_FF:
Andy McFadden62a75162009-04-17 17:23:37 -07005422 failure = VERIFY_ERROR_GENERIC;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005423 break;
5424
5425 /*
5426 * DO NOT add a "default" clause here. Without it the compiler will
5427 * complain if an instruction is missing (which is desirable).
5428 */
5429 }
5430
Andy McFadden62a75162009-04-17 17:23:37 -07005431 if (!VERIFY_OK(failure)) {
Andy McFaddenb51ea112009-05-08 16:50:17 -07005432 if (failure == VERIFY_ERROR_GENERIC || gDvm.optimizing) {
5433 /* immediate failure, reject class */
5434 LOG_VFY_METH(meth, "VFY: rejecting opcode 0x%02x at 0x%04x\n",
5435 decInsn.opCode, insnIdx);
5436 goto bail;
5437 } else {
5438 /* replace opcode and continue on */
5439 LOGD("VFY: replacing opcode 0x%02x at 0x%04x\n",
5440 decInsn.opCode, insnIdx);
5441 if (!replaceFailingInstruction(meth, insnFlags, insnIdx, failure)) {
5442 LOG_VFY_METH(meth, "VFY: rejecting opcode 0x%02x at 0x%04x\n",
5443 decInsn.opCode, insnIdx);
5444 goto bail;
5445 }
5446 /* IMPORTANT: meth->insns may have been changed */
5447 insns = meth->insns + insnIdx;
5448
5449 /* continue on as if we just handled a throw-verification-error */
5450 failure = VERIFY_ERROR_NONE;
5451 nextFlags = kInstrCanThrow;
5452 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005453 }
5454
5455 /*
5456 * If we didn't just set the result register, clear it out. This
5457 * ensures that you can only use "move-result" immediately after the
Andy McFadden2e1ee502010-03-24 13:25:53 -07005458 * result is set. (We could check this statically, but it's not
5459 * expensive and it makes our debugging output cleaner.)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005460 */
5461 if (!justSetResult) {
5462 int reg = RESULT_REGISTER(insnRegCount);
Andy McFadden319a33b2010-11-10 07:55:14 -08005463 setRegisterType(workLine, reg, kRegTypeUnknown);
5464 setRegisterType(workLine, reg+1, kRegTypeUnknown);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005465 }
5466
5467 /*
5468 * Handle "continue". Tag the next consecutive instruction.
5469 */
5470 if ((nextFlags & kInstrCanContinue) != 0) {
5471 int insnWidth = dvmInsnGetWidth(insnFlags, insnIdx);
5472 if (insnIdx+insnWidth >= insnsSize) {
5473 LOG_VFY_METH(meth,
5474 "VFY: execution can walk off end of code area (from 0x%x)\n",
5475 insnIdx);
5476 goto bail;
5477 }
5478
5479 /*
5480 * The only way to get to a move-exception instruction is to get
5481 * thrown there. Make sure the next instruction isn't one.
5482 */
5483 if (!checkMoveException(meth, insnIdx+insnWidth, "next"))
5484 goto bail;
5485
Andy McFadden319a33b2010-11-10 07:55:14 -08005486 if (getRegisterLine(regTable, insnIdx+insnWidth)->regTypes != NULL) {
Andy McFadden06b7a282009-05-11 10:44:52 -07005487 /*
5488 * Merge registers into what we have for the next instruction,
5489 * and set the "changed" flag if needed.
5490 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005491 updateRegisters(meth, insnFlags, regTable, insnIdx+insnWidth,
Andy McFadden319a33b2010-11-10 07:55:14 -08005492 workLine);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005493 } else {
The Android Open Source Project99409882009-03-18 22:20:24 -07005494 /*
Andy McFadden06b7a282009-05-11 10:44:52 -07005495 * We're not recording register data for the next instruction,
5496 * so we don't know what the prior state was. We have to
5497 * assume that something has changed and re-evaluate it.
The Android Open Source Project99409882009-03-18 22:20:24 -07005498 */
5499 dvmInsnSetChanged(insnFlags, insnIdx+insnWidth, true);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005500 }
5501 }
5502
5503 /*
5504 * Handle "branch". Tag the branch target.
5505 *
5506 * NOTE: instructions like OP_EQZ provide information about the state
5507 * of the register when the branch is taken or not taken. For example,
5508 * somebody could get a reference field, check it for zero, and if the
5509 * branch is taken immediately store that register in a boolean field
5510 * since the value is known to be zero. We do not currently account for
5511 * that, and will reject the code.
Andy McFadden319a33b2010-11-10 07:55:14 -08005512 *
5513 * TODO: avoid re-fetching the branch target
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005514 */
5515 if ((nextFlags & kInstrCanBranch) != 0) {
5516 bool isConditional;
5517
5518 if (!dvmGetBranchTarget(meth, insnFlags, insnIdx, &branchTarget,
5519 &isConditional))
5520 {
5521 /* should never happen after static verification */
5522 LOG_VFY_METH(meth, "VFY: bad branch at %d\n", insnIdx);
5523 goto bail;
5524 }
5525 assert(isConditional || (nextFlags & kInstrCanContinue) == 0);
5526 assert(!isConditional || (nextFlags & kInstrCanContinue) != 0);
5527
5528 if (!checkMoveException(meth, insnIdx+branchTarget, "branch"))
5529 goto bail;
5530
The Android Open Source Project99409882009-03-18 22:20:24 -07005531 /* update branch target, set "changed" if appropriate */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005532 updateRegisters(meth, insnFlags, regTable, insnIdx+branchTarget,
Andy McFadden319a33b2010-11-10 07:55:14 -08005533 workLine);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005534 }
5535
5536 /*
5537 * Handle "switch". Tag all possible branch targets.
5538 *
5539 * We've already verified that the table is structurally sound, so we
5540 * just need to walk through and tag the targets.
5541 */
5542 if ((nextFlags & kInstrCanSwitch) != 0) {
5543 int offsetToSwitch = insns[1] | (((s4)insns[2]) << 16);
5544 const u2* switchInsns = insns + offsetToSwitch;
5545 int switchCount = switchInsns[1];
5546 int offsetToTargets, targ;
5547
5548 if ((*insns & 0xff) == OP_PACKED_SWITCH) {
5549 /* 0=sig, 1=count, 2/3=firstKey */
5550 offsetToTargets = 4;
5551 } else {
5552 /* 0=sig, 1=count, 2..count*2 = keys */
5553 assert((*insns & 0xff) == OP_SPARSE_SWITCH);
5554 offsetToTargets = 2 + 2*switchCount;
5555 }
5556
5557 /* verify each switch target */
5558 for (targ = 0; targ < switchCount; targ++) {
5559 int offset, absOffset;
5560
5561 /* offsets are 32-bit, and only partly endian-swapped */
5562 offset = switchInsns[offsetToTargets + targ*2] |
5563 (((s4) switchInsns[offsetToTargets + targ*2 +1]) << 16);
5564 absOffset = insnIdx + offset;
5565
5566 assert(absOffset >= 0 && absOffset < insnsSize);
5567
5568 if (!checkMoveException(meth, absOffset, "switch"))
5569 goto bail;
5570
Andy McFadden319a33b2010-11-10 07:55:14 -08005571 updateRegisters(meth, insnFlags, regTable, absOffset, workLine);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005572 }
5573 }
5574
5575 /*
5576 * Handle instructions that can throw and that are sitting in a
5577 * "try" block. (If they're not in a "try" block when they throw,
5578 * control transfers out of the method.)
5579 */
5580 if ((nextFlags & kInstrCanThrow) != 0 && dvmInsnIsInTry(insnFlags, insnIdx))
5581 {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005582 const DexCode* pCode = dvmGetMethodCode(meth);
5583 DexCatchIterator iterator;
5584
5585 if (dexFindCatchHandler(&iterator, pCode, insnIdx)) {
5586 for (;;) {
5587 DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
5588
5589 if (handler == NULL) {
5590 break;
5591 }
5592
Andy McFadden319a33b2010-11-10 07:55:14 -08005593 /* note we use savedLine, not workLine */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005594 updateRegisters(meth, insnFlags, regTable, handler->address,
Andy McFadden319a33b2010-11-10 07:55:14 -08005595 &regTable->savedLine);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005596 }
5597 }
5598 }
5599
5600 /*
5601 * Update startGuess. Advance to the next instruction of that's
5602 * possible, otherwise use the branch target if one was found. If
5603 * neither of those exists we're in a return or throw; leave startGuess
5604 * alone and let the caller sort it out.
5605 */
5606 if ((nextFlags & kInstrCanContinue) != 0) {
5607 *pStartGuess = insnIdx + dvmInsnGetWidth(insnFlags, insnIdx);
5608 } else if ((nextFlags & kInstrCanBranch) != 0) {
5609 /* we're still okay if branchTarget is zero */
5610 *pStartGuess = insnIdx + branchTarget;
5611 }
5612
5613 assert(*pStartGuess >= 0 && *pStartGuess < insnsSize &&
5614 dvmInsnGetWidth(insnFlags, *pStartGuess) != 0);
5615
5616 result = true;
5617
5618bail:
5619 return result;
5620}
5621
Andy McFaddenb51ea112009-05-08 16:50:17 -07005622
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005623/*
5624 * callback function used in dumpRegTypes to print local vars
5625 * valid at a given address.
5626 */
5627static void logLocalsCb(void *cnxt, u2 reg, u4 startAddress, u4 endAddress,
5628 const char *name, const char *descriptor,
5629 const char *signature)
5630{
5631 int addr = *((int *)cnxt);
5632
5633 if (addr >= (int) startAddress && addr < (int) endAddress)
5634 {
5635 LOGI(" %2d: '%s' %s\n", reg, name, descriptor);
5636 }
5637}
5638
5639/*
5640 * Dump the register types for the specifed address to the log file.
5641 */
5642static void dumpRegTypes(const Method* meth, const InsnFlags* insnFlags,
Andy McFadden319a33b2010-11-10 07:55:14 -08005643 const RegisterLine* registerLine, int addr, const char* addrName,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005644 const UninitInstanceMap* uninitMap, int displayFlags)
5645{
Andy McFadden319a33b2010-11-10 07:55:14 -08005646 const RegType* addrRegs = registerLine->regTypes;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005647 int regCount = meth->registersSize;
5648 int fullRegCount = regCount + kExtraRegs;
5649 bool branchTarget = dvmInsnIsBranchTarget(insnFlags, addr);
5650 int i;
5651
5652 assert(addr >= 0 && addr < (int) dvmGetMethodInsnsSize(meth));
5653
5654 int regCharSize = fullRegCount + (fullRegCount-1)/4 + 2 +1;
5655 char regChars[regCharSize +1];
5656 memset(regChars, ' ', regCharSize);
5657 regChars[0] = '[';
5658 if (regCount == 0)
5659 regChars[1] = ']';
5660 else
5661 regChars[1 + (regCount-1) + (regCount-1)/4 +1] = ']';
5662 regChars[regCharSize] = '\0';
5663
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08005664 for (i = 0; i < regCount + kExtraRegs; i++) {
5665 char tch;
5666
5667 switch (addrRegs[i]) {
5668 case kRegTypeUnknown: tch = '.'; break;
5669 case kRegTypeConflict: tch = 'X'; break;
5670 case kRegTypeFloat: tch = 'F'; break;
5671 case kRegTypeZero: tch = '0'; break;
5672 case kRegTypeOne: tch = '1'; break;
5673 case kRegTypeBoolean: tch = 'Z'; break;
5674 case kRegTypePosByte: tch = 'b'; break;
5675 case kRegTypeByte: tch = 'B'; break;
5676 case kRegTypePosShort: tch = 's'; break;
5677 case kRegTypeShort: tch = 'S'; break;
5678 case kRegTypeChar: tch = 'C'; break;
5679 case kRegTypeInteger: tch = 'I'; break;
5680 case kRegTypeLongLo: tch = 'J'; break;
5681 case kRegTypeLongHi: tch = 'j'; break;
5682 case kRegTypeDoubleLo: tch = 'D'; break;
5683 case kRegTypeDoubleHi: tch = 'd'; break;
5684 default:
5685 if (regTypeIsReference(addrRegs[i])) {
5686 if (regTypeIsUninitReference(addrRegs[i]))
5687 tch = 'U';
5688 else
5689 tch = 'L';
5690 } else {
5691 tch = '*';
5692 assert(false);
5693 }
5694 break;
5695 }
5696
5697 if (i < regCount)
5698 regChars[1 + i + (i/4)] = tch;
5699 else
5700 regChars[1 + i + (i/4) + 2] = tch;
5701 }
5702
5703 if (addr == 0 && addrName != NULL)
5704 LOGI("%c%s %s\n", branchTarget ? '>' : ' ', addrName, regChars);
5705 else
5706 LOGI("%c0x%04x %s\n", branchTarget ? '>' : ' ', addr, regChars);
5707
5708 if (displayFlags & DRT_SHOW_REF_TYPES) {
5709 for (i = 0; i < regCount + kExtraRegs; i++) {
5710 if (regTypeIsReference(addrRegs[i]) && addrRegs[i] != kRegTypeZero)
5711 {
5712 ClassObject* clazz;
5713
5714 clazz = regTypeReferenceToClass(addrRegs[i], uninitMap);
5715 assert(dvmValidateObject((Object*)clazz));
5716 if (i < regCount) {
5717 LOGI(" %2d: 0x%08x %s%s\n",
5718 i, addrRegs[i],
5719 regTypeIsUninitReference(addrRegs[i]) ? "[U]" : "",
5720 clazz->descriptor);
5721 } else {
5722 LOGI(" RS: 0x%08x %s%s\n",
5723 addrRegs[i],
5724 regTypeIsUninitReference(addrRegs[i]) ? "[U]" : "",
5725 clazz->descriptor);
5726 }
5727 }
5728 }
5729 }
5730 if (displayFlags & DRT_SHOW_LOCALS) {
5731 dexDecodeDebugInfo(meth->clazz->pDvmDex->pDexFile,
5732 dvmGetMethodCode(meth),
5733 meth->clazz->descriptor,
5734 meth->prototype.protoIdx,
5735 meth->accessFlags,
5736 NULL, logLocalsCb, &addr);
5737 }
5738}