OSDN Git Service

am ac60268a: (-s ours) am f1823804: Merge change 26285 into eclair
[android-x86/dalvik.git] / vm / analysis / VerifySubs.c
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 verification subroutines.
19  */
20 #include "Dalvik.h"
21 #include "analysis/CodeVerify.h"
22 #include "libdex/DexCatch.h"
23 #include "libdex/InstrUtils.h"
24
25
26 /*
27  * Compute the width of the instruction at each address in the instruction
28  * stream.  Addresses that are in the middle of an instruction, or that
29  * are part of switch table data, are not set (so the caller should probably
30  * initialize "insnFlags" to zero).
31  *
32  * If "pNewInstanceCount" is not NULL, it will be set to the number of
33  * new-instance instructions in the method.
34  *
35  * Logs an error and returns "false" on failure.
36  */
37 bool dvmComputeCodeWidths(const Method* meth, InsnFlags* insnFlags,
38     int* pNewInstanceCount)
39 {
40     const int insnCount = dvmGetMethodInsnsSize(meth);
41     const u2* insns = meth->insns;
42     bool result = false;
43     int newInstanceCount = 0;
44     int i;
45
46
47     for (i = 0; i < insnCount; /**/) {
48         int width;
49
50         /*
51          * Switch tables and array data tables are identified with
52          * "extended NOP" opcodes.  They contain no executable code,
53          * so we can just skip past them.
54          */
55         if (*insns == kPackedSwitchSignature) {
56             width = 4 + insns[1] * 2;
57         } else if (*insns == kSparseSwitchSignature) {
58             width = 2 + insns[1] * 4;
59         } else if (*insns == kArrayDataSignature) {
60             u4 size = insns[2] | (((u4)insns[3]) << 16);
61             width = 4 + (insns[1] * size + 1) / 2;
62         } else {
63             int instr = *insns & 0xff;
64             width = dexGetInstrWidthAbs(gDvm.instrWidth, instr);
65             if (width == 0) {
66                 LOG_VFY_METH(meth,
67                     "VFY: invalid post-opt instruction (0x%x)\n", instr);
68                 LOGI("### instr=%d width=%d table=%d\n",
69                     instr, width, dexGetInstrWidthAbs(gDvm.instrWidth, instr));
70                 goto bail;
71             }
72             if (width < 0 || width > 5) {
73                 LOGE("VFY: bizarre width value %d\n", width);
74                 dvmAbort();
75             }
76
77             if (instr == OP_NEW_INSTANCE)
78                 newInstanceCount++;
79         }
80
81         if (width > 65535) {
82             LOG_VFY_METH(meth, "VFY: insane width %d\n", width);
83             goto bail;
84         }
85
86         insnFlags[i] |= width;
87         i += width;
88         insns += width;
89     }
90     if (i != (int) dvmGetMethodInsnsSize(meth)) {
91         LOG_VFY_METH(meth, "VFY: code did not end where expected (%d vs. %d)\n",
92             i, dvmGetMethodInsnsSize(meth));
93         goto bail;
94     }
95
96     result = true;
97     if (pNewInstanceCount != NULL)
98         *pNewInstanceCount = newInstanceCount;
99
100 bail:
101     return result;
102 }
103
104 /*
105  * Set the "in try" flags for all instructions protected by "try" statements.
106  * Also sets the "branch target" flags for exception handlers.
107  *
108  * Call this after widths have been set in "insnFlags".
109  *
110  * Returns "false" if something in the exception table looks fishy, but
111  * we're expecting the exception table to be somewhat sane.
112  */
113 bool dvmSetTryFlags(const Method* meth, InsnFlags* insnFlags)
114 {
115     u4 insnsSize = dvmGetMethodInsnsSize(meth);
116     DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
117     const DexCode* pCode = dvmGetMethodCode(meth);
118     u4 triesSize = pCode->triesSize;
119     const DexTry* pTries;
120     u4 handlersSize;
121     u4 offset;
122     u4 i;
123
124     if (triesSize == 0) {
125         return true;
126     }
127
128     pTries = dexGetTries(pCode);
129     handlersSize = dexGetHandlersSize(pCode);
130
131     for (i = 0; i < triesSize; i++) {
132         const DexTry* pTry = &pTries[i];
133         u4 start = pTry->startAddr;
134         u4 end = start + pTry->insnCount;
135         u4 addr;
136
137         if ((start >= end) || (start >= insnsSize) || (end > insnsSize)) {
138             LOG_VFY_METH(meth,
139                 "VFY: bad exception entry: startAddr=%d endAddr=%d (size=%d)\n",
140                 start, end, insnsSize);
141             return false;
142         }
143
144         if (dvmInsnGetWidth(insnFlags, start) == 0) {
145             LOG_VFY_METH(meth,
146                 "VFY: 'try' block starts inside an instruction (%d)\n",
147                 start);
148             return false;
149         }
150
151         for (addr = start; addr < end;
152             addr += dvmInsnGetWidth(insnFlags, addr))
153         {
154             assert(dvmInsnGetWidth(insnFlags, addr) != 0);
155             dvmInsnSetInTry(insnFlags, addr, true);
156         }
157     }
158
159     /* Iterate over each of the handlers to verify target addresses. */
160     offset = dexGetFirstHandlerOffset(pCode);
161     for (i = 0; i < handlersSize; i++) {
162         DexCatchIterator iterator;
163         dexCatchIteratorInit(&iterator, pCode, offset);
164
165         for (;;) {
166             DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
167             u4 addr;
168
169             if (handler == NULL) {
170                 break;
171             }
172
173             addr = handler->address;
174             if (dvmInsnGetWidth(insnFlags, addr) == 0) {
175                 LOG_VFY_METH(meth,
176                     "VFY: exception handler starts at bad address (%d)\n",
177                     addr);
178                 return false;
179             }
180
181             dvmInsnSetBranchTarget(insnFlags, addr, true);
182         }
183
184         offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
185     }
186
187     return true;
188 }
189
190 /*
191  * Verify a switch table.  "curOffset" is the offset of the switch
192  * instruction.
193  */
194 bool dvmCheckSwitchTargets(const Method* meth, InsnFlags* insnFlags,
195     int curOffset)
196 {
197     const int insnCount = dvmGetMethodInsnsSize(meth);
198     const u2* insns = meth->insns + curOffset;
199     const u2* switchInsns;
200     u2 expectedSignature;
201     int switchCount, tableSize;
202     int offsetToSwitch, offsetToKeys, offsetToTargets, targ;
203     int offset, absOffset;
204
205     assert(curOffset >= 0 && curOffset < insnCount);
206
207     /* make sure the start of the switch is in range */
208     offsetToSwitch = (s2) insns[1];
209     if (curOffset + offsetToSwitch < 0 ||
210         curOffset + offsetToSwitch + 2 >= insnCount)
211     {
212         LOG_VFY_METH(meth,
213             "VFY: invalid switch start: at %d, switch offset %d, count %d\n",
214             curOffset, offsetToSwitch, insnCount);
215         return false;
216     }
217
218     /* offset to switch table is a relative branch-style offset */
219     switchInsns = insns + offsetToSwitch;
220
221     /* make sure the table is 32-bit aligned */
222     if ((((u4) switchInsns) & 0x03) != 0) {
223         LOG_VFY_METH(meth,
224             "VFY: unaligned switch table: at %d, switch offset %d\n",
225             curOffset, offsetToSwitch);
226         return false;
227     }
228
229     switchCount = switchInsns[1];
230
231     if ((*insns & 0xff) == OP_PACKED_SWITCH) {
232         /* 0=sig, 1=count, 2/3=firstKey */
233         offsetToTargets = 4;
234         offsetToKeys = -1;
235         expectedSignature = kPackedSwitchSignature;
236     } else {
237         /* 0=sig, 1=count, 2..count*2 = keys */
238         offsetToKeys = 2;
239         offsetToTargets = 2 + 2*switchCount;
240         expectedSignature = kSparseSwitchSignature;
241     }
242     tableSize = offsetToTargets + switchCount*2;
243
244     if (switchInsns[0] != expectedSignature) {
245         LOG_VFY_METH(meth,
246             "VFY: wrong signature for switch table (0x%04x, wanted 0x%04x)\n",
247             switchInsns[0], expectedSignature);
248         return false;
249     }
250
251     /* make sure the end of the switch is in range */
252     if (curOffset + offsetToSwitch + tableSize > insnCount) {
253         LOG_VFY_METH(meth,
254             "VFY: invalid switch end: at %d, switch offset %d, end %d, count %d\n",
255             curOffset, offsetToSwitch, curOffset + offsetToSwitch + tableSize,
256             insnCount);
257         return false;
258     }
259
260     /* for a sparse switch, verify the keys are in ascending order */
261     if (offsetToKeys > 0 && switchCount > 1) {
262         s4 lastKey;
263
264         lastKey = switchInsns[offsetToKeys] |
265                   (switchInsns[offsetToKeys+1] << 16);
266         for (targ = 1; targ < switchCount; targ++) {
267             s4 key = (s4) switchInsns[offsetToKeys + targ*2] |
268                     (s4) (switchInsns[offsetToKeys + targ*2 +1] << 16);
269             if (key <= lastKey) {
270                 LOG_VFY_METH(meth,
271                     "VFY: invalid packed switch: last key=%d, this=%d\n",
272                     lastKey, key);
273                 return false;
274             }
275
276             lastKey = key;
277         }
278     }
279
280     /* verify each switch target */
281     for (targ = 0; targ < switchCount; targ++) {
282         offset = (s4) switchInsns[offsetToTargets + targ*2] |
283                 (s4) (switchInsns[offsetToTargets + targ*2 +1] << 16);
284         absOffset = curOffset + offset;
285
286         if (absOffset < 0 || absOffset >= insnCount ||
287             !dvmInsnIsOpcode(insnFlags, absOffset))
288         {
289             LOG_VFY_METH(meth,
290                 "VFY: invalid switch target %d (-> 0x%x) at 0x%x[%d]\n",
291                 offset, absOffset, curOffset, targ);
292             return false;
293         }
294         dvmInsnSetBranchTarget(insnFlags, absOffset, true);
295     }
296
297     return true;
298 }
299
300 /*
301  * Verify that the target of a branch instruction is valid.
302  *
303  * We don't expect code to jump directly into an exception handler, but
304  * it's valid to do so as long as the target isn't a "move-exception"
305  * instruction.  We verify that in a later stage.
306  *
307  * The VM spec doesn't forbid an instruction from branching to itself,
308  * but the Dalvik spec declares that only certain instructions can do so.
309  */
310 bool dvmCheckBranchTarget(const Method* meth, InsnFlags* insnFlags,
311     int curOffset, bool selfOkay)
312 {
313     const int insnCount = dvmGetMethodInsnsSize(meth);
314     const u2* insns = meth->insns + curOffset;
315     int offset, absOffset;
316     bool isConditional;
317
318     if (!dvmGetBranchTarget(meth, insnFlags, curOffset, &offset,
319             &isConditional))
320         return false;
321
322     if (!selfOkay && offset == 0) {
323         LOG_VFY_METH(meth, "VFY: branch offset of zero not allowed at 0x%x\n",
324             curOffset);
325         return false;
326     }
327
328     /*
329      * Check for 32-bit overflow.  This isn't strictly necessary if we can
330      * depend on the VM to have identical "wrap-around" behavior, but
331      * it's unwise to depend on that.
332      */
333     if (((s8) curOffset + (s8) offset) != (s8)(curOffset + offset)) {
334         LOG_VFY_METH(meth, "VFY: branch target overflow 0x%x +%d\n",
335             curOffset, offset);
336         return false;
337     }
338     absOffset = curOffset + offset;
339     if (absOffset < 0 || absOffset >= insnCount ||
340         !dvmInsnIsOpcode(insnFlags, absOffset))
341     {
342         LOG_VFY_METH(meth,
343             "VFY: invalid branch target %d (-> 0x%x) at 0x%x\n",
344             offset, absOffset, curOffset);
345         return false;
346     }
347     dvmInsnSetBranchTarget(insnFlags, absOffset, true);
348
349     return true;
350 }
351
352
353 /*
354  * Output a code verifier warning message.  For the pre-verifier it's not
355  * a big deal if something fails (and it may even be expected), but if
356  * we're doing just-in-time verification it's significant.
357  */
358 void dvmLogVerifyFailure(const Method* meth, const char* format, ...)
359 {
360     va_list ap;
361     int logLevel;
362
363     if (gDvm.optimizing) {
364         return;
365         //logLevel = ANDROID_LOG_DEBUG;
366     } else {
367         logLevel = ANDROID_LOG_WARN;
368     }
369
370     va_start(ap, format);
371     LOG_PRI_VA(logLevel, LOG_TAG, format, ap);
372     if (meth != NULL) {
373         char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
374         LOG_PRI(logLevel, LOG_TAG, "VFY:  rejected %s.%s %s\n",
375             meth->clazz->descriptor, meth->name, desc);
376         free(desc);
377     }
378 }
379
380 /*
381  * Show a relatively human-readable message describing the failure to
382  * resolve a class.
383  *
384  * TODO: this is somewhat misleading when resolution fails because of
385  * illegal access rather than nonexistent class.
386  */
387 void dvmLogUnableToResolveClass(const char* missingClassDescr,
388     const Method* meth)
389 {
390     if (gDvm.optimizing)
391         return;
392
393     char* dotMissingClass = dvmDescriptorToDot(missingClassDescr);
394     char* dotFromClass = dvmDescriptorToDot(meth->clazz->descriptor);
395     //char* methodDescr = dexProtoCopyMethodDescriptor(&meth->prototype);
396
397     LOGE("Could not find class '%s', referenced from method %s.%s\n",
398         dotMissingClass, dotFromClass, meth->name/*, methodDescr*/);
399
400     free(dotMissingClass);
401     free(dotFromClass);
402     //free(methodDescr);
403 }
404
405 /*
406  * Extract the relative offset from a branch instruction.
407  *
408  * Returns "false" on failure (e.g. this isn't a branch instruction).
409  */
410 bool dvmGetBranchTarget(const Method* meth, InsnFlags* insnFlags,
411     int curOffset, int* pOffset, bool* pConditional)
412 {
413     const u2* insns = meth->insns + curOffset;
414     int tmp;
415
416     switch (*insns & 0xff) {
417     case OP_GOTO:
418         *pOffset = ((s2) *insns) >> 8;
419         *pConditional = false;
420         break;
421     case OP_GOTO_32:
422         *pOffset = insns[1] | (((u4) insns[2]) << 16);
423         *pConditional = false;
424         break;
425     case OP_GOTO_16:
426         *pOffset = (s2) insns[1];
427         *pConditional = false;
428         break;
429     case OP_IF_EQ:
430     case OP_IF_NE:
431     case OP_IF_LT:
432     case OP_IF_GE:
433     case OP_IF_GT:
434     case OP_IF_LE:
435     case OP_IF_EQZ:
436     case OP_IF_NEZ:
437     case OP_IF_LTZ:
438     case OP_IF_GEZ:
439     case OP_IF_GTZ:
440     case OP_IF_LEZ:
441         *pOffset = (s2) insns[1];
442         *pConditional = true;
443         break;
444     default:
445         return false;
446         break;
447     }
448
449     return true;
450 }
451
452 /*
453  * Given a 32-bit constant, return the most-restricted RegType enum entry
454  * that can hold the value.
455  */
456 char dvmDetermineCat1Const(s4 value)
457 {
458     if (value < -32768)
459         return kRegTypeInteger;
460     else if (value < -128)
461         return kRegTypeShort;
462     else if (value < 0)
463         return kRegTypeByte;
464     else if (value == 0)
465         return kRegTypeZero;
466     else if (value == 1)
467         return kRegTypeOne;
468     else if (value < 128)
469         return kRegTypePosByte;
470     else if (value < 32768)
471         return kRegTypePosShort;
472     else if (value < 65536)
473         return kRegTypeChar;
474     else
475         return kRegTypeInteger;
476 }
477