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