1 /*
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"
32 #include "analysis/RegisterMap.h"
33 #include "libdex/DexCatch.h"
34 #include "libdex/InstrUtils.h"
35
36 #include <stddef.h>
37
38
39 /*
40 * We don't need to store the register data for many instructions, because
41 * we either only need it at branch points (for verification) or GC points
42 * and branches (for verification + type-precise register analysis).
43 */
44 typedef enum RegisterTrackingMode {
45 kTrackRegsBranches,
46 kTrackRegsGcPoints,
47 kTrackRegsAll
48 } RegisterTrackingMode;
49
50 /*
51 * Set this to enable dead code scanning. This is not required, but it's
52 * very useful when testing changes to the verifier (to make sure we're not
53 * skipping over stuff) and for checking the optimized output from "dx".
54 * The only reason not to do it is that it slightly increases the time
55 * required to perform verification.
56 */
57 #define DEAD_CODE_SCAN true
58
59 static bool gDebugVerbose = false; // TODO: remove this
60
61 #if 0
62 int gDvm__totalInstr = 0;
63 int gDvm__gcInstr = 0;
64 int gDvm__gcData = 0;
65 int gDvm__gcSimpleData = 0;
66 #endif
67
68 /*
69 * Selectively enable verbose debug logging -- use this to activate
70 * dumpRegTypes() calls for all instructions in the specified method.
71 */
doVerboseLogging(const Method * meth)72 static inline bool doVerboseLogging(const Method* meth) {
73 return false; /* COMMENT OUT to enable verbose debugging */
74
75 const char* cd = "Landroid/net/http/Request;";
76 const char* mn = "readResponse";
77 const char* sg = "(Landroid/net/http/AndroidHttpClientConnection;)V";
78 return (strcmp(meth->clazz->descriptor, cd) == 0 &&
79 dvmCompareNameDescriptorAndMethod(mn, sg, meth) == 0);
80 }
81
82 #define SHOW_REG_DETAILS (0 /*| DRT_SHOW_REF_TYPES | DRT_SHOW_LOCALS*/)
83
84 /*
85 * We need an extra "pseudo register" to hold the return type briefly. It
86 * can be category 1 or 2, so we need two slots.
87 */
88 #define kExtraRegs 2
89 #define RESULT_REGISTER(_insnRegCount) (_insnRegCount)
90
91 /*
92 * Big fat collection of registers.
93 */
94 typedef struct RegisterTable {
95 /*
96 * Array of RegType arrays, one per address in the method. We only
97 * set the pointers for certain addresses, based on what we're trying
98 * to accomplish.
99 */
100 RegType** addrRegs;
101
102 /*
103 * Number of registers we track for each instruction. This is equal
104 * to the method's declared "registersSize" plus kExtraRegs.
105 */
106 int insnRegCountPlus;
107
108 /*
109 * A single large alloc, with all of the storage needed for addrRegs.
110 */
111 RegType* regAlloc;
112 } RegisterTable;
113
114
115 /* fwd */
116 static void checkMergeTab(void);
117 static bool isInitMethod(const Method* meth);
118 static RegType getInvocationThis(const RegType* insnRegs,\
119 const int insnRegCount, const DecodedInstruction* pDecInsn,
120 VerifyError* pFailure);
121 static void verifyRegisterType(const RegType* insnRegs, const int insnRegCount,\
122 u4 vsrc, RegType checkType, VerifyError* pFailure);
123 static bool doCodeVerification(Method* meth, InsnFlags* insnFlags,\
124 RegisterTable* regTable, UninitInstanceMap* uninitMap);
125 static bool verifyInstruction(Method* meth, InsnFlags* insnFlags,\
126 RegisterTable* regTable, RegType* workRegs, int insnIdx,
127 UninitInstanceMap* uninitMap, int* pStartGuess);
128 static ClassObject* findCommonSuperclass(ClassObject* c1, ClassObject* c2);
129 static void dumpRegTypes(const Method* meth, const InsnFlags* insnFlags,\
130 const RegType* addrRegs, int addr, const char* addrName,
131 const UninitInstanceMap* uninitMap, int displayFlags);
132
133 /* bit values for dumpRegTypes() "displayFlags" */
134 enum {
135 DRT_SIMPLE = 0,
136 DRT_SHOW_REF_TYPES = 0x01,
137 DRT_SHOW_LOCALS = 0x02,
138 };
139
140
141 /*
142 * ===========================================================================
143 * RegType and UninitInstanceMap utility functions
144 * ===========================================================================
145 */
146
147 #define __ kRegTypeUnknown
148 #define _U kRegTypeUninit
149 #define _X kRegTypeConflict
150 #define _F kRegTypeFloat
151 #define _0 kRegTypeZero
152 #define _1 kRegTypeOne
153 #define _Z kRegTypeBoolean
154 #define _b kRegTypePosByte
155 #define _B kRegTypeByte
156 #define _s kRegTypePosShort
157 #define _S kRegTypeShort
158 #define _C kRegTypeChar
159 #define _I kRegTypeInteger
160 #define _J kRegTypeLongLo
161 #define _j kRegTypeLongHi
162 #define _D kRegTypeDoubleLo
163 #define _d kRegTypeDoubleHi
164
165 /*
166 * Merge result table for primitive values. The table is symmetric along
167 * the diagonal.
168 *
169 * Note that 32-bit int/float do not merge into 64-bit long/double. This
170 * is a register merge, not a widening conversion. Only the "implicit"
171 * widening within a category, e.g. byte to short, is allowed.
172 *
173 * Because Dalvik does not draw a distinction between int and float, we
174 * have to allow free exchange between 32-bit int/float and 64-bit
175 * long/double.
176 *
177 * Note that Uninit+Uninit=Uninit. This holds true because we only
178 * use this when the RegType value is exactly equal to kRegTypeUninit, which
179 * can only happen for the zeroeth entry in the table.
180 *
181 * "Unknown" never merges with anything known. The only time a register
182 * transitions from "unknown" to "known" is when we're executing code
183 * for the first time, and we handle that with a simple copy.
184 */
185 const char gDvmMergeTab[kRegTypeMAX][kRegTypeMAX] =
186 {
187 /* chk: _ U X F 0 1 Z b B s S C I J j D d */
188 { /*_*/ __,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X },
189 { /*U*/ _X,_U,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X },
190 { /*X*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X },
191 { /*F*/ _X,_X,_X,_F,_F,_F,_F,_F,_F,_F,_F,_F,_F,_X,_X,_X,_X },
192 { /*0*/ _X,_X,_X,_F,_0,_Z,_Z,_b,_B,_s,_S,_C,_I,_X,_X,_X,_X },
193 { /*1*/ _X,_X,_X,_F,_Z,_1,_Z,_b,_B,_s,_S,_C,_I,_X,_X,_X,_X },
194 { /*Z*/ _X,_X,_X,_F,_Z,_Z,_Z,_b,_B,_s,_S,_C,_I,_X,_X,_X,_X },
195 { /*b*/ _X,_X,_X,_F,_b,_b,_b,_b,_B,_s,_S,_C,_I,_X,_X,_X,_X },
196 { /*B*/ _X,_X,_X,_F,_B,_B,_B,_B,_B,_S,_S,_I,_I,_X,_X,_X,_X },
197 { /*s*/ _X,_X,_X,_F,_s,_s,_s,_s,_S,_s,_S,_C,_I,_X,_X,_X,_X },
198 { /*S*/ _X,_X,_X,_F,_S,_S,_S,_S,_S,_S,_S,_I,_I,_X,_X,_X,_X },
199 { /*C*/ _X,_X,_X,_F,_C,_C,_C,_C,_I,_C,_I,_C,_I,_X,_X,_X,_X },
200 { /*I*/ _X,_X,_X,_F,_I,_I,_I,_I,_I,_I,_I,_I,_I,_X,_X,_X,_X },
201 { /*J*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_J,_X,_J,_X },
202 { /*j*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_j,_X,_j },
203 { /*D*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_J,_X,_D,_X },
204 { /*d*/ _X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_X,_j,_X,_d },
205 };
206
207 #undef __
208 #undef _U
209 #undef _X
210 #undef _F
211 #undef _0
212 #undef _1
213 #undef _Z
214 #undef _b
215 #undef _B
216 #undef _s
217 #undef _S
218 #undef _C
219 #undef _I
220 #undef _J
221 #undef _j
222 #undef _D
223 #undef _d
224
225 #ifndef NDEBUG
226 /*
227 * Verify symmetry in the conversion table.
228 */
checkMergeTab(void)229 static void checkMergeTab(void)
230 {
231 int i, j;
232
233 for (i = 0; i < kRegTypeMAX; i++) {
234 for (j = i; j < kRegTypeMAX; j++) {
235 if (gDvmMergeTab[i][j] != gDvmMergeTab[j][i]) {
236 LOGE("Symmetry violation: %d,%d vs %d,%d\n", i, j, j, i);
237 dvmAbort();
238 }
239 }
240 }
241 }
242 #endif
243
244 /*
245 * Determine whether we can convert "srcType" to "checkType", where
246 * "checkType" is one of the category-1 non-reference types.
247 *
248 * 32-bit int and float are interchangeable.
249 */
canConvertTo1nr(RegType srcType,RegType checkType)250 static bool canConvertTo1nr(RegType srcType, RegType checkType)
251 {
252 static const char convTab
253 [kRegType1nrEND-kRegType1nrSTART+1][kRegType1nrEND-kRegType1nrSTART+1] =
254 {
255 /* chk: F 0 1 Z b B s S C I */
256 { /*F*/ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
257 { /*0*/ 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
258 { /*1*/ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 },
259 { /*Z*/ 1, 0, 0, 1, 1, 1, 1, 1, 1, 1 },
260 { /*b*/ 1, 0, 0, 0, 1, 1, 1, 1, 1, 1 },
261 { /*B*/ 1, 0, 0, 0, 0, 1, 0, 1, 0, 1 },
262 { /*s*/ 1, 0, 0, 0, 0, 0, 1, 1, 1, 1 },
263 { /*S*/ 1, 0, 0, 0, 0, 0, 0, 1, 0, 1 },
264 { /*C*/ 1, 0, 0, 0, 0, 0, 0, 0, 1, 1 },
265 { /*I*/ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
266 };
267
268 assert(checkType >= kRegType1nrSTART && checkType <= kRegType1nrEND);
269 #if 0
270 if (checkType < kRegType1nrSTART || checkType > kRegType1nrEND) {
271 LOG_VFY("Unexpected checkType %d (srcType=%d)\n", checkType, srcType);
272 assert(false);
273 return false;
274 }
275 #endif
276
277 //printf("convTab[%d][%d] = %d\n", srcType, checkType,
278 // convTab[srcType-kRegType1nrSTART][checkType-kRegType1nrSTART]);
279 if (srcType >= kRegType1nrSTART && srcType <= kRegType1nrEND)
280 return (bool) convTab[srcType-kRegType1nrSTART][checkType-kRegType1nrSTART];
281
282 return false;
283 }
284
285 /*
286 * Determine whether the types are compatible. In Dalvik, 64-bit doubles
287 * and longs are interchangeable.
288 */
canConvertTo2(RegType srcType,RegType checkType)289 static bool canConvertTo2(RegType srcType, RegType checkType)
290 {
291 return ((srcType == kRegTypeLongLo || srcType == kRegTypeDoubleLo) &&
292 (checkType == kRegTypeLongLo || checkType == kRegTypeDoubleLo));
293 }
294
295 /*
296 * Determine whether or not "instrType" and "targetType" are compatible,
297 * for purposes of getting or setting a value in a field or array. The
298 * idea is that an instruction with a category 1nr type (say, aget-short
299 * or iput-boolean) is accessing a static field, instance field, or array
300 * entry, and we want to make sure sure that the operation is legal.
301 *
302 * At a minimum, source and destination must have the same width. We
303 * further refine this to assert that "short" and "char" are not
304 * compatible, because the sign-extension is different on the "get"
305 * operations. As usual, "float" and "int" are interoperable.
306 *
307 * We're not considering the actual contents of the register, so we'll
308 * never get "pseudo-types" like kRegTypeZero or kRegTypePosShort. We
309 * could get kRegTypeUnknown in "targetType" if a field or array class
310 * lookup failed. Category 2 types and references are checked elsewhere.
311 */
checkFieldArrayStore1nr(RegType instrType,RegType targetType)312 static bool checkFieldArrayStore1nr(RegType instrType, RegType targetType)
313 {
314 if (instrType == targetType)
315 return true; /* quick positive; most common case */
316
317 if ((instrType == kRegTypeInteger && targetType == kRegTypeFloat) ||
318 (instrType == kRegTypeFloat && targetType == kRegTypeInteger))
319 {
320 return true;
321 }
322
323 return false;
324 }
325
326 /*
327 * Convert a VM PrimitiveType enum value to the equivalent RegType value.
328 */
primitiveTypeToRegType(PrimitiveType primType)329 static RegType primitiveTypeToRegType(PrimitiveType primType)
330 {
331 static const struct {
332 RegType regType; /* type equivalent */
333 PrimitiveType primType; /* verification */
334 } convTab[] = {
335 /* must match order of enum in Object.h */
336 { kRegTypeBoolean, PRIM_BOOLEAN },
337 { kRegTypeChar, PRIM_CHAR },
338 { kRegTypeFloat, PRIM_FLOAT },
339 { kRegTypeDoubleLo, PRIM_DOUBLE },
340 { kRegTypeByte, PRIM_BYTE },
341 { kRegTypeShort, PRIM_SHORT },
342 { kRegTypeInteger, PRIM_INT },
343 { kRegTypeLongLo, PRIM_LONG },
344 // PRIM_VOID
345 };
346
347 if (primType < 0 || primType > (int) (sizeof(convTab) / sizeof(convTab[0])))
348 {
349 assert(false);
350 return kRegTypeUnknown;
351 }
352
353 assert(convTab[primType].primType == primType);
354 return convTab[primType].regType;
355 }
356
357 /*
358 * Create a new uninitialized instance map.
359 *
360 * The map is allocated and populated with address entries. The addresses
361 * appear in ascending order to allow binary searching.
362 *
363 * Very few methods have 10 or more new-instance instructions; the
364 * majority have 0 or 1. Occasionally a static initializer will have 200+.
365 */
dvmCreateUninitInstanceMap(const Method * meth,const InsnFlags * insnFlags,int newInstanceCount)366 UninitInstanceMap* dvmCreateUninitInstanceMap(const Method* meth,
367 const InsnFlags* insnFlags, int newInstanceCount)
368 {
369 const int insnsSize = dvmGetMethodInsnsSize(meth);
370 const u2* insns = meth->insns;
371 UninitInstanceMap* uninitMap;
372 bool isInit = false;
373 int idx, addr;
374
375 if (isInitMethod(meth)) {
376 newInstanceCount++;
377 isInit = true;
378 }
379
380 /*
381 * Allocate the header and map as a single unit.
382 *
383 * TODO: consider having a static instance so we can avoid allocations.
384 * I don't think the verifier is guaranteed to be single-threaded when
385 * running in the VM (rather than dexopt), so that must be taken into
386 * account.
387 */
388 int size = offsetof(UninitInstanceMap, map) +
389 newInstanceCount * sizeof(uninitMap->map[0]);
390 uninitMap = calloc(1, size);
391 if (uninitMap == NULL)
392 return NULL;
393 uninitMap->numEntries = newInstanceCount;
394
395 idx = 0;
396 if (isInit) {
397 uninitMap->map[idx++].addr = kUninitThisArgAddr;
398 }
399
400 /*
401 * Run through and find the new-instance instructions.
402 */
403 for (addr = 0; addr < insnsSize; /**/) {
404 int width = dvmInsnGetWidth(insnFlags, addr);
405
406 if ((*insns & 0xff) == OP_NEW_INSTANCE)
407 uninitMap->map[idx++].addr = addr;
408
409 addr += width;
410 insns += width;
411 }
412
413 assert(idx == newInstanceCount);
414 return uninitMap;
415 }
416
417 /*
418 * Free the map.
419 */
dvmFreeUninitInstanceMap(UninitInstanceMap * uninitMap)420 void dvmFreeUninitInstanceMap(UninitInstanceMap* uninitMap)
421 {
422 free(uninitMap);
423 }
424
425 /*
426 * Set the class object associated with the instruction at "addr".
427 *
428 * Returns the map slot index, or -1 if the address isn't listed in the map
429 * (shouldn't happen) or if a class is already associated with the address
430 * (bad bytecode).
431 *
432 * Entries, once set, do not change -- a given address can only allocate
433 * one type of object.
434 */
dvmSetUninitInstance(UninitInstanceMap * uninitMap,int addr,ClassObject * clazz)435 int dvmSetUninitInstance(UninitInstanceMap* uninitMap, int addr,
436 ClassObject* clazz)
437 {
438 int idx;
439
440 assert(clazz != NULL);
441
442 /* TODO: binary search when numEntries > 8 */
443 for (idx = uninitMap->numEntries - 1; idx >= 0; idx--) {
444 if (uninitMap->map[idx].addr == addr) {
445 if (uninitMap->map[idx].clazz != NULL &&
446 uninitMap->map[idx].clazz != clazz)
447 {
448 LOG_VFY("VFY: addr %d already set to %p, not setting to %p\n",
449 addr, uninitMap->map[idx].clazz, clazz);
450 return -1; // already set to something else??
451 }
452 uninitMap->map[idx].clazz = clazz;
453 return idx;
454 }
455 }
456
457 LOG_VFY("VFY: addr %d not found in uninit map\n", addr);
458 assert(false); // shouldn't happen
459 return -1;
460 }
461
462 /*
463 * Get the class object at the specified index.
464 */
dvmGetUninitInstance(const UninitInstanceMap * uninitMap,int idx)465 ClassObject* dvmGetUninitInstance(const UninitInstanceMap* uninitMap, int idx)
466 {
467 assert(idx >= 0 && idx < uninitMap->numEntries);
468 return uninitMap->map[idx].clazz;
469 }
470
471 /* determine if "type" is actually an object reference (init/uninit/zero) */
regTypeIsReference(RegType type)472 static inline bool regTypeIsReference(RegType type) {
473 return (type > kRegTypeMAX || type == kRegTypeUninit ||
474 type == kRegTypeZero);
475 }
476
477 /* determine if "type" is an uninitialized object reference */
regTypeIsUninitReference(RegType type)478 static inline bool regTypeIsUninitReference(RegType type) {
479 return ((type & kRegTypeUninitMask) == kRegTypeUninit);
480 }
481
482 /* convert the initialized reference "type" to a ClassObject pointer */
483 /* (does not expect uninit ref types or "zero") */
regTypeInitializedReferenceToClass(RegType type)484 static ClassObject* regTypeInitializedReferenceToClass(RegType type)
485 {
486 assert(regTypeIsReference(type) && type != kRegTypeZero);
487 if ((type & 0x01) == 0) {
488 return (ClassObject*) type;
489 } else {
490 //LOG_VFY("VFY: attempted to use uninitialized reference\n");
491 return NULL;
492 }
493 }
494
495 /* extract the index into the uninitialized instance map table */
regTypeToUninitIndex(RegType type)496 static inline int regTypeToUninitIndex(RegType type) {
497 assert(regTypeIsUninitReference(type));
498 return (type & ~kRegTypeUninitMask) >> kRegTypeUninitShift;
499 }
500
501 /* convert the reference "type" to a ClassObject pointer */
regTypeReferenceToClass(RegType type,const UninitInstanceMap * uninitMap)502 static ClassObject* regTypeReferenceToClass(RegType type,
503 const UninitInstanceMap* uninitMap)
504 {
505 assert(regTypeIsReference(type) && type != kRegTypeZero);
506 if (regTypeIsUninitReference(type)) {
507 assert(uninitMap != NULL);
508 return dvmGetUninitInstance(uninitMap, regTypeToUninitIndex(type));
509 } else {
510 return (ClassObject*) type;
511 }
512 }
513
514 /* convert the ClassObject pointer to an (initialized) register type */
regTypeFromClass(ClassObject * clazz)515 static inline RegType regTypeFromClass(ClassObject* clazz) {
516 return (u4) clazz;
517 }
518
519 /* return the RegType for the uninitialized reference in slot "uidx" */
regTypeFromUninitIndex(int uidx)520 static RegType regTypeFromUninitIndex(int uidx) {
521 return (u4) (kRegTypeUninit | (uidx << kRegTypeUninitShift));
522 }
523
524
525 /*
526 * ===========================================================================
527 * Signature operations
528 * ===========================================================================
529 */
530
531 /*
532 * Is this method a constructor?
533 */
isInitMethod(const Method * meth)534 static bool isInitMethod(const Method* meth)
535 {
536 return (*meth->name == '<' && strcmp(meth->name+1, "init>") == 0);
537 }
538
539 /*
540 * Is this method a class initializer?
541 */
isClassInitMethod(const Method * meth)542 static bool isClassInitMethod(const Method* meth)
543 {
544 return (*meth->name == '<' && strcmp(meth->name+1, "clinit>") == 0);
545 }
546
547 /*
548 * Look up a class reference given as a simple string descriptor.
549 *
550 * If we can't find it, return a generic substitute when possible.
551 */
lookupClassByDescriptor(const Method * meth,const char * pDescriptor,VerifyError * pFailure)552 static ClassObject* lookupClassByDescriptor(const Method* meth,
553 const char* pDescriptor, VerifyError* pFailure)
554 {
555 /*
556 * The javac compiler occasionally puts references to nonexistent
557 * classes in signatures. For example, if you have a non-static
558 * inner class with no constructor, the compiler provides
559 * a private <init> for you. Constructing the class
560 * requires <init>(parent), but the outer class can't call
561 * that because the method is private. So the compiler
562 * generates a package-scope <init>(parent,bogus) method that
563 * just calls the regular <init> (the "bogus" part being necessary
564 * to distinguish the signature of the synthetic method).
565 * Treating the bogus class as an instance of java.lang.Object
566 * allows the verifier to process the class successfully.
567 */
568
569 //LOGI("Looking up '%s'\n", typeStr);
570 ClassObject* clazz;
571 clazz = dvmFindClassNoInit(pDescriptor, meth->clazz->classLoader);
572 if (clazz == NULL) {
573 dvmClearOptException(dvmThreadSelf());
574 if (strchr(pDescriptor, '$') != NULL) {
575 LOGV("VFY: unable to find class referenced in signature (%s)\n",
576 pDescriptor);
577 } else {
578 LOG_VFY("VFY: unable to find class referenced in signature (%s)\n",
579 pDescriptor);
580 }
581
582 if (pDescriptor[0] == '[') {
583 /* We are looking at an array descriptor. */
584
585 /*
586 * There should never be a problem loading primitive arrays.
587 */
588 if (pDescriptor[1] != 'L' && pDescriptor[1] != '[') {
589 LOG_VFY("VFY: invalid char in signature in '%s'\n",
590 pDescriptor);
591 *pFailure = VERIFY_ERROR_GENERIC;
592 }
593
594 /*
595 * Try to continue with base array type. This will let
596 * us pass basic stuff (e.g. get array len) that wouldn't
597 * fly with an Object. This is NOT correct if the
598 * missing type is a primitive array, but we should never
599 * have a problem loading those. (I'm not convinced this
600 * is correct or even useful. Just use Object here?)
601 */
602 clazz = dvmFindClassNoInit("[Ljava/lang/Object;",
603 meth->clazz->classLoader);
604 } else if (pDescriptor[0] == 'L') {
605 /*
606 * We are looking at a non-array reference descriptor;
607 * try to continue with base reference type.
608 */
609 clazz = gDvm.classJavaLangObject;
610 } else {
611 /* We are looking at a primitive type. */
612 LOG_VFY("VFY: invalid char in signature in '%s'\n", pDescriptor);
613 *pFailure = VERIFY_ERROR_GENERIC;
614 }
615
616 if (clazz == NULL) {
617 *pFailure = VERIFY_ERROR_GENERIC;
618 }
619 }
620
621 if (dvmIsPrimitiveClass(clazz)) {
622 LOG_VFY("VFY: invalid use of primitive type '%s'\n", pDescriptor);
623 *pFailure = VERIFY_ERROR_GENERIC;
624 clazz = NULL;
625 }
626
627 return clazz;
628 }
629
630 /*
631 * Look up a class reference in a signature. Could be an arg or the
632 * return value.
633 *
634 * Advances "*pSig" to the last character in the signature (that is, to
635 * the ';').
636 *
637 * NOTE: this is also expected to verify the signature.
638 */
lookupSignatureClass(const Method * meth,const char ** pSig,VerifyError * pFailure)639 static ClassObject* lookupSignatureClass(const Method* meth, const char** pSig,
640 VerifyError* pFailure)
641 {
642 const char* sig = *pSig;
643 const char* endp = sig;
644
645 assert(sig != NULL && *sig == 'L');
646
647 while (*++endp != ';' && *endp != '\0')
648 ;
649 if (*endp != ';') {
650 LOG_VFY("VFY: bad signature component '%s' (missing ';')\n", sig);
651 *pFailure = VERIFY_ERROR_GENERIC;
652 return NULL;
653 }
654
655 endp++; /* Advance past the ';'. */
656 int typeLen = endp - sig;
657 char typeStr[typeLen+1]; /* +1 for the '\0' */
658 memcpy(typeStr, sig, typeLen);
659 typeStr[typeLen] = '\0';
660
661 *pSig = endp - 1; /* - 1 so that *pSig points at, not past, the ';' */
662
663 return lookupClassByDescriptor(meth, typeStr, pFailure);
664 }
665
666 /*
667 * Look up an array class reference in a signature. Could be an arg or the
668 * return value.
669 *
670 * Advances "*pSig" to the last character in the signature.
671 *
672 * NOTE: this is also expected to verify the signature.
673 */
lookupSignatureArrayClass(const Method * meth,const char ** pSig,VerifyError * pFailure)674 static ClassObject* lookupSignatureArrayClass(const Method* meth,
675 const char** pSig, VerifyError* pFailure)
676 {
677 const char* sig = *pSig;
678 const char* endp = sig;
679
680 assert(sig != NULL && *sig == '[');
681
682 /* find the end */
683 while (*++endp == '[' && *endp != '\0')
684 ;
685
686 if (*endp == 'L') {
687 while (*++endp != ';' && *endp != '\0')
688 ;
689 if (*endp != ';') {
690 LOG_VFY("VFY: bad signature component '%s' (missing ';')\n", sig);
691 *pFailure = VERIFY_ERROR_GENERIC;
692 return NULL;
693 }
694 }
695
696 int typeLen = endp - sig +1;
697 char typeStr[typeLen+1];
698 memcpy(typeStr, sig, typeLen);
699 typeStr[typeLen] = '\0';
700
701 *pSig = endp;
702
703 return lookupClassByDescriptor(meth, typeStr, pFailure);
704 }
705
706 /*
707 * Set the register types for the first instruction in the method based on
708 * the method signature.
709 *
710 * This has the side-effect of validating the signature.
711 *
712 * Returns "true" on success.
713 */
setTypesFromSignature(const Method * meth,RegType * regTypes,UninitInstanceMap * uninitMap)714 static bool setTypesFromSignature(const Method* meth, RegType* regTypes,
715 UninitInstanceMap* uninitMap)
716 {
717 DexParameterIterator iterator;
718 int actualArgs, expectedArgs, argStart;
719 VerifyError failure = VERIFY_ERROR_NONE;
720
721 dexParameterIteratorInit(&iterator, &meth->prototype);
722 argStart = meth->registersSize - meth->insSize;
723 expectedArgs = meth->insSize; /* long/double count as two */
724 actualArgs = 0;
725
726 assert(argStart >= 0); /* should have been verified earlier */
727
728 /*
729 * Include the "this" pointer.
730 */
731 if (!dvmIsStaticMethod(meth)) {
732 /*
733 * If this is a constructor for a class other than java.lang.Object,
734 * mark the first ("this") argument as uninitialized. This restricts
735 * field access until the superclass constructor is called.
736 */
737 if (isInitMethod(meth) && meth->clazz != gDvm.classJavaLangObject) {
738 int uidx = dvmSetUninitInstance(uninitMap, kUninitThisArgAddr,
739 meth->clazz);
740 assert(uidx == 0);
741 regTypes[argStart + actualArgs] = regTypeFromUninitIndex(uidx);
742 } else {
743 regTypes[argStart + actualArgs] = regTypeFromClass(meth->clazz);
744 }
745 actualArgs++;
746 }
747
748 for (;;) {
749 const char* descriptor = dexParameterIteratorNextDescriptor(&iterator);
750
751 if (descriptor == NULL) {
752 break;
753 }
754
755 if (actualArgs >= expectedArgs) {
756 LOG_VFY("VFY: expected %d args, found more (%s)\n",
757 expectedArgs, descriptor);
758 goto bad_sig;
759 }
760
761 switch (*descriptor) {
762 case 'L':
763 case '[':
764 /*
765 * We assume that reference arguments are initialized. The
766 * only way it could be otherwise (assuming the caller was
767 * verified) is if the current method is <init>, but in that
768 * case it's effectively considered initialized the instant
769 * we reach here (in the sense that we can return without
770 * doing anything or call virtual methods).
771 */
772 {
773 ClassObject* clazz =
774 lookupClassByDescriptor(meth, descriptor, &failure);
775 if (!VERIFY_OK(failure))
776 goto bad_sig;
777 regTypes[argStart + actualArgs] = regTypeFromClass(clazz);
778 }
779 actualArgs++;
780 break;
781 case 'Z':
782 regTypes[argStart + actualArgs] = kRegTypeBoolean;
783 actualArgs++;
784 break;
785 case 'C':
786 regTypes[argStart + actualArgs] = kRegTypeChar;
787 actualArgs++;
788 break;
789 case 'B':
790 regTypes[argStart + actualArgs] = kRegTypeByte;
791 actualArgs++;
792 break;
793 case 'I':
794 regTypes[argStart + actualArgs] = kRegTypeInteger;
795 actualArgs++;
796 break;
797 case 'S':
798 regTypes[argStart + actualArgs] = kRegTypeShort;
799 actualArgs++;
800 break;
801 case 'F':
802 regTypes[argStart + actualArgs] = kRegTypeFloat;
803 actualArgs++;
804 break;
805 case 'D':
806 regTypes[argStart + actualArgs] = kRegTypeDoubleLo;
807 regTypes[argStart + actualArgs +1] = kRegTypeDoubleHi;
808 actualArgs += 2;
809 break;
810 case 'J':
811 regTypes[argStart + actualArgs] = kRegTypeLongLo;
812 regTypes[argStart + actualArgs +1] = kRegTypeLongHi;
813 actualArgs += 2;
814 break;
815 default:
816 LOG_VFY("VFY: unexpected signature type char '%c'\n", *descriptor);
817 goto bad_sig;
818 }
819 }
820
821 if (actualArgs != expectedArgs) {
822 LOG_VFY("VFY: expected %d args, found %d\n", expectedArgs, actualArgs);
823 goto bad_sig;
824 }
825
826 const char* descriptor = dexProtoGetReturnType(&meth->prototype);
827
828 /*
829 * Validate return type. We don't do the type lookup; just want to make
830 * sure that it has the right format. Only major difference from the
831 * method argument format is that 'V' is supported.
832 */
833 switch (*descriptor) {
834 case 'I':
835 case 'C':
836 case 'S':
837 case 'B':
838 case 'Z':
839 case 'V':
840 case 'F':
841 case 'D':
842 case 'J':
843 if (*(descriptor+1) != '\0')
844 goto bad_sig;
845 break;
846 case '[':
847 /* single/multi, object/primitive */
848 while (*++descriptor == '[')
849 ;
850 if (*descriptor == 'L') {
851 while (*++descriptor != ';' && *descriptor != '\0')
852 ;
853 if (*descriptor != ';')
854 goto bad_sig;
855 } else {
856 if (*(descriptor+1) != '\0')
857 goto bad_sig;
858 }
859 break;
860 case 'L':
861 /* could be more thorough here, but shouldn't be required */
862 while (*++descriptor != ';' && *descriptor != '\0')
863 ;
864 if (*descriptor != ';')
865 goto bad_sig;
866 break;
867 default:
868 goto bad_sig;
869 }
870
871 return true;
872
873 //fail:
874 // LOG_VFY_METH(meth, "VFY: bad sig\n");
875 // return false;
876
877 bad_sig:
878 {
879 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
880 LOG_VFY("VFY: bad signature '%s' for %s.%s\n",
881 desc, meth->clazz->descriptor, meth->name);
882 free(desc);
883 }
884 return false;
885 }
886
887 /*
888 * Return the register type for the method. We can't just use the
889 * already-computed DalvikJniReturnType, because if it's a reference type
890 * we need to do the class lookup.
891 *
892 * Returned references are assumed to be initialized.
893 *
894 * Returns kRegTypeUnknown for "void".
895 */
getMethodReturnType(const Method * meth)896 static RegType getMethodReturnType(const Method* meth)
897 {
898 RegType type;
899 const char* descriptor = dexProtoGetReturnType(&meth->prototype);
900
901 switch (*descriptor) {
902 case 'I':
903 type = kRegTypeInteger;
904 break;
905 case 'C':
906 type = kRegTypeChar;
907 break;
908 case 'S':
909 type = kRegTypeShort;
910 break;
911 case 'B':
912 type = kRegTypeByte;
913 break;
914 case 'Z':
915 type = kRegTypeBoolean;
916 break;
917 case 'V':
918 type = kRegTypeUnknown;
919 break;
920 case 'F':
921 type = kRegTypeFloat;
922 break;
923 case 'D':
924 type = kRegTypeDoubleLo;
925 break;
926 case 'J':
927 type = kRegTypeLongLo;
928 break;
929 case 'L':
930 case '[':
931 {
932 VerifyError failure = VERIFY_ERROR_NONE;
933 ClassObject* clazz =
934 lookupClassByDescriptor(meth, descriptor, &failure);
935 assert(VERIFY_OK(failure));
936 type = regTypeFromClass(clazz);
937 }
938 break;
939 default:
940 /* we verified signature return type earlier, so this is impossible */
941 assert(false);
942 type = kRegTypeConflict;
943 break;
944 }
945
946 return type;
947 }
948
949 /*
950 * Convert a single-character signature value (i.e. a primitive type) to
951 * the corresponding RegType. This is intended for access to object fields
952 * holding primitive types.
953 *
954 * Returns kRegTypeUnknown for objects, arrays, and void.
955 */
primSigCharToRegType(char sigChar)956 static RegType primSigCharToRegType(char sigChar)
957 {
958 RegType type;
959
960 switch (sigChar) {
961 case 'I':
962 type = kRegTypeInteger;
963 break;
964 case 'C':
965 type = kRegTypeChar;
966 break;
967 case 'S':
968 type = kRegTypeShort;
969 break;
970 case 'B':
971 type = kRegTypeByte;
972 break;
973 case 'Z':
974 type = kRegTypeBoolean;
975 break;
976 case 'F':
977 type = kRegTypeFloat;
978 break;
979 case 'D':
980 type = kRegTypeDoubleLo;
981 break;
982 case 'J':
983 type = kRegTypeLongLo;
984 break;
985 case 'V':
986 case 'L':
987 case '[':
988 type = kRegTypeUnknown;
989 break;
990 default:
991 assert(false);
992 type = kRegTypeUnknown;
993 break;
994 }
995
996 return type;
997 }
998
999 /*
1000 * Verify the arguments to a method. We're executing in "method", making
1001 * a call to the method reference in vB.
1002 *
1003 * If this is a "direct" invoke, we allow calls to <init>. For calls to
1004 * <init>, the first argument may be an uninitialized reference. Otherwise,
1005 * calls to anything starting with '<' will be rejected, as will any
1006 * uninitialized reference arguments.
1007 *
1008 * For non-static method calls, this will verify that the method call is
1009 * appropriate for the "this" argument.
1010 *
1011 * The method reference is in vBBBB. The "isRange" parameter determines
1012 * whether we use 0-4 "args" values or a range of registers defined by
1013 * vAA and vCCCC.
1014 *
1015 * Widening conversions on integers and references are allowed, but
1016 * narrowing conversions are not.
1017 *
1018 * Returns the resolved method on success, NULL on failure (with *pFailure
1019 * set appropriately).
1020 */
verifyInvocationArgs(const Method * meth,const RegType * insnRegs,const int insnRegCount,const DecodedInstruction * pDecInsn,UninitInstanceMap * uninitMap,MethodType methodType,bool isRange,bool isSuper,VerifyError * pFailure)1021 static Method* verifyInvocationArgs(const Method* meth, const RegType* insnRegs,
1022 const int insnRegCount, const DecodedInstruction* pDecInsn,
1023 UninitInstanceMap* uninitMap, MethodType methodType, bool isRange,
1024 bool isSuper, VerifyError* pFailure)
1025 {
1026 Method* resMethod;
1027 char* sigOriginal = NULL;
1028
1029 /*
1030 * Resolve the method. This could be an abstract or concrete method
1031 * depending on what sort of call we're making.
1032 */
1033 if (methodType == METHOD_INTERFACE) {
1034 resMethod = dvmOptResolveInterfaceMethod(meth->clazz, pDecInsn->vB);
1035 } else {
1036 resMethod = dvmOptResolveMethod(meth->clazz, pDecInsn->vB, methodType,
1037 pFailure);
1038 }
1039 if (resMethod == NULL) {
1040 /* failed; print a meaningful failure message */
1041 DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
1042 const DexMethodId* pMethodId;
1043 const char* methodName;
1044 char* methodDesc;
1045 const char* classDescriptor;
1046
1047 pMethodId = dexGetMethodId(pDexFile, pDecInsn->vB);
1048 methodName = dexStringById(pDexFile, pMethodId->nameIdx);
1049 methodDesc = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
1050 classDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
1051
1052 if (!gDvm.optimizing) {
1053 char* dotMissingClass = dvmDescriptorToDot(classDescriptor);
1054 char* dotMethClass = dvmDescriptorToDot(meth->clazz->descriptor);
1055 //char* curMethodDesc =
1056 // dexProtoCopyMethodDescriptor(&meth->prototype);
1057
1058 LOGI("Could not find method %s.%s, referenced from "
1059 "method %s.%s\n",
1060 dotMissingClass, methodName/*, methodDesc*/,
1061 dotMethClass, meth->name/*, curMethodDesc*/);
1062
1063 free(dotMissingClass);
1064 free(dotMethClass);
1065 //free(curMethodDesc);
1066 }
1067
1068 LOG_VFY("VFY: unable to resolve %s method %u: %s.%s %s\n",
1069 dvmMethodTypeStr(methodType), pDecInsn->vB,
1070 classDescriptor, methodName, methodDesc);
1071 free(methodDesc);
1072 if (VERIFY_OK(*pFailure)) /* not set for interface resolve */
1073 *pFailure = VERIFY_ERROR_NO_METHOD;
1074 goto fail;
1075 }
1076
1077 /*
1078 * Only time you can explicitly call a method starting with '<' is when
1079 * making a "direct" invocation on "<init>". There are additional
1080 * restrictions but we don't enforce them here.
1081 */
1082 if (resMethod->name[0] == '<') {
1083 if (methodType != METHOD_DIRECT || !isInitMethod(resMethod)) {
1084 LOG_VFY("VFY: invalid call to %s.%s\n",
1085 resMethod->clazz->descriptor, resMethod->name);
1086 goto bad_sig;
1087 }
1088 }
1089
1090 /*
1091 * If we're using invoke-super(method), make sure that the executing
1092 * method's class' superclass has a vtable entry for the target method.
1093 */
1094 if (isSuper) {
1095 assert(methodType == METHOD_VIRTUAL);
1096 ClassObject* super = meth->clazz->super;
1097 if (super == NULL || resMethod->methodIndex > super->vtableCount) {
1098 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1099 LOG_VFY("VFY: invalid invoke-super from %s.%s to super %s.%s %s\n",
1100 meth->clazz->descriptor, meth->name,
1101 (super == NULL) ? "-" : super->descriptor,
1102 resMethod->name, desc);
1103 free(desc);
1104 *pFailure = VERIFY_ERROR_NO_METHOD;
1105 goto fail;
1106 }
1107 }
1108
1109 /*
1110 * We use vAA as our expected arg count, rather than resMethod->insSize,
1111 * because we need to match the call to the signature. Also, we might
1112 * might be calling through an abstract method definition (which doesn't
1113 * have register count values).
1114 */
1115 sigOriginal = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1116 const char* sig = sigOriginal;
1117 int expectedArgs = pDecInsn->vA;
1118 int actualArgs = 0;
1119
1120 if (!isRange && expectedArgs > 5) {
1121 LOG_VFY("VFY: invalid arg count in non-range invoke (%d)\n",
1122 pDecInsn->vA);
1123 goto fail;
1124 }
1125 if (expectedArgs > meth->outsSize) {
1126 LOG_VFY("VFY: invalid arg count (%d) exceeds outsSize (%d)\n",
1127 expectedArgs, meth->outsSize);
1128 goto fail;
1129 }
1130
1131 if (*sig++ != '(')
1132 goto bad_sig;
1133
1134 /*
1135 * Check the "this" argument, which must be an instance of the class
1136 * that declared the method. For an interface class, we don't do the
1137 * full interface merge, so we can't do a rigorous check here (which
1138 * is okay since we have to do it at runtime).
1139 */
1140 if (!dvmIsStaticMethod(resMethod)) {
1141 ClassObject* actualThisRef;
1142 RegType actualArgType;
1143
1144 actualArgType = getInvocationThis(insnRegs, insnRegCount, pDecInsn,
1145 pFailure);
1146 if (!VERIFY_OK(*pFailure))
1147 goto fail;
1148
1149 if (regTypeIsUninitReference(actualArgType) && resMethod->name[0] != '<')
1150 {
1151 LOG_VFY("VFY: 'this' arg must be initialized\n");
1152 goto fail;
1153 }
1154 if (methodType != METHOD_INTERFACE && actualArgType != kRegTypeZero) {
1155 actualThisRef = regTypeReferenceToClass(actualArgType, uninitMap);
1156 if (!dvmInstanceof(actualThisRef, resMethod->clazz)) {
1157 LOG_VFY("VFY: 'this' arg '%s' not instance of '%s'\n",
1158 actualThisRef->descriptor,
1159 resMethod->clazz->descriptor);
1160 goto fail;
1161 }
1162 }
1163 actualArgs++;
1164 }
1165
1166 /*
1167 * Process the target method's signature. This signature may or may not
1168 * have been verified, so we can't assume it's properly formed.
1169 */
1170 while (*sig != '\0' && *sig != ')') {
1171 if (actualArgs >= expectedArgs) {
1172 LOG_VFY("VFY: expected %d args, found more (%c)\n",
1173 expectedArgs, *sig);
1174 goto bad_sig;
1175 }
1176
1177 u4 getReg;
1178 if (isRange)
1179 getReg = pDecInsn->vC + actualArgs;
1180 else
1181 getReg = pDecInsn->arg[actualArgs];
1182
1183 switch (*sig) {
1184 case 'L':
1185 {
1186 ClassObject* clazz = lookupSignatureClass(meth, &sig, pFailure);
1187 if (!VERIFY_OK(*pFailure))
1188 goto bad_sig;
1189 verifyRegisterType(insnRegs, insnRegCount, getReg,
1190 regTypeFromClass(clazz), pFailure);
1191 if (!VERIFY_OK(*pFailure)) {
1192 LOG_VFY("VFY: bad arg %d (into %s)\n",
1193 actualArgs, clazz->descriptor);
1194 goto bad_sig;
1195 }
1196 }
1197 actualArgs++;
1198 break;
1199 case '[':
1200 {
1201 ClassObject* clazz =
1202 lookupSignatureArrayClass(meth, &sig, pFailure);
1203 if (!VERIFY_OK(*pFailure))
1204 goto bad_sig;
1205 verifyRegisterType(insnRegs, insnRegCount, getReg,
1206 regTypeFromClass(clazz), pFailure);
1207 if (!VERIFY_OK(*pFailure)) {
1208 LOG_VFY("VFY: bad arg %d (into %s)\n",
1209 actualArgs, clazz->descriptor);
1210 goto bad_sig;
1211 }
1212 }
1213 actualArgs++;
1214 break;
1215 case 'Z':
1216 verifyRegisterType(insnRegs, insnRegCount, getReg,
1217 kRegTypeBoolean, pFailure);
1218 actualArgs++;
1219 break;
1220 case 'C':
1221 verifyRegisterType(insnRegs, insnRegCount, getReg,
1222 kRegTypeChar, pFailure);
1223 actualArgs++;
1224 break;
1225 case 'B':
1226 verifyRegisterType(insnRegs, insnRegCount, getReg,
1227 kRegTypeByte, pFailure);
1228 actualArgs++;
1229 break;
1230 case 'I':
1231 verifyRegisterType(insnRegs, insnRegCount, getReg,
1232 kRegTypeInteger, pFailure);
1233 actualArgs++;
1234 break;
1235 case 'S':
1236 verifyRegisterType(insnRegs, insnRegCount, getReg,
1237 kRegTypeShort, pFailure);
1238 actualArgs++;
1239 break;
1240 case 'F':
1241 verifyRegisterType(insnRegs, insnRegCount, getReg,
1242 kRegTypeFloat, pFailure);
1243 actualArgs++;
1244 break;
1245 case 'D':
1246 verifyRegisterType(insnRegs, insnRegCount, getReg,
1247 kRegTypeDoubleLo, pFailure);
1248 actualArgs += 2;
1249 break;
1250 case 'J':
1251 verifyRegisterType(insnRegs, insnRegCount, getReg,
1252 kRegTypeLongLo, pFailure);
1253 actualArgs += 2;
1254 break;
1255 default:
1256 LOG_VFY("VFY: invocation target: bad signature type char '%c'\n",
1257 *sig);
1258 goto bad_sig;
1259 }
1260
1261 sig++;
1262 }
1263 if (*sig != ')') {
1264 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1265 LOG_VFY("VFY: invocation target: bad signature '%s'\n", desc);
1266 free(desc);
1267 goto bad_sig;
1268 }
1269
1270 if (actualArgs != expectedArgs) {
1271 LOG_VFY("VFY: expected %d args, found %d\n", expectedArgs, actualArgs);
1272 goto bad_sig;
1273 }
1274
1275 free(sigOriginal);
1276 return resMethod;
1277
1278 bad_sig:
1279 if (resMethod != NULL) {
1280 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1281 LOG_VFY("VFY: rejecting call to %s.%s %s\n",
1282 resMethod->clazz->descriptor, resMethod->name, desc);
1283 free(desc);
1284 }
1285
1286 fail:
1287 free(sigOriginal);
1288 if (*pFailure == VERIFY_ERROR_NONE)
1289 *pFailure = VERIFY_ERROR_GENERIC;
1290 return NULL;
1291 }
1292
1293 /*
1294 * Get the class object for the type of data stored in a field. This isn't
1295 * stored in the Field struct, so we have to recover it from the signature.
1296 *
1297 * This only works for reference types. Don't call this for primitive types.
1298 *
1299 * If we can't find the class, we return java.lang.Object, so that
1300 * verification can continue if a field is only accessed in trivial ways.
1301 */
getFieldClass(const Method * meth,const Field * field)1302 static ClassObject* getFieldClass(const Method* meth, const Field* field)
1303 {
1304 ClassObject* fieldClass;
1305 const char* signature = field->signature;
1306
1307 if ((*signature == 'L') || (*signature == '[')) {
1308 fieldClass = dvmFindClassNoInit(signature,
1309 meth->clazz->classLoader);
1310 } else {
1311 return NULL;
1312 }
1313
1314 if (fieldClass == NULL) {
1315 dvmClearOptException(dvmThreadSelf());
1316 LOGV("VFY: unable to find class '%s' for field %s.%s, trying Object\n",
1317 field->signature, meth->clazz->descriptor, field->name);
1318 fieldClass = gDvm.classJavaLangObject;
1319 } else {
1320 assert(!dvmIsPrimitiveClass(fieldClass));
1321 }
1322 return fieldClass;
1323 }
1324
1325
1326 /*
1327 * ===========================================================================
1328 * Register operations
1329 * ===========================================================================
1330 */
1331
1332 /*
1333 * Get the type of register N, verifying that the register is valid.
1334 *
1335 * Sets "*pFailure" appropriately if the register number is out of range.
1336 */
getRegisterType(const RegType * insnRegs,const int insnRegCount,u4 vsrc,VerifyError * pFailure)1337 static inline RegType getRegisterType(const RegType* insnRegs,
1338 const int insnRegCount, u4 vsrc, VerifyError* pFailure)
1339 {
1340 RegType type;
1341
1342 if (vsrc >= (u4) insnRegCount) {
1343 *pFailure = VERIFY_ERROR_GENERIC;
1344 return kRegTypeUnknown;
1345 } else {
1346 return insnRegs[vsrc];
1347 }
1348 }
1349
1350 /*
1351 * Get the value from a register, and cast it to a ClassObject. Sets
1352 * "*pFailure" if something fails.
1353 *
1354 * This fails if the register holds an uninitialized class.
1355 *
1356 * If the register holds kRegTypeZero, this returns a NULL pointer.
1357 */
getClassFromRegister(const RegType * insnRegs,const int insnRegCount,u4 vsrc,VerifyError * pFailure)1358 static ClassObject* getClassFromRegister(const RegType* insnRegs,
1359 const int insnRegCount, u4 vsrc, VerifyError* pFailure)
1360 {
1361 ClassObject* clazz = NULL;
1362 RegType type;
1363
1364 /* get the element type of the array held in vsrc */
1365 type = getRegisterType(insnRegs, insnRegCount, vsrc, pFailure);
1366 if (!VERIFY_OK(*pFailure))
1367 goto bail;
1368
1369 /* if "always zero", we allow it to fail at runtime */
1370 if (type == kRegTypeZero)
1371 goto bail;
1372
1373 if (!regTypeIsReference(type)) {
1374 LOG_VFY("VFY: tried to get class from non-ref register v%d (type=%d)\n",
1375 vsrc, type);
1376 *pFailure = VERIFY_ERROR_GENERIC;
1377 goto bail;
1378 }
1379 if (regTypeIsUninitReference(type)) {
1380 LOG_VFY("VFY: register %u holds uninitialized reference\n", vsrc);
1381 *pFailure = VERIFY_ERROR_GENERIC;
1382 goto bail;
1383 }
1384
1385 clazz = regTypeInitializedReferenceToClass(type);
1386
1387 bail:
1388 return clazz;
1389 }
1390
1391 /*
1392 * Get the "this" pointer from a non-static method invocation. This
1393 * returns the RegType so the caller can decide whether it needs the
1394 * reference to be initialized or not. (Can also return kRegTypeZero
1395 * if the reference can only be zero at this point.)
1396 *
1397 * The argument count is in vA, and the first argument is in vC, for both
1398 * "simple" and "range" versions. We just need to make sure vA is >= 1
1399 * and then return vC.
1400 */
getInvocationThis(const RegType * insnRegs,const int insnRegCount,const DecodedInstruction * pDecInsn,VerifyError * pFailure)1401 static RegType getInvocationThis(const RegType* insnRegs,
1402 const int insnRegCount, const DecodedInstruction* pDecInsn,
1403 VerifyError* pFailure)
1404 {
1405 RegType thisType = kRegTypeUnknown;
1406
1407 if (pDecInsn->vA < 1) {
1408 LOG_VFY("VFY: invoke lacks 'this'\n");
1409 *pFailure = VERIFY_ERROR_GENERIC;
1410 goto bail;
1411 }
1412
1413 /* get the element type of the array held in vsrc */
1414 thisType = getRegisterType(insnRegs, insnRegCount, pDecInsn->vC, pFailure);
1415 if (!VERIFY_OK(*pFailure)) {
1416 LOG_VFY("VFY: failed to get 'this' from register %u\n", pDecInsn->vC);
1417 goto bail;
1418 }
1419
1420 if (!regTypeIsReference(thisType)) {
1421 LOG_VFY("VFY: tried to get class from non-ref register v%d (type=%d)\n",
1422 pDecInsn->vC, thisType);
1423 *pFailure = VERIFY_ERROR_GENERIC;
1424 goto bail;
1425 }
1426
1427 bail:
1428 return thisType;
1429 }
1430
1431 /*
1432 * Set the type of register N, verifying that the register is valid. If
1433 * "newType" is the "Lo" part of a 64-bit value, register N+1 will be
1434 * set to "newType+1".
1435 *
1436 * Sets "*pFailure" if the register number is out of range.
1437 */
setRegisterType(RegType * insnRegs,const int insnRegCount,u4 vdst,RegType newType,VerifyError * pFailure)1438 static void setRegisterType(RegType* insnRegs, const int insnRegCount,
1439 u4 vdst, RegType newType, VerifyError* pFailure)
1440 {
1441 //LOGD("set-reg v%u = %d\n", vdst, newType);
1442 switch (newType) {
1443 case kRegTypeUnknown:
1444 case kRegTypeBoolean:
1445 case kRegTypeOne:
1446 case kRegTypeByte:
1447 case kRegTypePosByte:
1448 case kRegTypeShort:
1449 case kRegTypePosShort:
1450 case kRegTypeChar:
1451 case kRegTypeInteger:
1452 case kRegTypeFloat:
1453 case kRegTypeZero:
1454 if (vdst >= (u4) insnRegCount) {
1455 *pFailure = VERIFY_ERROR_GENERIC;
1456 } else {
1457 insnRegs[vdst] = newType;
1458 }
1459 break;
1460 case kRegTypeLongLo:
1461 case kRegTypeDoubleLo:
1462 if (vdst+1 >= (u4) insnRegCount) {
1463 *pFailure = VERIFY_ERROR_GENERIC;
1464 } else {
1465 insnRegs[vdst] = newType;
1466 insnRegs[vdst+1] = newType+1;
1467 }
1468 break;
1469 case kRegTypeLongHi:
1470 case kRegTypeDoubleHi:
1471 /* should never set these explicitly */
1472 *pFailure = VERIFY_ERROR_GENERIC;
1473 break;
1474
1475 case kRegTypeUninit:
1476 default:
1477 if (regTypeIsReference(newType)) {
1478 if (vdst >= (u4) insnRegCount) {
1479 *pFailure = VERIFY_ERROR_GENERIC;
1480 break;
1481 }
1482 insnRegs[vdst] = newType;
1483
1484 /*
1485 * In most circumstances we won't see a reference to a primitive
1486 * class here (e.g. "D"), since that would mean the object in the
1487 * register is actually a primitive type. It can happen as the
1488 * result of an assumed-successful check-cast instruction in
1489 * which the second argument refers to a primitive class. (In
1490 * practice, such an instruction will always throw an exception.)
1491 *
1492 * This is not an issue for instructions like const-class, where
1493 * the object in the register is a java.lang.Class instance.
1494 */
1495 break;
1496 }
1497 /* bad - fall through */
1498
1499 case kRegTypeConflict: // should only be set during a merge
1500 LOG_VFY("Unexpected set type %d\n", newType);
1501 assert(false);
1502 *pFailure = VERIFY_ERROR_GENERIC;
1503 break;
1504 }
1505 }
1506
1507 /*
1508 * Verify that the contents of the specified register have the specified
1509 * type (or can be converted to it through an implicit widening conversion).
1510 *
1511 * In theory we could use this to modify the type of the source register,
1512 * e.g. a generic 32-bit constant, once used as a float, would thereafter
1513 * remain a float. There is no compelling reason to require this though.
1514 *
1515 * If "vsrc" is a reference, both it and the "vsrc" register must be
1516 * initialized ("vsrc" may be Zero). This will verify that the value in
1517 * the register is an instance of checkType, or if checkType is an
1518 * interface, verify that the register implements checkType.
1519 */
verifyRegisterType(const RegType * insnRegs,const int insnRegCount,u4 vsrc,RegType checkType,VerifyError * pFailure)1520 static void verifyRegisterType(const RegType* insnRegs, const int insnRegCount,
1521 u4 vsrc, RegType checkType, VerifyError* pFailure)
1522 {
1523 if (vsrc >= (u4) insnRegCount) {
1524 *pFailure = VERIFY_ERROR_GENERIC;
1525 return;
1526 }
1527
1528 RegType srcType = insnRegs[vsrc];
1529
1530 //LOGD("check-reg v%u = %d\n", vsrc, checkType);
1531 switch (checkType) {
1532 case kRegTypeFloat:
1533 case kRegTypeBoolean:
1534 case kRegTypePosByte:
1535 case kRegTypeByte:
1536 case kRegTypePosShort:
1537 case kRegTypeShort:
1538 case kRegTypeChar:
1539 case kRegTypeInteger:
1540 if (!canConvertTo1nr(srcType, checkType)) {
1541 LOG_VFY("VFY: register1 v%u type %d, wanted %d\n",
1542 vsrc, srcType, checkType);
1543 *pFailure = VERIFY_ERROR_GENERIC;
1544 }
1545 break;
1546 case kRegTypeLongLo:
1547 case kRegTypeDoubleLo:
1548 if (vsrc+1 >= (u4) insnRegCount) {
1549 LOG_VFY("VFY: register2 v%u out of range (%d)\n",
1550 vsrc, insnRegCount);
1551 *pFailure = VERIFY_ERROR_GENERIC;
1552 } else if (insnRegs[vsrc+1] != srcType+1) {
1553 LOG_VFY("VFY: register2 v%u-%u values %d,%d\n",
1554 vsrc, vsrc+1, insnRegs[vsrc], insnRegs[vsrc+1]);
1555 *pFailure = VERIFY_ERROR_GENERIC;
1556 } else if (!canConvertTo2(srcType, checkType)) {
1557 LOG_VFY("VFY: register2 v%u type %d, wanted %d\n",
1558 vsrc, srcType, checkType);
1559 *pFailure = VERIFY_ERROR_GENERIC;
1560 }
1561 break;
1562
1563 case kRegTypeLongHi:
1564 case kRegTypeDoubleHi:
1565 case kRegTypeZero:
1566 case kRegTypeOne:
1567 case kRegTypeUnknown:
1568 case kRegTypeConflict:
1569 /* should never be checking for these explicitly */
1570 assert(false);
1571 *pFailure = VERIFY_ERROR_GENERIC;
1572 return;
1573 case kRegTypeUninit:
1574 default:
1575 /* make sure checkType is initialized reference */
1576 if (!regTypeIsReference(checkType)) {
1577 LOG_VFY("VFY: unexpected check type %d\n", checkType);
1578 assert(false);
1579 *pFailure = VERIFY_ERROR_GENERIC;
1580 break;
1581 }
1582 if (regTypeIsUninitReference(checkType)) {
1583 LOG_VFY("VFY: uninitialized ref not expected as reg check\n");
1584 *pFailure = VERIFY_ERROR_GENERIC;
1585 break;
1586 }
1587 /* make sure srcType is initialized reference or always-NULL */
1588 if (!regTypeIsReference(srcType)) {
1589 LOG_VFY("VFY: register1 v%u type %d, wanted ref\n", vsrc, srcType);
1590 *pFailure = VERIFY_ERROR_GENERIC;
1591 break;
1592 }
1593 if (regTypeIsUninitReference(srcType)) {
1594 LOG_VFY("VFY: register1 v%u holds uninitialized ref\n", vsrc);
1595 *pFailure = VERIFY_ERROR_GENERIC;
1596 break;
1597 }
1598 /* if the register isn't Zero, make sure it's an instance of check */
1599 if (srcType != kRegTypeZero) {
1600 ClassObject* srcClass = regTypeInitializedReferenceToClass(srcType);
1601 ClassObject* checkClass = regTypeInitializedReferenceToClass(checkType);
1602 assert(srcClass != NULL);
1603 assert(checkClass != NULL);
1604
1605 if (dvmIsInterfaceClass(checkClass)) {
1606 /*
1607 * All objects implement all interfaces as far as the
1608 * verifier is concerned. The runtime has to sort it out.
1609 * See comments above findCommonSuperclass.
1610 */
1611 /*
1612 if (srcClass != checkClass &&
1613 !dvmImplements(srcClass, checkClass))
1614 {
1615 LOG_VFY("VFY: %s does not implement %s\n",
1616 srcClass->descriptor, checkClass->descriptor);
1617 *pFailure = VERIFY_ERROR_GENERIC;
1618 }
1619 */
1620 } else {
1621 if (!dvmInstanceof(srcClass, checkClass)) {
1622 LOG_VFY("VFY: %s is not instance of %s\n",
1623 srcClass->descriptor, checkClass->descriptor);
1624 *pFailure = VERIFY_ERROR_GENERIC;
1625 }
1626 }
1627 }
1628 break;
1629 }
1630 }
1631
1632 /*
1633 * Set the type of the "result" register. Mostly this exists to expand
1634 * "insnRegCount" to encompass the result register.
1635 */
setResultRegisterType(RegType * insnRegs,const int insnRegCount,RegType newType,VerifyError * pFailure)1636 static void setResultRegisterType(RegType* insnRegs, const int insnRegCount,
1637 RegType newType, VerifyError* pFailure)
1638 {
1639 setRegisterType(insnRegs, insnRegCount + kExtraRegs,
1640 RESULT_REGISTER(insnRegCount), newType, pFailure);
1641 }
1642
1643
1644 /*
1645 * Update all registers holding "uninitType" to instead hold the
1646 * corresponding initialized reference type. This is called when an
1647 * appropriate <init> method is invoked -- all copies of the reference
1648 * must be marked as initialized.
1649 */
markRefsAsInitialized(RegType * insnRegs,int insnRegCount,UninitInstanceMap * uninitMap,RegType uninitType,VerifyError * pFailure)1650 static void markRefsAsInitialized(RegType* insnRegs, int insnRegCount,
1651 UninitInstanceMap* uninitMap, RegType uninitType, VerifyError* pFailure)
1652 {
1653 ClassObject* clazz;
1654 RegType initType;
1655 int i, changed;
1656
1657 clazz = dvmGetUninitInstance(uninitMap, regTypeToUninitIndex(uninitType));
1658 if (clazz == NULL) {
1659 LOGE("VFY: unable to find type=0x%x (idx=%d)\n",
1660 uninitType, regTypeToUninitIndex(uninitType));
1661 *pFailure = VERIFY_ERROR_GENERIC;
1662 return;
1663 }
1664 initType = regTypeFromClass(clazz);
1665
1666 changed = 0;
1667 for (i = 0; i < insnRegCount; i++) {
1668 if (insnRegs[i] == uninitType) {
1669 insnRegs[i] = initType;
1670 changed++;
1671 }
1672 }
1673 //LOGD("VFY: marked %d registers as initialized\n", changed);
1674 assert(changed > 0);
1675
1676 return;
1677 }
1678
1679 /*
1680 * We're creating a new instance of class C at address A. Any registers
1681 * holding instances previously created at address A must be initialized
1682 * by now. If not, we mark them as "conflict" to prevent them from being
1683 * used (otherwise, markRefsAsInitialized would mark the old ones and the
1684 * new ones at the same time).
1685 */
markUninitRefsAsInvalid(RegType * insnRegs,int insnRegCount,UninitInstanceMap * uninitMap,RegType uninitType)1686 static void markUninitRefsAsInvalid(RegType* insnRegs, int insnRegCount,
1687 UninitInstanceMap* uninitMap, RegType uninitType)
1688 {
1689 int i, changed;
1690
1691 changed = 0;
1692 for (i = 0; i < insnRegCount; i++) {
1693 if (insnRegs[i] == uninitType) {
1694 insnRegs[i] = kRegTypeConflict;
1695 changed++;
1696 }
1697 }
1698
1699 //if (changed)
1700 // LOGD("VFY: marked %d uninitialized registers as invalid\n", changed);
1701 }
1702
1703 /*
1704 * Find the start of the register set for the specified instruction in
1705 * the current method.
1706 */
getRegisterLine(const RegisterTable * regTable,int insnIdx)1707 static inline RegType* getRegisterLine(const RegisterTable* regTable,
1708 int insnIdx)
1709 {
1710 return regTable->addrRegs[insnIdx];
1711 }
1712
1713 /*
1714 * Copy a bunch of registers.
1715 */
copyRegisters(RegType * dst,const RegType * src,int numRegs)1716 static inline void copyRegisters(RegType* dst, const RegType* src,
1717 int numRegs)
1718 {
1719 memcpy(dst, src, numRegs * sizeof(RegType));
1720 }
1721
1722 /*
1723 * Compare a bunch of registers.
1724 *
1725 * Returns 0 if they match. Using this for a sort is unwise, since the
1726 * value can change based on machine endianness.
1727 */
compareRegisters(const RegType * src1,const RegType * src2,int numRegs)1728 static inline int compareRegisters(const RegType* src1, const RegType* src2,
1729 int numRegs)
1730 {
1731 return memcmp(src1, src2, numRegs * sizeof(RegType));
1732 }
1733
1734 /*
1735 * Register type categories, for type checking.
1736 *
1737 * The spec says category 1 includes boolean, byte, char, short, int, float,
1738 * reference, and returnAddress. Category 2 includes long and double.
1739 *
1740 * We treat object references separately, so we have "category1nr". We
1741 * don't support jsr/ret, so there is no "returnAddress" type.
1742 */
1743 typedef enum TypeCategory {
1744 kTypeCategoryUnknown = 0,
1745 kTypeCategory1nr, // byte, char, int, float, boolean
1746 kTypeCategory2, // long, double
1747 kTypeCategoryRef, // object reference
1748 } TypeCategory;
1749
1750 /*
1751 * See if "type" matches "cat". All we're really looking for here is that
1752 * we're not mixing and matching 32-bit and 64-bit quantities, and we're
1753 * not mixing references with numerics. (For example, the arguments to
1754 * "a < b" could be integers of different sizes, but they must both be
1755 * integers. Dalvik is less specific about int vs. float, so we treat them
1756 * as equivalent here.)
1757 *
1758 * For category 2 values, "type" must be the "low" half of the value.
1759 *
1760 * Sets "*pFailure" if something looks wrong.
1761 */
checkTypeCategory(RegType type,TypeCategory cat,VerifyError * pFailure)1762 static void checkTypeCategory(RegType type, TypeCategory cat,
1763 VerifyError* pFailure)
1764 {
1765 switch (cat) {
1766 case kTypeCategory1nr:
1767 switch (type) {
1768 case kRegTypeFloat:
1769 case kRegTypeZero:
1770 case kRegTypeOne:
1771 case kRegTypeBoolean:
1772 case kRegTypePosByte:
1773 case kRegTypeByte:
1774 case kRegTypePosShort:
1775 case kRegTypeShort:
1776 case kRegTypeChar:
1777 case kRegTypeInteger:
1778 break;
1779 default:
1780 *pFailure = VERIFY_ERROR_GENERIC;
1781 break;
1782 }
1783 break;
1784
1785 case kTypeCategory2:
1786 switch (type) {
1787 case kRegTypeLongLo:
1788 case kRegTypeDoubleLo:
1789 break;
1790 default:
1791 *pFailure = VERIFY_ERROR_GENERIC;
1792 break;
1793 }
1794 break;
1795
1796 case kTypeCategoryRef:
1797 if (type != kRegTypeZero && !regTypeIsReference(type))
1798 *pFailure = VERIFY_ERROR_GENERIC;
1799 break;
1800
1801 default:
1802 assert(false);
1803 *pFailure = VERIFY_ERROR_GENERIC;
1804 break;
1805 }
1806 }
1807
1808 /*
1809 * For a category 2 register pair, verify that "typeh" is the appropriate
1810 * high part for "typel".
1811 *
1812 * Does not verify that "typel" is in fact the low part of a 64-bit
1813 * register pair.
1814 */
checkWidePair(RegType typel,RegType typeh,VerifyError * pFailure)1815 static void checkWidePair(RegType typel, RegType typeh, VerifyError* pFailure)
1816 {
1817 if ((typeh != typel+1))
1818 *pFailure = VERIFY_ERROR_GENERIC;
1819 }
1820
1821 /*
1822 * Implement category-1 "move" instructions. Copy a 32-bit value from
1823 * "vsrc" to "vdst".
1824 *
1825 * "insnRegCount" is the number of registers available. The "vdst" and
1826 * "vsrc" values are checked against this.
1827 */
copyRegister1(RegType * insnRegs,int insnRegCount,u4 vdst,u4 vsrc,TypeCategory cat,VerifyError * pFailure)1828 static void copyRegister1(RegType* insnRegs, int insnRegCount, u4 vdst,
1829 u4 vsrc, TypeCategory cat, VerifyError* pFailure)
1830 {
1831 RegType type = getRegisterType(insnRegs, insnRegCount, vsrc, pFailure);
1832 if (VERIFY_OK(*pFailure))
1833 checkTypeCategory(type, cat, pFailure);
1834 if (VERIFY_OK(*pFailure))
1835 setRegisterType(insnRegs, insnRegCount, vdst, type, pFailure);
1836
1837 if (!VERIFY_OK(*pFailure)) {
1838 LOG_VFY("VFY: copy1 v%u<-v%u type=%d cat=%d\n", vdst, vsrc, type, cat);
1839 }
1840 }
1841
1842 /*
1843 * Implement category-2 "move" instructions. Copy a 64-bit value from
1844 * "vsrc" to "vdst". This copies both halves of the register.
1845 */
copyRegister2(RegType * insnRegs,int insnRegCount,u4 vdst,u4 vsrc,VerifyError * pFailure)1846 static void copyRegister2(RegType* insnRegs, int insnRegCount, u4 vdst,
1847 u4 vsrc, VerifyError* pFailure)
1848 {
1849 RegType typel = getRegisterType(insnRegs, insnRegCount, vsrc, pFailure);
1850 RegType typeh = getRegisterType(insnRegs, insnRegCount, vsrc+1, pFailure);
1851 if (VERIFY_OK(*pFailure)) {
1852 checkTypeCategory(typel, kTypeCategory2, pFailure);
1853 checkWidePair(typel, typeh, pFailure);
1854 }
1855 if (VERIFY_OK(*pFailure))
1856 setRegisterType(insnRegs, insnRegCount, vdst, typel, pFailure);
1857
1858 if (!VERIFY_OK(*pFailure)) {
1859 LOG_VFY("VFY: copy2 v%u<-v%u type=%d/%d\n", vdst, vsrc, typel, typeh);
1860 }
1861 }
1862
1863 /*
1864 * Implement "move-result". Copy the category-1 value from the result
1865 * register to another register, and reset the result register.
1866 *
1867 * We can't just call copyRegister1 with an altered insnRegCount,
1868 * because that would affect the test on "vdst" as well.
1869 */
copyResultRegister1(RegType * insnRegs,const int insnRegCount,u4 vdst,TypeCategory cat,VerifyError * pFailure)1870 static void copyResultRegister1(RegType* insnRegs, const int insnRegCount,
1871 u4 vdst, TypeCategory cat, VerifyError* pFailure)
1872 {
1873 RegType type;
1874 u4 vsrc;
1875
1876 vsrc = RESULT_REGISTER(insnRegCount);
1877 type = getRegisterType(insnRegs, insnRegCount + kExtraRegs, vsrc, pFailure);
1878 if (VERIFY_OK(*pFailure))
1879 checkTypeCategory(type, cat, pFailure);
1880 if (VERIFY_OK(*pFailure)) {
1881 setRegisterType(insnRegs, insnRegCount, vdst, type, pFailure);
1882 insnRegs[vsrc] = kRegTypeUnknown;
1883 }
1884
1885 if (!VERIFY_OK(*pFailure)) {
1886 LOG_VFY("VFY: copyRes1 v%u<-v%u cat=%d type=%d\n",
1887 vdst, vsrc, cat, type);
1888 }
1889 }
1890
1891 /*
1892 * Implement "move-result-wide". Copy the category-2 value from the result
1893 * register to another register, and reset the result register.
1894 *
1895 * We can't just call copyRegister2 with an altered insnRegCount,
1896 * because that would affect the test on "vdst" as well.
1897 */
copyResultRegister2(RegType * insnRegs,const int insnRegCount,u4 vdst,VerifyError * pFailure)1898 static void copyResultRegister2(RegType* insnRegs, const int insnRegCount,
1899 u4 vdst, VerifyError* pFailure)
1900 {
1901 RegType typel, typeh;
1902 u4 vsrc;
1903
1904 vsrc = RESULT_REGISTER(insnRegCount);
1905 typel = getRegisterType(insnRegs, insnRegCount + kExtraRegs, vsrc,
1906 pFailure);
1907 typeh = getRegisterType(insnRegs, insnRegCount + kExtraRegs, vsrc+1,
1908 pFailure);
1909 if (VERIFY_OK(*pFailure)) {
1910 checkTypeCategory(typel, kTypeCategory2, pFailure);
1911 checkWidePair(typel, typeh, pFailure);
1912 }
1913 if (VERIFY_OK(*pFailure)) {
1914 setRegisterType(insnRegs, insnRegCount, vdst, typel, pFailure);
1915 insnRegs[vsrc] = kRegTypeUnknown;
1916 insnRegs[vsrc+1] = kRegTypeUnknown;
1917 }
1918
1919 if (!VERIFY_OK(*pFailure)) {
1920 LOG_VFY("VFY: copyRes2 v%u<-v%u type=%d/%d\n",
1921 vdst, vsrc, typel, typeh);
1922 }
1923 }
1924
1925 /*
1926 * Verify types for a simple two-register instruction (e.g. "neg-int").
1927 * "dstType" is stored into vA, and "srcType" is verified against vB.
1928 */
checkUnop(RegType * insnRegs,const int insnRegCount,DecodedInstruction * pDecInsn,RegType dstType,RegType srcType,VerifyError * pFailure)1929 static void checkUnop(RegType* insnRegs, const int insnRegCount,
1930 DecodedInstruction* pDecInsn, RegType dstType, RegType srcType,
1931 VerifyError* pFailure)
1932 {
1933 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType, pFailure);
1934 setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pFailure);
1935 }
1936
1937 /*
1938 * We're performing an operation like "and-int/2addr" that can be
1939 * performed on booleans as well as integers. We get no indication of
1940 * boolean-ness, but we can infer it from the types of the arguments.
1941 *
1942 * Assumes we've already validated reg1/reg2.
1943 *
1944 * TODO: consider generalizing this. The key principle is that the
1945 * result of a bitwise operation can only be as wide as the widest of
1946 * the operands. You can safely AND/OR/XOR two chars together and know
1947 * you still have a char, so it's reasonable for the compiler or "dx"
1948 * to skip the int-to-char instruction. (We need to do this for boolean
1949 * because there is no int-to-boolean operation.)
1950 *
1951 * Returns true if both args are Boolean, Zero, or One.
1952 */
upcastBooleanOp(RegType * insnRegs,const int insnRegCount,u4 reg1,u4 reg2)1953 static bool upcastBooleanOp(RegType* insnRegs, const int insnRegCount,
1954 u4 reg1, u4 reg2)
1955 {
1956 RegType type1, type2;
1957
1958 type1 = insnRegs[reg1];
1959 type2 = insnRegs[reg2];
1960
1961 if ((type1 == kRegTypeBoolean || type1 == kRegTypeZero ||
1962 type1 == kRegTypeOne) &&
1963 (type2 == kRegTypeBoolean || type2 == kRegTypeZero ||
1964 type2 == kRegTypeOne))
1965 {
1966 return true;
1967 }
1968 return false;
1969 }
1970
1971 /*
1972 * Verify types for A two-register instruction with a literal constant
1973 * (e.g. "add-int/lit8"). "dstType" is stored into vA, and "srcType" is
1974 * verified against vB.
1975 *
1976 * If "checkBooleanOp" is set, we use the constant value in vC.
1977 */
checkLitop(RegType * insnRegs,const int insnRegCount,DecodedInstruction * pDecInsn,RegType dstType,RegType srcType,bool checkBooleanOp,VerifyError * pFailure)1978 static void checkLitop(RegType* insnRegs, const int insnRegCount,
1979 DecodedInstruction* pDecInsn, RegType dstType, RegType srcType,
1980 bool checkBooleanOp, VerifyError* pFailure)
1981 {
1982 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType, pFailure);
1983 if (VERIFY_OK(*pFailure) && checkBooleanOp) {
1984 assert(dstType == kRegTypeInteger);
1985 /* check vB with the call, then check the constant manually */
1986 if (upcastBooleanOp(insnRegs, insnRegCount, pDecInsn->vB, pDecInsn->vB)
1987 && (pDecInsn->vC == 0 || pDecInsn->vC == 1))
1988 {
1989 dstType = kRegTypeBoolean;
1990 }
1991 }
1992 setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pFailure);
1993 }
1994
1995 /*
1996 * Verify types for a simple three-register instruction (e.g. "add-int").
1997 * "dstType" is stored into vA, and "srcType1"/"srcType2" are verified
1998 * against vB/vC.
1999 */
checkBinop(RegType * insnRegs,const int insnRegCount,DecodedInstruction * pDecInsn,RegType dstType,RegType srcType1,RegType srcType2,bool checkBooleanOp,VerifyError * pFailure)2000 static void checkBinop(RegType* insnRegs, const int insnRegCount,
2001 DecodedInstruction* pDecInsn, RegType dstType, RegType srcType1,
2002 RegType srcType2, bool checkBooleanOp, VerifyError* pFailure)
2003 {
2004 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType1,
2005 pFailure);
2006 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vC, srcType2,
2007 pFailure);
2008 if (VERIFY_OK(*pFailure) && checkBooleanOp) {
2009 assert(dstType == kRegTypeInteger);
2010 if (upcastBooleanOp(insnRegs, insnRegCount, pDecInsn->vB, pDecInsn->vC))
2011 dstType = kRegTypeBoolean;
2012 }
2013 setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pFailure);
2014 }
2015
2016 /*
2017 * Verify types for a binary "2addr" operation. "srcType1"/"srcType2"
2018 * are verified against vA/vB, then "dstType" is stored into vA.
2019 */
checkBinop2addr(RegType * insnRegs,const int insnRegCount,DecodedInstruction * pDecInsn,RegType dstType,RegType srcType1,RegType srcType2,bool checkBooleanOp,VerifyError * pFailure)2020 static void checkBinop2addr(RegType* insnRegs, const int insnRegCount,
2021 DecodedInstruction* pDecInsn, RegType dstType, RegType srcType1,
2022 RegType srcType2, bool checkBooleanOp, VerifyError* pFailure)
2023 {
2024 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vA, srcType1,
2025 pFailure);
2026 verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType2,
2027 pFailure);
2028 if (VERIFY_OK(*pFailure) && checkBooleanOp) {
2029 assert(dstType == kRegTypeInteger);
2030 if (upcastBooleanOp(insnRegs, insnRegCount, pDecInsn->vA, pDecInsn->vB))
2031 dstType = kRegTypeBoolean;
2032 }
2033 setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pFailure);
2034 }
2035
2036 /*
2037 * Treat right-shifting as a narrowing conversion when possible.
2038 *
2039 * For example, right-shifting an int 24 times results in a value that can
2040 * be treated as a byte.
2041 *
2042 * Things get interesting when contemplating sign extension. Right-
2043 * shifting an integer by 16 yields a value that can be represented in a
2044 * "short" but not a "char", but an unsigned right shift by 16 yields a
2045 * value that belongs in a char rather than a short. (Consider what would
2046 * happen if the result of the shift were cast to a char or short and then
2047 * cast back to an int. If sign extension, or the lack thereof, causes
2048 * a change in the 32-bit representation, then the conversion was lossy.)
2049 *
2050 * A signed right shift by 17 on an integer results in a short. An unsigned
2051 * right shfit by 17 on an integer results in a posshort, which can be
2052 * assigned to a short or a char.
2053 *
2054 * An unsigned right shift on a short can actually expand the result into
2055 * a 32-bit integer. For example, 0xfffff123 >>> 8 becomes 0x00fffff1,
2056 * which can't be represented in anything smaller than an int.
2057 *
2058 * javac does not generate code that takes advantage of this, but some
2059 * of the code optimizers do. It's generally a peephole optimization
2060 * that replaces a particular sequence, e.g. (bipush 24, ishr, i2b) is
2061 * replaced by (bipush 24, ishr). Knowing that shifting a short 8 times
2062 * to the right yields a byte is really more than we need to handle the
2063 * code that's out there, but support is not much more complex than just
2064 * handling integer.
2065 *
2066 * Right-shifting never yields a boolean value.
2067 *
2068 * Returns the new register type.
2069 */
adjustForRightShift(RegType * workRegs,const int insnRegCount,int reg,unsigned int shiftCount,bool isUnsignedShift,VerifyError * pFailure)2070 static RegType adjustForRightShift(RegType* workRegs, const int insnRegCount,
2071 int reg, unsigned int shiftCount, bool isUnsignedShift,
2072 VerifyError* pFailure)
2073 {
2074 RegType srcType = getRegisterType(workRegs, insnRegCount, reg, pFailure);
2075 RegType newType;
2076
2077 /* no-op */
2078 if (shiftCount == 0)
2079 return srcType;
2080
2081 /* safe defaults */
2082 if (isUnsignedShift)
2083 newType = kRegTypeInteger;
2084 else
2085 newType = srcType;
2086
2087 if (shiftCount >= 32) {
2088 LOG_VFY("Got unexpectedly large shift count %u\n", shiftCount);
2089 /* fail? */
2090 return newType;
2091 }
2092
2093 switch (srcType) {
2094 case kRegTypeInteger: /* 32-bit signed value */
2095 case kRegTypeFloat: /* (allowed; treat same as int) */
2096 if (isUnsignedShift) {
2097 if (shiftCount > 24)
2098 newType = kRegTypePosByte;
2099 else if (shiftCount >= 16)
2100 newType = kRegTypeChar;
2101 } else {
2102 if (shiftCount >= 24)
2103 newType = kRegTypeByte;
2104 else if (shiftCount >= 16)
2105 newType = kRegTypeShort;
2106 }
2107 break;
2108 case kRegTypeShort: /* 16-bit signed value */
2109 if (isUnsignedShift) {
2110 /* default (kRegTypeInteger) is correct */
2111 } else {
2112 if (shiftCount >= 8)
2113 newType = kRegTypeByte;
2114 }
2115 break;
2116 case kRegTypePosShort: /* 15-bit unsigned value */
2117 if (shiftCount >= 8)
2118 newType = kRegTypePosByte;
2119 break;
2120 case kRegTypeChar: /* 16-bit unsigned value */
2121 if (shiftCount > 8)
2122 newType = kRegTypePosByte;
2123 break;
2124 case kRegTypeByte: /* 8-bit signed value */
2125 /* defaults (u=kRegTypeInteger / s=srcType) are correct */
2126 break;
2127 case kRegTypePosByte: /* 7-bit unsigned value */
2128 /* always use newType=srcType */
2129 newType = srcType;
2130 break;
2131 case kRegTypeZero: /* 1-bit unsigned value */
2132 case kRegTypeOne:
2133 case kRegTypeBoolean:
2134 /* unnecessary? */
2135 newType = kRegTypeZero;
2136 break;
2137 default:
2138 /* long, double, references; shouldn't be here! */
2139 assert(false);
2140 break;
2141 }
2142
2143 if (newType != srcType) {
2144 LOGVV("narrowing: %d(%d) --> %d to %d\n",
2145 shiftCount, isUnsignedShift, srcType, newType);
2146 } else {
2147 LOGVV("not narrowed: %d(%d) --> %d\n",
2148 shiftCount, isUnsignedShift, srcType);
2149 }
2150 return newType;
2151 }
2152
2153
2154 /*
2155 * ===========================================================================
2156 * Register merge
2157 * ===========================================================================
2158 */
2159
2160 /*
2161 * Compute the "class depth" of a class. This is the distance from the
2162 * class to the top of the tree, chasing superclass links. java.lang.Object
2163 * has a class depth of 0.
2164 */
getClassDepth(ClassObject * clazz)2165 static int getClassDepth(ClassObject* clazz)
2166 {
2167 int depth = 0;
2168
2169 while (clazz->super != NULL) {
2170 clazz = clazz->super;
2171 depth++;
2172 }
2173 return depth;
2174 }
2175
2176 /*
2177 * Given two classes, walk up the superclass tree to find a common
2178 * ancestor. (Called from findCommonSuperclass().)
2179 *
2180 * TODO: consider caching the class depth in the class object so we don't
2181 * have to search for it here.
2182 */
digForSuperclass(ClassObject * c1,ClassObject * c2)2183 static ClassObject* digForSuperclass(ClassObject* c1, ClassObject* c2)
2184 {
2185 int depth1, depth2;
2186
2187 depth1 = getClassDepth(c1);
2188 depth2 = getClassDepth(c2);
2189
2190 if (gDebugVerbose) {
2191 LOGVV("COMMON: %s(%d) + %s(%d)\n",
2192 c1->descriptor, depth1, c2->descriptor, depth2);
2193 }
2194
2195 /* pull the deepest one up */
2196 if (depth1 > depth2) {
2197 while (depth1 > depth2) {
2198 c1 = c1->super;
2199 depth1--;
2200 }
2201 } else {
2202 while (depth2 > depth1) {
2203 c2 = c2->super;
2204 depth2--;
2205 }
2206 }
2207
2208 /* walk up in lock-step */
2209 while (c1 != c2) {
2210 c1 = c1->super;
2211 c2 = c2->super;
2212
2213 assert(c1 != NULL && c2 != NULL);
2214 }
2215
2216 if (gDebugVerbose) {
2217 LOGVV(" : --> %s\n", c1->descriptor);
2218 }
2219 return c1;
2220 }
2221
2222 /*
2223 * Merge two array classes. We can't use the general "walk up to the
2224 * superclass" merge because the superclass of an array is always Object.
2225 * We want String[] + Integer[] = Object[]. This works for higher dimensions
2226 * as well, e.g. String[][] + Integer[][] = Object[][].
2227 *
2228 * If Foo1 and Foo2 are subclasses of Foo, Foo1[] + Foo2[] = Foo[].
2229 *
2230 * If Class implements Type, Class[] + Type[] = Type[].
2231 *
2232 * If the dimensions don't match, we want to convert to an array of Object
2233 * with the least dimension, e.g. String[][] + String[][][][] = Object[][].
2234 *
2235 * This gets a little awkward because we may have to ask the VM to create
2236 * a new array type with the appropriate element and dimensions. However, we
2237 * shouldn't be doing this often.
2238 */
findCommonArraySuperclass(ClassObject * c1,ClassObject * c2)2239 static ClassObject* findCommonArraySuperclass(ClassObject* c1, ClassObject* c2)
2240 {
2241 ClassObject* arrayClass = NULL;
2242 ClassObject* commonElem;
2243 int i, numDims;
2244
2245 assert(c1->arrayDim > 0);
2246 assert(c2->arrayDim > 0);
2247
2248 if (c1->arrayDim == c2->arrayDim) {
2249 //commonElem = digForSuperclass(c1->elementClass, c2->elementClass);
2250 commonElem = findCommonSuperclass(c1->elementClass, c2->elementClass);
2251 numDims = c1->arrayDim;
2252 } else {
2253 if (c1->arrayDim < c2->arrayDim)
2254 numDims = c1->arrayDim;
2255 else
2256 numDims = c2->arrayDim;
2257 commonElem = c1->super; // == java.lang.Object
2258 }
2259
2260 /* walk from the element to the (multi-)dimensioned array type */
2261 for (i = 0; i < numDims; i++) {
2262 arrayClass = dvmFindArrayClassForElement(commonElem);
2263 commonElem = arrayClass;
2264 }
2265
2266 LOGVV("ArrayMerge '%s' + '%s' --> '%s'\n",
2267 c1->descriptor, c2->descriptor, arrayClass->descriptor);
2268 return arrayClass;
2269 }
2270
2271 /*
2272 * Find the first common superclass of the two classes. We're not
2273 * interested in common interfaces.
2274 *
2275 * The easiest way to do this for concrete classes is to compute the "class
2276 * depth" of each, move up toward the root of the deepest one until they're
2277 * at the same depth, then walk both up to the root until they match.
2278 *
2279 * If both classes are arrays of non-primitive types, we need to merge
2280 * based on array depth and element type.
2281 *
2282 * If one class is an interface, we check to see if the other class/interface
2283 * (or one of its predecessors) implements the interface. If so, we return
2284 * the interface; otherwise, we return Object.
2285 *
2286 * NOTE: we continue the tradition of "lazy interface handling". To wit,
2287 * suppose we have three classes:
2288 * One implements Fancy, Free
2289 * Two implements Fancy, Free
2290 * Three implements Free
2291 * where Fancy and Free are unrelated interfaces. The code requires us
2292 * to merge One into Two. Ideally we'd use a common interface, which
2293 * gives us a choice between Fancy and Free, and no guidance on which to
2294 * use. If we use Free, we'll be okay when Three gets merged in, but if
2295 * we choose Fancy, we're hosed. The "ideal" solution is to create a
2296 * set of common interfaces and carry that around, merging further references
2297 * into it. This is a pain. The easy solution is to simply boil them
2298 * down to Objects and let the runtime invokeinterface call fail, which
2299 * is what we do.
2300 */
findCommonSuperclass(ClassObject * c1,ClassObject * c2)2301 static ClassObject* findCommonSuperclass(ClassObject* c1, ClassObject* c2)
2302 {
2303 assert(!dvmIsPrimitiveClass(c1) && !dvmIsPrimitiveClass(c2));
2304
2305 if (c1 == c2)
2306 return c1;
2307
2308 if (dvmIsInterfaceClass(c1) && dvmImplements(c2, c1)) {
2309 if (gDebugVerbose)
2310 LOGVV("COMMON/I1: %s + %s --> %s\n",
2311 c1->descriptor, c2->descriptor, c1->descriptor);
2312 return c1;
2313 }
2314 if (dvmIsInterfaceClass(c2) && dvmImplements(c1, c2)) {
2315 if (gDebugVerbose)
2316 LOGVV("COMMON/I2: %s + %s --> %s\n",
2317 c1->descriptor, c2->descriptor, c2->descriptor);
2318 return c2;
2319 }
2320
2321 if (dvmIsArrayClass(c1) && dvmIsArrayClass(c2) &&
2322 !dvmIsPrimitiveClass(c1->elementClass) &&
2323 !dvmIsPrimitiveClass(c2->elementClass))
2324 {
2325 return findCommonArraySuperclass(c1, c2);
2326 }
2327
2328 return digForSuperclass(c1, c2);
2329 }
2330
2331 /*
2332 * Merge two RegType values.
2333 *
2334 * Sets "*pChanged" to "true" if the result doesn't match "type1".
2335 */
mergeTypes(RegType type1,RegType type2,bool * pChanged)2336 static RegType mergeTypes(RegType type1, RegType type2, bool* pChanged)
2337 {
2338 RegType result;
2339
2340 /*
2341 * Check for trivial case so we don't have to hit memory.
2342 */
2343 if (type1 == type2)
2344 return type1;
2345
2346 /*
2347 * Use the table if we can, and reject any attempts to merge something
2348 * from the table with a reference type.
2349 *
2350 * The uninitialized table entry at index zero *will* show up as a
2351 * simple kRegTypeUninit value. Since this cannot be merged with
2352 * anything but itself, the rules do the right thing.
2353 */
2354 if (type1 < kRegTypeMAX) {
2355 if (type2 < kRegTypeMAX) {
2356 result = gDvmMergeTab[type1][type2];
2357 } else {
2358 /* simple + reference == conflict, usually */
2359 if (type1 == kRegTypeZero)
2360 result = type2;
2361 else
2362 result = kRegTypeConflict;
2363 }
2364 } else {
2365 if (type2 < kRegTypeMAX) {
2366 /* reference + simple == conflict, usually */
2367 if (type2 == kRegTypeZero)
2368 result = type1;
2369 else
2370 result = kRegTypeConflict;
2371 } else {
2372 /* merging two references */
2373 if (regTypeIsUninitReference(type1) ||
2374 regTypeIsUninitReference(type2))
2375 {
2376 /* can't merge uninit with anything but self */
2377 result = kRegTypeConflict;
2378 } else {
2379 ClassObject* clazz1 = regTypeInitializedReferenceToClass(type1);
2380 ClassObject* clazz2 = regTypeInitializedReferenceToClass(type2);
2381 ClassObject* mergedClass;
2382
2383 mergedClass = findCommonSuperclass(clazz1, clazz2);
2384 assert(mergedClass != NULL);
2385 result = regTypeFromClass(mergedClass);
2386 }
2387 }
2388 }
2389
2390 if (result != type1)
2391 *pChanged = true;
2392 return result;
2393 }
2394
2395 /*
2396 * Control can transfer to "nextInsn".
2397 *
2398 * Merge the registers from "workRegs" into "regTypes" at "nextInsn", and
2399 * set the "changed" flag on the target address if the registers have changed.
2400 */
updateRegisters(const Method * meth,InsnFlags * insnFlags,RegisterTable * regTable,int nextInsn,const RegType * workRegs)2401 static void updateRegisters(const Method* meth, InsnFlags* insnFlags,
2402 RegisterTable* regTable, int nextInsn, const RegType* workRegs)
2403 {
2404 RegType* targetRegs = getRegisterLine(regTable, nextInsn);
2405 const int insnRegCount = meth->registersSize;
2406
2407 #if 0
2408 if (!dvmInsnIsBranchTarget(insnFlags, nextInsn)) {
2409 LOGE("insnFlags[0x%x]=0x%08x\n", nextInsn, insnFlags[nextInsn]);
2410 LOGE(" In %s.%s %s\n",
2411 meth->clazz->descriptor, meth->name, meth->descriptor);
2412 assert(false);
2413 }
2414 #endif
2415
2416 if (!dvmInsnIsVisitedOrChanged(insnFlags, nextInsn)) {
2417 /*
2418 * We haven't processed this instruction before, and we haven't
2419 * touched the registers here, so there's nothing to "merge". Copy
2420 * the registers over and mark it as changed. (This is the only
2421 * way a register can transition out of "unknown", so this is not
2422 * just an optimization.)
2423 */
2424 LOGVV("COPY into 0x%04x\n", nextInsn);
2425 copyRegisters(targetRegs, workRegs, insnRegCount + kExtraRegs);
2426 dvmInsnSetChanged(insnFlags, nextInsn, true);
2427 } else {
2428 if (gDebugVerbose) {
2429 LOGVV("MERGE into 0x%04x\n", nextInsn);
2430 //dumpRegTypes(meth, insnFlags, targetRegs, 0, "targ", NULL, 0);
2431 //dumpRegTypes(meth, insnFlags, workRegs, 0, "work", NULL, 0);
2432 }
2433 /* merge registers, set Changed only if different */
2434 bool changed = false;
2435 int i;
2436
2437 for (i = 0; i < insnRegCount + kExtraRegs; i++) {
2438 targetRegs[i] = mergeTypes(targetRegs[i], workRegs[i], &changed);
2439 }
2440
2441 if (gDebugVerbose) {
2442 //LOGI(" RESULT (changed=%d)\n", changed);
2443 //dumpRegTypes(meth, insnFlags, targetRegs, 0, "rslt", NULL, 0);
2444 }
2445
2446 if (changed)
2447 dvmInsnSetChanged(insnFlags, nextInsn, true);
2448 }
2449 }
2450
2451
2452 /*
2453 * ===========================================================================
2454 * Utility functions
2455 * ===========================================================================
2456 */
2457
2458 /*
2459 * Look up an instance field, specified by "fieldIdx", that is going to be
2460 * accessed in object "objType". This resolves the field and then verifies
2461 * that the class containing the field is an instance of the reference in
2462 * "objType".
2463 *
2464 * It is possible for "objType" to be kRegTypeZero, meaning that we might
2465 * have a null reference. This is a runtime problem, so we allow it,
2466 * skipping some of the type checks.
2467 *
2468 * In general, "objType" must be an initialized reference. However, we
2469 * allow it to be uninitialized if this is an "<init>" method and the field
2470 * is declared within the "objType" class.
2471 *
2472 * Returns an InstField on success, returns NULL and sets "*pFailure"
2473 * on failure.
2474 */
getInstField(const Method * meth,const UninitInstanceMap * uninitMap,RegType objType,int fieldIdx,VerifyError * pFailure)2475 static InstField* getInstField(const Method* meth,
2476 const UninitInstanceMap* uninitMap, RegType objType, int fieldIdx,
2477 VerifyError* pFailure)
2478 {
2479 InstField* instField = NULL;
2480 ClassObject* objClass;
2481 bool mustBeLocal = false;
2482
2483 if (!regTypeIsReference(objType)) {
2484 LOG_VFY("VFY: attempt to access field in non-reference type %d\n",
2485 objType);
2486 *pFailure = VERIFY_ERROR_GENERIC;
2487 goto bail;
2488 }
2489
2490 instField = dvmOptResolveInstField(meth->clazz, fieldIdx, pFailure);
2491 if (instField == NULL) {
2492 LOG_VFY("VFY: unable to resolve instance field %u\n", fieldIdx);
2493 assert(!VERIFY_OK(*pFailure));
2494 goto bail;
2495 }
2496
2497 if (objType == kRegTypeZero)
2498 goto bail;
2499
2500 /*
2501 * Access to fields in uninitialized objects is allowed if this is
2502 * the <init> method for the object and the field in question is
2503 * declared by this class.
2504 */
2505 objClass = regTypeReferenceToClass(objType, uninitMap);
2506 assert(objClass != NULL);
2507 if (regTypeIsUninitReference(objType)) {
2508 if (!isInitMethod(meth) || meth->clazz != objClass) {
2509 LOG_VFY("VFY: attempt to access field via uninitialized ref\n");
2510 *pFailure = VERIFY_ERROR_GENERIC;
2511 goto bail;
2512 }
2513 mustBeLocal = true;
2514 }
2515
2516 if (!dvmInstanceof(objClass, instField->field.clazz)) {
2517 LOG_VFY("VFY: invalid field access (field %s.%s, through %s ref)\n",
2518 instField->field.clazz->descriptor, instField->field.name,
2519 objClass->descriptor);
2520 *pFailure = VERIFY_ERROR_NO_FIELD;
2521 goto bail;
2522 }
2523
2524 if (mustBeLocal) {
2525 /* for uninit ref, make sure it's defined by this class, not super */
2526 if (instField < objClass->ifields ||
2527 instField >= objClass->ifields + objClass->ifieldCount)
2528 {
2529 LOG_VFY("VFY: invalid constructor field access (field %s in %s)\n",
2530 instField->field.name, objClass->descriptor);
2531 *pFailure = VERIFY_ERROR_GENERIC;
2532 goto bail;
2533 }
2534 }
2535
2536 bail:
2537 return instField;
2538 }
2539
2540 /*
2541 * Look up a static field.
2542 *
2543 * Returns a StaticField on success, returns NULL and sets "*pFailure"
2544 * on failure.
2545 */
getStaticField(const Method * meth,int fieldIdx,VerifyError * pFailure)2546 static StaticField* getStaticField(const Method* meth, int fieldIdx,
2547 VerifyError* pFailure)
2548 {
2549 StaticField* staticField;
2550
2551 staticField = dvmOptResolveStaticField(meth->clazz, fieldIdx, pFailure);
2552 if (staticField == NULL) {
2553 DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
2554 const DexFieldId* pFieldId;
2555
2556 pFieldId = dexGetFieldId(pDexFile, fieldIdx);
2557
2558 LOG_VFY("VFY: unable to resolve static field %u (%s) in %s\n", fieldIdx,
2559 dexStringById(pDexFile, pFieldId->nameIdx),
2560 dexStringByTypeIdx(pDexFile, pFieldId->classIdx));
2561 assert(!VERIFY_OK(*pFailure));
2562 goto bail;
2563 }
2564
2565 bail:
2566 return staticField;
2567 }
2568
2569 /*
2570 * If "field" is marked "final", make sure this is the either <clinit>
2571 * or <init> as appropriate.
2572 *
2573 * Sets "*pFailure" on failure.
2574 */
checkFinalFieldAccess(const Method * meth,const Field * field,VerifyError * pFailure)2575 static void checkFinalFieldAccess(const Method* meth, const Field* field,
2576 VerifyError* pFailure)
2577 {
2578 if (!dvmIsFinalField(field))
2579 return;
2580
2581 /* make sure we're in the same class */
2582 if (meth->clazz != field->clazz) {
2583 LOG_VFY_METH(meth, "VFY: can't modify final field %s.%s\n",
2584 field->clazz->descriptor, field->name);
2585 *pFailure = VERIFY_ERROR_ACCESS_FIELD;
2586 return;
2587 }
2588
2589 /*
2590 * The VM spec descriptions of putfield and putstatic say that
2591 * IllegalAccessError is only thrown when the instructions appear
2592 * outside the declaring class. Our earlier attempts to restrict
2593 * final field modification to constructors are, therefore, wrong.
2594 */
2595 #if 0
2596 /* make sure we're in the right kind of constructor */
2597 if (dvmIsStaticField(field)) {
2598 if (!isClassInitMethod(meth)) {
2599 LOG_VFY_METH(meth,
2600 "VFY: can't modify final static field outside <clinit>\n");
2601 *pFailure = VERIFY_ERROR_GENERIC;
2602 }
2603 } else {
2604 if (!isInitMethod(meth)) {
2605 LOG_VFY_METH(meth,
2606 "VFY: can't modify final field outside <init>\n");
2607 *pFailure = VERIFY_ERROR_GENERIC;
2608 }
2609 }
2610 #endif
2611 }
2612
2613 /*
2614 * Make sure that the register type is suitable for use as an array index.
2615 *
2616 * Sets "*pFailure" if not.
2617 */
checkArrayIndexType(const Method * meth,RegType regType,VerifyError * pFailure)2618 static void checkArrayIndexType(const Method* meth, RegType regType,
2619 VerifyError* pFailure)
2620 {
2621 if (VERIFY_OK(*pFailure)) {
2622 /*
2623 * The 1nr types are interchangeable at this level. We could
2624 * do something special if we can definitively identify it as a
2625 * float, but there's no real value in doing so.
2626 */
2627 checkTypeCategory(regType, kTypeCategory1nr, pFailure);
2628 if (!VERIFY_OK(*pFailure)) {
2629 LOG_VFY_METH(meth, "Invalid reg type for array index (%d)\n",
2630 regType);
2631 }
2632 }
2633 }
2634
2635 /*
2636 * Check constraints on constructor return. Specifically, make sure that
2637 * the "this" argument got initialized.
2638 *
2639 * The "this" argument to <init> uses code offset kUninitThisArgAddr, which
2640 * puts it at the start of the list in slot 0. If we see a register with
2641 * an uninitialized slot 0 reference, we know it somehow didn't get
2642 * initialized.
2643 *
2644 * Returns "true" if all is well.
2645 */
checkConstructorReturn(const Method * meth,const RegType * insnRegs,const int insnRegCount)2646 static bool checkConstructorReturn(const Method* meth, const RegType* insnRegs,
2647 const int insnRegCount)
2648 {
2649 int i;
2650
2651 if (!isInitMethod(meth))
2652 return true;
2653
2654 RegType uninitThis = regTypeFromUninitIndex(kUninitThisArgSlot);
2655
2656 for (i = 0; i < insnRegCount; i++) {
2657 if (insnRegs[i] == uninitThis) {
2658 LOG_VFY("VFY: <init> returning without calling superclass init\n");
2659 return false;
2660 }
2661 }
2662 return true;
2663 }
2664
2665 /*
2666 * Verify that the target instruction is not "move-exception". It's important
2667 * that the only way to execute a move-exception is as the first instruction
2668 * of an exception handler.
2669 *
2670 * Returns "true" if all is well, "false" if the target instruction is
2671 * move-exception.
2672 */
checkMoveException(const Method * meth,int insnIdx,const char * logNote)2673 static bool checkMoveException(const Method* meth, int insnIdx,
2674 const char* logNote)
2675 {
2676 assert(insnIdx >= 0 && insnIdx < (int)dvmGetMethodInsnsSize(meth));
2677
2678 if ((meth->insns[insnIdx] & 0xff) == OP_MOVE_EXCEPTION) {
2679 LOG_VFY("VFY: invalid use of move-exception\n");
2680 return false;
2681 }
2682 return true;
2683 }
2684
2685 /*
2686 * For the "move-exception" instruction at "insnIdx", which must be at an
2687 * exception handler address, determine the first common superclass of
2688 * all exceptions that can land here. (For javac output, we're probably
2689 * looking at multiple spans of bytecode covered by one "try" that lands
2690 * at an exception-specific "catch", but in general the handler could be
2691 * shared for multiple exceptions.)
2692 *
2693 * Returns NULL if no matching exception handler can be found, or if the
2694 * exception is not a subclass of Throwable.
2695 */
getCaughtExceptionType(const Method * meth,int insnIdx,VerifyError * pFailure)2696 static ClassObject* getCaughtExceptionType(const Method* meth, int insnIdx,
2697 VerifyError* pFailure)
2698 {
2699 VerifyError localFailure;
2700 const DexCode* pCode;
2701 DexFile* pDexFile;
2702 ClassObject* commonSuper = NULL;
2703 bool foundPossibleHandler = false;
2704 u4 handlersSize;
2705 u4 offset;
2706 u4 i;
2707
2708 pDexFile = meth->clazz->pDvmDex->pDexFile;
2709 pCode = dvmGetMethodCode(meth);
2710
2711 if (pCode->triesSize != 0) {
2712 handlersSize = dexGetHandlersSize(pCode);
2713 offset = dexGetFirstHandlerOffset(pCode);
2714 } else {
2715 handlersSize = 0;
2716 offset = 0;
2717 }
2718
2719 for (i = 0; i < handlersSize; i++) {
2720 DexCatchIterator iterator;
2721 dexCatchIteratorInit(&iterator, pCode, offset);
2722
2723 for (;;) {
2724 const DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
2725
2726 if (handler == NULL) {
2727 break;
2728 }
2729
2730 if (handler->address == (u4) insnIdx) {
2731 ClassObject* clazz;
2732 foundPossibleHandler = true;
2733
2734 if (handler->typeIdx == kDexNoIndex)
2735 clazz = gDvm.classJavaLangThrowable;
2736 else
2737 clazz = dvmOptResolveClass(meth->clazz, handler->typeIdx,
2738 &localFailure);
2739
2740 if (clazz == NULL) {
2741 LOG_VFY("VFY: unable to resolve exception class %u (%s)\n",
2742 handler->typeIdx,
2743 dexStringByTypeIdx(pDexFile, handler->typeIdx));
2744 /* TODO: do we want to keep going? If we don't fail
2745 * this we run the risk of having a non-Throwable
2746 * introduced at runtime. However, that won't pass
2747 * an instanceof test, so is essentially harmless. */
2748 } else {
2749 if (commonSuper == NULL)
2750 commonSuper = clazz;
2751 else
2752 commonSuper = findCommonSuperclass(clazz, commonSuper);
2753 }
2754 }
2755 }
2756
2757 offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
2758 }
2759
2760 if (commonSuper == NULL) {
2761 /* no catch blocks, or no catches with classes we can find */
2762 LOG_VFY_METH(meth,
2763 "VFY: unable to find exception handler at addr 0x%x\n", insnIdx);
2764 *pFailure = VERIFY_ERROR_GENERIC;
2765 } else {
2766 // TODO: verify the class is an instance of Throwable?
2767 }
2768
2769 return commonSuper;
2770 }
2771
2772 /*
2773 * Initialize the RegisterTable.
2774 *
2775 * Every instruction address can have a different set of information about
2776 * what's in which register, but for verification purposes we only need to
2777 * store it at branch target addresses (because we merge into that).
2778 *
2779 * By zeroing out the storage we are effectively initializing the register
2780 * information to kRegTypeUnknown.
2781 */
initRegisterTable(const Method * meth,const InsnFlags * insnFlags,RegisterTable * regTable,RegisterTrackingMode trackRegsFor)2782 static bool initRegisterTable(const Method* meth, const InsnFlags* insnFlags,
2783 RegisterTable* regTable, RegisterTrackingMode trackRegsFor)
2784 {
2785 const int insnsSize = dvmGetMethodInsnsSize(meth);
2786 int i;
2787
2788 regTable->insnRegCountPlus = meth->registersSize + kExtraRegs;
2789 regTable->addrRegs = (RegType**) calloc(insnsSize, sizeof(RegType*));
2790 if (regTable->addrRegs == NULL)
2791 return false;
2792
2793 assert(insnsSize > 0);
2794
2795 /*
2796 * "All" means "every address that holds the start of an instruction".
2797 * "Branches" and "GcPoints" mean just those addresses.
2798 *
2799 * "GcPoints" fills about half the addresses, "Branches" about 15%.
2800 */
2801 int interestingCount = 0;
2802 //int insnCount = 0;
2803
2804 for (i = 0; i < insnsSize; i++) {
2805 bool interesting;
2806
2807 switch (trackRegsFor) {
2808 case kTrackRegsAll:
2809 interesting = dvmInsnIsOpcode(insnFlags, i);
2810 break;
2811 case kTrackRegsGcPoints:
2812 interesting = dvmInsnIsGcPoint(insnFlags, i) ||
2813 dvmInsnIsBranchTarget(insnFlags, i);
2814 break;
2815 case kTrackRegsBranches:
2816 interesting = dvmInsnIsBranchTarget(insnFlags, i);
2817 break;
2818 default:
2819 dvmAbort();
2820 return false;
2821 }
2822
2823 if (interesting)
2824 interestingCount++;
2825
2826 /* count instructions, for display only */
2827 //if (dvmInsnIsOpcode(insnFlags, i))
2828 // insnCount++;
2829 }
2830
2831 regTable->regAlloc = (RegType*)
2832 calloc(regTable->insnRegCountPlus * interestingCount, sizeof(RegType));
2833 if (regTable->regAlloc == NULL)
2834 return false;
2835
2836 RegType* regPtr = regTable->regAlloc;
2837 for (i = 0; i < insnsSize; i++) {
2838 bool interesting;
2839
2840 switch (trackRegsFor) {
2841 case kTrackRegsAll:
2842 interesting = dvmInsnIsOpcode(insnFlags, i);
2843 break;
2844 case kTrackRegsGcPoints:
2845 interesting = dvmInsnIsGcPoint(insnFlags, i) ||
2846 dvmInsnIsBranchTarget(insnFlags, i);
2847 break;
2848 case kTrackRegsBranches:
2849 interesting = dvmInsnIsBranchTarget(insnFlags, i);
2850 break;
2851 default:
2852 dvmAbort();
2853 return false;
2854 }
2855
2856 if (interesting) {
2857 regTable->addrRegs[i] = regPtr;
2858 regPtr += regTable->insnRegCountPlus;
2859 }
2860 }
2861
2862 //LOGD("Tracking registers for %d, total %d of %d(%d) (%d%%)\n",
2863 // TRACK_REGS_FOR, interestingCount, insnCount, insnsSize,
2864 // (interestingCount*100) / insnCount);
2865
2866 assert(regPtr - regTable->regAlloc ==
2867 regTable->insnRegCountPlus * interestingCount);
2868 assert(regTable->addrRegs[0] != NULL);
2869 return true;
2870 }
2871
2872
2873 /*
2874 * Verify that the arguments in a filled-new-array instruction are valid.
2875 *
2876 * "resClass" is the class refered to by pDecInsn->vB.
2877 */
verifyFilledNewArrayRegs(const Method * meth,const RegType * insnRegs,const int insnRegCount,const DecodedInstruction * pDecInsn,ClassObject * resClass,bool isRange,VerifyError * pFailure)2878 static void verifyFilledNewArrayRegs(const Method* meth,
2879 const RegType* insnRegs, const int insnRegCount,
2880 const DecodedInstruction* pDecInsn, ClassObject* resClass, bool isRange,
2881 VerifyError* pFailure)
2882 {
2883 u4 argCount = pDecInsn->vA;
2884 RegType expectedType;
2885 PrimitiveType elemType;
2886 unsigned int ui;
2887
2888 assert(dvmIsArrayClass(resClass));
2889 elemType = resClass->elementClass->primitiveType;
2890 if (elemType == PRIM_NOT) {
2891 expectedType = regTypeFromClass(resClass->elementClass);
2892 } else {
2893 expectedType = primitiveTypeToRegType(elemType);
2894 }
2895 //LOGI("filled-new-array: %s -> %d\n", resClass->descriptor, expectedType);
2896
2897 /*
2898 * Verify each register. If "argCount" is bad, verifyRegisterType()
2899 * will run off the end of the list and fail. It's legal, if silly,
2900 * for argCount to be zero.
2901 */
2902 for (ui = 0; ui < argCount; ui++) {
2903 u4 getReg;
2904
2905 if (isRange)
2906 getReg = pDecInsn->vC + ui;
2907 else
2908 getReg = pDecInsn->arg[ui];
2909
2910 verifyRegisterType(insnRegs, insnRegCount, getReg, expectedType,
2911 pFailure);
2912 if (!VERIFY_OK(*pFailure)) {
2913 LOG_VFY("VFY: filled-new-array arg %u(%u) not valid\n", ui, getReg);
2914 return;
2915 }
2916 }
2917 }
2918
2919
2920 /*
2921 * Replace an instruction with "throw-verification-error". This allows us to
2922 * defer error reporting until the code path is first used.
2923 *
2924 * The throw-verification-error instruction requires two code units. Some
2925 * of the replaced instructions require three; the third code unit will
2926 * receive a "nop". The instruction's length will be left unchanged
2927 * in "insnFlags".
2928 *
2929 * IMPORTANT: this may replace meth->insns with a pointer to a new copy of
2930 * the instructions.
2931 *
2932 * Returns "true" on success.
2933 */
replaceFailingInstruction(Method * meth,InsnFlags * insnFlags,int insnIdx,VerifyError failure)2934 static bool replaceFailingInstruction(Method* meth, InsnFlags* insnFlags,
2935 int insnIdx, VerifyError failure)
2936 {
2937 VerifyErrorRefType refType;
2938 const u2* oldInsns = meth->insns + insnIdx;
2939 u2 oldInsn = *oldInsns;
2940 bool result = false;
2941
2942 dvmMakeCodeReadWrite(meth);
2943
2944 //LOGD(" was 0x%04x\n", oldInsn);
2945 u2* newInsns = (u2*) meth->insns + insnIdx;
2946
2947 /*
2948 * Generate the new instruction out of the old.
2949 *
2950 * First, make sure this is an instruction we're expecting to stomp on.
2951 */
2952 switch (oldInsn & 0xff) {
2953 case OP_CONST_CLASS: // insn[1] == class ref, 2 bytes
2954 case OP_CHECK_CAST:
2955 case OP_INSTANCE_OF:
2956 case OP_NEW_INSTANCE:
2957 case OP_NEW_ARRAY:
2958 case OP_FILLED_NEW_ARRAY: // insn[1] == class ref, 3 bytes
2959 case OP_FILLED_NEW_ARRAY_RANGE:
2960 refType = VERIFY_ERROR_REF_CLASS;
2961 break;
2962
2963 case OP_IGET: // insn[1] == field ref, 2 bytes
2964 case OP_IGET_BOOLEAN:
2965 case OP_IGET_BYTE:
2966 case OP_IGET_CHAR:
2967 case OP_IGET_SHORT:
2968 case OP_IGET_WIDE:
2969 case OP_IGET_OBJECT:
2970 case OP_IPUT:
2971 case OP_IPUT_BOOLEAN:
2972 case OP_IPUT_BYTE:
2973 case OP_IPUT_CHAR:
2974 case OP_IPUT_SHORT:
2975 case OP_IPUT_WIDE:
2976 case OP_IPUT_OBJECT:
2977 case OP_SGET:
2978 case OP_SGET_BOOLEAN:
2979 case OP_SGET_BYTE:
2980 case OP_SGET_CHAR:
2981 case OP_SGET_SHORT:
2982 case OP_SGET_WIDE:
2983 case OP_SGET_OBJECT:
2984 case OP_SPUT:
2985 case OP_SPUT_BOOLEAN:
2986 case OP_SPUT_BYTE:
2987 case OP_SPUT_CHAR:
2988 case OP_SPUT_SHORT:
2989 case OP_SPUT_WIDE:
2990 case OP_SPUT_OBJECT:
2991 refType = VERIFY_ERROR_REF_FIELD;
2992 break;
2993
2994 case OP_INVOKE_VIRTUAL: // insn[1] == method ref, 3 bytes
2995 case OP_INVOKE_VIRTUAL_RANGE:
2996 case OP_INVOKE_SUPER:
2997 case OP_INVOKE_SUPER_RANGE:
2998 case OP_INVOKE_DIRECT:
2999 case OP_INVOKE_DIRECT_RANGE:
3000 case OP_INVOKE_STATIC:
3001 case OP_INVOKE_STATIC_RANGE:
3002 case OP_INVOKE_INTERFACE:
3003 case OP_INVOKE_INTERFACE_RANGE:
3004 refType = VERIFY_ERROR_REF_METHOD;
3005 break;
3006
3007 default:
3008 /* could handle this in a generic way, but this is probably safer */
3009 LOG_VFY("GLITCH: verifier asked to replace opcode 0x%02x\n",
3010 oldInsn & 0xff);
3011 goto bail;
3012 }
3013
3014 /* write a NOP over the third code unit, if necessary */
3015 int width = dvmInsnGetWidth(insnFlags, insnIdx);
3016 switch (width) {
3017 case 2:
3018 /* nothing to do */
3019 break;
3020 case 3:
3021 newInsns[2] = OP_NOP;
3022 break;
3023 default:
3024 /* whoops */
3025 LOGE("ERROR: stomped a %d-unit instruction with a verifier error\n",
3026 width);
3027 dvmAbort();
3028 }
3029
3030 /* encode the opcode, with the failure code in the high byte */
3031 newInsns[0] = OP_THROW_VERIFICATION_ERROR |
3032 (failure << 8) | (refType << (8 + kVerifyErrorRefTypeShift));
3033
3034 result = true;
3035
3036 bail:
3037 dvmMakeCodeReadOnly(meth);
3038 return result;
3039 }
3040
3041
3042 /*
3043 * ===========================================================================
3044 * Entry point and driver loop
3045 * ===========================================================================
3046 */
3047
3048 /*
3049 * Entry point for the detailed code-flow analysis.
3050 */
dvmVerifyCodeFlow(Method * meth,InsnFlags * insnFlags,UninitInstanceMap * uninitMap)3051 bool dvmVerifyCodeFlow(Method* meth, InsnFlags* insnFlags,
3052 UninitInstanceMap* uninitMap)
3053 {
3054 bool result = false;
3055 const int insnsSize = dvmGetMethodInsnsSize(meth);
3056 const u2* insns = meth->insns;
3057 const bool generateRegisterMap = gDvm.generateRegisterMaps;
3058 int i, offset;
3059 bool isConditional;
3060 RegisterTable regTable;
3061
3062 memset(®Table, 0, sizeof(regTable));
3063
3064 #ifndef NDEBUG
3065 checkMergeTab(); // only need to do this if table gets updated
3066 #endif
3067
3068 /*
3069 * We rely on these for verification of const-class, const-string,
3070 * and throw instructions. Make sure we have them.
3071 */
3072 if (gDvm.classJavaLangClass == NULL)
3073 gDvm.classJavaLangClass =
3074 dvmFindSystemClassNoInit("Ljava/lang/Class;");
3075 if (gDvm.classJavaLangString == NULL)
3076 gDvm.classJavaLangString =
3077 dvmFindSystemClassNoInit("Ljava/lang/String;");
3078 if (gDvm.classJavaLangThrowable == NULL) {
3079 gDvm.classJavaLangThrowable =
3080 dvmFindSystemClassNoInit("Ljava/lang/Throwable;");
3081 gDvm.offJavaLangThrowable_cause =
3082 dvmFindFieldOffset(gDvm.classJavaLangThrowable,
3083 "cause", "Ljava/lang/Throwable;");
3084 }
3085 if (gDvm.classJavaLangObject == NULL)
3086 gDvm.classJavaLangObject =
3087 dvmFindSystemClassNoInit("Ljava/lang/Object;");
3088
3089 if (meth->registersSize * insnsSize > 2*1024*1024) {
3090 /* should probably base this on actual memory requirements */
3091 LOG_VFY_METH(meth,
3092 "VFY: arbitrarily rejecting large method (regs=%d count=%d)\n",
3093 meth->registersSize, insnsSize);
3094 goto bail;
3095 }
3096
3097 /*
3098 * Create register lists, and initialize them to "Unknown". If we're
3099 * also going to create the register map, we need to retain the
3100 * register lists for a larger set of addresses.
3101 */
3102 if (!initRegisterTable(meth, insnFlags, ®Table,
3103 generateRegisterMap ? kTrackRegsGcPoints : kTrackRegsBranches))
3104 goto bail;
3105
3106 /*
3107 * Initialize the types of the registers that correspond to the
3108 * method arguments. We can determine this from the method signature.
3109 */
3110 if (!setTypesFromSignature(meth, regTable.addrRegs[0], uninitMap))
3111 goto bail;
3112
3113 /*
3114 * Run the verifier.
3115 */
3116 if (!doCodeVerification(meth, insnFlags, ®Table, uninitMap))
3117 goto bail;
3118
3119 /*
3120 * Generate a register map.
3121 */
3122 if (generateRegisterMap) {
3123 RegisterMap* pMap;
3124 VerifierData vd;
3125
3126 vd.method = meth;
3127 vd.insnsSize = insnsSize;
3128 vd.insnRegCount = meth->registersSize;
3129 vd.insnFlags = insnFlags;
3130 vd.addrRegs = regTable.addrRegs;
3131
3132 pMap = dvmGenerateRegisterMapV(&vd);
3133 if (pMap != NULL) {
3134 /*
3135 * Tuck it into the Method struct. It will either get used
3136 * directly or, if we're in dexopt, will be packed up and
3137 * appended to the DEX file.
3138 */
3139 dvmSetRegisterMap((Method*)meth, pMap);
3140 }
3141 }
3142
3143 /*
3144 * Success.
3145 */
3146 result = true;
3147
3148 bail:
3149 free(regTable.addrRegs);
3150 free(regTable.regAlloc);
3151 return result;
3152 }
3153
3154 /*
3155 * Grind through the instructions.
3156 *
3157 * The basic strategy is as outlined in v3 4.11.1.2: set the "changed" bit
3158 * on the first instruction, process it (setting additional "changed" bits),
3159 * and repeat until there are no more.
3160 *
3161 * v3 4.11.1.1
3162 * - (N/A) operand stack is always the same size
3163 * - operand stack [registers] contain the correct types of values
3164 * - local variables [registers] contain the correct types of values
3165 * - methods are invoked with the appropriate arguments
3166 * - fields are assigned using values of appropriate types
3167 * - opcodes have the correct type values in operand registers
3168 * - there is never an uninitialized class instance in a local variable in
3169 * code protected by an exception handler (operand stack is okay, because
3170 * the operand stack is discarded when an exception is thrown) [can't
3171 * know what's a local var w/o the debug info -- should fall out of
3172 * register typing]
3173 *
3174 * v3 4.11.1.2
3175 * - execution cannot fall off the end of the code
3176 *
3177 * (We also do many of the items described in the "static checks" sections,
3178 * because it's easier to do them here.)
3179 *
3180 * We need an array of RegType values, one per register, for every
3181 * instruction. In theory this could become quite large -- up to several
3182 * megabytes for a monster function. For self-preservation we reject
3183 * anything that requires more than a certain amount of memory. (Typical
3184 * "large" should be on the order of 4K code units * 8 registers.) This
3185 * will likely have to be adjusted.
3186 *
3187 *
3188 * The spec forbids backward branches when there's an uninitialized reference
3189 * in a register. The idea is to prevent something like this:
3190 * loop:
3191 * move r1, r0
3192 * new-instance r0, MyClass
3193 * ...
3194 * if-eq rN, loop // once
3195 * initialize r0
3196 *
3197 * This leaves us with two different instances, both allocated by the
3198 * same instruction, but only one is initialized. The scheme outlined in
3199 * v3 4.11.1.4 wouldn't catch this, so they work around it by preventing
3200 * backward branches. We achieve identical results without restricting
3201 * code reordering by specifying that you can't execute the new-instance
3202 * instruction if a register contains an uninitialized instance created
3203 * by that same instrutcion.
3204 */
doCodeVerification(Method * meth,InsnFlags * insnFlags,RegisterTable * regTable,UninitInstanceMap * uninitMap)3205 static bool doCodeVerification(Method* meth, InsnFlags* insnFlags,
3206 RegisterTable* regTable, UninitInstanceMap* uninitMap)
3207 {
3208 const int insnsSize = dvmGetMethodInsnsSize(meth);
3209 const u2* insns = meth->insns;
3210 RegType workRegs[meth->registersSize + kExtraRegs];
3211 bool result = false;
3212 bool debugVerbose = false;
3213 int insnIdx, startGuess, prevAddr;
3214
3215 /*
3216 * Begin by marking the first instruction as "changed".
3217 */
3218 dvmInsnSetChanged(insnFlags, 0, true);
3219
3220 if (doVerboseLogging(meth)) {
3221 IF_LOGI() {
3222 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
3223 LOGI("Now verifying: %s.%s %s (ins=%d regs=%d)\n",
3224 meth->clazz->descriptor, meth->name, desc,
3225 meth->insSize, meth->registersSize);
3226 LOGI(" ------ [0 4 8 12 16 20 24 28 32 36\n");
3227 free(desc);
3228 }
3229 debugVerbose = true;
3230 gDebugVerbose = true;
3231 } else {
3232 gDebugVerbose = false;
3233 }
3234
3235 startGuess = 0;
3236
3237 /*
3238 * Continue until no instructions are marked "changed".
3239 */
3240 while (true) {
3241 /*
3242 * Find the first marked one. Use "startGuess" as a way to find
3243 * one quickly.
3244 */
3245 for (insnIdx = startGuess; insnIdx < insnsSize; insnIdx++) {
3246 if (dvmInsnIsChanged(insnFlags, insnIdx))
3247 break;
3248 }
3249
3250 if (insnIdx == insnsSize) {
3251 if (startGuess != 0) {
3252 /* try again, starting from the top */
3253 startGuess = 0;
3254 continue;
3255 } else {
3256 /* all flags are clear */
3257 break;
3258 }
3259 }
3260
3261 /*
3262 * We carry the working set of registers from instruction to
3263 * instruction. If this address can be the target of a branch
3264 * (or throw) instruction, or if we're skipping around chasing
3265 * "changed" flags, we need to load the set of registers from
3266 * the table.
3267 *
3268 * Because we always prefer to continue on to the next instruction,
3269 * we should never have a situation where we have a stray
3270 * "changed" flag set on an instruction that isn't a branch target.
3271 */
3272 if (dvmInsnIsBranchTarget(insnFlags, insnIdx)) {
3273 RegType* insnRegs = getRegisterLine(regTable, insnIdx);
3274 assert(insnRegs != NULL);
3275 copyRegisters(workRegs, insnRegs, meth->registersSize + kExtraRegs);
3276
3277 if (debugVerbose) {
3278 dumpRegTypes(meth, insnFlags, workRegs, insnIdx, NULL,uninitMap,
3279 SHOW_REG_DETAILS);
3280 }
3281
3282 } else {
3283 if (debugVerbose) {
3284 dumpRegTypes(meth, insnFlags, workRegs, insnIdx, NULL,uninitMap,
3285 SHOW_REG_DETAILS);
3286 }
3287
3288 #ifndef NDEBUG
3289 /*
3290 * Sanity check: retrieve the stored register line (assuming
3291 * a full table) and make sure it actually matches.
3292 */
3293 RegType* insnRegs = getRegisterLine(regTable, insnIdx);
3294 if (insnRegs != NULL &&
3295 compareRegisters(workRegs, insnRegs,
3296 meth->registersSize + kExtraRegs) != 0)
3297 {
3298 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
3299 LOG_VFY("HUH? workRegs diverged in %s.%s %s\n",
3300 meth->clazz->descriptor, meth->name, desc);
3301 free(desc);
3302 dumpRegTypes(meth, insnFlags, workRegs, 0, "work",
3303 uninitMap, DRT_SHOW_REF_TYPES | DRT_SHOW_LOCALS);
3304 dumpRegTypes(meth, insnFlags, insnRegs, 0, "insn",
3305 uninitMap, DRT_SHOW_REF_TYPES | DRT_SHOW_LOCALS);
3306 }
3307 #endif
3308 }
3309
3310 //LOGI("process %s.%s %s %d\n",
3311 // meth->clazz->descriptor, meth->name, meth->descriptor, insnIdx);
3312 if (!verifyInstruction(meth, insnFlags, regTable, workRegs, insnIdx,
3313 uninitMap, &startGuess))
3314 {
3315 //LOGD("+++ %s bailing at %d\n", meth->name, insnIdx);
3316 goto bail;
3317 }
3318
3319 #if 0
3320 {
3321 static const int gcMask = kInstrCanBranch | kInstrCanSwitch |
3322 kInstrCanThrow | kInstrCanReturn;
3323 OpCode opCode = *(meth->insns + insnIdx) & 0xff;
3324 int flags = dexGetInstrFlags(gDvm.instrFlags, opCode);
3325
3326 /* 8, 16, 32, or 32*n -bit regs */
3327 int regWidth = (meth->registersSize + 7) / 8;
3328 if (regWidth == 3)
3329 regWidth = 4;
3330 if (regWidth > 4) {
3331 regWidth = ((regWidth + 3) / 4) * 4;
3332 if (false) {
3333 LOGW("WOW: %d regs -> %d %s.%s\n",
3334 meth->registersSize, regWidth,
3335 meth->clazz->descriptor, meth->name);
3336 //x = true;
3337 }
3338 }
3339
3340 if ((flags & gcMask) != 0) {
3341 /* this is a potential GC point */
3342 gDvm__gcInstr++;
3343
3344 if (insnsSize < 256)
3345 gDvm__gcData += 1;
3346 else
3347 gDvm__gcData += 2;
3348 gDvm__gcData += regWidth;
3349 }
3350 gDvm__gcSimpleData += regWidth;
3351
3352 gDvm__totalInstr++;
3353 }
3354 #endif
3355
3356 /*
3357 * Clear "changed" and mark as visited.
3358 */
3359 dvmInsnSetVisited(insnFlags, insnIdx, true);
3360 dvmInsnSetChanged(insnFlags, insnIdx, false);
3361 }
3362
3363 if (DEAD_CODE_SCAN && !IS_METHOD_FLAG_SET(meth, METHOD_ISWRITABLE)) {
3364 /*
3365 * Scan for dead code. There's nothing "evil" about dead code
3366 * (besides the wasted space), but it indicates a flaw somewhere
3367 * down the line, possibly in the verifier.
3368 *
3369 * If we've rewritten "always throw" instructions into the stream,
3370 * we are almost certainly going to have some dead code.
3371 */
3372 int deadStart = -1;
3373 for (insnIdx = 0; insnIdx < insnsSize;
3374 insnIdx += dvmInsnGetWidth(insnFlags, insnIdx))
3375 {
3376 /*
3377 * Switch-statement data doesn't get "visited" by scanner. It
3378 * may or may not be preceded by a padding NOP.
3379 */
3380 int instr = meth->insns[insnIdx];
3381 if (instr == kPackedSwitchSignature ||
3382 instr == kSparseSwitchSignature ||
3383 instr == kArrayDataSignature ||
3384 (instr == OP_NOP &&
3385 (meth->insns[insnIdx+1] == kPackedSwitchSignature ||
3386 meth->insns[insnIdx+1] == kSparseSwitchSignature ||
3387 meth->insns[insnIdx+1] == kArrayDataSignature)))
3388 {
3389 dvmInsnSetVisited(insnFlags, insnIdx, true);
3390 }
3391
3392 if (!dvmInsnIsVisited(insnFlags, insnIdx)) {
3393 if (deadStart < 0)
3394 deadStart = insnIdx;
3395 } else if (deadStart >= 0) {
3396 IF_LOGD() {
3397 char* desc =
3398 dexProtoCopyMethodDescriptor(&meth->prototype);
3399 LOGD("VFY: dead code 0x%04x-%04x in %s.%s %s\n",
3400 deadStart, insnIdx-1,
3401 meth->clazz->descriptor, meth->name, desc);
3402 free(desc);
3403 }
3404
3405 deadStart = -1;
3406 }
3407 }
3408 if (deadStart >= 0) {
3409 IF_LOGD() {
3410 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
3411 LOGD("VFY: dead code 0x%04x-%04x in %s.%s %s\n",
3412 deadStart, insnIdx-1,
3413 meth->clazz->descriptor, meth->name, desc);
3414 free(desc);
3415 }
3416 }
3417 }
3418
3419 result = true;
3420
3421 bail:
3422 return result;
3423 }
3424
3425
3426 /*
3427 * Perform verification for a single instruction.
3428 *
3429 * This requires fully decoding the instruction to determine the effect
3430 * it has on registers.
3431 *
3432 * Finds zero or more following instructions and sets the "changed" flag
3433 * if execution at that point needs to be (re-)evaluated. Register changes
3434 * are merged into "regTypes" at the target addresses. Does not set or
3435 * clear any other flags in "insnFlags".
3436 *
3437 * This may alter meth->insns if we need to replace an instruction with
3438 * throw-verification-error.
3439 */
verifyInstruction(Method * meth,InsnFlags * insnFlags,RegisterTable * regTable,RegType * workRegs,int insnIdx,UninitInstanceMap * uninitMap,int * pStartGuess)3440 static bool verifyInstruction(Method* meth, InsnFlags* insnFlags,
3441 RegisterTable* regTable, RegType* workRegs, int insnIdx,
3442 UninitInstanceMap* uninitMap, int* pStartGuess)
3443 {
3444 const int insnsSize = dvmGetMethodInsnsSize(meth);
3445 const u2* insns = meth->insns + insnIdx;
3446 bool result = false;
3447
3448 /*
3449 * Once we finish decoding the instruction, we need to figure out where
3450 * we can go from here. There are three possible ways to transfer
3451 * control to another statement:
3452 *
3453 * (1) Continue to the next instruction. Applies to all but
3454 * unconditional branches, method returns, and exception throws.
3455 * (2) Branch to one or more possible locations. Applies to branches
3456 * and switch statements.
3457 * (3) Exception handlers. Applies to any instruction that can
3458 * throw an exception that is handled by an encompassing "try"
3459 * block. (We simplify this to be any instruction that can
3460 * throw any exception.)
3461 *
3462 * We can also return, in which case there is no successor instruction
3463 * from this point.
3464 *
3465 * The behavior can be determined from the InstrFlags.
3466 */
3467
3468 const DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
3469 RegType entryRegs[meth->registersSize + kExtraRegs];
3470 ClassObject* resClass;
3471 const char* className;
3472 int branchTarget = 0;
3473 const int insnRegCount = meth->registersSize;
3474 RegType tmpType;
3475 DecodedInstruction decInsn;
3476 bool justSetResult = false;
3477 VerifyError failure = VERIFY_ERROR_NONE;
3478
3479 #ifndef NDEBUG
3480 memset(&decInsn, 0x81, sizeof(decInsn));
3481 #endif
3482 dexDecodeInstruction(gDvm.instrFormat, insns, &decInsn);
3483
3484 int nextFlags = dexGetInstrFlags(gDvm.instrFlags, decInsn.opCode);
3485
3486 /*
3487 * Make a copy of the previous register state. If the instruction
3488 * throws an exception, we merge *this* into the destination rather
3489 * than workRegs, because we don't want the result from the "successful"
3490 * code path (e.g. a check-cast that "improves" a type) to be visible
3491 * to the exception handler.
3492 */
3493 if ((nextFlags & kInstrCanThrow) != 0 && dvmInsnIsInTry(insnFlags, insnIdx))
3494 {
3495 copyRegisters(entryRegs, workRegs, meth->registersSize + kExtraRegs);
3496 } else {
3497 #ifndef NDEBUG
3498 memset(entryRegs, 0xdd,
3499 (meth->registersSize + kExtraRegs) * sizeof(RegType));
3500 #endif
3501 }
3502
3503 switch (decInsn.opCode) {
3504 case OP_NOP:
3505 /*
3506 * A "pure" NOP has no effect on anything. Data tables start with
3507 * a signature that looks like a NOP; if we see one of these in
3508 * the course of executing code then we have a problem.
3509 */
3510 if (decInsn.vA != 0) {
3511 LOG_VFY("VFY: encountered data table in instruction stream\n");
3512 failure = VERIFY_ERROR_GENERIC;
3513 }
3514 break;
3515
3516 case OP_MOVE:
3517 case OP_MOVE_FROM16:
3518 case OP_MOVE_16:
3519 copyRegister1(workRegs, insnRegCount, decInsn.vA, decInsn.vB,
3520 kTypeCategory1nr, &failure);
3521 break;
3522 case OP_MOVE_WIDE:
3523 case OP_MOVE_WIDE_FROM16:
3524 case OP_MOVE_WIDE_16:
3525 copyRegister2(workRegs, insnRegCount, decInsn.vA, decInsn.vB, &failure);
3526 break;
3527 case OP_MOVE_OBJECT:
3528 case OP_MOVE_OBJECT_FROM16:
3529 case OP_MOVE_OBJECT_16:
3530 copyRegister1(workRegs, insnRegCount, decInsn.vA, decInsn.vB,
3531 kTypeCategoryRef, &failure);
3532 break;
3533
3534 /*
3535 * The move-result instructions copy data out of a "pseudo-register"
3536 * with the results from the last method invocation. In practice we
3537 * might want to hold the result in an actual CPU register, so the
3538 * Dalvik spec requires that these only appear immediately after an
3539 * invoke or filled-new-array.
3540 *
3541 * These calls invalidate the "result" register. (This is now
3542 * redundant with the reset done below, but it can make the debug info
3543 * easier to read in some cases.)
3544 */
3545 case OP_MOVE_RESULT:
3546 copyResultRegister1(workRegs, insnRegCount, decInsn.vA,
3547 kTypeCategory1nr, &failure);
3548 break;
3549 case OP_MOVE_RESULT_WIDE:
3550 copyResultRegister2(workRegs, insnRegCount, decInsn.vA, &failure);
3551 break;
3552 case OP_MOVE_RESULT_OBJECT:
3553 copyResultRegister1(workRegs, insnRegCount, decInsn.vA,
3554 kTypeCategoryRef, &failure);
3555 break;
3556
3557 case OP_MOVE_EXCEPTION:
3558 /*
3559 * This statement can only appear as the first instruction in an
3560 * exception handler (though not all exception handlers need to
3561 * have one of these). We verify that as part of extracting the
3562 * exception type from the catch block list.
3563 *
3564 * "resClass" will hold the closest common superclass of all
3565 * exceptions that can be handled here.
3566 */
3567 resClass = getCaughtExceptionType(meth, insnIdx, &failure);
3568 if (resClass == NULL) {
3569 assert(!VERIFY_OK(failure));
3570 } else {
3571 setRegisterType(workRegs, insnRegCount, decInsn.vA,
3572 regTypeFromClass(resClass), &failure);
3573 }
3574 break;
3575
3576 case OP_RETURN_VOID:
3577 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3578 failure = VERIFY_ERROR_GENERIC;
3579 } else if (getMethodReturnType(meth) != kRegTypeUnknown) {
3580 LOG_VFY("VFY: return-void not expected\n");
3581 failure = VERIFY_ERROR_GENERIC;
3582 }
3583 break;
3584 case OP_RETURN:
3585 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3586 failure = VERIFY_ERROR_GENERIC;
3587 } else {
3588 /* check the method signature */
3589 RegType returnType = getMethodReturnType(meth);
3590 checkTypeCategory(returnType, kTypeCategory1nr, &failure);
3591 if (!VERIFY_OK(failure))
3592 LOG_VFY("VFY: return-32 not expected\n");
3593
3594 /* check the register contents */
3595 returnType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
3596 &failure);
3597 checkTypeCategory(returnType, kTypeCategory1nr, &failure);
3598 if (!VERIFY_OK(failure))
3599 LOG_VFY("VFY: return-32 on invalid register v%d\n", decInsn.vA);
3600 }
3601 break;
3602 case OP_RETURN_WIDE:
3603 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3604 failure = VERIFY_ERROR_GENERIC;
3605 } else {
3606 RegType returnType, returnTypeHi;
3607
3608 /* check the method signature */
3609 returnType = getMethodReturnType(meth);
3610 checkTypeCategory(returnType, kTypeCategory2, &failure);
3611 if (!VERIFY_OK(failure))
3612 LOG_VFY("VFY: return-wide not expected\n");
3613
3614 /* check the register contents */
3615 returnType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
3616 &failure);
3617 returnTypeHi = getRegisterType(workRegs, insnRegCount,
3618 decInsn.vA +1, &failure);
3619 if (VERIFY_OK(failure)) {
3620 checkTypeCategory(returnType, kTypeCategory2, &failure);
3621 checkWidePair(returnType, returnTypeHi, &failure);
3622 }
3623 if (!VERIFY_OK(failure)) {
3624 LOG_VFY("VFY: return-wide on invalid register pair v%d\n",
3625 decInsn.vA);
3626 }
3627 }
3628 break;
3629 case OP_RETURN_OBJECT:
3630 if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
3631 failure = VERIFY_ERROR_GENERIC;
3632 } else {
3633 RegType returnType = getMethodReturnType(meth);
3634 checkTypeCategory(returnType, kTypeCategoryRef, &failure);
3635 if (!VERIFY_OK(failure)) {
3636 LOG_VFY("VFY: return-object not expected\n");
3637 break;
3638 }
3639
3640 /* returnType is the *expected* return type, not register value */
3641 assert(returnType != kRegTypeZero);
3642 assert(!regTypeIsUninitReference(returnType));
3643
3644 /*
3645 * Verify that the reference in vAA is an instance of the type
3646 * in "returnType". The Zero type is allowed here. If the
3647 * method is declared to return an interface, then any
3648 * initialized reference is acceptable.
3649 *
3650 * Note getClassFromRegister fails if the register holds an
3651 * uninitialized reference, so we do not allow them to be
3652 * returned.
3653 */
3654 ClassObject* declClass;
3655
3656 declClass = regTypeInitializedReferenceToClass(returnType);
3657 resClass = getClassFromRegister(workRegs, insnRegCount,
3658 decInsn.vA, &failure);
3659 if (!VERIFY_OK(failure))
3660 break;
3661 if (resClass != NULL) {
3662 if (!dvmIsInterfaceClass(declClass) &&
3663 !dvmInstanceof(resClass, declClass))
3664 {
3665 LOG_VFY("VFY: returning %s (cl=%p), declared %s (cl=%p)\n",
3666 resClass->descriptor, resClass->classLoader,
3667 declClass->descriptor, declClass->classLoader);
3668 failure = VERIFY_ERROR_GENERIC;
3669 break;
3670 }
3671 }
3672 }
3673 break;
3674
3675 case OP_CONST_4:
3676 case OP_CONST_16:
3677 case OP_CONST:
3678 /* could be boolean, int, float, or a null reference */
3679 setRegisterType(workRegs, insnRegCount, decInsn.vA,
3680 dvmDetermineCat1Const((s4)decInsn.vB), &failure);
3681 break;
3682 case OP_CONST_HIGH16:
3683 /* could be boolean, int, float, or a null reference */
3684 setRegisterType(workRegs, insnRegCount, decInsn.vA,
3685 dvmDetermineCat1Const((s4) decInsn.vB << 16), &failure);
3686 break;
3687 case OP_CONST_WIDE_16:
3688 case OP_CONST_WIDE_32:
3689 case OP_CONST_WIDE:
3690 case OP_CONST_WIDE_HIGH16:
3691 /* could be long or double; default to long and allow conversion */
3692 setRegisterType(workRegs, insnRegCount, decInsn.vA,
3693 kRegTypeLongLo, &failure);
3694 break;
3695 case OP_CONST_STRING:
3696 case OP_CONST_STRING_JUMBO:
3697 assert(gDvm.classJavaLangString != NULL);
3698 setRegisterType(workRegs, insnRegCount, decInsn.vA,
3699 regTypeFromClass(gDvm.classJavaLangString), &failure);
3700 break;
3701 case OP_CONST_CLASS:
3702 assert(gDvm.classJavaLangClass != NULL);
3703 /* make sure we can resolve the class; access check is important */
3704 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
3705 if (resClass == NULL) {
3706 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3707 dvmLogUnableToResolveClass(badClassDesc, meth);
3708 LOG_VFY("VFY: unable to resolve const-class %d (%s) in %s\n",
3709 decInsn.vB, badClassDesc, meth->clazz->descriptor);
3710 assert(failure != VERIFY_ERROR_GENERIC);
3711 } else {
3712 setRegisterType(workRegs, insnRegCount, decInsn.vA,
3713 regTypeFromClass(gDvm.classJavaLangClass), &failure);
3714 }
3715 break;
3716
3717 case OP_MONITOR_ENTER:
3718 case OP_MONITOR_EXIT:
3719 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
3720 if (VERIFY_OK(failure)) {
3721 if (!regTypeIsReference(tmpType)) {
3722 LOG_VFY("VFY: monitor op on non-object\n");
3723 failure = VERIFY_ERROR_GENERIC;
3724 }
3725 }
3726 break;
3727
3728 case OP_CHECK_CAST:
3729 /*
3730 * If this instruction succeeds, we will promote register vA to
3731 * the type in vB. (This could be a demotion -- not expected, so
3732 * we don't try to address it.)
3733 *
3734 * If it fails, an exception is thrown, which we deal with later
3735 * by ignoring the update to decInsn.vA when branching to a handler.
3736 */
3737 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
3738 if (resClass == NULL) {
3739 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3740 dvmLogUnableToResolveClass(badClassDesc, meth);
3741 LOG_VFY("VFY: unable to resolve check-cast %d (%s) in %s\n",
3742 decInsn.vB, badClassDesc, meth->clazz->descriptor);
3743 assert(failure != VERIFY_ERROR_GENERIC);
3744 } else {
3745 RegType origType;
3746
3747 origType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
3748 &failure);
3749 if (!VERIFY_OK(failure))
3750 break;
3751 if (!regTypeIsReference(origType)) {
3752 LOG_VFY("VFY: check-cast on non-reference in v%u\n",decInsn.vA);
3753 failure = VERIFY_ERROR_GENERIC;
3754 break;
3755 }
3756 setRegisterType(workRegs, insnRegCount, decInsn.vA,
3757 regTypeFromClass(resClass), &failure);
3758 }
3759 break;
3760 case OP_INSTANCE_OF:
3761 /* make sure we're checking a reference type */
3762 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vB, &failure);
3763 if (!VERIFY_OK(failure))
3764 break;
3765 if (!regTypeIsReference(tmpType)) {
3766 LOG_VFY("VFY: vB not a reference (%d)\n", tmpType);
3767 failure = VERIFY_ERROR_GENERIC;
3768 break;
3769 }
3770
3771 /* make sure we can resolve the class; access check is important */
3772 resClass = dvmOptResolveClass(meth->clazz, decInsn.vC, &failure);
3773 if (resClass == NULL) {
3774 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vC);
3775 dvmLogUnableToResolveClass(badClassDesc, meth);
3776 LOG_VFY("VFY: unable to resolve instanceof %d (%s) in %s\n",
3777 decInsn.vC, badClassDesc, meth->clazz->descriptor);
3778 assert(failure != VERIFY_ERROR_GENERIC);
3779 } else {
3780 /* result is boolean */
3781 setRegisterType(workRegs, insnRegCount, decInsn.vA,
3782 kRegTypeBoolean, &failure);
3783 }
3784 break;
3785
3786 case OP_ARRAY_LENGTH:
3787 resClass = getClassFromRegister(workRegs, insnRegCount,
3788 decInsn.vB, &failure);
3789 if (!VERIFY_OK(failure))
3790 break;
3791 if (resClass != NULL && !dvmIsArrayClass(resClass)) {
3792 LOG_VFY("VFY: array-length on non-array\n");
3793 failure = VERIFY_ERROR_GENERIC;
3794 break;
3795 }
3796 setRegisterType(workRegs, insnRegCount, decInsn.vA, kRegTypeInteger,
3797 &failure);
3798 break;
3799
3800 case OP_NEW_INSTANCE:
3801 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
3802 if (resClass == NULL) {
3803 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3804 dvmLogUnableToResolveClass(badClassDesc, meth);
3805 LOG_VFY("VFY: unable to resolve new-instance %d (%s) in %s\n",
3806 decInsn.vB, badClassDesc, meth->clazz->descriptor);
3807 assert(failure != VERIFY_ERROR_GENERIC);
3808 } else {
3809 RegType uninitType;
3810
3811 /* can't create an instance of an interface or abstract class */
3812 if (dvmIsAbstractClass(resClass) || dvmIsInterfaceClass(resClass)) {
3813 LOG_VFY("VFY: new-instance on interface or abstract class %s\n",
3814 resClass->descriptor);
3815 failure = VERIFY_ERROR_INSTANTIATION;
3816 break;
3817 }
3818
3819 /* add resolved class to uninit map if not already there */
3820 int uidx = dvmSetUninitInstance(uninitMap, insnIdx, resClass);
3821 assert(uidx >= 0);
3822 uninitType = regTypeFromUninitIndex(uidx);
3823
3824 /*
3825 * Any registers holding previous allocations from this address
3826 * that have not yet been initialized must be marked invalid.
3827 */
3828 markUninitRefsAsInvalid(workRegs, insnRegCount, uninitMap,
3829 uninitType);
3830
3831 /* add the new uninitialized reference to the register ste */
3832 setRegisterType(workRegs, insnRegCount, decInsn.vA,
3833 uninitType, &failure);
3834 }
3835 break;
3836 case OP_NEW_ARRAY:
3837 resClass = dvmOptResolveClass(meth->clazz, decInsn.vC, &failure);
3838 if (resClass == NULL) {
3839 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vC);
3840 dvmLogUnableToResolveClass(badClassDesc, meth);
3841 LOG_VFY("VFY: unable to resolve new-array %d (%s) in %s\n",
3842 decInsn.vC, badClassDesc, meth->clazz->descriptor);
3843 assert(failure != VERIFY_ERROR_GENERIC);
3844 } else if (!dvmIsArrayClass(resClass)) {
3845 LOG_VFY("VFY: new-array on non-array class\n");
3846 failure = VERIFY_ERROR_GENERIC;
3847 } else {
3848 /* make sure "size" register is valid type */
3849 verifyRegisterType(workRegs, insnRegCount, decInsn.vB,
3850 kRegTypeInteger, &failure);
3851 /* set register type to array class */
3852 setRegisterType(workRegs, insnRegCount, decInsn.vA,
3853 regTypeFromClass(resClass), &failure);
3854 }
3855 break;
3856 case OP_FILLED_NEW_ARRAY:
3857 case OP_FILLED_NEW_ARRAY_RANGE:
3858 resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
3859 if (resClass == NULL) {
3860 const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
3861 dvmLogUnableToResolveClass(badClassDesc, meth);
3862 LOG_VFY("VFY: unable to resolve filled-array %d (%s) in %s\n",
3863 decInsn.vB, badClassDesc, meth->clazz->descriptor);
3864 assert(failure != VERIFY_ERROR_GENERIC);
3865 } else if (!dvmIsArrayClass(resClass)) {
3866 LOG_VFY("VFY: filled-new-array on non-array class\n");
3867 failure = VERIFY_ERROR_GENERIC;
3868 } else {
3869 bool isRange = (decInsn.opCode == OP_FILLED_NEW_ARRAY_RANGE);
3870
3871 /* check the arguments to the instruction */
3872 verifyFilledNewArrayRegs(meth, workRegs, insnRegCount, &decInsn,
3873 resClass, isRange, &failure);
3874 /* filled-array result goes into "result" register */
3875 setResultRegisterType(workRegs, insnRegCount,
3876 regTypeFromClass(resClass), &failure);
3877 justSetResult = true;
3878 }
3879 break;
3880
3881 case OP_CMPL_FLOAT:
3882 case OP_CMPG_FLOAT:
3883 verifyRegisterType(workRegs, insnRegCount, decInsn.vB, kRegTypeFloat,
3884 &failure);
3885 verifyRegisterType(workRegs, insnRegCount, decInsn.vC, kRegTypeFloat,
3886 &failure);
3887 setRegisterType(workRegs, insnRegCount, decInsn.vA, kRegTypeBoolean,
3888 &failure);
3889 break;
3890 case OP_CMPL_DOUBLE:
3891 case OP_CMPG_DOUBLE:
3892 verifyRegisterType(workRegs, insnRegCount, decInsn.vB, kRegTypeDoubleLo,
3893 &failure);
3894 verifyRegisterType(workRegs, insnRegCount, decInsn.vC, kRegTypeDoubleLo,
3895 &failure);
3896 setRegisterType(workRegs, insnRegCount, decInsn.vA, kRegTypeBoolean,
3897 &failure);
3898 break;
3899 case OP_CMP_LONG:
3900 verifyRegisterType(workRegs, insnRegCount, decInsn.vB, kRegTypeLongLo,
3901 &failure);
3902 verifyRegisterType(workRegs, insnRegCount, decInsn.vC, kRegTypeLongLo,
3903 &failure);
3904 setRegisterType(workRegs, insnRegCount, decInsn.vA, kRegTypeBoolean,
3905 &failure);
3906 break;
3907
3908 case OP_THROW:
3909 resClass = getClassFromRegister(workRegs, insnRegCount,
3910 decInsn.vA, &failure);
3911 if (VERIFY_OK(failure) && resClass != NULL) {
3912 if (!dvmInstanceof(resClass, gDvm.classJavaLangThrowable)) {
3913 LOG_VFY("VFY: thrown class %s not instanceof Throwable\n",
3914 resClass->descriptor);
3915 failure = VERIFY_ERROR_GENERIC;
3916 }
3917 }
3918 break;
3919
3920 case OP_GOTO:
3921 case OP_GOTO_16:
3922 case OP_GOTO_32:
3923 /* no effect on or use of registers */
3924 break;
3925
3926 case OP_PACKED_SWITCH:
3927 case OP_SPARSE_SWITCH:
3928 /* verify that vAA is an integer, or can be converted to one */
3929 verifyRegisterType(workRegs, insnRegCount, decInsn.vA,
3930 kRegTypeInteger, &failure);
3931 break;
3932
3933 case OP_FILL_ARRAY_DATA:
3934 {
3935 RegType valueType;
3936 const u2 *arrayData;
3937 u2 elemWidth;
3938
3939 /* Similar to the verification done for APUT */
3940 resClass = getClassFromRegister(workRegs, insnRegCount,
3941 decInsn.vA, &failure);
3942 if (!VERIFY_OK(failure))
3943 break;
3944
3945 /* resClass can be null if the reg type is Zero */
3946 if (resClass == NULL)
3947 break;
3948
3949 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
3950 resClass->elementClass->primitiveType == PRIM_NOT ||
3951 resClass->elementClass->primitiveType == PRIM_VOID)
3952 {
3953 LOG_VFY("VFY: invalid fill-array-data on %s\n",
3954 resClass->descriptor);
3955 failure = VERIFY_ERROR_GENERIC;
3956 break;
3957 }
3958
3959 valueType = primitiveTypeToRegType(
3960 resClass->elementClass->primitiveType);
3961 assert(valueType != kRegTypeUnknown);
3962
3963 /*
3964 * Now verify if the element width in the table matches the element
3965 * width declared in the array
3966 */
3967 arrayData = insns + (insns[1] | (((s4)insns[2]) << 16));
3968 if (arrayData[0] != kArrayDataSignature) {
3969 LOG_VFY("VFY: invalid magic for array-data\n");
3970 failure = VERIFY_ERROR_GENERIC;
3971 break;
3972 }
3973
3974 switch (resClass->elementClass->primitiveType) {
3975 case PRIM_BOOLEAN:
3976 case PRIM_BYTE:
3977 elemWidth = 1;
3978 break;
3979 case PRIM_CHAR:
3980 case PRIM_SHORT:
3981 elemWidth = 2;
3982 break;
3983 case PRIM_FLOAT:
3984 case PRIM_INT:
3985 elemWidth = 4;
3986 break;
3987 case PRIM_DOUBLE:
3988 case PRIM_LONG:
3989 elemWidth = 8;
3990 break;
3991 default:
3992 elemWidth = 0;
3993 break;
3994 }
3995
3996 /*
3997 * Since we don't compress the data in Dex, expect to see equal
3998 * width of data stored in the table and expected from the array
3999 * class.
4000 */
4001 if (arrayData[1] != elemWidth) {
4002 LOG_VFY("VFY: array-data size mismatch (%d vs %d)\n",
4003 arrayData[1], elemWidth);
4004 failure = VERIFY_ERROR_GENERIC;
4005 }
4006 }
4007 break;
4008
4009 case OP_IF_EQ:
4010 case OP_IF_NE:
4011 {
4012 RegType type1, type2;
4013 bool tmpResult;
4014
4015 type1 = getRegisterType(workRegs, insnRegCount, decInsn.vA,
4016 &failure);
4017 type2 = getRegisterType(workRegs, insnRegCount, decInsn.vB,
4018 &failure);
4019 if (!VERIFY_OK(failure))
4020 break;
4021
4022 /* both references? */
4023 if (regTypeIsReference(type1) && regTypeIsReference(type2))
4024 break;
4025
4026 /* both category-1nr? */
4027 checkTypeCategory(type1, kTypeCategory1nr, &failure);
4028 checkTypeCategory(type2, kTypeCategory1nr, &failure);
4029 if (!VERIFY_OK(failure)) {
4030 LOG_VFY("VFY: args to if-eq/if-ne must both be refs or cat1\n");
4031 break;
4032 }
4033 }
4034 break;
4035 case OP_IF_LT:
4036 case OP_IF_GE:
4037 case OP_IF_GT:
4038 case OP_IF_LE:
4039 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4040 if (!VERIFY_OK(failure))
4041 break;
4042 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
4043 if (!VERIFY_OK(failure)) {
4044 LOG_VFY("VFY: args to 'if' must be cat-1nr\n");
4045 break;
4046 }
4047 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vB, &failure);
4048 if (!VERIFY_OK(failure))
4049 break;
4050 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
4051 if (!VERIFY_OK(failure)) {
4052 LOG_VFY("VFY: args to 'if' must be cat-1nr\n");
4053 break;
4054 }
4055 break;
4056 case OP_IF_EQZ:
4057 case OP_IF_NEZ:
4058 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4059 if (!VERIFY_OK(failure))
4060 break;
4061 if (regTypeIsReference(tmpType))
4062 break;
4063 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
4064 if (!VERIFY_OK(failure))
4065 LOG_VFY("VFY: expected cat-1 arg to if\n");
4066 break;
4067 case OP_IF_LTZ:
4068 case OP_IF_GEZ:
4069 case OP_IF_GTZ:
4070 case OP_IF_LEZ:
4071 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4072 if (!VERIFY_OK(failure))
4073 break;
4074 checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
4075 if (!VERIFY_OK(failure))
4076 LOG_VFY("VFY: expected cat-1 arg to if\n");
4077 break;
4078
4079 case OP_AGET:
4080 tmpType = kRegTypeInteger;
4081 goto aget_1nr_common;
4082 case OP_AGET_BOOLEAN:
4083 tmpType = kRegTypeBoolean;
4084 goto aget_1nr_common;
4085 case OP_AGET_BYTE:
4086 tmpType = kRegTypeByte;
4087 goto aget_1nr_common;
4088 case OP_AGET_CHAR:
4089 tmpType = kRegTypeChar;
4090 goto aget_1nr_common;
4091 case OP_AGET_SHORT:
4092 tmpType = kRegTypeShort;
4093 goto aget_1nr_common;
4094 aget_1nr_common:
4095 {
4096 RegType srcType, indexType;
4097
4098 indexType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
4099 &failure);
4100 checkArrayIndexType(meth, indexType, &failure);
4101 if (!VERIFY_OK(failure))
4102 break;
4103
4104 resClass = getClassFromRegister(workRegs, insnRegCount,
4105 decInsn.vB, &failure);
4106 if (!VERIFY_OK(failure))
4107 break;
4108 if (resClass != NULL) {
4109 /* verify the class */
4110 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4111 resClass->elementClass->primitiveType == PRIM_NOT)
4112 {
4113 LOG_VFY("VFY: invalid aget-1nr target %s\n",
4114 resClass->descriptor);
4115 failure = VERIFY_ERROR_GENERIC;
4116 break;
4117 }
4118
4119 /* make sure array type matches instruction */
4120 srcType = primitiveTypeToRegType(
4121 resClass->elementClass->primitiveType);
4122
4123 if (!checkFieldArrayStore1nr(tmpType, srcType)) {
4124 LOG_VFY("VFY: invalid aget-1nr, array type=%d with"
4125 " inst type=%d (on %s)\n",
4126 srcType, tmpType, resClass->descriptor);
4127 failure = VERIFY_ERROR_GENERIC;
4128 break;
4129 }
4130
4131 }
4132 setRegisterType(workRegs, insnRegCount, decInsn.vA,
4133 tmpType, &failure);
4134 }
4135 break;
4136
4137 case OP_AGET_WIDE:
4138 {
4139 RegType dstType, indexType;
4140
4141 indexType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
4142 &failure);
4143 checkArrayIndexType(meth, indexType, &failure);
4144 if (!VERIFY_OK(failure))
4145 break;
4146
4147 resClass = getClassFromRegister(workRegs, insnRegCount,
4148 decInsn.vB, &failure);
4149 if (!VERIFY_OK(failure))
4150 break;
4151 if (resClass != NULL) {
4152 /* verify the class */
4153 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4154 resClass->elementClass->primitiveType == PRIM_NOT)
4155 {
4156 LOG_VFY("VFY: invalid aget-wide target %s\n",
4157 resClass->descriptor);
4158 failure = VERIFY_ERROR_GENERIC;
4159 break;
4160 }
4161
4162 /* try to refine "dstType" */
4163 switch (resClass->elementClass->primitiveType) {
4164 case PRIM_LONG:
4165 dstType = kRegTypeLongLo;
4166 break;
4167 case PRIM_DOUBLE:
4168 dstType = kRegTypeDoubleLo;
4169 break;
4170 default:
4171 LOG_VFY("VFY: invalid aget-wide on %s\n",
4172 resClass->descriptor);
4173 dstType = kRegTypeUnknown;
4174 failure = VERIFY_ERROR_GENERIC;
4175 break;
4176 }
4177 } else {
4178 /*
4179 * Null array ref; this code path will fail at runtime. We
4180 * know this is either long or double, and we don't really
4181 * discriminate between those during verification, so we
4182 * call it a long.
4183 */
4184 dstType = kRegTypeLongLo;
4185 }
4186 setRegisterType(workRegs, insnRegCount, decInsn.vA,
4187 dstType, &failure);
4188 }
4189 break;
4190
4191 case OP_AGET_OBJECT:
4192 {
4193 RegType dstType, indexType;
4194
4195 indexType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
4196 &failure);
4197 checkArrayIndexType(meth, indexType, &failure);
4198 if (!VERIFY_OK(failure))
4199 break;
4200
4201 /* get the class of the array we're pulling an object from */
4202 resClass = getClassFromRegister(workRegs, insnRegCount,
4203 decInsn.vB, &failure);
4204 if (!VERIFY_OK(failure))
4205 break;
4206 if (resClass != NULL) {
4207 ClassObject* elementClass;
4208
4209 assert(resClass != NULL);
4210 if (!dvmIsArrayClass(resClass)) {
4211 LOG_VFY("VFY: aget-object on non-array class\n");
4212 failure = VERIFY_ERROR_GENERIC;
4213 break;
4214 }
4215 assert(resClass->elementClass != NULL);
4216
4217 /*
4218 * Find the element class. resClass->elementClass indicates
4219 * the basic type, which won't be what we want for a
4220 * multi-dimensional array.
4221 */
4222 if (resClass->descriptor[1] == '[') {
4223 assert(resClass->arrayDim > 1);
4224 elementClass = dvmFindArrayClass(&resClass->descriptor[1],
4225 resClass->classLoader);
4226 } else if (resClass->descriptor[1] == 'L') {
4227 assert(resClass->arrayDim == 1);
4228 elementClass = resClass->elementClass;
4229 } else {
4230 LOG_VFY("VFY: aget-object on non-ref array class (%s)\n",
4231 resClass->descriptor);
4232 failure = VERIFY_ERROR_GENERIC;
4233 break;
4234 }
4235
4236 dstType = regTypeFromClass(elementClass);
4237 } else {
4238 /*
4239 * The array reference is NULL, so the current code path will
4240 * throw an exception. For proper merging with later code
4241 * paths, and correct handling of "if-eqz" tests on the
4242 * result of the array get, we want to treat this as a null
4243 * reference.
4244 */
4245 dstType = kRegTypeZero;
4246 }
4247 setRegisterType(workRegs, insnRegCount, decInsn.vA,
4248 dstType, &failure);
4249 }
4250 break;
4251 case OP_APUT:
4252 tmpType = kRegTypeInteger;
4253 goto aput_1nr_common;
4254 case OP_APUT_BOOLEAN:
4255 tmpType = kRegTypeBoolean;
4256 goto aput_1nr_common;
4257 case OP_APUT_BYTE:
4258 tmpType = kRegTypeByte;
4259 goto aput_1nr_common;
4260 case OP_APUT_CHAR:
4261 tmpType = kRegTypeChar;
4262 goto aput_1nr_common;
4263 case OP_APUT_SHORT:
4264 tmpType = kRegTypeShort;
4265 goto aput_1nr_common;
4266 aput_1nr_common:
4267 {
4268 RegType srcType, dstType, indexType;
4269
4270 indexType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
4271 &failure);
4272 checkArrayIndexType(meth, indexType, &failure);
4273 if (!VERIFY_OK(failure))
4274 break;
4275
4276 /* make sure the source register has the correct type */
4277 srcType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
4278 &failure);
4279 if (!canConvertTo1nr(srcType, tmpType)) {
4280 LOG_VFY("VFY: invalid reg type %d on aput instr (need %d)\n",
4281 srcType, tmpType);
4282 failure = VERIFY_ERROR_GENERIC;
4283 break;
4284 }
4285
4286 resClass = getClassFromRegister(workRegs, insnRegCount,
4287 decInsn.vB, &failure);
4288 if (!VERIFY_OK(failure))
4289 break;
4290
4291 /* resClass can be null if the reg type is Zero */
4292 if (resClass == NULL)
4293 break;
4294
4295 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4296 resClass->elementClass->primitiveType == PRIM_NOT)
4297 {
4298 LOG_VFY("VFY: invalid aput-1nr on %s\n", resClass->descriptor);
4299 failure = VERIFY_ERROR_GENERIC;
4300 break;
4301 }
4302
4303 /* verify that instruction matches array */
4304 dstType = primitiveTypeToRegType(
4305 resClass->elementClass->primitiveType);
4306 assert(dstType != kRegTypeUnknown);
4307
4308 if (!checkFieldArrayStore1nr(tmpType, dstType)) {
4309 LOG_VFY("VFY: invalid aput-1nr on %s (inst=%d dst=%d)\n",
4310 resClass->descriptor, tmpType, dstType);
4311 failure = VERIFY_ERROR_GENERIC;
4312 break;
4313 }
4314 }
4315 break;
4316 case OP_APUT_WIDE:
4317 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
4318 &failure);
4319 checkArrayIndexType(meth, tmpType, &failure);
4320 if (!VERIFY_OK(failure))
4321 break;
4322
4323 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4324 if (VERIFY_OK(failure)) {
4325 RegType typeHi =
4326 getRegisterType(workRegs, insnRegCount, decInsn.vA+1, &failure);
4327 checkTypeCategory(tmpType, kTypeCategory2, &failure);
4328 checkWidePair(tmpType, typeHi, &failure);
4329 }
4330 if (!VERIFY_OK(failure))
4331 break;
4332
4333 resClass = getClassFromRegister(workRegs, insnRegCount,
4334 decInsn.vB, &failure);
4335 if (!VERIFY_OK(failure))
4336 break;
4337 if (resClass != NULL) {
4338 /* verify the class and try to refine "dstType" */
4339 if (!dvmIsArrayClass(resClass) || resClass->arrayDim != 1 ||
4340 resClass->elementClass->primitiveType == PRIM_NOT)
4341 {
4342 LOG_VFY("VFY: invalid aput-wide on %s\n",
4343 resClass->descriptor);
4344 failure = VERIFY_ERROR_GENERIC;
4345 break;
4346 }
4347
4348 switch (resClass->elementClass->primitiveType) {
4349 case PRIM_LONG:
4350 case PRIM_DOUBLE:
4351 /* these are okay */
4352 break;
4353 default:
4354 LOG_VFY("VFY: invalid aput-wide on %s\n",
4355 resClass->descriptor);
4356 failure = VERIFY_ERROR_GENERIC;
4357 break;
4358 }
4359 }
4360 break;
4361 case OP_APUT_OBJECT:
4362 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
4363 &failure);
4364 checkArrayIndexType(meth, tmpType, &failure);
4365 if (!VERIFY_OK(failure))
4366 break;
4367
4368 /* get the ref we're storing; Zero is okay, Uninit is not */
4369 resClass = getClassFromRegister(workRegs, insnRegCount,
4370 decInsn.vA, &failure);
4371 if (!VERIFY_OK(failure))
4372 break;
4373 if (resClass != NULL) {
4374 ClassObject* arrayClass;
4375 ClassObject* elementClass;
4376
4377 /*
4378 * Get the array class. If the array ref is null, we won't
4379 * have type information (and we'll crash at runtime with a
4380 * null pointer exception).
4381 */
4382 arrayClass = getClassFromRegister(workRegs, insnRegCount,
4383 decInsn.vB, &failure);
4384
4385 if (arrayClass != NULL) {
4386 /* see if the array holds a compatible type */
4387 if (!dvmIsArrayClass(arrayClass)) {
4388 LOG_VFY("VFY: invalid aput-object on %s\n",
4389 arrayClass->descriptor);
4390 failure = VERIFY_ERROR_GENERIC;
4391 break;
4392 }
4393
4394 /*
4395 * Find the element class. resClass->elementClass indicates
4396 * the basic type, which won't be what we want for a
4397 * multi-dimensional array.
4398 *
4399 * All we want to check here is that the element type is a
4400 * reference class. We *don't* check instanceof here, because
4401 * you can still put a String into a String[] after the latter
4402 * has been cast to an Object[].
4403 */
4404 if (arrayClass->descriptor[1] == '[') {
4405 assert(arrayClass->arrayDim > 1);
4406 elementClass = dvmFindArrayClass(&arrayClass->descriptor[1],
4407 arrayClass->classLoader);
4408 } else {
4409 assert(arrayClass->arrayDim == 1);
4410 elementClass = arrayClass->elementClass;
4411 }
4412 if (elementClass->primitiveType != PRIM_NOT) {
4413 LOG_VFY("VFY: invalid aput-object of %s into %s\n",
4414 resClass->descriptor, arrayClass->descriptor);
4415 failure = VERIFY_ERROR_GENERIC;
4416 break;
4417 }
4418 }
4419 }
4420 break;
4421
4422 case OP_IGET:
4423 tmpType = kRegTypeInteger;
4424 goto iget_1nr_common;
4425 case OP_IGET_BOOLEAN:
4426 tmpType = kRegTypeBoolean;
4427 goto iget_1nr_common;
4428 case OP_IGET_BYTE:
4429 tmpType = kRegTypeByte;
4430 goto iget_1nr_common;
4431 case OP_IGET_CHAR:
4432 tmpType = kRegTypeChar;
4433 goto iget_1nr_common;
4434 case OP_IGET_SHORT:
4435 tmpType = kRegTypeShort;
4436 goto iget_1nr_common;
4437 iget_1nr_common:
4438 {
4439 ClassObject* fieldClass;
4440 InstField* instField;
4441 RegType objType, fieldType;
4442
4443 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
4444 &failure);
4445 if (!VERIFY_OK(failure))
4446 break;
4447 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
4448 &failure);
4449 if (!VERIFY_OK(failure))
4450 break;
4451
4452 /* make sure the field's type is compatible with expectation */
4453 fieldType = primSigCharToRegType(instField->field.signature[0]);
4454 if (fieldType == kRegTypeUnknown ||
4455 !checkFieldArrayStore1nr(tmpType, fieldType))
4456 {
4457 LOG_VFY("VFY: invalid iget-1nr of %s.%s (inst=%d field=%d)\n",
4458 instField->field.clazz->descriptor,
4459 instField->field.name, tmpType, fieldType);
4460 failure = VERIFY_ERROR_GENERIC;
4461 break;
4462 }
4463
4464 setRegisterType(workRegs, insnRegCount, decInsn.vA, tmpType,
4465 &failure);
4466 }
4467 break;
4468 case OP_IGET_WIDE:
4469 {
4470 RegType dstType;
4471 ClassObject* fieldClass;
4472 InstField* instField;
4473 RegType objType;
4474
4475 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
4476 &failure);
4477 if (!VERIFY_OK(failure))
4478 break;
4479 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
4480 &failure);
4481 if (!VERIFY_OK(failure))
4482 break;
4483 /* check the type, which should be prim */
4484 switch (instField->field.signature[0]) {
4485 case 'D':
4486 dstType = kRegTypeDoubleLo;
4487 break;
4488 case 'J':
4489 dstType = kRegTypeLongLo;
4490 break;
4491 default:
4492 LOG_VFY("VFY: invalid iget-wide of %s.%s\n",
4493 instField->field.clazz->descriptor,
4494 instField->field.name);
4495 dstType = kRegTypeUnknown;
4496 failure = VERIFY_ERROR_GENERIC;
4497 break;
4498 }
4499 if (VERIFY_OK(failure)) {
4500 setRegisterType(workRegs, insnRegCount, decInsn.vA,
4501 dstType, &failure);
4502 }
4503 }
4504 break;
4505 case OP_IGET_OBJECT:
4506 {
4507 ClassObject* fieldClass;
4508 InstField* instField;
4509 RegType objType;
4510
4511 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
4512 &failure);
4513 if (!VERIFY_OK(failure))
4514 break;
4515 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
4516 &failure);
4517 if (!VERIFY_OK(failure))
4518 break;
4519 fieldClass = getFieldClass(meth, &instField->field);
4520 if (fieldClass == NULL) {
4521 /* class not found or primitive type */
4522 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4523 instField->field.signature);
4524 failure = VERIFY_ERROR_GENERIC;
4525 break;
4526 }
4527 if (VERIFY_OK(failure)) {
4528 assert(!dvmIsPrimitiveClass(fieldClass));
4529 setRegisterType(workRegs, insnRegCount, decInsn.vA,
4530 regTypeFromClass(fieldClass), &failure);
4531 }
4532 }
4533 break;
4534 case OP_IPUT:
4535 tmpType = kRegTypeInteger;
4536 goto iput_1nr_common;
4537 case OP_IPUT_BOOLEAN:
4538 tmpType = kRegTypeBoolean;
4539 goto iput_1nr_common;
4540 case OP_IPUT_BYTE:
4541 tmpType = kRegTypeByte;
4542 goto iput_1nr_common;
4543 case OP_IPUT_CHAR:
4544 tmpType = kRegTypeChar;
4545 goto iput_1nr_common;
4546 case OP_IPUT_SHORT:
4547 tmpType = kRegTypeShort;
4548 goto iput_1nr_common;
4549 iput_1nr_common:
4550 {
4551 RegType srcType, fieldType, objType;
4552 ClassObject* fieldClass;
4553 InstField* instField;
4554
4555 srcType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
4556 &failure);
4557
4558 /*
4559 * javac generates synthetic functions that write byte values
4560 * into boolean fields.
4561 */
4562 if (tmpType == kRegTypeBoolean && srcType == kRegTypeByte)
4563 srcType = kRegTypeBoolean;
4564
4565 /* make sure the source register has the correct type */
4566 if (!canConvertTo1nr(srcType, tmpType)) {
4567 LOG_VFY("VFY: invalid reg type %d on iput instr (need %d)\n",
4568 srcType, tmpType);
4569 failure = VERIFY_ERROR_GENERIC;
4570 break;
4571 }
4572
4573 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
4574 &failure);
4575 if (!VERIFY_OK(failure))
4576 break;
4577 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
4578 &failure);
4579 if (!VERIFY_OK(failure))
4580 break;
4581 checkFinalFieldAccess(meth, &instField->field, &failure);
4582 if (!VERIFY_OK(failure))
4583 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);
4593 failure = VERIFY_ERROR_GENERIC;
4594 break;
4595 }
4596 }
4597 break;
4598 case OP_IPUT_WIDE:
4599 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4600 if (VERIFY_OK(failure)) {
4601 RegType typeHi =
4602 getRegisterType(workRegs, insnRegCount, decInsn.vA+1, &failure);
4603 checkTypeCategory(tmpType, kTypeCategory2, &failure);
4604 checkWidePair(tmpType, typeHi, &failure);
4605 }
4606 if (VERIFY_OK(failure)) {
4607 ClassObject* fieldClass;
4608 InstField* instField;
4609 RegType objType;
4610
4611 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
4612 &failure);
4613 if (!VERIFY_OK(failure))
4614 break;
4615 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
4616 &failure);
4617 if (!VERIFY_OK(failure))
4618 break;
4619 checkFinalFieldAccess(meth, &instField->field, &failure);
4620 if (!VERIFY_OK(failure))
4621 break;
4622
4623 /* check the type, which should be prim */
4624 switch (instField->field.signature[0]) {
4625 case 'D':
4626 case 'J':
4627 /* these are okay (and interchangeable) */
4628 break;
4629 default:
4630 LOG_VFY("VFY: invalid iput-wide of %s.%s\n",
4631 instField->field.clazz->descriptor,
4632 instField->field.name);
4633 failure = VERIFY_ERROR_GENERIC;
4634 break;
4635 }
4636 }
4637 break;
4638 case OP_IPUT_OBJECT:
4639 {
4640 ClassObject* fieldClass;
4641 ClassObject* valueClass;
4642 InstField* instField;
4643 RegType objType, valueType;
4644
4645 objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
4646 &failure);
4647 if (!VERIFY_OK(failure))
4648 break;
4649 instField = getInstField(meth, uninitMap, objType, decInsn.vC,
4650 &failure);
4651 if (!VERIFY_OK(failure))
4652 break;
4653 checkFinalFieldAccess(meth, &instField->field, &failure);
4654 if (!VERIFY_OK(failure))
4655 break;
4656
4657 fieldClass = getFieldClass(meth, &instField->field);
4658 if (fieldClass == NULL) {
4659 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4660 instField->field.signature);
4661 failure = VERIFY_ERROR_GENERIC;
4662 break;
4663 }
4664
4665 valueType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
4666 &failure);
4667 if (!VERIFY_OK(failure))
4668 break;
4669 if (!regTypeIsReference(valueType)) {
4670 LOG_VFY("VFY: storing non-ref v%d into ref field '%s' (%s)\n",
4671 decInsn.vA, instField->field.name,
4672 fieldClass->descriptor);
4673 failure = VERIFY_ERROR_GENERIC;
4674 break;
4675 }
4676 if (valueType != kRegTypeZero) {
4677 valueClass = regTypeInitializedReferenceToClass(valueType);
4678 if (valueClass == NULL) {
4679 LOG_VFY("VFY: storing uninit ref v%d into ref field\n",
4680 decInsn.vA);
4681 failure = VERIFY_ERROR_GENERIC;
4682 break;
4683 }
4684 /* allow if field is any interface or field is base class */
4685 if (!dvmIsInterfaceClass(fieldClass) &&
4686 !dvmInstanceof(valueClass, fieldClass))
4687 {
4688 LOG_VFY("VFY: storing type '%s' into field type '%s' (%s.%s)\n",
4689 valueClass->descriptor, fieldClass->descriptor,
4690 instField->field.clazz->descriptor,
4691 instField->field.name);
4692 failure = VERIFY_ERROR_GENERIC;
4693 break;
4694 }
4695 }
4696 }
4697 break;
4698
4699 case OP_SGET:
4700 tmpType = kRegTypeInteger;
4701 goto sget_1nr_common;
4702 case OP_SGET_BOOLEAN:
4703 tmpType = kRegTypeBoolean;
4704 goto sget_1nr_common;
4705 case OP_SGET_BYTE:
4706 tmpType = kRegTypeByte;
4707 goto sget_1nr_common;
4708 case OP_SGET_CHAR:
4709 tmpType = kRegTypeChar;
4710 goto sget_1nr_common;
4711 case OP_SGET_SHORT:
4712 tmpType = kRegTypeShort;
4713 goto sget_1nr_common;
4714 sget_1nr_common:
4715 {
4716 StaticField* staticField;
4717 RegType fieldType;
4718
4719 staticField = getStaticField(meth, decInsn.vB, &failure);
4720 if (!VERIFY_OK(failure))
4721 break;
4722
4723 /*
4724 * Make sure the field's type is compatible with expectation.
4725 * We can get ourselves into trouble if we mix & match loads
4726 * and stores with different widths, so rather than just checking
4727 * "canConvertTo1nr" we require that the field types have equal
4728 * widths. (We can't generally require an exact type match,
4729 * because e.g. "int" and "float" are interchangeable.)
4730 */
4731 fieldType = primSigCharToRegType(staticField->field.signature[0]);
4732 if (!checkFieldArrayStore1nr(tmpType, fieldType)) {
4733 LOG_VFY("VFY: invalid sget-1nr of %s.%s (inst=%d actual=%d)\n",
4734 staticField->field.clazz->descriptor,
4735 staticField->field.name, tmpType, fieldType);
4736 failure = VERIFY_ERROR_GENERIC;
4737 break;
4738 }
4739
4740 setRegisterType(workRegs, insnRegCount, decInsn.vA, tmpType,
4741 &failure);
4742 }
4743 break;
4744 case OP_SGET_WIDE:
4745 {
4746 StaticField* staticField;
4747 RegType dstType;
4748
4749 staticField = getStaticField(meth, decInsn.vB, &failure);
4750 if (!VERIFY_OK(failure))
4751 break;
4752 /* check the type, which should be prim */
4753 switch (staticField->field.signature[0]) {
4754 case 'D':
4755 dstType = kRegTypeDoubleLo;
4756 break;
4757 case 'J':
4758 dstType = kRegTypeLongLo;
4759 break;
4760 default:
4761 LOG_VFY("VFY: invalid sget-wide of %s.%s\n",
4762 staticField->field.clazz->descriptor,
4763 staticField->field.name);
4764 dstType = kRegTypeUnknown;
4765 failure = VERIFY_ERROR_GENERIC;
4766 break;
4767 }
4768 if (VERIFY_OK(failure)) {
4769 setRegisterType(workRegs, insnRegCount, decInsn.vA,
4770 dstType, &failure);
4771 }
4772 }
4773 break;
4774 case OP_SGET_OBJECT:
4775 {
4776 StaticField* staticField;
4777 ClassObject* fieldClass;
4778
4779 staticField = getStaticField(meth, decInsn.vB, &failure);
4780 if (!VERIFY_OK(failure))
4781 break;
4782 fieldClass = getFieldClass(meth, &staticField->field);
4783 if (fieldClass == NULL) {
4784 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4785 staticField->field.signature);
4786 failure = VERIFY_ERROR_GENERIC;
4787 break;
4788 }
4789 if (dvmIsPrimitiveClass(fieldClass)) {
4790 LOG_VFY("VFY: attempt to get prim field with sget-object\n");
4791 failure = VERIFY_ERROR_GENERIC;
4792 break;
4793 }
4794 setRegisterType(workRegs, insnRegCount, decInsn.vA,
4795 regTypeFromClass(fieldClass), &failure);
4796 }
4797 break;
4798 case OP_SPUT:
4799 tmpType = kRegTypeInteger;
4800 goto sput_1nr_common;
4801 case OP_SPUT_BOOLEAN:
4802 tmpType = kRegTypeBoolean;
4803 goto sput_1nr_common;
4804 case OP_SPUT_BYTE:
4805 tmpType = kRegTypeByte;
4806 goto sput_1nr_common;
4807 case OP_SPUT_CHAR:
4808 tmpType = kRegTypeChar;
4809 goto sput_1nr_common;
4810 case OP_SPUT_SHORT:
4811 tmpType = kRegTypeShort;
4812 goto sput_1nr_common;
4813 sput_1nr_common:
4814 {
4815 RegType srcType, fieldType;
4816 StaticField* staticField;
4817
4818 srcType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
4819 &failure);
4820
4821 /*
4822 * javac generates synthetic functions that write byte values
4823 * into boolean fields.
4824 */
4825 if (tmpType == kRegTypeBoolean && srcType == kRegTypeByte)
4826 srcType = kRegTypeBoolean;
4827
4828 /* make sure the source register has the correct type */
4829 if (!canConvertTo1nr(srcType, tmpType)) {
4830 LOG_VFY("VFY: invalid reg type %d on sput instr (need %d)\n",
4831 srcType, tmpType);
4832 failure = VERIFY_ERROR_GENERIC;
4833 break;
4834 }
4835
4836 staticField = getStaticField(meth, decInsn.vB, &failure);
4837 if (!VERIFY_OK(failure))
4838 break;
4839 checkFinalFieldAccess(meth, &staticField->field, &failure);
4840 if (!VERIFY_OK(failure))
4841 break;
4842
4843 /*
4844 * Get type of field we're storing into. We know that the
4845 * contents of the register match the instruction, but we also
4846 * need to ensure that the instruction matches the field type.
4847 * Using e.g. sput-short to write into a 32-bit integer field
4848 * can lead to trouble if we do 16-bit writes.
4849 */
4850 fieldType = primSigCharToRegType(staticField->field.signature[0]);
4851 if (!checkFieldArrayStore1nr(tmpType, fieldType)) {
4852 LOG_VFY("VFY: invalid sput-1nr of %s.%s (inst=%d actual=%d)\n",
4853 staticField->field.clazz->descriptor,
4854 staticField->field.name, tmpType, fieldType);
4855 failure = VERIFY_ERROR_GENERIC;
4856 break;
4857 }
4858 }
4859 break;
4860 case OP_SPUT_WIDE:
4861 tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
4862 if (VERIFY_OK(failure)) {
4863 RegType typeHi =
4864 getRegisterType(workRegs, insnRegCount, decInsn.vA+1, &failure);
4865 checkTypeCategory(tmpType, kTypeCategory2, &failure);
4866 checkWidePair(tmpType, typeHi, &failure);
4867 }
4868 if (VERIFY_OK(failure)) {
4869 StaticField* staticField;
4870
4871 staticField = getStaticField(meth, decInsn.vB, &failure);
4872 if (!VERIFY_OK(failure))
4873 break;
4874 checkFinalFieldAccess(meth, &staticField->field, &failure);
4875 if (!VERIFY_OK(failure))
4876 break;
4877
4878 /* check the type, which should be prim */
4879 switch (staticField->field.signature[0]) {
4880 case 'D':
4881 case 'J':
4882 /* these are okay */
4883 break;
4884 default:
4885 LOG_VFY("VFY: invalid sput-wide of %s.%s\n",
4886 staticField->field.clazz->descriptor,
4887 staticField->field.name);
4888 failure = VERIFY_ERROR_GENERIC;
4889 break;
4890 }
4891 }
4892 break;
4893 case OP_SPUT_OBJECT:
4894 {
4895 ClassObject* fieldClass;
4896 ClassObject* valueClass;
4897 StaticField* staticField;
4898 RegType valueType;
4899
4900 staticField = getStaticField(meth, decInsn.vB, &failure);
4901 if (!VERIFY_OK(failure))
4902 break;
4903 checkFinalFieldAccess(meth, &staticField->field, &failure);
4904 if (!VERIFY_OK(failure))
4905 break;
4906
4907 fieldClass = getFieldClass(meth, &staticField->field);
4908 if (fieldClass == NULL) {
4909 LOG_VFY("VFY: unable to recover field class from '%s'\n",
4910 staticField->field.signature);
4911 failure = VERIFY_ERROR_GENERIC;
4912 break;
4913 }
4914
4915 valueType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
4916 &failure);
4917 if (!VERIFY_OK(failure))
4918 break;
4919 if (!regTypeIsReference(valueType)) {
4920 LOG_VFY("VFY: storing non-ref v%d into ref field '%s' (%s)\n",
4921 decInsn.vA, staticField->field.name,
4922 fieldClass->descriptor);
4923 failure = VERIFY_ERROR_GENERIC;
4924 break;
4925 }
4926 if (valueType != kRegTypeZero) {
4927 valueClass = regTypeInitializedReferenceToClass(valueType);
4928 if (valueClass == NULL) {
4929 LOG_VFY("VFY: storing uninit ref v%d into ref field\n",
4930 decInsn.vA);
4931 failure = VERIFY_ERROR_GENERIC;
4932 break;
4933 }
4934 /* allow if field is any interface or field is base class */
4935 if (!dvmIsInterfaceClass(fieldClass) &&
4936 !dvmInstanceof(valueClass, fieldClass))
4937 {
4938 LOG_VFY("VFY: storing type '%s' into field type '%s' (%s.%s)\n",
4939 valueClass->descriptor, fieldClass->descriptor,
4940 staticField->field.clazz->descriptor,
4941 staticField->field.name);
4942 failure = VERIFY_ERROR_GENERIC;
4943 break;
4944 }
4945 }
4946 }
4947 break;
4948
4949 case OP_INVOKE_VIRTUAL:
4950 case OP_INVOKE_VIRTUAL_RANGE:
4951 case OP_INVOKE_SUPER:
4952 case OP_INVOKE_SUPER_RANGE:
4953 {
4954 Method* calledMethod;
4955 RegType returnType;
4956 bool isRange;
4957 bool isSuper;
4958
4959 isRange = (decInsn.opCode == OP_INVOKE_VIRTUAL_RANGE ||
4960 decInsn.opCode == OP_INVOKE_SUPER_RANGE);
4961 isSuper = (decInsn.opCode == OP_INVOKE_SUPER ||
4962 decInsn.opCode == OP_INVOKE_SUPER_RANGE);
4963
4964 calledMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
4965 &decInsn, uninitMap, METHOD_VIRTUAL, isRange,
4966 isSuper, &failure);
4967 if (!VERIFY_OK(failure))
4968 break;
4969 returnType = getMethodReturnType(calledMethod);
4970 setResultRegisterType(workRegs, insnRegCount, returnType, &failure);
4971 justSetResult = true;
4972 }
4973 break;
4974 case OP_INVOKE_DIRECT:
4975 case OP_INVOKE_DIRECT_RANGE:
4976 {
4977 RegType returnType;
4978 Method* calledMethod;
4979 bool isRange;
4980
4981 isRange = (decInsn.opCode == OP_INVOKE_DIRECT_RANGE);
4982 calledMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
4983 &decInsn, uninitMap, METHOD_DIRECT, isRange,
4984 false, &failure);
4985 if (!VERIFY_OK(failure))
4986 break;
4987
4988 /*
4989 * Some additional checks when calling <init>. We know from
4990 * the invocation arg check that the "this" argument is an
4991 * instance of calledMethod->clazz. Now we further restrict
4992 * that to require that calledMethod->clazz is the same as
4993 * this->clazz or this->super, allowing the latter only if
4994 * the "this" argument is the same as the "this" argument to
4995 * this method (which implies that we're in <init> ourselves).
4996 */
4997 if (isInitMethod(calledMethod)) {
4998 RegType thisType;
4999 thisType = getInvocationThis(workRegs, insnRegCount,
5000 &decInsn, &failure);
5001 if (!VERIFY_OK(failure))
5002 break;
5003
5004 /* no null refs allowed (?) */
5005 if (thisType == kRegTypeZero) {
5006 LOG_VFY("VFY: unable to initialize null ref\n");
5007 failure = VERIFY_ERROR_GENERIC;
5008 break;
5009 }
5010
5011 ClassObject* thisClass;
5012
5013 thisClass = regTypeReferenceToClass(thisType, uninitMap);
5014 assert(thisClass != NULL);
5015
5016 /* must be in same class or in superclass */
5017 if (calledMethod->clazz == thisClass->super) {
5018 if (thisClass != meth->clazz) {
5019 LOG_VFY("VFY: invoke-direct <init> on super only "
5020 "allowed for 'this' in <init>");
5021 failure = VERIFY_ERROR_GENERIC;
5022 break;
5023 }
5024 } else if (calledMethod->clazz != thisClass) {
5025 LOG_VFY("VFY: invoke-direct <init> must be on current "
5026 "class or super\n");
5027 failure = VERIFY_ERROR_GENERIC;
5028 break;
5029 }
5030
5031 /* arg must be an uninitialized reference */
5032 if (!regTypeIsUninitReference(thisType)) {
5033 LOG_VFY("VFY: can only initialize the uninitialized\n");
5034 failure = VERIFY_ERROR_GENERIC;
5035 break;
5036 }
5037
5038 /*
5039 * Replace the uninitialized reference with an initialized
5040 * one, and clear the entry in the uninit map. We need to
5041 * do this for all registers that have the same object
5042 * instance in them, not just the "this" register.
5043 */
5044 int uidx = regTypeToUninitIndex(thisType);
5045 markRefsAsInitialized(workRegs, insnRegCount, uninitMap,
5046 thisType, &failure);
5047 if (!VERIFY_OK(failure))
5048 break;
5049 }
5050 returnType = getMethodReturnType(calledMethod);
5051 setResultRegisterType(workRegs, insnRegCount,
5052 returnType, &failure);
5053 justSetResult = true;
5054 }
5055 break;
5056 case OP_INVOKE_STATIC:
5057 case OP_INVOKE_STATIC_RANGE:
5058 {
5059 RegType returnType;
5060 Method* calledMethod;
5061 bool isRange;
5062
5063 isRange = (decInsn.opCode == OP_INVOKE_STATIC_RANGE);
5064 calledMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
5065 &decInsn, uninitMap, METHOD_STATIC, isRange,
5066 false, &failure);
5067 if (!VERIFY_OK(failure))
5068 break;
5069
5070 returnType = getMethodReturnType(calledMethod);
5071 setResultRegisterType(workRegs, insnRegCount, returnType, &failure);
5072 justSetResult = true;
5073 }
5074 break;
5075 case OP_INVOKE_INTERFACE:
5076 case OP_INVOKE_INTERFACE_RANGE:
5077 {
5078 RegType /*thisType,*/ returnType;
5079 Method* absMethod;
5080 bool isRange;
5081
5082 isRange = (decInsn.opCode == OP_INVOKE_INTERFACE_RANGE);
5083 absMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
5084 &decInsn, uninitMap, METHOD_INTERFACE, isRange,
5085 false, &failure);
5086 if (!VERIFY_OK(failure))
5087 break;
5088
5089 #if 0 /* can't do this here, fails on dalvik test 052-verifier-fun */
5090 /*
5091 * Get the type of the "this" arg, which should always be an
5092 * interface class. Because we don't do a full merge on
5093 * interface classes, this might have reduced to Object.
5094 */
5095 thisType = getInvocationThis(workRegs, insnRegCount,
5096 &decInsn, &failure);
5097 if (!VERIFY_OK(failure))
5098 break;
5099
5100 if (thisType == kRegTypeZero) {
5101 /* null pointer always passes (and always fails at runtime) */
5102 } else {
5103 ClassObject* thisClass;
5104
5105 thisClass = regTypeInitializedReferenceToClass(thisType);
5106 if (thisClass == NULL) {
5107 LOG_VFY("VFY: interface call on uninitialized\n");
5108 failure = VERIFY_ERROR_GENERIC;
5109 break;
5110 }
5111
5112 /*
5113 * Either "thisClass" needs to be the interface class that
5114 * defined absMethod, or absMethod's class needs to be one
5115 * of the interfaces implemented by "thisClass". (Or, if
5116 * we couldn't complete the merge, this will be Object.)
5117 */
5118 if (thisClass != absMethod->clazz &&
5119 thisClass != gDvm.classJavaLangObject &&
5120 !dvmImplements(thisClass, absMethod->clazz))
5121 {
5122 LOG_VFY("VFY: unable to match absMethod '%s' with %s interfaces\n",
5123 absMethod->name, thisClass->descriptor);
5124 failure = VERIFY_ERROR_GENERIC;
5125 break;
5126 }
5127 }
5128 #endif
5129
5130 /*
5131 * We don't have an object instance, so we can't find the
5132 * concrete method. However, all of the type information is
5133 * in the abstract method, so we're good.
5134 */
5135 returnType = getMethodReturnType(absMethod);
5136 setResultRegisterType(workRegs, insnRegCount, returnType, &failure);
5137 justSetResult = true;
5138 }
5139 break;
5140
5141 case OP_NEG_INT:
5142 case OP_NOT_INT:
5143 checkUnop(workRegs, insnRegCount, &decInsn,
5144 kRegTypeInteger, kRegTypeInteger, &failure);
5145 break;
5146 case OP_NEG_LONG:
5147 case OP_NOT_LONG:
5148 checkUnop(workRegs, insnRegCount, &decInsn,
5149 kRegTypeLongLo, kRegTypeLongLo, &failure);
5150 break;
5151 case OP_NEG_FLOAT:
5152 checkUnop(workRegs, insnRegCount, &decInsn,
5153 kRegTypeFloat, kRegTypeFloat, &failure);
5154 break;
5155 case OP_NEG_DOUBLE:
5156 checkUnop(workRegs, insnRegCount, &decInsn,
5157 kRegTypeDoubleLo, kRegTypeDoubleLo, &failure);
5158 break;
5159 case OP_INT_TO_LONG:
5160 checkUnop(workRegs, insnRegCount, &decInsn,
5161 kRegTypeLongLo, kRegTypeInteger, &failure);
5162 break;
5163 case OP_INT_TO_FLOAT:
5164 checkUnop(workRegs, insnRegCount, &decInsn,
5165 kRegTypeFloat, kRegTypeInteger, &failure);
5166 break;
5167 case OP_INT_TO_DOUBLE:
5168 checkUnop(workRegs, insnRegCount, &decInsn,
5169 kRegTypeDoubleLo, kRegTypeInteger, &failure);
5170 break;
5171 case OP_LONG_TO_INT:
5172 checkUnop(workRegs, insnRegCount, &decInsn,
5173 kRegTypeInteger, kRegTypeLongLo, &failure);
5174 break;
5175 case OP_LONG_TO_FLOAT:
5176 checkUnop(workRegs, insnRegCount, &decInsn,
5177 kRegTypeFloat, kRegTypeLongLo, &failure);
5178 break;
5179 case OP_LONG_TO_DOUBLE:
5180 checkUnop(workRegs, insnRegCount, &decInsn,
5181 kRegTypeDoubleLo, kRegTypeLongLo, &failure);
5182 break;
5183 case OP_FLOAT_TO_INT:
5184 checkUnop(workRegs, insnRegCount, &decInsn,
5185 kRegTypeInteger, kRegTypeFloat, &failure);
5186 break;
5187 case OP_FLOAT_TO_LONG:
5188 checkUnop(workRegs, insnRegCount, &decInsn,
5189 kRegTypeLongLo, kRegTypeFloat, &failure);
5190 break;
5191 case OP_FLOAT_TO_DOUBLE:
5192 checkUnop(workRegs, insnRegCount, &decInsn,
5193 kRegTypeDoubleLo, kRegTypeFloat, &failure);
5194 break;
5195 case OP_DOUBLE_TO_INT:
5196 checkUnop(workRegs, insnRegCount, &decInsn,
5197 kRegTypeInteger, kRegTypeDoubleLo, &failure);
5198 break;
5199 case OP_DOUBLE_TO_LONG:
5200 checkUnop(workRegs, insnRegCount, &decInsn,
5201 kRegTypeLongLo, kRegTypeDoubleLo, &failure);
5202 break;
5203 case OP_DOUBLE_TO_FLOAT:
5204 checkUnop(workRegs, insnRegCount, &decInsn,
5205 kRegTypeFloat, kRegTypeDoubleLo, &failure);
5206 break;
5207 case OP_INT_TO_BYTE:
5208 checkUnop(workRegs, insnRegCount, &decInsn,
5209 kRegTypeByte, kRegTypeInteger, &failure);
5210 break;
5211 case OP_INT_TO_CHAR:
5212 checkUnop(workRegs, insnRegCount, &decInsn,
5213 kRegTypeChar, kRegTypeInteger, &failure);
5214 break;
5215 case OP_INT_TO_SHORT:
5216 checkUnop(workRegs, insnRegCount, &decInsn,
5217 kRegTypeShort, kRegTypeInteger, &failure);
5218 break;
5219
5220 case OP_ADD_INT:
5221 case OP_SUB_INT:
5222 case OP_MUL_INT:
5223 case OP_REM_INT:
5224 case OP_DIV_INT:
5225 case OP_SHL_INT:
5226 case OP_SHR_INT:
5227 case OP_USHR_INT:
5228 checkBinop(workRegs, insnRegCount, &decInsn,
5229 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
5230 break;
5231 case OP_AND_INT:
5232 case OP_OR_INT:
5233 case OP_XOR_INT:
5234 checkBinop(workRegs, insnRegCount, &decInsn,
5235 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, true, &failure);
5236 break;
5237 case OP_ADD_LONG:
5238 case OP_SUB_LONG:
5239 case OP_MUL_LONG:
5240 case OP_DIV_LONG:
5241 case OP_REM_LONG:
5242 case OP_AND_LONG:
5243 case OP_OR_LONG:
5244 case OP_XOR_LONG:
5245 checkBinop(workRegs, insnRegCount, &decInsn,
5246 kRegTypeLongLo, kRegTypeLongLo, kRegTypeLongLo, false, &failure);
5247 break;
5248 case OP_SHL_LONG:
5249 case OP_SHR_LONG:
5250 case OP_USHR_LONG:
5251 /* shift distance is Int, making these different from other binops */
5252 checkBinop(workRegs, insnRegCount, &decInsn,
5253 kRegTypeLongLo, kRegTypeLongLo, kRegTypeInteger, false, &failure);
5254 break;
5255 case OP_ADD_FLOAT:
5256 case OP_SUB_FLOAT:
5257 case OP_MUL_FLOAT:
5258 case OP_DIV_FLOAT:
5259 case OP_REM_FLOAT:
5260 checkBinop(workRegs, insnRegCount, &decInsn,
5261 kRegTypeFloat, kRegTypeFloat, kRegTypeFloat, false, &failure);
5262 break;
5263 case OP_ADD_DOUBLE:
5264 case OP_SUB_DOUBLE:
5265 case OP_MUL_DOUBLE:
5266 case OP_DIV_DOUBLE:
5267 case OP_REM_DOUBLE:
5268 checkBinop(workRegs, insnRegCount, &decInsn,
5269 kRegTypeDoubleLo, kRegTypeDoubleLo, kRegTypeDoubleLo, false,
5270 &failure);
5271 break;
5272 case OP_ADD_INT_2ADDR:
5273 case OP_SUB_INT_2ADDR:
5274 case OP_MUL_INT_2ADDR:
5275 case OP_REM_INT_2ADDR:
5276 case OP_SHL_INT_2ADDR:
5277 case OP_SHR_INT_2ADDR:
5278 case OP_USHR_INT_2ADDR:
5279 checkBinop2addr(workRegs, insnRegCount, &decInsn,
5280 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
5281 break;
5282 case OP_AND_INT_2ADDR:
5283 case OP_OR_INT_2ADDR:
5284 case OP_XOR_INT_2ADDR:
5285 checkBinop2addr(workRegs, insnRegCount, &decInsn,
5286 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, true, &failure);
5287 break;
5288 case OP_DIV_INT_2ADDR:
5289 checkBinop2addr(workRegs, insnRegCount, &decInsn,
5290 kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
5291 break;
5292 case OP_ADD_LONG_2ADDR:
5293 case OP_SUB_LONG_2ADDR:
5294 case OP_MUL_LONG_2ADDR:
5295 case OP_DIV_LONG_2ADDR:
5296 case OP_REM_LONG_2ADDR:
5297 case OP_AND_LONG_2ADDR:
5298 case OP_OR_LONG_2ADDR:
5299 case OP_XOR_LONG_2ADDR:
5300 checkBinop2addr(workRegs, insnRegCount, &decInsn,
5301 kRegTypeLongLo, kRegTypeLongLo, kRegTypeLongLo, false, &failure);
5302 break;
5303 case OP_SHL_LONG_2ADDR:
5304 case OP_SHR_LONG_2ADDR:
5305 case OP_USHR_LONG_2ADDR:
5306 checkBinop2addr(workRegs, insnRegCount, &decInsn,
5307 kRegTypeLongLo, kRegTypeLongLo, kRegTypeInteger, false, &failure);
5308 break;
5309 case OP_ADD_FLOAT_2ADDR:
5310 case OP_SUB_FLOAT_2ADDR:
5311 case OP_MUL_FLOAT_2ADDR:
5312 case OP_DIV_FLOAT_2ADDR:
5313 case OP_REM_FLOAT_2ADDR:
5314 checkBinop2addr(workRegs, insnRegCount, &decInsn,
5315 kRegTypeFloat, kRegTypeFloat, kRegTypeFloat, false, &failure);
5316 break;
5317 case OP_ADD_DOUBLE_2ADDR:
5318 case OP_SUB_DOUBLE_2ADDR:
5319 case OP_MUL_DOUBLE_2ADDR:
5320 case OP_DIV_DOUBLE_2ADDR:
5321 case OP_REM_DOUBLE_2ADDR:
5322 checkBinop2addr(workRegs, insnRegCount, &decInsn,
5323 kRegTypeDoubleLo, kRegTypeDoubleLo, kRegTypeDoubleLo, false,
5324 &failure);
5325 break;
5326 case OP_ADD_INT_LIT16:
5327 case OP_RSUB_INT:
5328 case OP_MUL_INT_LIT16:
5329 case OP_DIV_INT_LIT16:
5330 case OP_REM_INT_LIT16:
5331 checkLitop(workRegs, insnRegCount, &decInsn,
5332 kRegTypeInteger, kRegTypeInteger, false, &failure);
5333 break;
5334 case OP_AND_INT_LIT16:
5335 case OP_OR_INT_LIT16:
5336 case OP_XOR_INT_LIT16:
5337 checkLitop(workRegs, insnRegCount, &decInsn,
5338 kRegTypeInteger, kRegTypeInteger, true, &failure);
5339 break;
5340 case OP_ADD_INT_LIT8:
5341 case OP_RSUB_INT_LIT8:
5342 case OP_MUL_INT_LIT8:
5343 case OP_DIV_INT_LIT8:
5344 case OP_REM_INT_LIT8:
5345 case OP_SHL_INT_LIT8:
5346 checkLitop(workRegs, insnRegCount, &decInsn,
5347 kRegTypeInteger, kRegTypeInteger, false, &failure);
5348 break;
5349 case OP_SHR_INT_LIT8:
5350 tmpType = adjustForRightShift(workRegs, insnRegCount,
5351 decInsn.vB, decInsn.vC, false, &failure);
5352 checkLitop(workRegs, insnRegCount, &decInsn,
5353 tmpType, kRegTypeInteger, false, &failure);
5354 break;
5355 case OP_USHR_INT_LIT8:
5356 tmpType = adjustForRightShift(workRegs, insnRegCount,
5357 decInsn.vB, decInsn.vC, true, &failure);
5358 checkLitop(workRegs, insnRegCount, &decInsn,
5359 tmpType, kRegTypeInteger, false, &failure);
5360 break;
5361 case OP_AND_INT_LIT8:
5362 case OP_OR_INT_LIT8:
5363 case OP_XOR_INT_LIT8:
5364 checkLitop(workRegs, insnRegCount, &decInsn,
5365 kRegTypeInteger, kRegTypeInteger, true, &failure);
5366 break;
5367
5368 /*
5369 * This falls into the general category of "optimized" instructions,
5370 * which don't generally appear during verification. Because it's
5371 * inserted in the course of verification, we can expect to see it here.
5372 */
5373 case OP_THROW_VERIFICATION_ERROR:
5374 break;
5375
5376 /*
5377 * Verifying "quickened" instructions is tricky, because we have
5378 * discarded the original field/method information. The byte offsets
5379 * and vtable indices only have meaning in the context of an object
5380 * instance.
5381 *
5382 * If a piece of code declares a local reference variable, assigns
5383 * null to it, and then issues a virtual method call on it, we
5384 * cannot evaluate the method call during verification. This situation
5385 * isn't hard to handle, since we know the call will always result in an
5386 * NPE, and the arguments and return value don't matter. Any code that
5387 * depends on the result of the method call is inaccessible, so the
5388 * fact that we can't fully verify anything that comes after the bad
5389 * call is not a problem.
5390 *
5391 * We must also consider the case of multiple code paths, only some of
5392 * which involve a null reference. We can completely verify the method
5393 * if we sidestep the results of executing with a null reference.
5394 * For example, if on the first pass through the code we try to do a
5395 * virtual method invocation through a null ref, we have to skip the
5396 * method checks and have the method return a "wildcard" type (which
5397 * merges with anything to become that other thing). The move-result
5398 * will tell us if it's a reference, single-word numeric, or double-word
5399 * value. We continue to perform the verification, and at the end of
5400 * the function any invocations that were never fully exercised are
5401 * marked as null-only.
5402 *
5403 * We would do something similar for the field accesses. The field's
5404 * type, once known, can be used to recover the width of short integers.
5405 * If the object reference was null, the field-get returns the "wildcard"
5406 * type, which is acceptable for any operation.
5407 */
5408 case OP_EXECUTE_INLINE:
5409 case OP_INVOKE_DIRECT_EMPTY:
5410 case OP_IGET_QUICK:
5411 case OP_IGET_WIDE_QUICK:
5412 case OP_IGET_OBJECT_QUICK:
5413 case OP_IPUT_QUICK:
5414 case OP_IPUT_WIDE_QUICK:
5415 case OP_IPUT_OBJECT_QUICK:
5416 case OP_INVOKE_VIRTUAL_QUICK:
5417 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
5418 case OP_INVOKE_SUPER_QUICK:
5419 case OP_INVOKE_SUPER_QUICK_RANGE:
5420 failure = VERIFY_ERROR_GENERIC;
5421 break;
5422
5423 /* these should never appear */
5424 case OP_UNUSED_3E:
5425 case OP_UNUSED_3F:
5426 case OP_UNUSED_40:
5427 case OP_UNUSED_41:
5428 case OP_UNUSED_42:
5429 case OP_UNUSED_43:
5430 case OP_UNUSED_73:
5431 case OP_UNUSED_79:
5432 case OP_UNUSED_7A:
5433 case OP_UNUSED_E3:
5434 case OP_UNUSED_E4:
5435 case OP_UNUSED_E5:
5436 case OP_UNUSED_E6:
5437 case OP_UNUSED_E7:
5438 case OP_UNUSED_E8:
5439 case OP_UNUSED_E9:
5440 case OP_UNUSED_EA:
5441 case OP_UNUSED_EB:
5442 case OP_UNUSED_EC:
5443 case OP_UNUSED_EF:
5444 case OP_UNUSED_F1:
5445 case OP_UNUSED_FC:
5446 case OP_UNUSED_FD:
5447 case OP_UNUSED_FE:
5448 case OP_UNUSED_FF:
5449 failure = VERIFY_ERROR_GENERIC;
5450 break;
5451
5452 /*
5453 * DO NOT add a "default" clause here. Without it the compiler will
5454 * complain if an instruction is missing (which is desirable).
5455 */
5456 }
5457
5458 if (!VERIFY_OK(failure)) {
5459 if (failure == VERIFY_ERROR_GENERIC || gDvm.optimizing) {
5460 /* immediate failure, reject class */
5461 LOG_VFY_METH(meth, "VFY: rejecting opcode 0x%02x at 0x%04x\n",
5462 decInsn.opCode, insnIdx);
5463 goto bail;
5464 } else {
5465 /* replace opcode and continue on */
5466 LOGD("VFY: replacing opcode 0x%02x at 0x%04x\n",
5467 decInsn.opCode, insnIdx);
5468 if (!replaceFailingInstruction(meth, insnFlags, insnIdx, failure)) {
5469 LOG_VFY_METH(meth, "VFY: rejecting opcode 0x%02x at 0x%04x\n",
5470 decInsn.opCode, insnIdx);
5471 goto bail;
5472 }
5473 /* IMPORTANT: meth->insns may have been changed */
5474 insns = meth->insns + insnIdx;
5475
5476 /* continue on as if we just handled a throw-verification-error */
5477 failure = VERIFY_ERROR_NONE;
5478 nextFlags = kInstrCanThrow;
5479 }
5480 }
5481
5482 /*
5483 * If we didn't just set the result register, clear it out. This
5484 * ensures that you can only use "move-result" immediately after the
5485 * result is set.
5486 */
5487 if (!justSetResult) {
5488 int reg = RESULT_REGISTER(insnRegCount);
5489 workRegs[reg] = workRegs[reg+1] = kRegTypeUnknown;
5490 }
5491
5492 /*
5493 * Handle "continue". Tag the next consecutive instruction.
5494 */
5495 if ((nextFlags & kInstrCanContinue) != 0) {
5496 int insnWidth = dvmInsnGetWidth(insnFlags, insnIdx);
5497 if (insnIdx+insnWidth >= insnsSize) {
5498 LOG_VFY_METH(meth,
5499 "VFY: execution can walk off end of code area (from 0x%x)\n",
5500 insnIdx);
5501 goto bail;
5502 }
5503
5504 /*
5505 * The only way to get to a move-exception instruction is to get
5506 * thrown there. Make sure the next instruction isn't one.
5507 */
5508 if (!checkMoveException(meth, insnIdx+insnWidth, "next"))
5509 goto bail;
5510
5511 if (getRegisterLine(regTable, insnIdx+insnWidth) != NULL) {
5512 /*
5513 * Merge registers into what we have for the next instruction,
5514 * and set the "changed" flag if needed.
5515 */
5516 updateRegisters(meth, insnFlags, regTable, insnIdx+insnWidth,
5517 workRegs);
5518 } else {
5519 /*
5520 * We're not recording register data for the next instruction,
5521 * so we don't know what the prior state was. We have to
5522 * assume that something has changed and re-evaluate it.
5523 */
5524 dvmInsnSetChanged(insnFlags, insnIdx+insnWidth, true);
5525 }
5526 }
5527
5528 /*
5529 * Handle "branch". Tag the branch target.
5530 *
5531 * NOTE: instructions like OP_EQZ provide information about the state
5532 * of the register when the branch is taken or not taken. For example,
5533 * somebody could get a reference field, check it for zero, and if the
5534 * branch is taken immediately store that register in a boolean field
5535 * since the value is known to be zero. We do not currently account for
5536 * that, and will reject the code.
5537 */
5538 if ((nextFlags & kInstrCanBranch) != 0) {
5539 bool isConditional;
5540
5541 if (!dvmGetBranchTarget(meth, insnFlags, insnIdx, &branchTarget,
5542 &isConditional))
5543 {
5544 /* should never happen after static verification */
5545 LOG_VFY_METH(meth, "VFY: bad branch at %d\n", insnIdx);
5546 goto bail;
5547 }
5548 assert(isConditional || (nextFlags & kInstrCanContinue) == 0);
5549 assert(!isConditional || (nextFlags & kInstrCanContinue) != 0);
5550
5551 if (!checkMoveException(meth, insnIdx+branchTarget, "branch"))
5552 goto bail;
5553
5554 /* update branch target, set "changed" if appropriate */
5555 updateRegisters(meth, insnFlags, regTable, insnIdx+branchTarget,
5556 workRegs);
5557 }
5558
5559 /*
5560 * Handle "switch". Tag all possible branch targets.
5561 *
5562 * We've already verified that the table is structurally sound, so we
5563 * just need to walk through and tag the targets.
5564 */
5565 if ((nextFlags & kInstrCanSwitch) != 0) {
5566 int offsetToSwitch = insns[1] | (((s4)insns[2]) << 16);
5567 const u2* switchInsns = insns + offsetToSwitch;
5568 int switchCount = switchInsns[1];
5569 int offsetToTargets, targ;
5570
5571 if ((*insns & 0xff) == OP_PACKED_SWITCH) {
5572 /* 0=sig, 1=count, 2/3=firstKey */
5573 offsetToTargets = 4;
5574 } else {
5575 /* 0=sig, 1=count, 2..count*2 = keys */
5576 assert((*insns & 0xff) == OP_SPARSE_SWITCH);
5577 offsetToTargets = 2 + 2*switchCount;
5578 }
5579
5580 /* verify each switch target */
5581 for (targ = 0; targ < switchCount; targ++) {
5582 int offset, absOffset;
5583
5584 /* offsets are 32-bit, and only partly endian-swapped */
5585 offset = switchInsns[offsetToTargets + targ*2] |
5586 (((s4) switchInsns[offsetToTargets + targ*2 +1]) << 16);
5587 absOffset = insnIdx + offset;
5588
5589 assert(absOffset >= 0 && absOffset < insnsSize);
5590
5591 if (!checkMoveException(meth, absOffset, "switch"))
5592 goto bail;
5593
5594 updateRegisters(meth, insnFlags, regTable, absOffset, workRegs);
5595 }
5596 }
5597
5598 /*
5599 * Handle instructions that can throw and that are sitting in a
5600 * "try" block. (If they're not in a "try" block when they throw,
5601 * control transfers out of the method.)
5602 */
5603 if ((nextFlags & kInstrCanThrow) != 0 && dvmInsnIsInTry(insnFlags, insnIdx))
5604 {
5605 DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
5606 const DexCode* pCode = dvmGetMethodCode(meth);
5607 DexCatchIterator iterator;
5608
5609 if (dexFindCatchHandler(&iterator, pCode, insnIdx)) {
5610 for (;;) {
5611 DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
5612
5613 if (handler == NULL) {
5614 break;
5615 }
5616
5617 /* note we use entryRegs, not workRegs */
5618 updateRegisters(meth, insnFlags, regTable, handler->address,
5619 entryRegs);
5620 }
5621 }
5622 }
5623
5624 /*
5625 * Update startGuess. Advance to the next instruction of that's
5626 * possible, otherwise use the branch target if one was found. If
5627 * neither of those exists we're in a return or throw; leave startGuess
5628 * alone and let the caller sort it out.
5629 */
5630 if ((nextFlags & kInstrCanContinue) != 0) {
5631 *pStartGuess = insnIdx + dvmInsnGetWidth(insnFlags, insnIdx);
5632 } else if ((nextFlags & kInstrCanBranch) != 0) {
5633 /* we're still okay if branchTarget is zero */
5634 *pStartGuess = insnIdx + branchTarget;
5635 }
5636
5637 assert(*pStartGuess >= 0 && *pStartGuess < insnsSize &&
5638 dvmInsnGetWidth(insnFlags, *pStartGuess) != 0);
5639
5640 result = true;
5641
5642 bail:
5643 return result;
5644 }
5645
5646
5647 /*
5648 * callback function used in dumpRegTypes to print local vars
5649 * valid at a given address.
5650 */
logLocalsCb(void * cnxt,u2 reg,u4 startAddress,u4 endAddress,const char * name,const char * descriptor,const char * signature)5651 static void logLocalsCb(void *cnxt, u2 reg, u4 startAddress, u4 endAddress,
5652 const char *name, const char *descriptor,
5653 const char *signature)
5654 {
5655 int addr = *((int *)cnxt);
5656
5657 if (addr >= (int) startAddress && addr < (int) endAddress)
5658 {
5659 LOGI(" %2d: '%s' %s\n", reg, name, descriptor);
5660 }
5661 }
5662
5663 /*
5664 * Dump the register types for the specifed address to the log file.
5665 */
dumpRegTypes(const Method * meth,const InsnFlags * insnFlags,const RegType * addrRegs,int addr,const char * addrName,const UninitInstanceMap * uninitMap,int displayFlags)5666 static void dumpRegTypes(const Method* meth, const InsnFlags* insnFlags,
5667 const RegType* addrRegs, int addr, const char* addrName,
5668 const UninitInstanceMap* uninitMap, int displayFlags)
5669 {
5670 int regCount = meth->registersSize;
5671 int fullRegCount = regCount + kExtraRegs;
5672 bool branchTarget = dvmInsnIsBranchTarget(insnFlags, addr);
5673 int i;
5674
5675 assert(addr >= 0 && addr < (int) dvmGetMethodInsnsSize(meth));
5676
5677 int regCharSize = fullRegCount + (fullRegCount-1)/4 + 2 +1;
5678 char regChars[regCharSize +1];
5679 memset(regChars, ' ', regCharSize);
5680 regChars[0] = '[';
5681 if (regCount == 0)
5682 regChars[1] = ']';
5683 else
5684 regChars[1 + (regCount-1) + (regCount-1)/4 +1] = ']';
5685 regChars[regCharSize] = '\0';
5686
5687 //const RegType* addrRegs = getRegisterLine(regTable, addr);
5688
5689 for (i = 0; i < regCount + kExtraRegs; i++) {
5690 char tch;
5691
5692 switch (addrRegs[i]) {
5693 case kRegTypeUnknown: tch = '.'; break;
5694 case kRegTypeConflict: tch = 'X'; break;
5695 case kRegTypeFloat: tch = 'F'; break;
5696 case kRegTypeZero: tch = '0'; break;
5697 case kRegTypeOne: tch = '1'; break;
5698 case kRegTypeBoolean: tch = 'Z'; break;
5699 case kRegTypePosByte: tch = 'b'; break;
5700 case kRegTypeByte: tch = 'B'; break;
5701 case kRegTypePosShort: tch = 's'; break;
5702 case kRegTypeShort: tch = 'S'; break;
5703 case kRegTypeChar: tch = 'C'; break;
5704 case kRegTypeInteger: tch = 'I'; break;
5705 case kRegTypeLongLo: tch = 'J'; break;
5706 case kRegTypeLongHi: tch = 'j'; break;
5707 case kRegTypeDoubleLo: tch = 'D'; break;
5708 case kRegTypeDoubleHi: tch = 'd'; break;
5709 default:
5710 if (regTypeIsReference(addrRegs[i])) {
5711 if (regTypeIsUninitReference(addrRegs[i]))
5712 tch = 'U';
5713 else
5714 tch = 'L';
5715 } else {
5716 tch = '*';
5717 assert(false);
5718 }
5719 break;
5720 }
5721
5722 if (i < regCount)
5723 regChars[1 + i + (i/4)] = tch;
5724 else
5725 regChars[1 + i + (i/4) + 2] = tch;
5726 }
5727
5728 if (addr == 0 && addrName != NULL)
5729 LOGI("%c%s %s\n", branchTarget ? '>' : ' ', addrName, regChars);
5730 else
5731 LOGI("%c0x%04x %s\n", branchTarget ? '>' : ' ', addr, regChars);
5732
5733 if (displayFlags & DRT_SHOW_REF_TYPES) {
5734 for (i = 0; i < regCount + kExtraRegs; i++) {
5735 if (regTypeIsReference(addrRegs[i]) && addrRegs[i] != kRegTypeZero)
5736 {
5737 ClassObject* clazz;
5738
5739 clazz = regTypeReferenceToClass(addrRegs[i], uninitMap);
5740 assert(dvmValidateObject((Object*)clazz));
5741 if (i < regCount) {
5742 LOGI(" %2d: 0x%08x %s%s\n",
5743 i, addrRegs[i],
5744 regTypeIsUninitReference(addrRegs[i]) ? "[U]" : "",
5745 clazz->descriptor);
5746 } else {
5747 LOGI(" RS: 0x%08x %s%s\n",
5748 addrRegs[i],
5749 regTypeIsUninitReference(addrRegs[i]) ? "[U]" : "",
5750 clazz->descriptor);
5751 }
5752 }
5753 }
5754 }
5755 if (displayFlags & DRT_SHOW_LOCALS) {
5756 dexDecodeDebugInfo(meth->clazz->pDvmDex->pDexFile,
5757 dvmGetMethodCode(meth),
5758 meth->clazz->descriptor,
5759 meth->prototype.protoIdx,
5760 meth->accessFlags,
5761 NULL, logLocalsCb, &addr);
5762 }
5763 }
5764
5765