blob: 0e62b258bde9a6487aa47b3e1ea932e2ba6c97d9 [file] [log] [blame]
Carl Shapiro0e5d75d2011-07-06 18:28:37 -07001// Copyright 2011 Google Inc. All Rights Reserved.
2
Brian Carlstrom578bbdc2011-07-21 14:07:47 -07003#include "dex_verifier.h"
Carl Shapiro0e5d75d2011-07-06 18:28:37 -07004
Elliott Hughes1f359b02011-07-17 14:27:17 -07005#include <iostream>
6
Brian Carlstrom1f870082011-08-23 16:02:11 -07007#include "class_linker.h"
8#include "dex_file.h"
9#include "dex_instruction.h"
10#include "dex_instruction_visitor.h"
Elliott Hughes1f359b02011-07-17 14:27:17 -070011#include "logging.h"
Brian Carlstrom1f870082011-08-23 16:02:11 -070012#include "runtime.h"
Elliott Hughes1f359b02011-07-17 14:27:17 -070013#include "stringpiece.h"
Carl Shapiro0e5d75d2011-07-06 18:28:37 -070014
15namespace art {
16
jeffhaoba5ebb92011-08-25 17:24:37 -070017/*
18 * Returns "true" if the flags indicate that this address holds the start
19 * of an instruction.
20 */
21inline bool InsnIsOpcode(const uint32_t insn_flags[], int addr) {
22 return (insn_flags[addr] & DexVerify::kInsnFlagWidthMask) != 0;
23}
24
25/*
26 * Extract the unsigned 16-bit instruction width from "flags".
27 */
28inline int InsnGetWidth(const uint32_t insn_flags[], int addr) {
29 return insn_flags[addr] & DexVerify::kInsnFlagWidthMask;
30}
31
32/*
33 * Changed?
34 */
35inline bool InsnIsChanged(const uint32_t insn_flags[], int addr) {
36 return (insn_flags[addr] & DexVerify::kInsnFlagChanged) != 0;
37}
38inline void InsnSetChanged(uint32_t insn_flags[], int addr, bool changed) {
39 if (changed)
40 insn_flags[addr] |= DexVerify::kInsnFlagChanged;
41 else
42 insn_flags[addr] &= ~DexVerify::kInsnFlagChanged;
43}
44
45/*
46 * Visited?
47 */
48inline bool InsnIsVisited(const uint32_t insn_flags[], int addr) {
49 return (insn_flags[addr] & DexVerify::kInsnFlagVisited) != 0;
50}
51inline void InsnSetVisited(uint32_t insn_flags[], int addr, bool changed) {
52 if (changed)
53 insn_flags[addr] |= DexVerify::kInsnFlagVisited;
54 else
55 insn_flags[addr] &= ~DexVerify::kInsnFlagVisited;
56}
57
58/*
59 * Visited or changed?
60 */
61inline bool InsnIsVisitedOrChanged(const uint32_t insn_flags[], int addr) {
62 return (insn_flags[addr] & (DexVerify::kInsnFlagVisited |
63 DexVerify::kInsnFlagChanged)) != 0;
64}
65
66/*
67 * In a "try" block?
68 */
69inline bool InsnIsInTry(const uint32_t insn_flags[], int addr) {
70 return (insn_flags[addr] & DexVerify::kInsnFlagInTry) != 0;
71}
72inline void InsnSetInTry(uint32_t insn_flags[], int addr, bool inTry) {
73 insn_flags[addr] |= DexVerify::kInsnFlagInTry;
74}
75
76/*
77 * Instruction is a branch target or exception handler?
78 */
79inline bool InsnIsBranchTarget(const uint32_t insn_flags[], int addr) {
80 return (insn_flags[addr] & DexVerify::kInsnFlagBranchTarget) != 0;
81}
82inline void InsnSetBranchTarget(uint32_t insn_flags[], int addr, bool isBranch)
83{
84 insn_flags[addr] |= DexVerify::kInsnFlagBranchTarget;
85}
86
87/*
88 * Instruction is a GC point?
89 */
90inline bool InsnIsGcPoint(const uint32_t insn_flags[], int addr) {
91 return (insn_flags[addr] & DexVerify::kInsnFlagGcPoint) != 0;
92}
93inline void InsnSetGcPoint(uint32_t insn_flags[], int addr, bool isGcPoint) {
94 insn_flags[addr] |= DexVerify::kInsnFlagGcPoint;
95}
96
97
98/*
99 * Extract the relative offset from a branch instruction.
100 *
101 * Returns "false" on failure (e.g. this isn't a branch instruction).
102 */
103bool GetBranchOffset(const DexFile::CodeItem* code_item,
104 const uint32_t insn_flags[], int cur_offset, int32_t* pOffset,
105 bool* pConditional, bool* selfOkay) {
106 const uint16_t* insns = code_item->insns_ + cur_offset;
107
108 switch (*insns & 0xff) {
109 case Instruction::GOTO:
110 *pOffset = ((int16_t) *insns) >> 8;
111 *pConditional = false;
112 *selfOkay = false;
113 break;
114 case Instruction::GOTO_32:
115 *pOffset = insns[1] | (((uint32_t) insns[2]) << 16);
116 *pConditional = false;
117 *selfOkay = true;
118 break;
119 case Instruction::GOTO_16:
120 *pOffset = (int16_t) insns[1];
121 *pConditional = false;
122 *selfOkay = false;
123 break;
124 case Instruction::IF_EQ:
125 case Instruction::IF_NE:
126 case Instruction::IF_LT:
127 case Instruction::IF_GE:
128 case Instruction::IF_GT:
129 case Instruction::IF_LE:
130 case Instruction::IF_EQZ:
131 case Instruction::IF_NEZ:
132 case Instruction::IF_LTZ:
133 case Instruction::IF_GEZ:
134 case Instruction::IF_GTZ:
135 case Instruction::IF_LEZ:
136 *pOffset = (int16_t) insns[1];
137 *pConditional = true;
138 *selfOkay = false;
139 break;
140 default:
141 return false;
142 break;
143 }
144
145 return true;
146}
147
148
149/*
150 * Verify an array data table. "cur_offset" is the offset of the
151 * fill-array-data instruction.
152 */
153static bool CheckArrayData(const DexFile::CodeItem* code_item,
154 uint32_t cur_offset) {
155 const uint32_t insn_count = code_item->insns_size_;
156 const uint16_t* insns = code_item->insns_ + cur_offset;
157 const uint16_t* array_data;
158 int32_t array_data_offset;
159
160 assert(cur_offset < insn_count);
161
162 /* make sure the start of the array data table is in range */
163 array_data_offset = insns[1] | (((int32_t) insns[2]) << 16);
164 if ((int32_t) cur_offset + array_data_offset < 0 ||
165 cur_offset + array_data_offset + 2 >= insn_count)
166 {
167 LOG(ERROR) << "VFY: invalid array data start: at " << cur_offset
168 << ", data offset " << array_data_offset << ", count "
169 << insn_count;
170 return false;
171 }
172
173 /* offset to array data table is a relative branch-style offset */
174 array_data = insns + array_data_offset;
175
176 /* make sure the table is 32-bit aligned */
177 if ((((uint32_t) array_data) & 0x03) != 0) {
178 LOG(ERROR) << "VFY: unaligned array data table: at " << cur_offset
179 << ", data offset " << array_data_offset;
180 return false;
181 }
182
183 uint32_t value_width = array_data[1];
184 uint32_t value_count = *(uint32_t*) (&array_data[2]);
185 uint32_t table_size = 4 + (value_width * value_count + 1) / 2;
186
187 /* make sure the end of the switch is in range */
188 if (cur_offset + array_data_offset + table_size > insn_count) {
189 LOG(ERROR) << "VFY: invalid array data end: at " << cur_offset
190 << ", data offset " << array_data_offset << ", end "
191 << cur_offset + array_data_offset + table_size << ", count "
192 << insn_count;
193 return false;
194 }
195
196 return true;
197}
198
199/*
200 * Perform static checks on a "new-instance" instruction. Specifically,
201 * make sure the class reference isn't for an array class.
202 *
203 * We don't need the actual class, just a pointer to the class name.
204 */
205static bool CheckNewInstance(const DexFile* dex_file, uint32_t idx) {
206 if (idx >= dex_file->GetHeader().type_ids_size_) {
207 LOG(ERROR) << "VFY: bad type index " << idx << " (max "
208 << dex_file->GetHeader().type_ids_size_ << ")";
209 return false;
210 }
211
212 const char* descriptor = dex_file->dexStringByTypeIdx(idx);
213 if (descriptor[0] != 'L') {
214 LOG(ERROR) << "VFY: can't call new-instance on type '"
215 << descriptor << "'";
216 return false;
217 }
218
219 return true;
220}
221
222/*
223 * Perform static checks on a "new-array" instruction. Specifically, make
224 * sure they aren't creating an array of arrays that causes the number of
225 * dimensions to exceed 255.
226 */
227static bool CheckNewArray(const DexFile* dex_file, uint32_t idx) {
228 if (idx >= dex_file->GetHeader().type_ids_size_) {
229 LOG(ERROR) << "VFY: bad type index " << idx << " (max "
230 << dex_file->GetHeader().type_ids_size_ << ")";
231 return false;
232 }
233
234 int bracket_count = 0;
235 const char* descriptor = dex_file->dexStringByTypeIdx(idx);
236 const char* cp = descriptor;
237 while (*cp++ == '[')
238 bracket_count++;
239
240 if (bracket_count == 0) {
241 /* The given class must be an array type. */
242 LOG(ERROR) << "VFY: can't new-array class '" << descriptor
243 << "' (not an array)";
244 return false;
245 } else if (bracket_count > 255) {
246 /* It is illegal to create an array of more than 255 dimensions. */
247 LOG(ERROR) << "VFY: can't new-array class '" << descriptor
248 << "' (exceeds limit)";
249 return false;
250 }
251
252 return true;
253}
254
255/*
256 * Perform static checks on an instruction that takes a class constant.
257 * Ensure that the class index is in the valid range.
258 */
259static bool CheckTypeIndex(const DexFile* dex_file, uint32_t idx) {
260 if (idx >= dex_file->GetHeader().type_ids_size_) {
261 LOG(ERROR) << "VFY: bad type index " << idx << " (max "
262 << dex_file->GetHeader().type_ids_size_ << ")";
263 return false;
264 }
265 return true;
266}
267
268/*
269 * Perform static checks on a field get or set instruction. All we do
270 * here is ensure that the field index is in the valid range.
271 */
272static bool CheckFieldIndex(const DexFile* dex_file, uint32_t idx) {
273 if (idx >= dex_file->GetHeader().field_ids_size_) {
274 LOG(ERROR) << "VFY: bad field index " << idx << " (max "
275 << dex_file->GetHeader().field_ids_size_ << ")";
276 return false;
277 }
278 return true;
279}
280
281/*
282 * Perform static checks on a method invocation instruction. All we do
283 * here is ensure that the method index is in the valid range.
284 */
285static bool CheckMethodIndex(const DexFile* dex_file, uint32_t idx) {
286 if (idx >= dex_file->GetHeader().method_ids_size_) {
287 LOG(ERROR) << "VFY: bad method index " << idx << " (max "
288 << dex_file->GetHeader().method_ids_size_ << ")";
289 return false;
290 }
291 return true;
292}
293
294/*
295 * Ensure that the string index is in the valid range.
296 */
297static bool CheckStringIndex(const DexFile* dex_file, uint32_t idx) {
298 if (idx >= dex_file->GetHeader().string_ids_size_) {
299 LOG(ERROR) << "VFY: bad string index " << idx << " (max "
300 << dex_file->GetHeader().string_ids_size_ << ")";
301 return false;
302 }
303 return true;
304}
305
306/*
307 * Ensure that the register index is valid for this code item.
308 */
309static bool CheckRegisterIndex(const DexFile::CodeItem* code_item, uint32_t idx)
310{
311 if (idx >= code_item->registers_size_) {
312 LOG(ERROR) << "VFY: register index out of range (" << idx << " >= "
313 << code_item->registers_size_ << ")";
314 return false;
315 }
316 return true;
317}
318
319/*
320 * Ensure that the wide register index is valid for this code item.
321 */
322static bool CheckWideRegisterIndex(const DexFile::CodeItem* code_item,
323 uint32_t idx) {
324 if (idx + 1 >= code_item->registers_size_) {
325 LOG(ERROR) << "VFY: wide register index out of range (" << idx
326 << "+1 >= " << code_item->registers_size_ << ")";
327 return false;
328 }
329 return true;
330}
331
332/*
333 * Check the register indices used in a "vararg" instruction, such as
334 * invoke-virtual or filled-new-array.
335 *
336 * vA holds word count (0-5), args[] have values.
337 *
338 * There are some tests we don't do here, e.g. we don't try to verify
339 * that invoking a method that takes a double is done with consecutive
340 * registers. This requires parsing the target method signature, which
341 * we will be doing later on during the code flow analysis.
342 */
343static bool CheckVarArgRegs(const DexFile::CodeItem* code_item, uint32_t vA,
344 uint32_t arg[]) {
345 uint16_t registers_size = code_item->registers_size_;
346 uint32_t idx;
347
348 if (vA > 5) {
349 LOG(ERROR) << "VFY: invalid arg count (" << vA << ") in non-range invoke)";
350 return false;
351 }
352
353 for (idx = 0; idx < vA; idx++) {
354 if (arg[idx] > registers_size) {
355 LOG(ERROR) << "VFY: invalid reg index (" << arg[idx]
356 << ") in non-range invoke (> " << registers_size << ")";
357 return false;
358 }
359 }
360
361 return true;
362}
363
364/*
365 * Check the register indices used in a "vararg/range" instruction, such as
366 * invoke-virtual/range or filled-new-array/range.
367 *
368 * vA holds word count, vC holds index of first reg.
369 */
370static bool CheckVarArgRangeRegs(const DexFile::CodeItem* code_item,
371 uint32_t vA, uint32_t vC) {
372 uint16_t registers_size = code_item->registers_size_;
373
374 /*
375 * vA/vC are unsigned 8-bit/16-bit quantities for /range instructions,
376 * so there's no risk of integer overflow when adding them here.
377 */
378 if (vA + vC > registers_size) {
379 LOG(ERROR) << "VFY: invalid reg index " << vA << "+" << vC
380 << " in range invoke (> " << registers_size << ")";
381 return false;
382 }
383
384 return true;
385}
386
387/*
388 * Verify a switch table. "cur_offset" is the offset of the switch instruction.
389 *
390 * Updates "insnFlags", setting the "branch target" flag.
391 */
392static bool CheckSwitchTargets(const DexFile::CodeItem* code_item,
393 uint32_t insn_flags[], uint32_t cur_offset) {
394 const uint32_t insn_count = code_item->insns_size_;
395 const uint16_t* insns = code_item->insns_ + cur_offset;
396 const uint16_t* switch_insns;
397 uint16_t expected_signature;
398 uint32_t switch_count, table_size;
399 int32_t switch_offset, keys_offset, targets_offset;
400 int32_t offset, abs_offset;
401 uint32_t targ;
402
403 /* make sure the start of the switch is in range */
404 switch_offset = insns[1] | ((int32_t) insns[2]) << 16;
405 if ((int32_t) cur_offset + switch_offset < 0 ||
406 cur_offset + switch_offset + 2 >= insn_count) {
407 LOG(ERROR) << "VFY: invalid switch start: at " << cur_offset
408 << ", switch offset " << switch_offset << ", count "
409 << insn_count;
410 return false;
411 }
412
413 /* offset to switch table is a relative branch-style offset */
414 switch_insns = insns + switch_offset;
415
416 /* make sure the table is 32-bit aligned */
417 if ((((uint32_t) switch_insns) & 0x03) != 0) {
418 LOG(ERROR) << "VFY: unaligned switch table: at " << cur_offset
419 << ", switch offset " << switch_offset;
420 return false;
421 }
422
423 switch_count = switch_insns[1];
424
425 if ((*insns & 0xff) == Instruction::PACKED_SWITCH) {
426 /* 0=sig, 1=count, 2/3=firstKey */
427 targets_offset = 4;
428 keys_offset = -1;
429 expected_signature = Instruction::kPackedSwitchSignature;
430 } else {
431 /* 0=sig, 1=count, 2..count*2 = keys */
432 keys_offset = 2;
433 targets_offset = 2 + 2 * switch_count;
434 expected_signature = Instruction::kSparseSwitchSignature;
435 }
436 table_size = targets_offset + switch_count * 2;
437
438 if (switch_insns[0] != expected_signature) {
439 LOG(ERROR) << "VFY: wrong signature for switch table (0x" << switch_insns[0]
440 << ", wanted 0x" << expected_signature << ")";
441 return false;
442 }
443
444 /* make sure the end of the switch is in range */
445 if (cur_offset + switch_offset + table_size > (uint32_t) insn_count) {
446 LOG(ERROR) << "VFY: invalid switch end: at " << cur_offset
447 << ", switch offset " << switch_offset << ", end "
448 << cur_offset + switch_offset + table_size << ", count "
449 << insn_count;
450 return false;
451 }
452
453 /* for a sparse switch, verify the keys are in ascending order */
454 if (keys_offset > 0 && switch_count > 1) {
455 int32_t last_key;
456
457 last_key = switch_insns[keys_offset] |
458 (switch_insns[keys_offset + 1] << 16);
459 for (targ = 1; targ < switch_count; targ++) {
460 int32_t key = (int32_t) switch_insns[keys_offset + targ * 2] |
461 (int32_t) (switch_insns[keys_offset + targ * 2 + 1] << 16);
462 if (key <= last_key) {
463 LOG(ERROR) << "VFY: invalid packed switch: last key=" << last_key
464 << ", this=" << key;
465 return false;
466 }
467
468 last_key = key;
469 }
470 }
471
472 /* verify each switch target */
473 for (targ = 0; targ < switch_count; targ++) {
474 offset = (int32_t) switch_insns[targets_offset + targ * 2] |
475 (int32_t) (switch_insns[targets_offset + targ * 2 + 1] << 16);
476 abs_offset = cur_offset + offset;
477
478 if (abs_offset < 0 || abs_offset >= (int32_t) insn_count ||
479 !InsnIsOpcode(insn_flags, abs_offset)) {
480 LOG(ERROR) << "VFY: invalid switch target " << offset << " (-> "
481 << abs_offset << ") at " << cur_offset << "[" << targ << "]";
482 return false;
483 }
484 InsnSetBranchTarget(insn_flags, abs_offset, true);
485 }
486
487 return true;
488}
489
490/*
491 * Verify that the target of a branch instruction is valid.
492 *
493 * We don't expect code to jump directly into an exception handler, but
494 * it's valid to do so as long as the target isn't a "move-exception"
495 * instruction. We verify that in a later stage.
496 *
497 * The VM spec doesn't forbid an instruction from branching to itself,
498 * but the Dalvik spec declares that only certain instructions can do so.
499 *
500 * Updates "insnFlags", setting the "branch target" flag.
501 */
502static bool CheckBranchTarget(const DexFile::CodeItem* code_item,
503 uint32_t insn_flags[], int cur_offset) {
504 const int insn_count = code_item->insns_size_;
505 int32_t offset, abs_offset;
506 bool isConditional, selfOkay;
507
508 if (!GetBranchOffset(code_item, insn_flags, cur_offset, &offset,
509 &isConditional, &selfOkay))
510 return false;
511
512 if (!selfOkay && offset == 0) {
513 LOG(ERROR) << "VFY: branch offset of zero not allowed at" << cur_offset;
514 return false;
515 }
516
517 /*
518 * Check for 32-bit overflow. This isn't strictly necessary if we can
519 * depend on the VM to have identical "wrap-around" behavior, but
520 * it's unwise to depend on that.
521 */
522 if (((int64_t) cur_offset + (int64_t) offset) !=
523 (int64_t)(cur_offset + offset)) {
524 LOG(ERROR) << "VFY: branch target overflow " << cur_offset << " +"
525 << offset;
526 return false;
527 }
528 abs_offset = cur_offset + offset;
529 if (abs_offset < 0 || abs_offset >= insn_count ||
530 !InsnIsOpcode(insn_flags, abs_offset))
531 {
532 LOG(ERROR) << "VFY: invalid branch target " << offset << " (-> "
533 << abs_offset << ") at " << cur_offset;
534 return false;
535 }
536 InsnSetBranchTarget(insn_flags, abs_offset, true);
537
538 return true;
539}
540
541bool CheckInsnWidth(const uint16_t* insns, uint32_t insns_size,
542 uint32_t insn_flags[]) {
543 const byte* ptr = reinterpret_cast<const byte*>(insns);
544 const Instruction* inst = Instruction::At(ptr);
545
546 size_t width = 0;
547
548 while (width < insns_size) {
549 insn_flags[width] |= inst->Size();
550 width += inst->Size();
551 inst = inst->Next();
552 }
553
554 if (width != insns_size) {
555 LOG(ERROR) << "VFY: code did not end where expected (" << width << " vs. "
556 << insns_size << ")";
557 return false;
558 }
559
560 return true;
561}
562
563/*
564 * Set the "in try" flags for all instructions protected by "try" statements.
565 * Also sets the "branch target" flags for exception handlers.
566 *
567 * Call this after widths have been set in "insn_flags".
568 *
569 * Returns "false" if something in the exception table looks fishy, but
570 * we're expecting the exception table to be somewhat sane.
571 */
572static bool ScanTryCatchBlocks(const DexFile::CodeItem* code_item,
573 uint32_t insn_flags[]) {
574 uint32_t insns_size = code_item->insns_size_;
575 uint32_t tries_size = code_item->tries_size_;
576
577 if (tries_size == 0) {
578 return true;
579 }
580
581 const DexFile::TryItem* tries = DexFile::dexGetTryItems(*code_item, 0);
582
583 for (uint32_t idx = 0; idx < tries_size; idx++) {
584 const DexFile::TryItem* try_item = &tries[idx];
585 uint32_t start = try_item->start_addr_;
586 uint32_t end = start + try_item->insn_count_;
587
588 if ((start >= end) || (start >= insns_size) || (end > insns_size)) {
589 LOG(ERROR) << "VFY: bad exception entry: startAddr=" << start
590 << " endAddr=" << end << " (size=" << insns_size << ")";
591 return false;
592 }
593
594 if (InsnGetWidth(insn_flags, start) == 0) {
595 LOG(ERROR) << "VFY: 'try' block starts inside an instruction ("
596 << start << ")";
597 return false;
598 }
599
600 uint32_t addr;
601 for (addr = start; addr < end; addr += InsnGetWidth(insn_flags, addr)) {
602 InsnSetInTry(insn_flags, addr, true);
603 }
604 }
605
606 /* Iterate over each of the handlers to verify target addresses. */
607 const byte* handlers_ptr = DexFile::dexGetCatchHandlerData(*code_item, 0);
608 uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
609 for (uint32_t idx = 0; idx < handlers_size; idx++) {
610 DexFile::CatchHandlerIterator iterator(handlers_ptr);
611
612 for (; !iterator.HasNext(); iterator.Next()) {
613 uint32_t addr = iterator.Get().address_;
614 if (InsnGetWidth(insn_flags, addr) == 0) {
615 LOG(ERROR) << "VFY: exception handler starts at bad address ("
616 << addr << ")";
617 return false;
618 }
619
620 InsnSetBranchTarget(insn_flags, addr, true);
621 }
622
623 handlers_ptr = iterator.GetData();
624 }
625
626 return true;
627}
628
629
630
Carl Shapiro0e5d75d2011-07-06 18:28:37 -0700631bool DexVerify::VerifyClass(Class* klass) {
632 if (klass->IsVerified()) {
633 return true;
634 }
635 for (size_t i = 0; i < klass->NumDirectMethods(); ++i) {
636 Method* method = klass->GetDirectMethod(i);
637 if (!VerifyMethod(method)) {
jeffhaoba5ebb92011-08-25 17:24:37 -0700638 LOG(ERROR) << "Verifier rejected class "
639 << klass->GetDescriptor()->ToModifiedUtf8();
Carl Shapiro0e5d75d2011-07-06 18:28:37 -0700640 return false;
641 }
642 }
643 for (size_t i = 0; i < klass->NumVirtualMethods(); ++i) {
644 Method* method = klass->GetVirtualMethod(i);
645 if (!VerifyMethod(method)) {
jeffhaoba5ebb92011-08-25 17:24:37 -0700646 LOG(ERROR) << "Verifier rejected class "
647 << klass->GetDescriptor()->ToModifiedUtf8();
Carl Shapiro0e5d75d2011-07-06 18:28:37 -0700648 return false;
649 }
650 }
651 return true;
652}
653
654bool DexVerify::VerifyMethod(Method* method) {
jeffhaoba5ebb92011-08-25 17:24:37 -0700655 const DexCache* dex_cache = method->GetDeclaringClass()->GetDexCache();
656 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
657 const DexFile& dex_file = class_linker->FindDexFile(dex_cache);
658 const DexFile::CodeItem *code_item = dex_file.GetCodeItem(method->code_off_);
659
660 /*
661 * If there aren't any instructions, make sure that's expected, then
662 * exit successfully.
663 */
664 if (code_item == NULL) {
665 if (!method->IsNative() && !method->IsAbstract()) {
666 LOG(ERROR) << "VFY: zero-length code in concrete non-native method";
667 return false;
668 }
669 return true;
670 }
671
672 /*
673 * Sanity-check the register counts. ins + locals = registers, so make
674 * sure that ins <= registers.
675 */
676 if (code_item->ins_size_ > code_item->registers_size_) {
677 LOG(ERROR) << "VFY: bad register counts (ins=" << code_item->ins_size_
678 << " regs=" << code_item->registers_size_;
679 return false;
680 }
681
682 /*
683 * Allocate and initialize an array to hold instruction data.
684 */
685 uint32_t* insn_flags = new uint32_t[code_item->insns_size_]();
686
687 /*
688 * Run through the instructions and see if the width checks out.
689 */
690 if (!CheckInsnWidth(code_item->insns_, code_item->insns_size_, insn_flags)) {
691 delete insn_flags;
692 return false;
693 }
694
695 /*
696 * Flag instructions guarded by a "try" block and check exception handlers.
697 */
698 if (!ScanTryCatchBlocks(code_item, insn_flags)) {
699 delete insn_flags;
700 return false;
701 }
702
703 /*
704 * Perform static instruction verification.
705 */
706 if (!VerifyInstructions(&dex_file, code_item, insn_flags)) {
707 delete insn_flags;
708 return false;
709 }
710
711 /*
712 * TODO: Code flow analysis
713 */
714
715 delete insn_flags;
716 return true;
Carl Shapiro0e5d75d2011-07-06 18:28:37 -0700717}
718
jeffhaoba5ebb92011-08-25 17:24:37 -0700719bool DexVerify::VerifyInstructions(const DexFile* dex_file,
720 const DexFile::CodeItem* code_item, uint32_t insn_flags[]) {
721 const byte* ptr = reinterpret_cast<const byte*>(code_item->insns_);
722 const Instruction* inst = Instruction::At(ptr);
723
724 /* Flag the start of the method as a branch target. */
725 InsnSetBranchTarget(insn_flags, 0, true);
726
727 uint32_t width = 0;
728 uint32_t insns_size = code_item->insns_size_;
729
730 while (width < insns_size) {
731 if (!VerifyInstruction(dex_file, inst, width, code_item, insn_flags)) {
732 LOG(ERROR) << "VFY: rejecting opcode 0x" << std::hex
733 << (int) inst->Opcode() << " at 0x" << width << std::dec;
734 return false;
735 }
736
737 /* Flag instructions that are garbage collection points */
738 if (inst->IsBranch() || inst->IsSwitch() || inst->IsThrow() ||
739 inst->IsReturn()) {
740 InsnSetGcPoint(insn_flags, width, true);
741 }
742
743 width += inst->Size();
744 inst = inst->Next();
745 }
746 return true;
747}
748
749bool DexVerify::VerifyInstruction(const DexFile* dex_file,
750 const Instruction* inst, uint32_t code_offset,
751 const DexFile::CodeItem* code_item, uint32_t insn_flags[]) {
752 Instruction::Code opcode = inst->Opcode();
753 bool result = true;
754 uint32_t vA, vB, vC;
755 uint64_t vB_wide;
756 uint32_t arg[5];
757
758 inst->Decode(vA, vB, vB_wide, vC, arg);
759
760 int argumentA = inst->GetVerifyTypeArgumentA();
761 int argumentB = inst->GetVerifyTypeArgumentB();
762 int argumentC = inst->GetVerifyTypeArgumentC();
763 int extra_flags = inst->GetVerifyExtraFlags();
764
765 switch (argumentA) {
766 case Instruction::kVerifyRegA:
767 result &= CheckRegisterIndex(code_item, vA);
768 break;
769 case Instruction::kVerifyRegAWide:
770 result &= CheckWideRegisterIndex(code_item, vA);
771 break;
772 }
773
774 switch (argumentB) {
775 case Instruction::kVerifyRegB:
776 result &= CheckRegisterIndex(code_item, vB);
777 break;
778 case Instruction::kVerifyRegBField:
779 result &= CheckFieldIndex(dex_file, vB);
780 break;
781 case Instruction::kVerifyRegBMethod:
782 result &= CheckMethodIndex(dex_file, vB);
783 break;
784 case Instruction::kVerifyRegBNewInstance:
785 result &= CheckNewInstance(dex_file, vB);
786 break;
787 case Instruction::kVerifyRegBString:
788 result &= CheckStringIndex(dex_file, vB);
789 break;
790 case Instruction::kVerifyRegBType:
791 result &= CheckTypeIndex(dex_file, vB);
792 break;
793 case Instruction::kVerifyRegBWide:
794 result &= CheckWideRegisterIndex(code_item, vB);
795 break;
796 }
797
798 switch (argumentC) {
799 case Instruction::kVerifyRegC:
800 result &= CheckRegisterIndex(code_item, vC);
801 break;
802 case Instruction::kVerifyRegCField:
803 result &= CheckFieldIndex(dex_file, vC);
804 break;
805 case Instruction::kVerifyRegCNewArray:
806 result &= CheckNewArray(dex_file, vC);
807 break;
808 case Instruction::kVerifyRegCType:
809 result &= CheckTypeIndex(dex_file, vC);
810 break;
811 case Instruction::kVerifyRegCWide:
812 result &= CheckWideRegisterIndex(code_item, vC);
813 break;
814 }
815
816 switch (extra_flags) {
817 case Instruction::kVerifyArrayData:
818 result &= CheckArrayData(code_item, code_offset);
819 break;
820 case Instruction::kVerifyBranchTarget:
821 result &= CheckBranchTarget(code_item, insn_flags, code_offset);
822 break;
823 case Instruction::kVerifySwitchTargets:
824 result &= CheckSwitchTargets(code_item, insn_flags, code_offset);
825 break;
826 case Instruction::kVerifyVarArg:
827 result &= CheckVarArgRegs(code_item, vA, arg);
828 break;
829 case Instruction::kVerifyVarArgRange:
830 result &= CheckVarArgRangeRegs(code_item, vA, vC);
831 break;
832 case Instruction::kVerifyError:
833 LOG(ERROR) << "VFY: unexpected opcode " << (int) opcode;
834 result = false;
835 break;
836 }
837
838 return result;
839};
840
Carl Shapiro0e5d75d2011-07-06 18:28:37 -0700841} // namespace art