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