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