blob: 329508f8e3d4dcad2a129dc85c1e4b96fbd24106 [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"
jeffhaob4df5142011-09-19 20:25:32 -07008#include "dex_cache.h"
Brian Carlstrom1f870082011-08-23 16:02:11 -07009#include "dex_file.h"
10#include "dex_instruction.h"
11#include "dex_instruction_visitor.h"
jeffhaobdb76512011-09-07 11:43:16 -070012#include "dex_verifier.h"
Elliott Hughes1f359b02011-07-17 14:27:17 -070013#include "logging.h"
Brian Carlstrom1f870082011-08-23 16:02:11 -070014#include "runtime.h"
Elliott Hughes1f359b02011-07-17 14:27:17 -070015#include "stringpiece.h"
Carl Shapiro0e5d75d2011-07-06 18:28:37 -070016
17namespace art {
18
jeffhaobdb76512011-09-07 11:43:16 -070019#define k_ kRegTypeUnknown
20#define kU kRegTypeUninit
21#define kX kRegTypeConflict
22#define k0 kRegTypeZero
23#define k1 kRegTypeOne
24#define kZ kRegTypeBoolean
25#define ky kRegTypeConstPosByte
26#define kY kRegTypeConstByte
27#define kh kRegTypeConstPosShort
28#define kH kRegTypeConstShort
29#define kc kRegTypeConstChar
30#define ki kRegTypeConstInteger
31#define kb kRegTypePosByte
32#define kB kRegTypeByte
33#define ks kRegTypePosShort
34#define kS kRegTypeShort
35#define kC kRegTypeChar
36#define kI kRegTypeInteger
37#define kF kRegTypeFloat
38#define kN kRegTypeConstLo
39#define kn kRegTypeConstHi
40#define kJ kRegTypeLongLo
41#define kj kRegTypeLongHi
42#define kD kRegTypeDoubleLo
43#define kd kRegTypeDoubleHi
44
45const char DexVerifier::merge_table_[kRegTypeMAX][kRegTypeMAX] =
46 {
47 /* 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 */
48 { /*_*/ k_,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX },
49 { /*U*/ kX,kU,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX },
50 { /*X*/ kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX },
51 { /*0*/ kX,kX,kX,k0,kZ,kZ,ky,kY,kh,kH,kc,ki,kb,kB,ks,kS,kC,kI,kF,kX,kX,kX,kX,kX,kX },
52 { /*1*/ kX,kX,kX,kZ,k1,kZ,ky,kY,kh,kH,kc,ki,kb,kB,ks,kS,kC,kI,kF,kX,kX,kX,kX,kX,kX },
53 { /*Z*/ kX,kX,kX,kZ,kZ,kZ,ky,kY,kh,kH,kc,ki,kb,kB,ks,kS,kC,kI,kF,kX,kX,kX,kX,kX,kX },
54 { /*y*/ kX,kX,kX,ky,ky,ky,ky,kY,kh,kH,kc,ki,kb,kB,ks,kS,kC,kI,kF,kX,kX,kX,kX,kX,kX },
55 { /*Y*/ kX,kX,kX,kY,kY,kY,kY,kY,kh,kH,kc,ki,kB,kB,kS,kS,kI,kI,kF,kX,kX,kX,kX,kX,kX },
56 { /*h*/ kX,kX,kX,kh,kh,kh,kh,kh,kh,kH,kc,ki,ks,kS,ks,kS,kC,kI,kF,kX,kX,kX,kX,kX,kX },
57 { /*H*/ kX,kX,kX,kH,kH,kH,kH,kH,kH,kH,kc,ki,kS,kS,kS,kS,kI,kI,kF,kX,kX,kX,kX,kX,kX },
58 { /*c*/ kX,kX,kX,kc,kc,kc,kc,kc,kc,kc,kc,ki,kC,kI,kC,kI,kC,kI,kF,kX,kX,kX,kX,kX,kX },
59 { /*i*/ kX,kX,kX,ki,ki,ki,ki,ki,ki,ki,ki,ki,kI,kI,kI,kI,kI,kI,kF,kX,kX,kX,kX,kX,kX },
60 { /*b*/ kX,kX,kX,kb,kb,kb,kb,kB,ks,kS,kC,kI,kb,kB,ks,kS,kC,kI,kX,kX,kX,kX,kX,kX,kX },
61 { /*B*/ kX,kX,kX,kB,kB,kB,kB,kB,kS,kS,kI,kI,kB,kB,kS,kS,kI,kI,kX,kX,kX,kX,kX,kX,kX },
62 { /*s*/ kX,kX,kX,ks,ks,ks,ks,kS,ks,kS,kC,kI,ks,kS,ks,kS,kC,kI,kX,kX,kX,kX,kX,kX,kX },
63 { /*S*/ kX,kX,kX,kS,kS,kS,kS,kS,kS,kS,kI,kI,kS,kS,kS,kS,kI,kI,kX,kX,kX,kX,kX,kX,kX },
64 { /*C*/ kX,kX,kX,kC,kC,kC,kC,kI,kC,kI,kC,kI,kC,kI,kC,kI,kC,kI,kX,kX,kX,kX,kX,kX,kX },
65 { /*I*/ kX,kX,kX,kI,kI,kI,kI,kI,kI,kI,kI,kI,kI,kI,kI,kI,kI,kI,kX,kX,kX,kX,kX,kX,kX },
66 { /*F*/ kX,kX,kX,kF,kF,kF,kF,kF,kF,kF,kF,kF,kX,kX,kX,kX,kX,kX,kF,kX,kX,kX,kX,kX,kX },
67 { /*N*/ kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kN,kX,kJ,kX,kD,kX },
68 { /*n*/ kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kn,kX,kj,kX,kd },
69 { /*J*/ kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kJ,kX,kJ,kX,kX,kX },
70 { /*j*/ kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kj,kX,kj,kX,kX },
71 { /*D*/ kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kD,kX,kX,kX,kD,kX },
72 { /*d*/ kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kX,kd,kX,kX,kX,kd },
73 };
74
75#undef k_
76#undef kU
77#undef kX
78#undef k0
79#undef k1
80#undef kZ
81#undef ky
82#undef kY
83#undef kh
84#undef kH
85#undef kc
86#undef ki
87#undef kb
88#undef kB
89#undef ks
90#undef kS
91#undef kC
92#undef kI
93#undef kF
94#undef kN
95#undef kn
96#undef kJ
97#undef kj
98#undef kD
99#undef kd
100
101bool DexVerifier::VerifyClass(Class* klass) {
102 if (klass->IsVerified()) {
103 return true;
104 }
105 for (size_t i = 0; i < klass->NumDirectMethods(); ++i) {
106 Method* method = klass->GetDirectMethod(i);
107 if (!VerifyMethod(method)) {
jeffhao98eacac2011-09-14 16:11:53 -0700108 LOG(ERROR) << "Verifier rejected class "
109 << klass->GetDescriptor()->ToModifiedUtf8();
jeffhaobdb76512011-09-07 11:43:16 -0700110 return false;
111 }
112 }
113 for (size_t i = 0; i < klass->NumVirtualMethods(); ++i) {
114 Method* method = klass->GetVirtualMethod(i);
115 if (!VerifyMethod(method)) {
jeffhao98eacac2011-09-14 16:11:53 -0700116 LOG(ERROR) << "Verifier rejected class "
117 << klass->GetDescriptor()->ToModifiedUtf8();
jeffhaobdb76512011-09-07 11:43:16 -0700118 return false;
119 }
120 }
121 return true;
jeffhaoba5ebb92011-08-25 17:24:37 -0700122}
123
jeffhaobdb76512011-09-07 11:43:16 -0700124bool DexVerifier::VerifyMethod(Method* method) {
125 const DexCache* dex_cache = method->GetDeclaringClass()->GetDexCache();
126 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
127 const DexFile& dex_file = class_linker->FindDexFile(dex_cache);
Elliott Hughes5fe594f2011-09-08 12:33:17 -0700128 const DexFile::CodeItem* code_item =
jeffhaobdb76512011-09-07 11:43:16 -0700129 dex_file.GetCodeItem(method->GetCodeItemOffset());
130
131 /*
132 * Construct the verifier state container object.
133 */
134 VerifierData vdata(method, &dex_file, code_item);
135
136 /*
137 * If there aren't any instructions, make sure that's expected, then
138 * exit successfully.
139 */
140 if (code_item == NULL) {
141 if (!method->IsNative() && !method->IsAbstract()) {
142 LOG(ERROR) << "VFY: zero-length code in concrete non-native method";
143 return false;
144 }
145 return true;
146 }
147
148 /*
jeffhaod1f0fde2011-09-08 17:25:33 -0700149 * Sanity-check the register counts. ins + locals = registers, so make
jeffhaobdb76512011-09-07 11:43:16 -0700150 * sure that ins <= registers.
151 */
152 if (code_item->ins_size_ > code_item->registers_size_) {
153 LOG(ERROR) << "VFY: bad register counts (ins=" << code_item->ins_size_
154 << " regs=" << code_item->registers_size_;
155 return false;
156 }
157
158 /*
159 * Allocate and initialize an array to hold instruction data.
160 */
Elliott Hughes5fe594f2011-09-08 12:33:17 -0700161 vdata.insn_flags_.reset(new InsnFlags[code_item->insns_size_]());
jeffhaobdb76512011-09-07 11:43:16 -0700162
163 /*
164 * Run through the instructions and see if the width checks out.
165 */
166 if (!ComputeWidthsAndCountOps(&vdata)) {
167 return false;
168 }
169
170 /*
171 * Flag instructions guarded by a "try" block and check exception handlers.
172 */
173 if (!ScanTryCatchBlocks(&vdata)) {
174 return false;
175 }
176
177 /*
178 * Perform static instruction verification.
179 */
180 if (!VerifyInstructions(&vdata)) {
181 return false;
182 }
183
184 /*
185 * Perform code flow analysis.
186 */
187 if (!VerifyCodeFlow(&vdata)) {
188 return false;
189 }
190
191 return true;
jeffhaoba5ebb92011-08-25 17:24:37 -0700192}
193
jeffhaobdb76512011-09-07 11:43:16 -0700194bool DexVerifier::VerifyInstructions(VerifierData* vdata) {
195 const DexFile::CodeItem* code_item = vdata->code_item_;
Elliott Hughes5fe594f2011-09-08 12:33:17 -0700196 InsnFlags* insn_flags = vdata->insn_flags_.get();
jeffhaobdb76512011-09-07 11:43:16 -0700197 const byte* ptr = reinterpret_cast<const byte*>(code_item->insns_);
198 const Instruction* inst = Instruction::At(ptr);
199
200 /* Flag the start of the method as a branch target. */
201 InsnSetBranchTarget(insn_flags, 0);
202
203 uint32_t width = 0;
204 uint32_t insns_size = code_item->insns_size_;
205
206 while (width < insns_size) {
207 if (!VerifyInstruction(vdata, inst, width)) {
jeffhaod1f0fde2011-09-08 17:25:33 -0700208 LOG(ERROR) << "VFY: rejecting opcode 0x" << std::hex
jeffhaobdb76512011-09-07 11:43:16 -0700209 << (int) inst->Opcode() << " at 0x" << width << std::dec;
210 return false;
211 }
212
213 /* Flag instructions that are garbage collection points */
214 if (inst->IsBranch() || inst->IsSwitch() || inst->IsThrow() ||
215 inst->IsReturn()) {
216 InsnSetGcPoint(insn_flags, width);
217 }
218
219 width += inst->Size();
220 inst = inst->Next();
221 }
222 return true;
jeffhaoba5ebb92011-08-25 17:24:37 -0700223}
224
jeffhaobdb76512011-09-07 11:43:16 -0700225bool DexVerifier::VerifyInstruction(VerifierData* vdata,
226 const Instruction* inst, uint32_t code_offset) {
227 const DexFile* dex_file = vdata->dex_file_;
228 const DexFile::CodeItem* code_item = vdata->code_item_;
Elliott Hughes5fe594f2011-09-08 12:33:17 -0700229 InsnFlags* insn_flags = vdata->insn_flags_.get();
jeffhaobdb76512011-09-07 11:43:16 -0700230 Instruction::DecodedInstruction dec_insn(inst);
231 bool result = true;
232
233 int argumentA = inst->GetVerifyTypeArgumentA();
234 int argumentB = inst->GetVerifyTypeArgumentB();
235 int argumentC = inst->GetVerifyTypeArgumentC();
236 int extra_flags = inst->GetVerifyExtraFlags();
237
238 switch (argumentA) {
239 case Instruction::kVerifyRegA:
240 result &= CheckRegisterIndex(code_item, dec_insn.vA_);
241 break;
242 case Instruction::kVerifyRegAWide:
243 result &= CheckWideRegisterIndex(code_item, dec_insn.vA_);
244 break;
245 }
246
247 switch (argumentB) {
248 case Instruction::kVerifyRegB:
249 result &= CheckRegisterIndex(code_item, dec_insn.vB_);
250 break;
251 case Instruction::kVerifyRegBField:
252 result &= CheckFieldIndex(dex_file, dec_insn.vB_);
253 break;
254 case Instruction::kVerifyRegBMethod:
255 result &= CheckMethodIndex(dex_file, dec_insn.vB_);
256 break;
257 case Instruction::kVerifyRegBNewInstance:
258 result &= CheckNewInstance(dex_file, dec_insn.vB_);
259 break;
260 case Instruction::kVerifyRegBString:
261 result &= CheckStringIndex(dex_file, dec_insn.vB_);
262 break;
263 case Instruction::kVerifyRegBType:
264 result &= CheckTypeIndex(dex_file, dec_insn.vB_);
265 break;
266 case Instruction::kVerifyRegBWide:
267 result &= CheckWideRegisterIndex(code_item, dec_insn.vB_);
268 break;
269 }
270
271 switch (argumentC) {
272 case Instruction::kVerifyRegC:
273 result &= CheckRegisterIndex(code_item, dec_insn.vC_);
274 break;
275 case Instruction::kVerifyRegCField:
276 result &= CheckFieldIndex(dex_file, dec_insn.vC_);
277 break;
278 case Instruction::kVerifyRegCNewArray:
279 result &= CheckNewArray(dex_file, dec_insn.vC_);
280 break;
281 case Instruction::kVerifyRegCType:
282 result &= CheckTypeIndex(dex_file, dec_insn.vC_);
283 break;
284 case Instruction::kVerifyRegCWide:
285 result &= CheckWideRegisterIndex(code_item, dec_insn.vC_);
286 break;
287 }
288
289 switch (extra_flags) {
290 case Instruction::kVerifyArrayData:
291 result &= CheckArrayData(code_item, code_offset);
292 break;
293 case Instruction::kVerifyBranchTarget:
294 result &= CheckBranchTarget(code_item, insn_flags, code_offset);
295 break;
296 case Instruction::kVerifySwitchTargets:
297 result &= CheckSwitchTargets(code_item, insn_flags, code_offset);
298 break;
299 case Instruction::kVerifyVarArg:
300 result &= CheckVarArgRegs(code_item, dec_insn.vA_, dec_insn.arg_);
301 break;
302 case Instruction::kVerifyVarArgRange:
303 result &= CheckVarArgRangeRegs(code_item, dec_insn.vA_, dec_insn.vC_);
304 break;
305 case Instruction::kVerifyError:
306 LOG(ERROR) << "VFY: unexpected opcode " << std::hex
307 << (int) dec_insn.opcode_ << std::dec;
308 result = false;
309 break;
310 }
311
312 return result;
jeffhaoba5ebb92011-08-25 17:24:37 -0700313}
314
jeffhaobdb76512011-09-07 11:43:16 -0700315bool DexVerifier::VerifyCodeFlow(VerifierData* vdata) {
316 Method* method = vdata->method_;
317 const DexFile::CodeItem* code_item = vdata->code_item_;
318 uint16_t registers_size = code_item->registers_size_;
319 uint32_t insns_size = code_item->insns_size_;
320 RegisterTable reg_table;
jeffhaoba5ebb92011-08-25 17:24:37 -0700321
jeffhaobdb76512011-09-07 11:43:16 -0700322 if (registers_size * insns_size > 4*1024*1024) {
323 LOG(ERROR) << "VFY: warning: method is huge (regs=" << registers_size
324 << " insns_size=" << insns_size << ")";
325 }
jeffhaoba5ebb92011-08-25 17:24:37 -0700326
jeffhaobdb76512011-09-07 11:43:16 -0700327 /* Create and initialize register lists. */
jeffhaoa0a764a2011-09-16 10:43:38 -0700328 if (!InitRegisterTable(vdata, &reg_table, kTrackRegsGcPoints)) {
jeffhaobdb76512011-09-07 11:43:16 -0700329 return false;
330 }
jeffhaoba5ebb92011-08-25 17:24:37 -0700331
Elliott Hughes5fe594f2011-09-08 12:33:17 -0700332 vdata->register_lines_ = reg_table.register_lines_.get();
jeffhaobdb76512011-09-07 11:43:16 -0700333
334 /* Allocate a map to hold the classes of uninitialized instances. */
Elliott Hughes5fe594f2011-09-08 12:33:17 -0700335 vdata->uninit_map_.reset(CreateUninitInstanceMap(vdata));
jeffhaobdb76512011-09-07 11:43:16 -0700336
337 /* Initialize register types of method arguments. */
Elliott Hughes5fe594f2011-09-08 12:33:17 -0700338 if (!SetTypesFromSignature(vdata, reg_table.register_lines_[0].reg_types_.get())) {
jeffhaobdb76512011-09-07 11:43:16 -0700339 LOG(ERROR) << "VFY: bad signature '"
340 << method->GetSignature()->ToModifiedUtf8() << "' for "
341 << method->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8()
342 << "." << method->GetName()->ToModifiedUtf8();
343 return false;
344 }
345
346 /* Perform code flow verification. */
347 if (!CodeFlowVerifyMethod(vdata, &reg_table)) {
348 return false;
349 }
350
jeffhaoa0a764a2011-09-16 10:43:38 -0700351 /* Generate a register map and add it to the method. */
352 UniquePtr<RegisterMap> map(GenerateRegisterMapV(vdata));
353 ByteArray* header = ByteArray::Alloc(sizeof(RegisterMapHeader));
354 ByteArray* data = ByteArray::Alloc(ComputeRegisterMapSize(map.get()));
jeffhaoe23d93c2011-09-15 14:48:43 -0700355
jeffhaoa0a764a2011-09-16 10:43:38 -0700356 memcpy(header->GetData(), map.get()->header_, sizeof(RegisterMapHeader));
357 memcpy(data->GetData(), map.get()->data_, ComputeRegisterMapSize(map.get()));
jeffhaoe23d93c2011-09-15 14:48:43 -0700358
jeffhaoa0a764a2011-09-16 10:43:38 -0700359 method->SetRegisterMapHeader(header);
360 method->SetRegisterMapData(data);
jeffhaoba5ebb92011-08-25 17:24:37 -0700361
jeffhaobdb76512011-09-07 11:43:16 -0700362 return true;
363}
364
365bool DexVerifier::ComputeWidthsAndCountOps(VerifierData* vdata) {
366 const uint16_t* insns = vdata->code_item_->insns_;
367 uint32_t insns_size = vdata->code_item_->insns_size_;
Elliott Hughes5fe594f2011-09-08 12:33:17 -0700368 InsnFlags* insn_flags = vdata->insn_flags_.get();
jeffhaobdb76512011-09-07 11:43:16 -0700369 const byte* ptr = reinterpret_cast<const byte*>(insns);
370 const Instruction* inst = Instruction::At(ptr);
371 size_t new_instance_count = 0;
372 size_t monitor_enter_count = 0;
373 size_t width = 0;
374
375 while (width < insns_size) {
376 Instruction::Code opcode = inst->Opcode();
377 if (opcode == Instruction::NEW_INSTANCE) {
378 new_instance_count++;
379 } else if (opcode == Instruction::MONITOR_ENTER) {
380 monitor_enter_count++;
381 }
382
383 insn_flags[width] |= inst->Size();
384 width += inst->Size();
385 inst = inst->Next();
386 }
387
388 if (width != insns_size) {
389 LOG(ERROR) << "VFY: code did not end where expected (" << width << " vs. "
390 << insns_size << ")";
391 return false;
392 }
393
394 vdata->new_instance_count_ = new_instance_count;
395 vdata->monitor_enter_count_ = monitor_enter_count;
396 return true;
397}
398
399bool DexVerifier::ScanTryCatchBlocks(VerifierData* vdata) {
400 const DexFile::CodeItem* code_item = vdata->code_item_;
Elliott Hughes5fe594f2011-09-08 12:33:17 -0700401 InsnFlags* insn_flags = vdata->insn_flags_.get();
jeffhaobdb76512011-09-07 11:43:16 -0700402 uint32_t insns_size = code_item->insns_size_;
403 uint32_t tries_size = code_item->tries_size_;
404
405 if (tries_size == 0) {
406 return true;
407 }
408
409 const DexFile::TryItem* tries = DexFile::dexGetTryItems(*code_item, 0);
410
411 for (uint32_t idx = 0; idx < tries_size; idx++) {
412 const DexFile::TryItem* try_item = &tries[idx];
413 uint32_t start = try_item->start_addr_;
414 uint32_t end = start + try_item->insn_count_;
415
416 if ((start >= end) || (start >= insns_size) || (end > insns_size)) {
417 LOG(ERROR) << "VFY: bad exception entry: startAddr=" << start
418 << " endAddr=" << end << " (size=" << insns_size << ")";
419 return false;
420 }
421
422 if (InsnGetWidth(insn_flags, start) == 0) {
423 LOG(ERROR) << "VFY: 'try' block starts inside an instruction ("
424 << start << ")";
425 return false;
426 }
427
428 uint32_t addr;
429 for (addr = start; addr < end; addr += InsnGetWidth(insn_flags, addr)) {
430 InsnSetInTry(insn_flags, addr);
431 }
432 }
433
434 /* Iterate over each of the handlers to verify target addresses. */
435 const byte* handlers_ptr = DexFile::dexGetCatchHandlerData(*code_item, 0);
436 uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
437 for (uint32_t idx = 0; idx < handlers_size; idx++) {
438 DexFile::CatchHandlerIterator iterator(handlers_ptr);
439
440 for (; !iterator.HasNext(); iterator.Next()) {
441 uint32_t addr = iterator.Get().address_;
442 if (InsnGetWidth(insn_flags, addr) == 0) {
443 LOG(ERROR) << "VFY: exception handler starts at bad address ("
444 << addr << ")";
445 return false;
446 }
447
448 InsnSetBranchTarget(insn_flags, addr);
449 }
450
451 handlers_ptr = iterator.GetData();
452 }
453
454 return true;
455}
456
457bool DexVerifier::GetBranchOffset(const DexFile::CodeItem* code_item,
458 const InsnFlags insn_flags[], uint32_t cur_offset, int32_t* pOffset,
jeffhaoba5ebb92011-08-25 17:24:37 -0700459 bool* pConditional, bool* selfOkay) {
460 const uint16_t* insns = code_item->insns_ + cur_offset;
461
462 switch (*insns & 0xff) {
463 case Instruction::GOTO:
464 *pOffset = ((int16_t) *insns) >> 8;
465 *pConditional = false;
466 *selfOkay = false;
467 break;
468 case Instruction::GOTO_32:
469 *pOffset = insns[1] | (((uint32_t) insns[2]) << 16);
470 *pConditional = false;
471 *selfOkay = true;
472 break;
473 case Instruction::GOTO_16:
474 *pOffset = (int16_t) insns[1];
475 *pConditional = false;
476 *selfOkay = false;
477 break;
478 case Instruction::IF_EQ:
479 case Instruction::IF_NE:
480 case Instruction::IF_LT:
481 case Instruction::IF_GE:
482 case Instruction::IF_GT:
483 case Instruction::IF_LE:
484 case Instruction::IF_EQZ:
485 case Instruction::IF_NEZ:
486 case Instruction::IF_LTZ:
487 case Instruction::IF_GEZ:
488 case Instruction::IF_GTZ:
489 case Instruction::IF_LEZ:
490 *pOffset = (int16_t) insns[1];
491 *pConditional = true;
492 *selfOkay = false;
493 break;
494 default:
495 return false;
496 break;
497 }
498
499 return true;
500}
501
jeffhaobdb76512011-09-07 11:43:16 -0700502bool DexVerifier::CheckArrayData(const DexFile::CodeItem* code_item,
jeffhaoba5ebb92011-08-25 17:24:37 -0700503 uint32_t cur_offset) {
504 const uint32_t insn_count = code_item->insns_size_;
505 const uint16_t* insns = code_item->insns_ + cur_offset;
506 const uint16_t* array_data;
507 int32_t array_data_offset;
508
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -0700509 DCHECK_LT(cur_offset, insn_count);
jeffhaoba5ebb92011-08-25 17:24:37 -0700510
511 /* make sure the start of the array data table is in range */
512 array_data_offset = insns[1] | (((int32_t) insns[2]) << 16);
513 if ((int32_t) cur_offset + array_data_offset < 0 ||
514 cur_offset + array_data_offset + 2 >= insn_count)
515 {
516 LOG(ERROR) << "VFY: invalid array data start: at " << cur_offset
517 << ", data offset " << array_data_offset << ", count "
518 << insn_count;
519 return false;
520 }
521
522 /* offset to array data table is a relative branch-style offset */
523 array_data = insns + array_data_offset;
524
525 /* make sure the table is 32-bit aligned */
526 if ((((uint32_t) array_data) & 0x03) != 0) {
527 LOG(ERROR) << "VFY: unaligned array data table: at " << cur_offset
528 << ", data offset " << array_data_offset;
529 return false;
530 }
531
532 uint32_t value_width = array_data[1];
533 uint32_t value_count = *(uint32_t*) (&array_data[2]);
534 uint32_t table_size = 4 + (value_width * value_count + 1) / 2;
535
536 /* make sure the end of the switch is in range */
537 if (cur_offset + array_data_offset + table_size > insn_count) {
538 LOG(ERROR) << "VFY: invalid array data end: at " << cur_offset
539 << ", data offset " << array_data_offset << ", end "
540 << cur_offset + array_data_offset + table_size << ", count "
541 << insn_count;
542 return false;
543 }
544
545 return true;
546}
547
jeffhaobdb76512011-09-07 11:43:16 -0700548bool DexVerifier::CheckNewInstance(const DexFile* dex_file, uint32_t idx) {
jeffhaoba5ebb92011-08-25 17:24:37 -0700549 if (idx >= dex_file->GetHeader().type_ids_size_) {
550 LOG(ERROR) << "VFY: bad type index " << idx << " (max "
551 << dex_file->GetHeader().type_ids_size_ << ")";
552 return false;
553 }
554
555 const char* descriptor = dex_file->dexStringByTypeIdx(idx);
556 if (descriptor[0] != 'L') {
557 LOG(ERROR) << "VFY: can't call new-instance on type '"
558 << descriptor << "'";
559 return false;
560 }
561
562 return true;
563}
564
jeffhaobdb76512011-09-07 11:43:16 -0700565bool DexVerifier::CheckNewArray(const DexFile* dex_file, uint32_t idx) {
jeffhaoba5ebb92011-08-25 17:24:37 -0700566 if (idx >= dex_file->GetHeader().type_ids_size_) {
567 LOG(ERROR) << "VFY: bad type index " << idx << " (max "
568 << dex_file->GetHeader().type_ids_size_ << ")";
569 return false;
570 }
571
572 int bracket_count = 0;
573 const char* descriptor = dex_file->dexStringByTypeIdx(idx);
574 const char* cp = descriptor;
575 while (*cp++ == '[')
576 bracket_count++;
577
578 if (bracket_count == 0) {
579 /* The given class must be an array type. */
580 LOG(ERROR) << "VFY: can't new-array class '" << descriptor
581 << "' (not an array)";
582 return false;
583 } else if (bracket_count > 255) {
584 /* It is illegal to create an array of more than 255 dimensions. */
585 LOG(ERROR) << "VFY: can't new-array class '" << descriptor
586 << "' (exceeds limit)";
587 return false;
588 }
589
590 return true;
591}
592
jeffhaobdb76512011-09-07 11:43:16 -0700593bool DexVerifier::CheckTypeIndex(const DexFile* dex_file, uint32_t idx) {
jeffhaoba5ebb92011-08-25 17:24:37 -0700594 if (idx >= dex_file->GetHeader().type_ids_size_) {
595 LOG(ERROR) << "VFY: bad type index " << idx << " (max "
596 << dex_file->GetHeader().type_ids_size_ << ")";
597 return false;
598 }
599 return true;
600}
601
jeffhaobdb76512011-09-07 11:43:16 -0700602bool DexVerifier::CheckFieldIndex(const DexFile* dex_file, uint32_t idx) {
jeffhaoba5ebb92011-08-25 17:24:37 -0700603 if (idx >= dex_file->GetHeader().field_ids_size_) {
604 LOG(ERROR) << "VFY: bad field index " << idx << " (max "
605 << dex_file->GetHeader().field_ids_size_ << ")";
606 return false;
607 }
608 return true;
609}
610
jeffhaobdb76512011-09-07 11:43:16 -0700611bool DexVerifier::CheckMethodIndex(const DexFile* dex_file, uint32_t idx) {
jeffhaoba5ebb92011-08-25 17:24:37 -0700612 if (idx >= dex_file->GetHeader().method_ids_size_) {
613 LOG(ERROR) << "VFY: bad method index " << idx << " (max "
614 << dex_file->GetHeader().method_ids_size_ << ")";
615 return false;
616 }
617 return true;
618}
619
jeffhaobdb76512011-09-07 11:43:16 -0700620bool DexVerifier::CheckStringIndex(const DexFile* dex_file, uint32_t idx) {
jeffhaoba5ebb92011-08-25 17:24:37 -0700621 if (idx >= dex_file->GetHeader().string_ids_size_) {
622 LOG(ERROR) << "VFY: bad string index " << idx << " (max "
623 << dex_file->GetHeader().string_ids_size_ << ")";
624 return false;
625 }
626 return true;
627}
628
jeffhaobdb76512011-09-07 11:43:16 -0700629bool DexVerifier::CheckRegisterIndex(const DexFile::CodeItem* code_item,
630 uint32_t idx) {
jeffhaoba5ebb92011-08-25 17:24:37 -0700631 if (idx >= code_item->registers_size_) {
632 LOG(ERROR) << "VFY: register index out of range (" << idx << " >= "
633 << code_item->registers_size_ << ")";
634 return false;
635 }
636 return true;
637}
638
jeffhaobdb76512011-09-07 11:43:16 -0700639bool DexVerifier::CheckWideRegisterIndex(const DexFile::CodeItem* code_item,
jeffhaoba5ebb92011-08-25 17:24:37 -0700640 uint32_t idx) {
641 if (idx + 1 >= code_item->registers_size_) {
642 LOG(ERROR) << "VFY: wide register index out of range (" << idx
643 << "+1 >= " << code_item->registers_size_ << ")";
644 return false;
645 }
646 return true;
647}
648
jeffhaobdb76512011-09-07 11:43:16 -0700649bool DexVerifier::CheckVarArgRegs(const DexFile::CodeItem* code_item,
650 uint32_t vA, uint32_t arg[]) {
jeffhaoba5ebb92011-08-25 17:24:37 -0700651 uint16_t registers_size = code_item->registers_size_;
652 uint32_t idx;
653
654 if (vA > 5) {
655 LOG(ERROR) << "VFY: invalid arg count (" << vA << ") in non-range invoke)";
656 return false;
657 }
658
659 for (idx = 0; idx < vA; idx++) {
660 if (arg[idx] > registers_size) {
661 LOG(ERROR) << "VFY: invalid reg index (" << arg[idx]
662 << ") in non-range invoke (> " << registers_size << ")";
663 return false;
664 }
665 }
666
667 return true;
668}
669
jeffhaobdb76512011-09-07 11:43:16 -0700670bool DexVerifier::CheckVarArgRangeRegs(const DexFile::CodeItem* code_item,
jeffhaoba5ebb92011-08-25 17:24:37 -0700671 uint32_t vA, uint32_t vC) {
672 uint16_t registers_size = code_item->registers_size_;
673
674 /*
675 * vA/vC are unsigned 8-bit/16-bit quantities for /range instructions,
676 * so there's no risk of integer overflow when adding them here.
677 */
678 if (vA + vC > registers_size) {
679 LOG(ERROR) << "VFY: invalid reg index " << vA << "+" << vC
680 << " in range invoke (> " << registers_size << ")";
681 return false;
682 }
683
684 return true;
685}
686
jeffhaobdb76512011-09-07 11:43:16 -0700687bool DexVerifier::CheckSwitchTargets(const DexFile::CodeItem* code_item,
688 InsnFlags insn_flags[], uint32_t cur_offset) {
jeffhaoba5ebb92011-08-25 17:24:37 -0700689 const uint32_t insn_count = code_item->insns_size_;
690 const uint16_t* insns = code_item->insns_ + cur_offset;
691 const uint16_t* switch_insns;
692 uint16_t expected_signature;
693 uint32_t switch_count, table_size;
694 int32_t switch_offset, keys_offset, targets_offset;
695 int32_t offset, abs_offset;
696 uint32_t targ;
697
698 /* make sure the start of the switch is in range */
699 switch_offset = insns[1] | ((int32_t) insns[2]) << 16;
700 if ((int32_t) cur_offset + switch_offset < 0 ||
701 cur_offset + switch_offset + 2 >= insn_count) {
702 LOG(ERROR) << "VFY: invalid switch start: at " << cur_offset
703 << ", switch offset " << switch_offset << ", count "
704 << insn_count;
705 return false;
706 }
707
708 /* offset to switch table is a relative branch-style offset */
709 switch_insns = insns + switch_offset;
710
711 /* make sure the table is 32-bit aligned */
712 if ((((uint32_t) switch_insns) & 0x03) != 0) {
713 LOG(ERROR) << "VFY: unaligned switch table: at " << cur_offset
714 << ", switch offset " << switch_offset;
715 return false;
716 }
717
718 switch_count = switch_insns[1];
719
720 if ((*insns & 0xff) == Instruction::PACKED_SWITCH) {
721 /* 0=sig, 1=count, 2/3=firstKey */
722 targets_offset = 4;
723 keys_offset = -1;
724 expected_signature = Instruction::kPackedSwitchSignature;
725 } else {
726 /* 0=sig, 1=count, 2..count*2 = keys */
727 keys_offset = 2;
728 targets_offset = 2 + 2 * switch_count;
729 expected_signature = Instruction::kSparseSwitchSignature;
730 }
731 table_size = targets_offset + switch_count * 2;
732
733 if (switch_insns[0] != expected_signature) {
jeffhaobdb76512011-09-07 11:43:16 -0700734 LOG(ERROR) << "VFY: wrong signature for switch table (0x" << std::hex
735 << switch_insns[0] << ", wanted 0x" << expected_signature << ")"
736 << std::dec;
jeffhaoba5ebb92011-08-25 17:24:37 -0700737 return false;
738 }
739
740 /* make sure the end of the switch is in range */
741 if (cur_offset + switch_offset + table_size > (uint32_t) insn_count) {
742 LOG(ERROR) << "VFY: invalid switch end: at " << cur_offset
743 << ", switch offset " << switch_offset << ", end "
744 << cur_offset + switch_offset + table_size << ", count "
745 << insn_count;
746 return false;
747 }
748
749 /* for a sparse switch, verify the keys are in ascending order */
750 if (keys_offset > 0 && switch_count > 1) {
751 int32_t last_key;
752
753 last_key = switch_insns[keys_offset] |
754 (switch_insns[keys_offset + 1] << 16);
755 for (targ = 1; targ < switch_count; targ++) {
756 int32_t key = (int32_t) switch_insns[keys_offset + targ * 2] |
757 (int32_t) (switch_insns[keys_offset + targ * 2 + 1] << 16);
758 if (key <= last_key) {
759 LOG(ERROR) << "VFY: invalid packed switch: last key=" << last_key
760 << ", this=" << key;
761 return false;
762 }
763
764 last_key = key;
765 }
766 }
767
768 /* verify each switch target */
769 for (targ = 0; targ < switch_count; targ++) {
770 offset = (int32_t) switch_insns[targets_offset + targ * 2] |
771 (int32_t) (switch_insns[targets_offset + targ * 2 + 1] << 16);
772 abs_offset = cur_offset + offset;
773
774 if (abs_offset < 0 || abs_offset >= (int32_t) insn_count ||
775 !InsnIsOpcode(insn_flags, abs_offset)) {
776 LOG(ERROR) << "VFY: invalid switch target " << offset << " (-> "
jeffhaobdb76512011-09-07 11:43:16 -0700777 << std::hex << abs_offset << ") at " << cur_offset << std::dec
778 << "[" << targ << "]";
jeffhaoba5ebb92011-08-25 17:24:37 -0700779 return false;
780 }
jeffhaobdb76512011-09-07 11:43:16 -0700781 InsnSetBranchTarget(insn_flags, abs_offset);
jeffhaoba5ebb92011-08-25 17:24:37 -0700782 }
783
784 return true;
785}
786
jeffhaobdb76512011-09-07 11:43:16 -0700787bool DexVerifier::CheckBranchTarget(const DexFile::CodeItem* code_item,
788 InsnFlags insn_flags[], uint32_t cur_offset) {
789 const uint32_t insn_count = code_item->insns_size_;
jeffhaoba5ebb92011-08-25 17:24:37 -0700790 int32_t offset, abs_offset;
791 bool isConditional, selfOkay;
792
793 if (!GetBranchOffset(code_item, insn_flags, cur_offset, &offset,
794 &isConditional, &selfOkay))
795 return false;
796
797 if (!selfOkay && offset == 0) {
jeffhaobdb76512011-09-07 11:43:16 -0700798 LOG(ERROR) << "VFY: branch offset of zero not allowed at" << std::hex
799 << cur_offset << std::dec;
jeffhaoba5ebb92011-08-25 17:24:37 -0700800 return false;
801 }
802
803 /*
jeffhaod1f0fde2011-09-08 17:25:33 -0700804 * Check for 32-bit overflow. This isn't strictly necessary if we can
jeffhaoba5ebb92011-08-25 17:24:37 -0700805 * depend on the VM to have identical "wrap-around" behavior, but
806 * it's unwise to depend on that.
807 */
808 if (((int64_t) cur_offset + (int64_t) offset) !=
jeffhaobdb76512011-09-07 11:43:16 -0700809 (int64_t) (cur_offset + offset)) {
810 LOG(ERROR) << "VFY: branch target overflow " << std::hex << cur_offset
811 << std::dec << " +" << offset;
jeffhaoba5ebb92011-08-25 17:24:37 -0700812 return false;
813 }
814 abs_offset = cur_offset + offset;
jeffhaobdb76512011-09-07 11:43:16 -0700815 if (abs_offset < 0 || (uint32_t) abs_offset >= insn_count ||
jeffhaoba5ebb92011-08-25 17:24:37 -0700816 !InsnIsOpcode(insn_flags, abs_offset))
817 {
818 LOG(ERROR) << "VFY: invalid branch target " << offset << " (-> "
jeffhaobdb76512011-09-07 11:43:16 -0700819 << std::hex << abs_offset << ") at " << cur_offset << std::dec;
jeffhaoba5ebb92011-08-25 17:24:37 -0700820 return false;
821 }
jeffhaobdb76512011-09-07 11:43:16 -0700822 InsnSetBranchTarget(insn_flags, abs_offset);
jeffhaoba5ebb92011-08-25 17:24:37 -0700823
824 return true;
825}
826
jeffhaobdb76512011-09-07 11:43:16 -0700827bool DexVerifier::InitRegisterTable(VerifierData* vdata,
828 RegisterTable* reg_table, RegisterTrackingMode track_regs_for) {
829 const DexFile::CodeItem* code_item = vdata->code_item_;
Elliott Hughes5fe594f2011-09-08 12:33:17 -0700830 InsnFlags* insn_flags = vdata->insn_flags_.get();
jeffhaobdb76512011-09-07 11:43:16 -0700831 uint16_t registers_size = code_item->registers_size_;
832 uint32_t insns_size = code_item->insns_size_;
833 uint32_t i;
834
835 /*
jeffhaod1f0fde2011-09-08 17:25:33 -0700836 * Every address gets a RegisterLine struct. This is wasteful, but
jeffhaobdb76512011-09-07 11:43:16 -0700837 * not so much that it's worth chasing through an extra level of
838 * indirection.
839 */
840 reg_table->insn_reg_count_plus_ = registers_size + kExtraRegs;
Elliott Hughes5fe594f2011-09-08 12:33:17 -0700841 reg_table->register_lines_.reset(new RegisterLine[insns_size]());
jeffhaobdb76512011-09-07 11:43:16 -0700842
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -0700843 DCHECK_GT(insns_size, 0U);
jeffhaobdb76512011-09-07 11:43:16 -0700844
845 bool track_monitors;
846 //if (gDvm.monitorVerification) {
847 //track_monitors = (vdata->monitor_enter_count_ != 0);
848 //} else {
849 track_monitors = false;
850 //}
851
852 /*
853 * Allocate entries in the sparse register line table.
854 *
855 * There is a RegisterLine associated with every address, but not
856 * every RegisterLine has non-NULL pointers to storage for its fields.
857 */
858 for (i = 0; i < insns_size; i++) {
859 bool interesting;
860
861 switch (track_regs_for) {
862 case kTrackRegsAll:
863 interesting = InsnIsOpcode(insn_flags, i);
864 break;
865 case kTrackRegsGcPoints:
866 interesting = InsnIsGcPoint(insn_flags, i) ||
867 InsnIsBranchTarget(insn_flags, i);
868 break;
869 case kTrackRegsBranches:
870 interesting = InsnIsBranchTarget(insn_flags, i);
871 break;
872 default:
873 return false;
874 }
875
876 if (interesting) {
877 reg_table->register_lines_[i].Alloc(reg_table->insn_reg_count_plus_,
878 track_monitors);
879 }
880 }
881
882 /*
883 * Allocate space for our "temporary" register lines.
884 */
885 reg_table->work_line_.Alloc(reg_table->insn_reg_count_plus_, track_monitors);
886 reg_table->saved_line_.Alloc(reg_table->insn_reg_count_plus_, track_monitors);
887
888 return true;
889}
890
891DexVerifier::UninitInstanceMap* DexVerifier::CreateUninitInstanceMap(
892 VerifierData* vdata) {
893 Method* method = vdata->method_;
894 const DexFile::CodeItem* code_item = vdata->code_item_;
895 size_t new_instance_count = vdata->new_instance_count_;
896
897 if (IsInitMethod(method)) {
898 new_instance_count++;
899 }
900
901 /*
902 * Allocate the header and map as a single unit.
903 *
904 * TODO: consider having a static instance so we can avoid allocations.
905 * I don't think the verifier is guaranteed to be single-threaded when
906 * running in the VM (rather than dexopt), so that must be taken into
907 * account.
908 */
909 UninitInstanceMap* uninit_map = new UninitInstanceMap(new_instance_count);
910
911 size_t idx = 0;
912 if (IsInitMethod(method)) {
913 uninit_map->map_[idx++].addr_ = kUninitThisArgAddr;
914 }
915
916 /*
917 * Run through and find the new-instance instructions.
918 */
919 uint32_t addr = 0;
920 uint32_t insns_size = code_item->insns_size_;
921 const byte* ptr = reinterpret_cast<const byte*>(code_item->insns_);
jeffhaoba5ebb92011-08-25 17:24:37 -0700922 const Instruction* inst = Instruction::At(ptr);
jeffhaobdb76512011-09-07 11:43:16 -0700923 while (addr < insns_size) {
924 Instruction::Code opcode = inst->Opcode();
925 if (opcode == Instruction::NEW_INSTANCE) {
926 uninit_map->map_[idx++].addr_ = addr;
927 }
jeffhaoba5ebb92011-08-25 17:24:37 -0700928
jeffhaobdb76512011-09-07 11:43:16 -0700929 addr += inst->Size();
jeffhaoba5ebb92011-08-25 17:24:37 -0700930 inst = inst->Next();
931 }
932
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -0700933 CHECK_EQ(idx, new_instance_count);
jeffhaobdb76512011-09-07 11:43:16 -0700934 return uninit_map;
935}
936
937bool DexVerifier::IsInitMethod(const Method* method) {
938 return (method->GetName()->Equals("<init>"));
939}
940
941Class* DexVerifier::LookupClassByDescriptor(const Method* method,
942 const char* descriptor, VerifyError* failure) {
943 /*
jeffhaod1f0fde2011-09-08 17:25:33 -0700944 * The compiler occasionally puts references to nonexistent classes in
945 * signatures. For example, if you have a non-static inner class with no
946 * constructor, the compiler provides a private <init> for you.
947 * Constructing the class requires <init>(parent), but the outer class can't
948 * call that because the method is private. So the compiler generates a
949 * package-scope <init>(parent,bogus) method that just calls the regular
950 * <init> (the "bogus" part being necessary to distinguish the signature of
951 * the synthetic method). Treating the bogus class as an instance of
952 * java.lang.Object allows the verifier to process the class successfully.
jeffhaobdb76512011-09-07 11:43:16 -0700953 */
954 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
955 const ClassLoader* class_loader =
956 method->GetDeclaringClass()->GetClassLoader();
957 Class* klass = class_linker->FindClass(descriptor, class_loader);
958
959 if (klass == NULL) {
960 Thread::Current()->ClearException();
961 if (strchr(descriptor, '$') != NULL) {
962 LOG(INFO) << "VFY: unable to find class referenced in signature ("
963 << descriptor << ")";
964 } else {
965 LOG(ERROR) << "VFY: unable to find class referenced in signature ("
966 << descriptor << ")";
967 }
968
969 /* Check if the descriptor is an array. */
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -0700970 if (descriptor[0] == '[' && descriptor[1] != '\0') {
jeffhaobdb76512011-09-07 11:43:16 -0700971 /*
972 * There should never be a problem loading primitive arrays.
973 */
974 if (descriptor[1] != 'L' && descriptor[1] != '[') {
975 LOG(ERROR) << "VFY: invalid char in signature in '" << descriptor
976 << "'";
977 *failure = VERIFY_ERROR_GENERIC;
978 }
979
980 /*
jeffhaod1f0fde2011-09-08 17:25:33 -0700981 * Try to continue with base array type. This will let us pass basic
982 * stuff (e.g. get array len) that wouldn't fly with an Object. This
983 * is NOT correct if the missing type is a primitive array, but we
984 * should never have a problem loading those. (I'm not convinced this
985 * is correct or even useful. Just use Object here?)
jeffhaobdb76512011-09-07 11:43:16 -0700986 */
987 klass = class_linker->FindClass("[Ljava/lang/Object;", class_loader);
988 } else if (descriptor[0] == 'L') {
989 /*
990 * We are looking at a non-array reference descriptor;
991 * try to continue with base reference type.
992 */
993 klass = class_linker->FindSystemClass("Ljava/lang/Object;");
994 } else {
995 /* We are looking at a primitive type. */
996 LOG(ERROR) << "VFY: invalid char in signature in '" << descriptor << "'";
997 *failure = VERIFY_ERROR_GENERIC;
998 }
999
1000 if (klass == NULL) {
1001 *failure = VERIFY_ERROR_GENERIC;
1002 }
1003 }
1004
1005 if (klass->IsPrimitive()) {
1006 LOG(ERROR) << "VFY: invalid use of primitive type '" << descriptor << "'";
1007 *failure = VERIFY_ERROR_GENERIC;
1008 klass = NULL;
1009 }
1010
1011 return klass;
1012}
1013
1014Class* DexVerifier::LookupSignatureClass(const Method* method, std::string sig,
1015 VerifyError* failure) {
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07001016 DCHECK_EQ(sig[0], 'L');
jeffhaobdb76512011-09-07 11:43:16 -07001017 size_t end = sig.find(';');
1018
1019 if (end == std::string::npos) {
1020 LOG(ERROR) << "VFY: bad signature component '" << sig << "' (missing ';')";
1021 *failure = VERIFY_ERROR_GENERIC;
1022 return NULL;
1023 }
1024
1025 return LookupClassByDescriptor(method, sig.substr(0, end + 1).c_str(),
1026 failure);
1027}
1028
1029Class* DexVerifier::LookupSignatureArrayClass(const Method* method,
1030 std::string sig, VerifyError* failure) {
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07001031 DCHECK_EQ(sig[0], '[');
jeffhaobdb76512011-09-07 11:43:16 -07001032 size_t end = 0;
1033
1034 while (sig[end] == '[')
1035 end++;
1036
1037 if (sig[end] == 'L') {
1038 end = sig.find(';');
1039 if (end == std::string::npos) {
1040 LOG(ERROR) << "VFY: bad signature component '" << sig
1041 << "' (missing ';')";
1042 *failure = VERIFY_ERROR_GENERIC;
1043 return NULL;
1044 }
1045 }
1046
1047 return LookupClassByDescriptor(method, sig.substr(0, end + 1).c_str(),
1048 failure);
1049}
1050
1051bool DexVerifier::SetTypesFromSignature(VerifierData* vdata, RegType* reg_types)
1052{
1053 Method* method = vdata->method_;
1054 const DexFile* dex_file = vdata->dex_file_;
1055 const DexFile::CodeItem* code_item = vdata->code_item_;
Elliott Hughes5fe594f2011-09-08 12:33:17 -07001056 UninitInstanceMap* uninit_map = vdata->uninit_map_.get();
jeffhaobdb76512011-09-07 11:43:16 -07001057
1058 int arg_start = code_item->registers_size_ - code_item->ins_size_;
1059 int expected_args = code_item->ins_size_; /* long/double count as two */
1060 int actual_args = 0;
1061
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07001062 DCHECK_GE(arg_start, 0); /* should have been verified earlier */
jeffhaobdb76512011-09-07 11:43:16 -07001063
1064 /*
1065 * Include the "this" pointer.
1066 */
1067 if (!method->IsStatic()) {
1068 /*
1069 * If this is a constructor for a class other than java.lang.Object,
jeffhaod1f0fde2011-09-08 17:25:33 -07001070 * mark the first ("this") argument as uninitialized. This restricts
jeffhaobdb76512011-09-07 11:43:16 -07001071 * field access until the superclass constructor is called.
1072 */
1073 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
1074 Class* klass_object = class_linker->FindSystemClass("Ljava/lang/Object;");
1075 if (IsInitMethod(method) && method->GetDeclaringClass() != klass_object) {
1076 int idx = SetUninitInstance(uninit_map, kUninitThisArgAddr,
1077 method->GetDeclaringClass());
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07001078 DCHECK_EQ(idx, 0);
jeffhaobdb76512011-09-07 11:43:16 -07001079 reg_types[arg_start + actual_args] = RegTypeFromUninitIndex(idx);
1080 } else {
1081 reg_types[arg_start + actual_args] =
1082 RegTypeFromClass(method->GetDeclaringClass());
1083 }
1084 actual_args++;
1085 }
1086
1087 const DexFile::ProtoId& proto_id =
1088 dex_file->GetProtoId(method->GetProtoIdx());
1089 DexFile::ParameterIterator iterator(*dex_file, proto_id);
1090 VerifyError failure = VERIFY_ERROR_NONE;
1091
1092 for (; iterator.HasNext(); iterator.Next()) {
1093 const char* descriptor = iterator.GetDescriptor();
1094
1095 if (descriptor == NULL) {
1096 break;
1097 }
1098
1099 if (actual_args >= expected_args) {
1100 LOG(ERROR) << "VFY: expected " << expected_args << " args, found more ("
1101 << descriptor << ")";
1102 return false;
1103 }
1104
1105 switch (*descriptor) {
1106 case 'L':
1107 case '[':
1108 /*
jeffhaod1f0fde2011-09-08 17:25:33 -07001109 * We assume that reference arguments are initialized. The only way
1110 * it could be otherwise (assuming the caller was verified) is if
1111 * the current method is <init>, but in that case it's effectively
1112 * considered initialized the instant we reach here (in the sense
1113 * that we can return without doing anything or call virtual methods).
jeffhaobdb76512011-09-07 11:43:16 -07001114 */
1115 {
1116 Class* klass =
1117 LookupClassByDescriptor(method, descriptor, &failure);
1118 if (failure != VERIFY_ERROR_NONE)
1119 return false;
1120 reg_types[arg_start + actual_args] = RegTypeFromClass(klass);
1121 }
1122 actual_args++;
1123 break;
1124 case 'Z':
1125 reg_types[arg_start + actual_args] = kRegTypeBoolean;
1126 actual_args++;
1127 break;
1128 case 'C':
1129 reg_types[arg_start + actual_args] = kRegTypeChar;
1130 actual_args++;
1131 break;
1132 case 'B':
1133 reg_types[arg_start + actual_args] = kRegTypeByte;
1134 actual_args++;
1135 break;
1136 case 'I':
1137 reg_types[arg_start + actual_args] = kRegTypeInteger;
1138 actual_args++;
1139 break;
1140 case 'S':
1141 reg_types[arg_start + actual_args] = kRegTypeShort;
1142 actual_args++;
1143 break;
1144 case 'F':
1145 reg_types[arg_start + actual_args] = kRegTypeFloat;
1146 actual_args++;
1147 break;
1148 case 'D':
1149 reg_types[arg_start + actual_args] = kRegTypeDoubleLo;
1150 reg_types[arg_start + actual_args +1] = kRegTypeDoubleHi;
1151 actual_args += 2;
1152 break;
1153 case 'J':
1154 reg_types[arg_start + actual_args] = kRegTypeLongLo;
1155 reg_types[arg_start + actual_args +1] = kRegTypeLongHi;
1156 actual_args += 2;
1157 break;
1158 default:
1159 LOG(ERROR) << "VFY: unexpected signature type char '" << descriptor
1160 << "'";
1161 return false;
1162 }
1163 }
1164
1165 if (actual_args != expected_args) {
1166 LOG(ERROR) << "VFY: expected " << expected_args << " args, found "
1167 << actual_args;
jeffhaoba5ebb92011-08-25 17:24:37 -07001168 return false;
1169 }
1170
jeffhaobdb76512011-09-07 11:43:16 -07001171 const char* descriptor = dex_file->GetReturnTypeDescriptor(proto_id);
1172
1173 /*
jeffhaod1f0fde2011-09-08 17:25:33 -07001174 * Validate return type. We don't do the type lookup; just want to make
1175 * sure that it has the right format. Only major difference from the
jeffhaobdb76512011-09-07 11:43:16 -07001176 * method argument format is that 'V' is supported.
1177 */
1178 switch (*descriptor) {
1179 case 'I':
1180 case 'C':
1181 case 'S':
1182 case 'B':
1183 case 'Z':
1184 case 'V':
1185 case 'F':
1186 case 'D':
1187 case 'J':
1188 if (*(descriptor + 1) != '\0')
1189 return false;
1190 break;
1191 case '[':
1192 /* single/multi, object/primitive */
1193 while (*++descriptor == '[')
1194 ;
1195 if (*descriptor == 'L') {
1196 while (*++descriptor != ';' && *descriptor != '\0')
1197 ;
1198 if (*descriptor != ';')
1199 return false;
1200 } else {
1201 if (*(descriptor+1) != '\0')
1202 return false;
1203 }
1204 break;
1205 case 'L':
1206 /* could be more thorough here, but shouldn't be required */
1207 while (*++descriptor != ';' && *descriptor != '\0')
1208 ;
1209 if (*descriptor != ';')
1210 return false;
1211 break;
1212 default:
1213 return false;
1214 }
1215
jeffhaoba5ebb92011-08-25 17:24:37 -07001216 return true;
1217}
1218
jeffhaobdb76512011-09-07 11:43:16 -07001219int DexVerifier::SetUninitInstance(UninitInstanceMap* uninit_map, int addr,
1220 Class* klass) {
1221 int idx;
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07001222 DCHECK(klass != NULL);
jeffhaobdb76512011-09-07 11:43:16 -07001223
jeffhaod1f0fde2011-09-08 17:25:33 -07001224 /* TODO: binary search when num_entries > 8 */
jeffhaobdb76512011-09-07 11:43:16 -07001225 for (idx = uninit_map->num_entries_ - 1; idx >= 0; idx--) {
1226 if (uninit_map->map_[idx].addr_ == addr) {
1227 if (uninit_map->map_[idx].klass_ != NULL &&
1228 uninit_map->map_[idx].klass_ != klass) {
1229 LOG(ERROR) << "VFY: addr " << addr << " already set to "
1230 << (int) uninit_map->map_[idx].klass_ << ", not setting to "
1231 << (int) klass;
1232 return -1; // already set to something else??
1233 }
1234 uninit_map->map_[idx].klass_ = klass;
1235 return idx;
1236 }
1237 }
1238
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07001239 LOG(FATAL) << "VFY: addr " << addr << " not found in uninit map";
jeffhaobdb76512011-09-07 11:43:16 -07001240 return -1;
1241}
1242
1243bool DexVerifier::CodeFlowVerifyMethod(VerifierData* vdata,
1244 RegisterTable* reg_table) {
1245 const Method* method = vdata->method_;
1246 const DexFile::CodeItem* code_item = vdata->code_item_;
Elliott Hughes5fe594f2011-09-08 12:33:17 -07001247 InsnFlags* insn_flags = vdata->insn_flags_.get();
jeffhaobdb76512011-09-07 11:43:16 -07001248 const uint16_t* insns = code_item->insns_;
jeffhaoba5ebb92011-08-25 17:24:37 -07001249 uint32_t insns_size = code_item->insns_size_;
jeffhaobdb76512011-09-07 11:43:16 -07001250 size_t insn_idx, start_guess;
jeffhaoba5ebb92011-08-25 17:24:37 -07001251
jeffhaobdb76512011-09-07 11:43:16 -07001252 /* Begin by marking the first instruction as "changed". */
1253 InsnSetChanged(insn_flags, 0, true);
jeffhaoba5ebb92011-08-25 17:24:37 -07001254
jeffhaobdb76512011-09-07 11:43:16 -07001255 start_guess = 0;
jeffhaoba5ebb92011-08-25 17:24:37 -07001256
jeffhaobdb76512011-09-07 11:43:16 -07001257 /* Continue until no instructions are marked "changed". */
1258 while (true) {
1259 /*
jeffhaod1f0fde2011-09-08 17:25:33 -07001260 * Find the first marked one. Use "start_guess" as a way to find
jeffhaobdb76512011-09-07 11:43:16 -07001261 * one quickly.
1262 */
1263 for (insn_idx = start_guess; insn_idx < insns_size; insn_idx++) {
1264 if (InsnIsChanged(insn_flags, insn_idx))
1265 break;
1266 }
jeffhaoba5ebb92011-08-25 17:24:37 -07001267
jeffhaobdb76512011-09-07 11:43:16 -07001268 if (insn_idx == insns_size) {
1269 if (start_guess != 0) {
1270 /* try again, starting from the top */
1271 start_guess = 0;
1272 continue;
1273 } else {
1274 /* all flags are clear */
1275 break;
1276 }
1277 }
1278
1279 /*
jeffhaod1f0fde2011-09-08 17:25:33 -07001280 * We carry the working set of registers from instruction to instruction.
1281 * If this address can be the target of a branch (or throw) instruction,
1282 * or if we're skipping around chasing "changed" flags, we need to load
1283 * the set of registers from the table.
jeffhaobdb76512011-09-07 11:43:16 -07001284 *
jeffhaod1f0fde2011-09-08 17:25:33 -07001285 * Because we always prefer to continue on to the next instruction, we
1286 * should never have a situation where we have a stray "changed" flag set
1287 * on an instruction that isn't a branch target.
jeffhaobdb76512011-09-07 11:43:16 -07001288 */
1289 if (InsnIsBranchTarget(insn_flags, insn_idx)) {
1290 RegisterLine* work_line = &reg_table->work_line_;
1291 CopyLineFromTable(work_line, reg_table, insn_idx);
1292 } else {
1293#ifndef NDEBUG
1294 /*
1295 * Sanity check: retrieve the stored register line (assuming
1296 * a full table) and make sure it actually matches.
1297 */
1298 RegisterLine* register_line = GetRegisterLine(reg_table, insn_idx);
Elliott Hughes5fe594f2011-09-08 12:33:17 -07001299 if (register_line->reg_types_.get() != NULL && CompareLineToTable(reg_table,
jeffhaobdb76512011-09-07 11:43:16 -07001300 insn_idx, &reg_table->work_line_) != 0) {
1301 Class* klass = method->GetDeclaringClass();
1302 LOG(ERROR) << "HUH? work_line diverged in "
1303 << klass->GetDescriptor()->ToModifiedUtf8() << "."
1304 << method->GetName()->ToModifiedUtf8() << " "
1305 << method->GetSignature()->ToModifiedUtf8();
1306 }
1307#endif
1308 }
1309
1310 if (!CodeFlowVerifyInstruction(vdata, reg_table, insn_idx, &start_guess)) {
1311 Class* klass = method->GetDeclaringClass();
1312 LOG(ERROR) << "VFY: failure to verify "
1313 << klass->GetDescriptor()->ToModifiedUtf8() << "."
1314 << method->GetName()->ToModifiedUtf8() << " "
1315 << method->GetSignature()->ToModifiedUtf8();
jeffhaoba5ebb92011-08-25 17:24:37 -07001316 return false;
1317 }
1318
jeffhaobdb76512011-09-07 11:43:16 -07001319 /* Clear "changed" and mark as visited. */
1320 InsnSetVisited(insn_flags, insn_idx, true);
1321 InsnSetChanged(insn_flags, insn_idx, false);
1322 }
jeffhaoba5ebb92011-08-25 17:24:37 -07001323
jeffhaobdb76512011-09-07 11:43:16 -07001324 if (DEAD_CODE_SCAN && ((method->GetAccessFlags() & kAccWritable) == 0)) {
1325 /*
jeffhaod1f0fde2011-09-08 17:25:33 -07001326 * Scan for dead code. There's nothing "evil" about dead code
jeffhaobdb76512011-09-07 11:43:16 -07001327 * (besides the wasted space), but it indicates a flaw somewhere
1328 * down the line, possibly in the verifier.
1329 *
1330 * If we've substituted "always throw" instructions into the stream,
1331 * we are almost certainly going to have some dead code.
1332 */
1333 int dead_start = -1;
1334 for (insn_idx = 0; insn_idx < insns_size;
1335 insn_idx += InsnGetWidth(insn_flags, insn_idx)) {
1336 /*
jeffhaod1f0fde2011-09-08 17:25:33 -07001337 * Switch-statement data doesn't get "visited" by scanner. It
jeffhaobdb76512011-09-07 11:43:16 -07001338 * may or may not be preceded by a padding NOP (for alignment).
1339 */
1340 if (insns[insn_idx] == Instruction::kPackedSwitchSignature ||
1341 insns[insn_idx] == Instruction::kSparseSwitchSignature ||
1342 insns[insn_idx] == Instruction::kArrayDataSignature ||
1343 (insns[insn_idx] == Instruction::NOP &&
1344 (insns[insn_idx + 1] == Instruction::kPackedSwitchSignature ||
1345 insns[insn_idx + 1] == Instruction::kSparseSwitchSignature ||
1346 insns[insn_idx + 1] == Instruction::kArrayDataSignature))) {
1347 InsnSetVisited(insn_flags, insn_idx, true);
1348 }
1349
1350 if (!InsnIsVisited(insn_flags, insn_idx)) {
1351 if (dead_start < 0)
1352 dead_start = insn_idx;
1353 } else if (dead_start >= 0) {
1354 Class* klass = method->GetDeclaringClass();
1355 LOG(INFO) << "VFY: dead code 0x" << std::hex << dead_start << "-"
1356 << insn_idx - 1 << std::dec << " in "
1357 << klass->GetDescriptor()->ToModifiedUtf8() << "."
1358 << method->GetName()->ToModifiedUtf8() << " "
1359 << method->GetSignature()->ToModifiedUtf8();
1360 dead_start = -1;
1361 }
1362 }
1363 if (dead_start >= 0) {
1364 Class* klass = method->GetDeclaringClass();
1365 LOG(INFO) << "VFY: dead code 0x" << std::hex << dead_start << "-"
1366 << insn_idx - 1 << std::dec << " in "
1367 << klass->GetDescriptor()->ToModifiedUtf8() << "."
1368 << method->GetName()->ToModifiedUtf8() << " "
1369 << method->GetSignature()->ToModifiedUtf8();
jeffhaoba5ebb92011-08-25 17:24:37 -07001370 }
1371 }
1372
jeffhaobdb76512011-09-07 11:43:16 -07001373 return true;
1374}
1375
1376bool DexVerifier::CodeFlowVerifyInstruction(VerifierData* vdata,
1377 RegisterTable* reg_table, uint32_t insn_idx, size_t* start_guess) {
1378 const Method* method = vdata->method_;
1379 Class* klass = method->GetDeclaringClass();
1380 const DexFile::CodeItem* code_item = vdata->code_item_;
Elliott Hughes5fe594f2011-09-08 12:33:17 -07001381 InsnFlags* insn_flags = vdata->insn_flags_.get();
jeffhaobdb76512011-09-07 11:43:16 -07001382 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Elliott Hughes5fe594f2011-09-08 12:33:17 -07001383 UninitInstanceMap* uninit_map = vdata->uninit_map_.get();
jeffhaoe0cfb6f2011-09-22 16:42:56 -07001384 const ClassLoader* class_loader =
1385 method->GetDeclaringClass()->GetClassLoader();
jeffhaobdb76512011-09-07 11:43:16 -07001386 const uint16_t* insns = code_item->insns_ + insn_idx;
1387 uint32_t insns_size = code_item->insns_size_;
1388 uint32_t registers_size = code_item->registers_size_;
1389
1390#ifdef VERIFIER_STATS
1391 if (InsnIsVisited(insn_flags, insn_idx)) {
1392 gDvm.verifierStats.instrsReexamined++;
1393 } else {
1394 gDvm.verifierStats.instrsExamined++;
1395 }
1396#endif
1397
1398 /*
1399 * Once we finish decoding the instruction, we need to figure out where
jeffhaod1f0fde2011-09-08 17:25:33 -07001400 * we can go from here. There are three possible ways to transfer
jeffhaobdb76512011-09-07 11:43:16 -07001401 * control to another statement:
1402 *
jeffhaod1f0fde2011-09-08 17:25:33 -07001403 * (1) Continue to the next instruction. Applies to all but
jeffhaobdb76512011-09-07 11:43:16 -07001404 * unconditional branches, method returns, and exception throws.
jeffhaod1f0fde2011-09-08 17:25:33 -07001405 * (2) Branch to one or more possible locations. Applies to branches
jeffhaobdb76512011-09-07 11:43:16 -07001406 * and switch statements.
jeffhaod1f0fde2011-09-08 17:25:33 -07001407 * (3) Exception handlers. Applies to any instruction that can
jeffhaobdb76512011-09-07 11:43:16 -07001408 * throw an exception that is handled by an encompassing "try"
1409 * block.
1410 *
1411 * We can also return, in which case there is no successor instruction
1412 * from this point.
1413 *
1414 * The behavior can be determined from the OpcodeFlags.
1415 */
1416 RegisterLine* work_line = &reg_table->work_line_;
1417 const DexFile* dex_file = vdata->dex_file_;
1418 const byte* ptr = reinterpret_cast<const byte*>(insns);
1419 const Instruction* inst = Instruction::At(ptr);
1420 Instruction::DecodedInstruction dec_insn(inst);
1421 int opcode_flag = inst->Flag();
1422
1423 Class* res_class;
1424 int32_t branch_target = 0;
1425 RegType tmp_type;
1426 bool just_set_result = false;
1427 VerifyError failure = VERIFY_ERROR_NONE;
1428
1429 /*
jeffhaod1f0fde2011-09-08 17:25:33 -07001430 * Make a copy of the previous register state. If the instruction
jeffhaobdb76512011-09-07 11:43:16 -07001431 * can throw an exception, we will copy/merge this into the "catch"
1432 * address rather than work_line, because we don't want the result
1433 * from the "successful" code path (e.g. a check-cast that "improves"
1434 * a type) to be visible to the exception handler.
1435 */
1436 if ((opcode_flag & Instruction::kThrow) != 0 &&
1437 InsnIsInTry(insn_flags, insn_idx)) {
1438 CopyRegisterLine(&reg_table->saved_line_, work_line,
1439 reg_table->insn_reg_count_plus_);
1440 } else {
1441#ifndef NDEBUG
Elliott Hughes5fe594f2011-09-08 12:33:17 -07001442 memset(reg_table->saved_line_.reg_types_.get(), 0xdd,
jeffhaobdb76512011-09-07 11:43:16 -07001443 reg_table->insn_reg_count_plus_ * sizeof(RegType));
1444#endif
1445 }
1446
1447 switch (dec_insn.opcode_) {
1448 case Instruction::NOP:
1449 /*
jeffhaod1f0fde2011-09-08 17:25:33 -07001450 * A "pure" NOP has no effect on anything. Data tables start with
jeffhaobdb76512011-09-07 11:43:16 -07001451 * a signature that looks like a NOP; if we see one of these in
1452 * the course of executing code then we have a problem.
1453 */
1454 if (dec_insn.vA_ != 0) {
1455 LOG(ERROR) << "VFY: encountered data table in instruction stream";
1456 failure = VERIFY_ERROR_GENERIC;
1457 }
1458 break;
1459
1460 case Instruction::MOVE:
1461 case Instruction::MOVE_FROM16:
1462 case Instruction::MOVE_16:
1463 CopyRegister1(work_line, dec_insn.vA_, dec_insn.vB_, kTypeCategory1nr,
1464 &failure);
1465 break;
1466 case Instruction::MOVE_WIDE:
1467 case Instruction::MOVE_WIDE_FROM16:
1468 case Instruction::MOVE_WIDE_16:
1469 CopyRegister2(work_line, dec_insn.vA_, dec_insn.vB_, &failure);
1470 break;
1471 case Instruction::MOVE_OBJECT:
1472 case Instruction::MOVE_OBJECT_FROM16:
1473 case Instruction::MOVE_OBJECT_16:
1474 CopyRegister1(work_line, dec_insn.vA_, dec_insn.vB_, kTypeCategoryRef,
1475 &failure);
1476 break;
1477
1478 /*
1479 * The move-result instructions copy data out of a "pseudo-register"
jeffhaod1f0fde2011-09-08 17:25:33 -07001480 * with the results from the last method invocation. In practice we
jeffhaobdb76512011-09-07 11:43:16 -07001481 * might want to hold the result in an actual CPU register, so the
1482 * Dalvik spec requires that these only appear immediately after an
1483 * invoke or filled-new-array.
1484 *
jeffhaod1f0fde2011-09-08 17:25:33 -07001485 * These calls invalidate the "result" register. (This is now
jeffhaobdb76512011-09-07 11:43:16 -07001486 * redundant with the reset done below, but it can make the debug info
1487 * easier to read in some cases.)
1488 */
1489 case Instruction::MOVE_RESULT:
1490 CopyResultRegister1(work_line, registers_size, dec_insn.vA_,
1491 kTypeCategory1nr, &failure);
1492 break;
1493 case Instruction::MOVE_RESULT_WIDE:
1494 CopyResultRegister2(work_line, registers_size, dec_insn.vA_, &failure);
1495 break;
1496 case Instruction::MOVE_RESULT_OBJECT:
1497 CopyResultRegister1(work_line, registers_size, dec_insn.vA_,
1498 kTypeCategoryRef, &failure);
1499 break;
1500
1501 case Instruction::MOVE_EXCEPTION:
1502 /*
1503 * This statement can only appear as the first instruction in an
1504 * exception handler (though not all exception handlers need to
jeffhaod1f0fde2011-09-08 17:25:33 -07001505 * have one of these). We verify that as part of extracting the
jeffhaobdb76512011-09-07 11:43:16 -07001506 * exception type from the catch block list.
1507 *
1508 * "res_class" will hold the closest common superclass of all
1509 * exceptions that can be handled here.
1510 */
1511 res_class = GetCaughtExceptionType(vdata, insn_idx, &failure);
1512 if (res_class == NULL) {
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07001513 DCHECK(failure != VERIFY_ERROR_NONE);
jeffhaobdb76512011-09-07 11:43:16 -07001514 } else {
1515 SetRegisterType(work_line, dec_insn.vA_, RegTypeFromClass(res_class));
1516 }
1517 break;
1518
1519 case Instruction::RETURN_VOID:
1520 if (!CheckConstructorReturn(method, work_line, registers_size)) {
1521 failure = VERIFY_ERROR_GENERIC;
1522 } else if (GetMethodReturnType(dex_file, method) != kRegTypeUnknown) {
1523 LOG(ERROR) << "VFY: return-void not expected";
1524 failure = VERIFY_ERROR_GENERIC;
1525 }
1526 break;
1527 case Instruction::RETURN:
1528 if (!CheckConstructorReturn(method, work_line, registers_size)) {
1529 failure = VERIFY_ERROR_GENERIC;
1530 } else {
1531 /* check the method signature */
1532 RegType return_type = GetMethodReturnType(dex_file, method);
1533 CheckTypeCategory(return_type, kTypeCategory1nr, &failure);
1534 if (failure != VERIFY_ERROR_NONE)
1535 LOG(ERROR) << "VFY: return-1nr not expected";
1536
1537 /*
1538 * compiler may generate synthetic functions that write byte
1539 * values into boolean fields. Also, it may use integer values
1540 * for boolean, byte, short, and character return types.
1541 */
1542 RegType src_type = GetRegisterType(work_line, dec_insn.vA_);
1543 if ((return_type == kRegTypeBoolean && src_type == kRegTypeByte) ||
1544 ((return_type == kRegTypeBoolean || return_type == kRegTypeByte ||
1545 return_type == kRegTypeShort || return_type == kRegTypeChar) &&
1546 src_type == kRegTypeInteger))
1547 return_type = src_type;
1548
1549 /* check the register contents */
1550 VerifyRegisterType(work_line, dec_insn.vA_, return_type, &failure);
1551 if (failure != VERIFY_ERROR_NONE) {
1552 LOG(ERROR) << "VFY: return-1nr on invalid register v" << dec_insn.vA_;
1553 }
1554 }
1555 break;
1556 case Instruction::RETURN_WIDE:
1557 if (!CheckConstructorReturn(method, work_line, registers_size)) {
1558 failure = VERIFY_ERROR_GENERIC;
1559 } else {
1560 RegType return_type;
1561
1562 /* check the method signature */
1563 return_type = GetMethodReturnType(dex_file, method);
1564 CheckTypeCategory(return_type, kTypeCategory2, &failure);
1565 if (failure != VERIFY_ERROR_NONE)
1566 LOG(ERROR) << "VFY: return-wide not expected";
1567
1568 /* check the register contents */
1569 VerifyRegisterType(work_line, dec_insn.vA_, return_type, &failure);
1570 if (failure != VERIFY_ERROR_NONE) {
1571 LOG(ERROR) << "VFY: return-wide on invalid register pair v"
1572 << dec_insn.vA_;
1573 }
1574 }
1575 break;
1576 case Instruction::RETURN_OBJECT:
1577 if (!CheckConstructorReturn(method, work_line, registers_size)) {
1578 failure = VERIFY_ERROR_GENERIC;
1579 } else {
1580 RegType return_type = GetMethodReturnType(dex_file, method);
1581 CheckTypeCategory(return_type, kTypeCategoryRef, &failure);
1582 if (failure != VERIFY_ERROR_NONE) {
1583 LOG(ERROR) << "VFY: return-object not expected";
1584 break;
1585 }
1586
1587 /* return_type is the *expected* return type, not register value */
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07001588 DCHECK(return_type != kRegTypeZero);
1589 DCHECK(!RegTypeIsUninitReference(return_type));
jeffhaobdb76512011-09-07 11:43:16 -07001590
1591 /*
1592 * Verify that the reference in vAA is an instance of the type
jeffhaod1f0fde2011-09-08 17:25:33 -07001593 * in "return_type". The Zero type is allowed here. If the
jeffhaobdb76512011-09-07 11:43:16 -07001594 * method is declared to return an interface, then any
1595 * initialized reference is acceptable.
1596 *
1597 * Note GetClassFromRegister fails if the register holds an
1598 * uninitialized reference, so we do not allow them to be
1599 * returned.
1600 */
1601 Class* decl_class = RegTypeInitializedReferenceToClass(return_type);
1602 res_class = GetClassFromRegister(work_line, dec_insn.vA_, &failure);
1603 if (failure != VERIFY_ERROR_NONE)
1604 break;
1605 if (res_class != NULL) {
1606 if (!decl_class->IsInterface() &&
jeffhaobdb76512011-09-07 11:43:16 -07001607 !decl_class->IsAssignableFrom(res_class)) {
1608 LOG(ERROR) << "VFY: returning " << std::hex
1609 << res_class->GetDescriptor()->ToModifiedUtf8()
1610 << " (cl=0x" << (int) res_class->GetClassLoader()
1611 << "), declared "
1612 << decl_class->GetDescriptor()->ToModifiedUtf8()
1613 << " (cl=0x" << (int) decl_class->GetClassLoader()
1614 << ")" << std::dec;
1615 failure = VERIFY_ERROR_GENERIC;
1616 break;
1617 }
1618 }
1619 }
1620 break;
1621
1622 case Instruction::CONST_4:
1623 case Instruction::CONST_16:
1624 case Instruction::CONST:
1625 /* could be boolean, int, float, or a null reference */
1626 SetRegisterType(work_line, dec_insn.vA_,
1627 DetermineCat1Const((int32_t) dec_insn.vB_));
1628 break;
1629 case Instruction::CONST_HIGH16:
1630 /* could be boolean, int, float, or a null reference */
1631 SetRegisterType(work_line, dec_insn.vA_,
1632 DetermineCat1Const((int32_t) dec_insn.vB_ << 16));
1633 break;
1634 case Instruction::CONST_WIDE_16:
1635 case Instruction::CONST_WIDE_32:
1636 case Instruction::CONST_WIDE:
1637 case Instruction::CONST_WIDE_HIGH16:
1638 /* could be long or double; resolved upon use */
1639 SetRegisterType(work_line, dec_insn.vA_, kRegTypeConstLo);
1640 break;
1641 case Instruction::CONST_STRING:
1642 case Instruction::CONST_STRING_JUMBO:
1643 SetRegisterType(work_line, dec_insn.vA_, RegTypeFromClass(
1644 class_linker->FindSystemClass("Ljava/lang/String;")));
1645 break;
1646 case Instruction::CONST_CLASS:
1647 /* make sure we can resolve the class; access check is important */
jeffhao98eacac2011-09-14 16:11:53 -07001648 res_class = ResolveClassAndCheckAccess(dex_file, dec_insn.vB_, klass, &failure);
jeffhaobdb76512011-09-07 11:43:16 -07001649 if (res_class == NULL) {
1650 const char* bad_class_desc = dex_file->dexStringByTypeIdx(dec_insn.vB_);
1651 LOG(ERROR) << "VFY: unable to resolve const-class " << dec_insn.vB_
1652 << " (" << bad_class_desc << ") in "
1653 << klass->GetDescriptor()->ToModifiedUtf8();
jeffhaoe0cfb6f2011-09-22 16:42:56 -07001654 if (failure != VERIFY_ERROR_NONE) {
1655 break;
1656 }
jeffhaobdb76512011-09-07 11:43:16 -07001657 }
jeffhaoe0cfb6f2011-09-22 16:42:56 -07001658 SetRegisterType(work_line, dec_insn.vA_, RegTypeFromClass(
1659 class_linker->FindSystemClass("Ljava/lang/Class;")));
jeffhaobdb76512011-09-07 11:43:16 -07001660 break;
1661
1662 case Instruction::MONITOR_ENTER:
1663 HandleMonitorEnter(work_line, dec_insn.vA_, insn_idx, &failure);
1664 break;
1665 case Instruction::MONITOR_EXIT:
1666 /*
jeffhaod1f0fde2011-09-08 17:25:33 -07001667 * monitor-exit instructions are odd. They can throw exceptions,
jeffhaobdb76512011-09-07 11:43:16 -07001668 * but when they do they act as if they succeeded and the PC is
jeffhaod1f0fde2011-09-08 17:25:33 -07001669 * pointing to the following instruction. (This behavior goes back
jeffhaobdb76512011-09-07 11:43:16 -07001670 * to the need to handle asynchronous exceptions, a now-deprecated
1671 * feature that Dalvik doesn't support.)
1672 *
jeffhaod1f0fde2011-09-08 17:25:33 -07001673 * In practice we don't need to worry about this. The only
jeffhaobdb76512011-09-07 11:43:16 -07001674 * exceptions that can be thrown from monitor-exit are for a
jeffhaod1f0fde2011-09-08 17:25:33 -07001675 * null reference and -exit without a matching -enter. If the
jeffhaobdb76512011-09-07 11:43:16 -07001676 * structured locking checks are working, the former would have
1677 * failed on the -enter instruction, and the latter is impossible.
1678 *
1679 * This is fortunate, because issue 3221411 prevents us from
1680 * chasing the "can throw" path when monitor verification is
jeffhaod1f0fde2011-09-08 17:25:33 -07001681 * enabled. If we can fully verify the locking we can ignore
jeffhaobdb76512011-09-07 11:43:16 -07001682 * some catch blocks (which will show up as "dead" code when
1683 * we skip them here); if we can't, then the code path could be
1684 * "live" so we still need to check it.
1685 */
Elliott Hughes5fe594f2011-09-08 12:33:17 -07001686 if (work_line->monitor_entries_.get() != NULL)
jeffhaobdb76512011-09-07 11:43:16 -07001687 opcode_flag &= ~Instruction::kThrow;
1688 HandleMonitorExit(work_line, dec_insn.vA_, insn_idx, &failure);
1689 break;
1690
1691 case Instruction::CHECK_CAST:
1692 /*
1693 * If this instruction succeeds, we will promote register vA to
jeffhaod1f0fde2011-09-08 17:25:33 -07001694 * the type in vB. (This could be a demotion -- not expected, so
jeffhaobdb76512011-09-07 11:43:16 -07001695 * we don't try to address it.)
1696 *
1697 * If it fails, an exception is thrown, which we deal with later
1698 * by ignoring the update to dec_insn.vA_ when branching to a handler.
1699 */
jeffhao98eacac2011-09-14 16:11:53 -07001700 res_class = ResolveClassAndCheckAccess(dex_file, dec_insn.vB_, klass, &failure);
jeffhaobdb76512011-09-07 11:43:16 -07001701 if (res_class == NULL) {
1702 const char* bad_class_desc = dex_file->dexStringByTypeIdx(dec_insn.vB_);
1703 LOG(ERROR) << "VFY: unable to resolve check-cast " << dec_insn.vB_
1704 << " (" << bad_class_desc << ") in "
1705 << klass->GetDescriptor()->ToModifiedUtf8();
jeffhaoe0cfb6f2011-09-22 16:42:56 -07001706 if (failure != VERIFY_ERROR_NONE) {
jeffhaobdb76512011-09-07 11:43:16 -07001707 break;
1708 }
jeffhaoe0cfb6f2011-09-22 16:42:56 -07001709 /* if the class is unresolvable, treat it as an object */
1710 res_class = class_linker->FindClass("Ljava/lang/Object;", class_loader);
jeffhaobdb76512011-09-07 11:43:16 -07001711 }
jeffhaoe0cfb6f2011-09-22 16:42:56 -07001712 RegType orig_type;
1713
1714 orig_type = GetRegisterType(work_line, dec_insn.vA_);
1715 if (!RegTypeIsReference(orig_type)) {
1716 LOG(ERROR) << "VFY: check-cast on non-reference in v" << dec_insn.vA_;
1717 failure = VERIFY_ERROR_GENERIC;
1718 break;
1719 }
1720 SetRegisterType(work_line, dec_insn.vA_, RegTypeFromClass(res_class));
jeffhaobdb76512011-09-07 11:43:16 -07001721 break;
1722 case Instruction::INSTANCE_OF:
1723 /* make sure we're checking a reference type */
1724 tmp_type = GetRegisterType(work_line, dec_insn.vB_);
1725 if (!RegTypeIsReference(tmp_type)) {
1726 LOG(ERROR) << "VFY: vB not a reference (" << tmp_type << ")";
1727 failure = VERIFY_ERROR_GENERIC;
1728 break;
1729 }
1730
1731 /* make sure we can resolve the class; access check is important */
jeffhao98eacac2011-09-14 16:11:53 -07001732 res_class = ResolveClassAndCheckAccess(dex_file, dec_insn.vC_, klass, &failure);
jeffhaobdb76512011-09-07 11:43:16 -07001733 if (res_class == NULL) {
1734 const char* bad_class_desc = dex_file->dexStringByTypeIdx(dec_insn.vC_);
1735 LOG(ERROR) << "VFY: unable to resolve instanceof " << dec_insn.vC_
1736 << " (" << bad_class_desc << ") in "
1737 << klass->GetDescriptor()->ToModifiedUtf8();
jeffhaoe0cfb6f2011-09-22 16:42:56 -07001738 if (failure != VERIFY_ERROR_NONE) {
1739 break;
1740 }
jeffhaobdb76512011-09-07 11:43:16 -07001741 }
jeffhaoe0cfb6f2011-09-22 16:42:56 -07001742 /* result is boolean */
1743 SetRegisterType(work_line, dec_insn.vA_, kRegTypeBoolean);
jeffhaobdb76512011-09-07 11:43:16 -07001744 break;
1745
1746 case Instruction::ARRAY_LENGTH:
1747 res_class = GetClassFromRegister(work_line, dec_insn.vB_, &failure);
1748 if (failure != VERIFY_ERROR_NONE)
1749 break;
1750 if (res_class != NULL && !res_class->IsArrayClass()) {
1751 LOG(ERROR) << "VFY: array-length on non-array";
1752 failure = VERIFY_ERROR_GENERIC;
1753 break;
1754 }
1755 SetRegisterType(work_line, dec_insn.vA_, kRegTypeInteger);
1756 break;
1757
1758 case Instruction::NEW_INSTANCE:
jeffhaoe0cfb6f2011-09-22 16:42:56 -07001759 {
1760 res_class = ResolveClassAndCheckAccess(dex_file, dec_insn.vB_, klass, &failure);
1761 if (res_class == NULL) {
1762 const char* bad_class_desc = dex_file->dexStringByTypeIdx(dec_insn.vB_);
1763 LOG(ERROR) << "VFY: unable to resolve new-instance " << dec_insn.vB_
1764 << " (" << bad_class_desc << ") in "
1765 << klass->GetDescriptor()->ToModifiedUtf8();
1766 if (failure != VERIFY_ERROR_NONE) {
1767 break;
1768 }
1769 /* if the class is unresolvable, treat it as an object */
1770 res_class = class_linker->FindClass("Ljava/lang/Object;", class_loader);
1771 }
jeffhaobdb76512011-09-07 11:43:16 -07001772 RegType uninit_type;
1773
1774 /* can't create an instance of an interface or abstract class */
1775 if (res_class->IsAbstract() || res_class->IsInterface()) {
1776 LOG(ERROR) << "VFY: new-instance on interface or abstract class"
1777 << res_class->GetDescriptor()->ToModifiedUtf8();
1778 failure = VERIFY_ERROR_INSTANTIATION;
1779 break;
1780 }
1781
1782 /* add resolved class to uninit map if not already there */
1783 int uidx = SetUninitInstance(uninit_map, insn_idx, res_class);
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07001784 DCHECK_GE(uidx, 0);
jeffhaobdb76512011-09-07 11:43:16 -07001785 uninit_type = RegTypeFromUninitIndex(uidx);
1786
1787 /*
1788 * Any registers holding previous allocations from this address
1789 * that have not yet been initialized must be marked invalid.
1790 */
1791 MarkUninitRefsAsInvalid(work_line, registers_size, uninit_map,
1792 uninit_type);
1793
1794 /* add the new uninitialized reference to the register ste */
1795 SetRegisterType(work_line, dec_insn.vA_, uninit_type);
jeffhaoe0cfb6f2011-09-22 16:42:56 -07001796 break;
jeffhaobdb76512011-09-07 11:43:16 -07001797 }
jeffhaobdb76512011-09-07 11:43:16 -07001798 case Instruction::NEW_ARRAY:
jeffhao98eacac2011-09-14 16:11:53 -07001799 res_class = ResolveClassAndCheckAccess(dex_file, dec_insn.vC_, klass, &failure);
jeffhaobdb76512011-09-07 11:43:16 -07001800 if (res_class == NULL) {
1801 const char* bad_class_desc = dex_file->dexStringByTypeIdx(dec_insn.vC_);
1802 LOG(ERROR) << "VFY: unable to resolve new-array " << dec_insn.vC_
1803 << " (" << bad_class_desc << ") in "
1804 << klass->GetDescriptor()->ToModifiedUtf8();
jeffhaoe0cfb6f2011-09-22 16:42:56 -07001805 if (failure != VERIFY_ERROR_NONE) {
1806 break;
1807 }
1808 /* if the class is unresolvable, treat it as an object array */
1809 res_class = class_linker->FindClass("[Ljava/lang/Object;", class_loader);
1810 }
1811 if (!res_class->IsArrayClass()) {
jeffhaobdb76512011-09-07 11:43:16 -07001812 LOG(ERROR) << "VFY: new-array on non-array class";
1813 failure = VERIFY_ERROR_GENERIC;
1814 } else {
1815 /* make sure "size" register is valid type */
1816 VerifyRegisterType(work_line, dec_insn.vB_, kRegTypeInteger, &failure);
1817 /* set register type to array class */
1818 SetRegisterType(work_line, dec_insn.vA_, RegTypeFromClass(res_class));
1819 }
1820 break;
1821 case Instruction::FILLED_NEW_ARRAY:
1822 case Instruction::FILLED_NEW_ARRAY_RANGE:
jeffhao98eacac2011-09-14 16:11:53 -07001823 res_class = ResolveClassAndCheckAccess(dex_file, dec_insn.vB_, klass, &failure);
jeffhaobdb76512011-09-07 11:43:16 -07001824 if (res_class == NULL) {
1825 const char* bad_class_desc = dex_file->dexStringByTypeIdx(dec_insn.vB_);
1826 LOG(ERROR) << "VFY: unable to resolve filled-array " << dec_insn.vB_
1827 << " (" << bad_class_desc << ") in "
1828 << klass->GetDescriptor()->ToModifiedUtf8();
jeffhaoe0cfb6f2011-09-22 16:42:56 -07001829 if (failure != VERIFY_ERROR_NONE) {
1830 break;
1831 }
1832 /* if the class is unresolvable, treat it as an object array */
1833 res_class = class_linker->FindClass("[Ljava/lang/Object;", class_loader);
1834 }
1835 if (!res_class->IsArrayClass()) {
jeffhaobdb76512011-09-07 11:43:16 -07001836 LOG(ERROR) << "VFY: filled-new-array on non-array class";
1837 failure = VERIFY_ERROR_GENERIC;
1838 } else {
jeffhaoe0cfb6f2011-09-22 16:42:56 -07001839 bool is_range = (dec_insn.opcode_ == Instruction::FILLED_NEW_ARRAY_RANGE);
jeffhaobdb76512011-09-07 11:43:16 -07001840
1841 /* check the arguments to the instruction */
1842 VerifyFilledNewArrayRegs(method, work_line, &dec_insn, res_class,
1843 is_range, &failure);
1844 /* filled-array result goes into "result" register */
1845 SetResultRegisterType(work_line, registers_size,
1846 RegTypeFromClass(res_class));
1847 just_set_result = true;
1848 }
1849 break;
1850
1851 case Instruction::CMPL_FLOAT:
1852 case Instruction::CMPG_FLOAT:
1853 VerifyRegisterType(work_line, dec_insn.vB_, kRegTypeFloat, &failure);
1854 VerifyRegisterType(work_line, dec_insn.vC_, kRegTypeFloat, &failure);
1855 SetRegisterType(work_line, dec_insn.vA_, kRegTypeBoolean);
1856 break;
1857 case Instruction::CMPL_DOUBLE:
1858 case Instruction::CMPG_DOUBLE:
1859 VerifyRegisterType(work_line, dec_insn.vB_, kRegTypeDoubleLo, &failure);
1860 VerifyRegisterType(work_line, dec_insn.vC_, kRegTypeDoubleLo, &failure);
1861 SetRegisterType(work_line, dec_insn.vA_, kRegTypeBoolean);
1862 break;
1863 case Instruction::CMP_LONG:
1864 VerifyRegisterType(work_line, dec_insn.vB_, kRegTypeLongLo, &failure);
1865 VerifyRegisterType(work_line, dec_insn.vC_, kRegTypeLongLo, &failure);
1866 SetRegisterType(work_line, dec_insn.vA_, kRegTypeBoolean);
1867 break;
1868
1869 case Instruction::THROW:
1870 res_class = GetClassFromRegister(work_line, dec_insn.vA_, &failure);
1871 if (failure == VERIFY_ERROR_NONE && res_class != NULL) {
1872 Class* throwable_class =
1873 class_linker->FindSystemClass("Ljava/lang/Throwable;");
1874 if (!throwable_class->IsAssignableFrom(res_class)) {
1875 LOG(ERROR) << "VFY: thrown class "
1876 << res_class->GetDescriptor()->ToModifiedUtf8()
1877 << " not instanceof Throwable",
1878 failure = VERIFY_ERROR_GENERIC;
1879 }
1880 }
1881 break;
1882
1883 case Instruction::GOTO:
1884 case Instruction::GOTO_16:
1885 case Instruction::GOTO_32:
1886 /* no effect on or use of registers */
1887 break;
1888
1889 case Instruction::PACKED_SWITCH:
1890 case Instruction::SPARSE_SWITCH:
1891 /* verify that vAA is an integer, or can be converted to one */
1892 VerifyRegisterType(work_line, dec_insn.vA_, kRegTypeInteger, &failure);
1893 break;
1894
1895 case Instruction::FILL_ARRAY_DATA:
1896 {
1897 RegType value_type;
1898 const uint16_t *array_data;
1899 uint16_t elem_width;
1900
1901 /* Similar to the verification done for APUT */
1902 res_class = GetClassFromRegister(work_line, dec_insn.vA_, &failure);
1903 if (failure != VERIFY_ERROR_NONE)
1904 break;
1905
1906 /* res_class can be null if the reg type is Zero */
1907 if (res_class == NULL)
1908 break;
1909
1910 Class::PrimitiveType prim_type =
1911 res_class->GetComponentType()->GetPrimitiveType();
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07001912 if (!res_class->IsArrayClass() ||
jeffhaobdb76512011-09-07 11:43:16 -07001913 prim_type == Class::kPrimNot || prim_type == Class::kPrimVoid) {
1914 LOG(ERROR) << "VFY: invalid fill-array-data on " <<
1915 res_class->GetDescriptor()->ToModifiedUtf8();
1916 failure = VERIFY_ERROR_GENERIC;
1917 break;
1918 }
1919
1920 value_type = PrimitiveTypeToRegType(prim_type);
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07001921 DCHECK(value_type != kRegTypeUnknown);
jeffhaobdb76512011-09-07 11:43:16 -07001922
1923 /*
1924 * Now verify if the element width in the table matches the element
1925 * width declared in the array
1926 */
1927 array_data = insns + (insns[1] | (((int32_t) insns[2]) << 16));
1928 if (array_data[0] != Instruction::kArrayDataSignature) {
1929 LOG(ERROR) << "VFY: invalid magic for array-data";
1930 failure = VERIFY_ERROR_GENERIC;
1931 break;
1932 }
1933
1934 switch (prim_type) {
1935 case Class::kPrimBoolean:
1936 case Class::kPrimByte:
1937 elem_width = 1;
1938 break;
1939 case Class::kPrimChar:
1940 case Class::kPrimShort:
1941 elem_width = 2;
1942 break;
1943 case Class::kPrimFloat:
1944 case Class::kPrimInt:
1945 elem_width = 4;
1946 break;
1947 case Class::kPrimDouble:
1948 case Class::kPrimLong:
1949 elem_width = 8;
1950 break;
1951 default:
1952 elem_width = 0;
1953 break;
1954 }
1955
1956 /*
1957 * Since we don't compress the data in Dex, expect to see equal
1958 * width of data stored in the table and expected from the array
1959 * class.
1960 */
1961 if (array_data[1] != elem_width) {
1962 LOG(ERROR) << "VFY: array-data size mismatch (" << array_data[1]
1963 << " vs " << elem_width << ")";
1964 failure = VERIFY_ERROR_GENERIC;
1965 }
1966 }
1967 break;
1968
1969 case Instruction::IF_EQ:
1970 case Instruction::IF_NE:
1971 {
1972 RegType type1, type2;
1973
1974 type1 = GetRegisterType(work_line, dec_insn.vA_);
1975 type2 = GetRegisterType(work_line, dec_insn.vB_);
1976
1977 /* both references? */
1978 if (RegTypeIsReference(type1) && RegTypeIsReference(type2))
1979 break;
1980
1981 /* both category-1nr? */
1982 CheckTypeCategory(type1, kTypeCategory1nr, &failure);
1983 CheckTypeCategory(type2, kTypeCategory1nr, &failure);
1984 if (failure != VERIFY_ERROR_NONE) {
1985 LOG(ERROR) << "VFY: args to if-eq/if-ne must both be refs or cat1";
1986 break;
1987 }
1988 }
1989 break;
1990 case Instruction::IF_LT:
1991 case Instruction::IF_GE:
1992 case Instruction::IF_GT:
1993 case Instruction::IF_LE:
1994 tmp_type = GetRegisterType(work_line, dec_insn.vA_);
1995 CheckTypeCategory(tmp_type, kTypeCategory1nr, &failure);
1996 if (failure != VERIFY_ERROR_NONE) {
1997 LOG(ERROR) << "VFY: args to 'if' must be cat-1nr";
1998 break;
1999 }
2000 tmp_type = GetRegisterType(work_line, dec_insn.vB_);
2001 CheckTypeCategory(tmp_type, kTypeCategory1nr, &failure);
2002 if (failure != VERIFY_ERROR_NONE) {
2003 LOG(ERROR) << "VFY: args to 'if' must be cat-1nr";
2004 break;
2005 }
2006 break;
2007 case Instruction::IF_EQZ:
2008 case Instruction::IF_NEZ:
2009 tmp_type = GetRegisterType(work_line, dec_insn.vA_);
2010 if (RegTypeIsReference(tmp_type))
2011 break;
2012 CheckTypeCategory(tmp_type, kTypeCategory1nr, &failure);
2013 if (failure != VERIFY_ERROR_NONE)
2014 LOG(ERROR) << "VFY: expected cat-1 arg to if";
2015 break;
2016 case Instruction::IF_LTZ:
2017 case Instruction::IF_GEZ:
2018 case Instruction::IF_GTZ:
2019 case Instruction::IF_LEZ:
2020 tmp_type = GetRegisterType(work_line, dec_insn.vA_);
2021 CheckTypeCategory(tmp_type, kTypeCategory1nr, &failure);
2022 if (failure != VERIFY_ERROR_NONE)
2023 LOG(ERROR) << "VFY: expected cat-1 arg to if";
2024 break;
2025
2026 case Instruction::AGET:
2027 tmp_type = kRegTypeConstInteger;
2028 goto aget_1nr_common;
2029 case Instruction::AGET_BOOLEAN:
2030 tmp_type = kRegTypeBoolean;
2031 goto aget_1nr_common;
2032 case Instruction::AGET_BYTE:
2033 tmp_type = kRegTypeByte;
2034 goto aget_1nr_common;
2035 case Instruction::AGET_CHAR:
2036 tmp_type = kRegTypeChar;
2037 goto aget_1nr_common;
2038 case Instruction::AGET_SHORT:
2039 tmp_type = kRegTypeShort;
2040 goto aget_1nr_common;
2041aget_1nr_common:
2042 {
2043 RegType src_type, index_type;
2044
2045 index_type = GetRegisterType(work_line, dec_insn.vC_);
2046 CheckArrayIndexType(method, index_type, &failure);
2047 if (failure != VERIFY_ERROR_NONE)
2048 break;
2049
2050 res_class = GetClassFromRegister(work_line, dec_insn.vB_, &failure);
2051 if (failure != VERIFY_ERROR_NONE)
2052 break;
2053 if (res_class != NULL) {
2054 /* verify the class */
2055 Class::PrimitiveType prim_type =
2056 res_class->GetComponentType()->GetPrimitiveType();
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07002057 if (!res_class->IsArrayClass() || prim_type == Class::kPrimNot) {
jeffhaobdb76512011-09-07 11:43:16 -07002058 LOG(ERROR) << "VFY: invalid aget-1nr target "
2059 << res_class->GetDescriptor()->ToModifiedUtf8();
2060 failure = VERIFY_ERROR_GENERIC;
2061 break;
2062 }
2063
2064 /* make sure array type matches instruction */
2065 src_type = PrimitiveTypeToRegType(prim_type);
2066
2067 /* differentiate between float and int */
2068 if (src_type == kRegTypeFloat || src_type == kRegTypeInteger)
2069 tmp_type = src_type;
2070
2071 if (tmp_type != src_type) {
2072 LOG(ERROR) << "VFY: invalid aget-1nr, array type=" << src_type
2073 << " with inst type=" << tmp_type << " (on "
2074 << res_class->GetDescriptor()->ToModifiedUtf8() << ")";
2075 failure = VERIFY_ERROR_GENERIC;
2076 break;
2077 }
2078
2079 }
2080 SetRegisterType(work_line, dec_insn.vA_, tmp_type);
2081 }
2082 break;
2083
2084 case Instruction::AGET_WIDE:
2085 {
2086 RegType dst_type, index_type;
2087
2088 index_type = GetRegisterType(work_line, dec_insn.vC_);
2089 CheckArrayIndexType(method, index_type, &failure);
2090 if (failure != VERIFY_ERROR_NONE)
2091 break;
2092
2093 res_class = GetClassFromRegister(work_line, dec_insn.vB_, &failure);
2094 if (failure != VERIFY_ERROR_NONE)
2095 break;
2096 if (res_class != NULL) {
2097 /* verify the class */
2098 Class::PrimitiveType prim_type =
2099 res_class->GetComponentType()->GetPrimitiveType();
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07002100 if (!res_class->IsArrayClass() || prim_type == Class::kPrimNot) {
jeffhaobdb76512011-09-07 11:43:16 -07002101 LOG(ERROR) << "VFY: invalid aget-wide target "
2102 << res_class->GetDescriptor()->ToModifiedUtf8();
2103 failure = VERIFY_ERROR_GENERIC;
2104 break;
2105 }
2106
2107 /* try to refine "dst_type" */
2108 switch (prim_type) {
2109 case Class::kPrimLong:
2110 dst_type = kRegTypeLongLo;
2111 break;
2112 case Class::kPrimDouble:
2113 dst_type = kRegTypeDoubleLo;
2114 break;
2115 default:
2116 LOG(ERROR) << "VFY: invalid aget-wide on "
2117 << res_class->GetDescriptor()->ToModifiedUtf8();
2118 dst_type = kRegTypeUnknown;
2119 failure = VERIFY_ERROR_GENERIC;
2120 break;
2121 }
2122 } else {
2123 /*
jeffhaod1f0fde2011-09-08 17:25:33 -07002124 * Null array ref; this code path will fail at runtime. We
jeffhaobdb76512011-09-07 11:43:16 -07002125 * know this is either long or double, so label it const.
2126 */
2127 dst_type = kRegTypeConstLo;
2128 }
2129 SetRegisterType(work_line, dec_insn.vA_, dst_type);
2130 }
2131 break;
2132
2133 case Instruction::AGET_OBJECT:
2134 {
2135 RegType dst_type, index_type;
2136
2137 index_type = GetRegisterType(work_line, dec_insn.vC_);
2138 CheckArrayIndexType(method, index_type, &failure);
2139 if (failure != VERIFY_ERROR_NONE)
2140 break;
2141
2142 /* get the class of the array we're pulling an object from */
2143 res_class = GetClassFromRegister(work_line, dec_insn.vB_, &failure);
2144 if (failure != VERIFY_ERROR_NONE)
2145 break;
2146 if (res_class != NULL) {
2147 Class* element_class;
2148
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07002149 DCHECK(res_class != NULL);
jeffhaobdb76512011-09-07 11:43:16 -07002150 if (!res_class->IsArrayClass()) {
2151 LOG(ERROR) << "VFY: aget-object on non-array class";
2152 failure = VERIFY_ERROR_GENERIC;
2153 break;
2154 }
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07002155 DCHECK(res_class->GetComponentType() != NULL);
jeffhaobdb76512011-09-07 11:43:16 -07002156
2157 /*
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07002158 * Find the element class.
jeffhaobdb76512011-09-07 11:43:16 -07002159 */
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07002160 element_class = res_class->GetComponentType();
2161 if (element_class->IsPrimitive()) {
jeffhaobdb76512011-09-07 11:43:16 -07002162 LOG(ERROR) << "VFY: aget-object on non-ref array class ("
2163 << res_class->GetDescriptor()->ToModifiedUtf8() << ")";
2164 failure = VERIFY_ERROR_GENERIC;
2165 break;
2166 }
2167
2168 dst_type = RegTypeFromClass(element_class);
2169 } else {
2170 /*
2171 * The array reference is NULL, so the current code path will
jeffhaod1f0fde2011-09-08 17:25:33 -07002172 * throw an exception. For proper merging with later code
jeffhaobdb76512011-09-07 11:43:16 -07002173 * paths, and correct handling of "if-eqz" tests on the
2174 * result of the array get, we want to treat this as a null
2175 * reference.
2176 */
2177 dst_type = kRegTypeZero;
2178 }
2179 SetRegisterType(work_line, dec_insn.vA_, dst_type);
2180 }
2181 break;
2182 case Instruction::APUT:
2183 tmp_type = kRegTypeInteger;
2184 goto aput_1nr_common;
2185 case Instruction::APUT_BOOLEAN:
2186 tmp_type = kRegTypeBoolean;
2187 goto aput_1nr_common;
2188 case Instruction::APUT_BYTE:
2189 tmp_type = kRegTypeByte;
2190 goto aput_1nr_common;
2191 case Instruction::APUT_CHAR:
2192 tmp_type = kRegTypeChar;
2193 goto aput_1nr_common;
2194 case Instruction::APUT_SHORT:
2195 tmp_type = kRegTypeShort;
2196 goto aput_1nr_common;
2197aput_1nr_common:
2198 {
2199 RegType src_type, dst_type, index_type;
2200
2201 index_type = GetRegisterType(work_line, dec_insn.vC_);
2202 CheckArrayIndexType(method, index_type, &failure);
2203 if (failure != VERIFY_ERROR_NONE)
2204 break;
2205
2206 res_class = GetClassFromRegister(work_line, dec_insn.vB_, &failure);
2207 if (failure != VERIFY_ERROR_NONE)
2208 break;
2209
2210 /* res_class can be null if the reg type is Zero */
2211 if (res_class == NULL)
2212 break;
2213
2214 Class::PrimitiveType prim_type =
2215 res_class->GetComponentType()->GetPrimitiveType();
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07002216 if (!res_class->IsArrayClass() || prim_type == Class::kPrimNot) {
jeffhaobdb76512011-09-07 11:43:16 -07002217 LOG(ERROR) << "VFY: invalid aput-1nr on "
2218 << res_class->GetDescriptor()->ToModifiedUtf8();
2219 failure = VERIFY_ERROR_GENERIC;
2220 break;
2221 }
2222
2223 /* verify that instruction matches array */
2224 dst_type = PrimitiveTypeToRegType(prim_type);
2225
2226 /* correct if float */
2227 if (dst_type == kRegTypeFloat)
2228 tmp_type = kRegTypeFloat;
2229
2230 /* make sure the source register has the correct type */
2231 src_type = GetRegisterType(work_line, dec_insn.vA_);
2232 if (!CanConvertTo1nr(src_type, tmp_type)) {
2233 LOG(ERROR) << "VFY: invalid reg type " << src_type
2234 << " on aput instr (need " << tmp_type << ")";
2235 failure = VERIFY_ERROR_GENERIC;
2236 break;
2237 }
2238
2239 VerifyRegisterType(work_line, dec_insn.vA_, dst_type, &failure);
2240
2241 if (failure != VERIFY_ERROR_NONE || dst_type == kRegTypeUnknown ||
2242 tmp_type != dst_type) {
2243 LOG(ERROR) << "VFY: invalid aput-1nr on "
2244 << res_class->GetDescriptor()->ToModifiedUtf8()
2245 << " (inst=" << tmp_type << " dst=" << dst_type << ")";
2246 failure = VERIFY_ERROR_GENERIC;
2247 break;
2248 }
2249 }
2250 break;
2251 case Instruction::APUT_WIDE:
2252 tmp_type = GetRegisterType(work_line, dec_insn.vC_);
2253 CheckArrayIndexType(method, tmp_type, &failure);
2254 if (failure != VERIFY_ERROR_NONE)
2255 break;
2256
2257 res_class = GetClassFromRegister(work_line, dec_insn.vB_, &failure);
2258 if (failure != VERIFY_ERROR_NONE)
2259 break;
2260 if (res_class != NULL) {
2261 Class::PrimitiveType prim_type =
2262 res_class->GetComponentType()->GetPrimitiveType();
2263 /* verify the class and try to refine "dst_type" */
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07002264 if (!res_class->IsArrayClass() || prim_type == Class::kPrimNot)
jeffhaobdb76512011-09-07 11:43:16 -07002265 {
2266 LOG(ERROR) << "VFY: invalid aput-wide on "
2267 << res_class->GetDescriptor()->ToModifiedUtf8();
2268 failure = VERIFY_ERROR_GENERIC;
2269 break;
2270 }
2271
2272 switch (prim_type) {
2273 case Class::kPrimLong:
2274 VerifyRegisterType(work_line, dec_insn.vA_, kRegTypeLongLo,
2275 &failure);
2276 break;
2277 case Class::kPrimDouble:
2278 VerifyRegisterType(work_line, dec_insn.vA_, kRegTypeDoubleLo,
2279 &failure);
2280 break;
2281 default:
2282 LOG(ERROR) << "VFY: invalid aput-wide on "
2283 << res_class->GetDescriptor()->ToModifiedUtf8();
2284 failure = VERIFY_ERROR_GENERIC;
2285 break;
2286 }
2287 }
2288 break;
2289 case Instruction::APUT_OBJECT:
2290 tmp_type = GetRegisterType(work_line, dec_insn.vC_);
2291 CheckArrayIndexType(method, tmp_type, &failure);
2292 if (failure != VERIFY_ERROR_NONE)
2293 break;
2294
2295 /* get the ref we're storing; Zero is okay, Uninit is not */
2296 res_class = GetClassFromRegister(work_line, dec_insn.vA_, &failure);
2297 if (failure != VERIFY_ERROR_NONE)
2298 break;
2299 if (res_class != NULL) {
2300 Class* array_class;
2301 Class* element_class;
2302
2303 /*
jeffhaod1f0fde2011-09-08 17:25:33 -07002304 * Get the array class. If the array ref is null, we won't
jeffhaobdb76512011-09-07 11:43:16 -07002305 * have type information (and we'll crash at runtime with a
2306 * null pointer exception).
2307 */
2308 array_class = GetClassFromRegister(work_line, dec_insn.vB_, &failure);
2309
2310 if (array_class != NULL) {
2311 /* see if the array holds a compatible type */
2312 if (!array_class->IsArrayClass()) {
2313 LOG(ERROR) << "VFY: invalid aput-object on "
2314 << array_class->GetDescriptor()->ToModifiedUtf8();
2315 failure = VERIFY_ERROR_GENERIC;
2316 break;
2317 }
2318
2319 /*
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07002320 * Find the element class.
jeffhaobdb76512011-09-07 11:43:16 -07002321 *
2322 * All we want to check here is that the element type is a
jeffhaod1f0fde2011-09-08 17:25:33 -07002323 * reference class. We *don't* check instanceof here, because
jeffhaobdb76512011-09-07 11:43:16 -07002324 * you can still put a String into a String[] after the latter
2325 * has been cast to an Object[].
2326 */
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07002327 element_class = array_class->GetComponentType();
2328 if (element_class->IsPrimitive()) {
jeffhaobdb76512011-09-07 11:43:16 -07002329 LOG(ERROR) << "VFY: invalid aput-object of "
2330 << res_class->GetDescriptor()->ToModifiedUtf8()
2331 << " into "
2332 << array_class->GetDescriptor()->ToModifiedUtf8();
2333 failure = VERIFY_ERROR_GENERIC;
2334 break;
2335 }
2336 }
2337 }
2338 break;
2339
2340 case Instruction::IGET:
2341 tmp_type = kRegTypeInteger;
2342 goto iget_1nr_common;
2343 case Instruction::IGET_BOOLEAN:
2344 tmp_type = kRegTypeBoolean;
2345 goto iget_1nr_common;
2346 case Instruction::IGET_BYTE:
2347 tmp_type = kRegTypeByte;
2348 goto iget_1nr_common;
2349 case Instruction::IGET_CHAR:
2350 tmp_type = kRegTypeChar;
2351 goto iget_1nr_common;
2352 case Instruction::IGET_SHORT:
2353 tmp_type = kRegTypeShort;
2354 goto iget_1nr_common;
2355iget_1nr_common:
2356 {
2357 Field* inst_field;
2358 RegType obj_type, field_type;
2359
2360 obj_type = GetRegisterType(work_line, dec_insn.vB_);
2361 inst_field = GetInstField(vdata, obj_type, dec_insn.vC_, &failure);
2362 if (failure != VERIFY_ERROR_NONE)
2363 break;
2364
2365 /* make sure the field's type is compatible with expectation */
2366 field_type =
2367 PrimitiveTypeToRegType(inst_field->GetType()->GetPrimitiveType());
2368
2369 /* correct if float */
2370 if (field_type == kRegTypeFloat)
2371 tmp_type = kRegTypeFloat;
2372
2373 if (field_type == kRegTypeUnknown || tmp_type != field_type) {
2374 Class* inst_field_class = inst_field->GetDeclaringClass();
2375 LOG(ERROR) << "VFY: invalid iget-1nr of "
2376 << inst_field_class->GetDescriptor()->ToModifiedUtf8()
2377 << "." << inst_field->GetName()->ToModifiedUtf8()
2378 << " (inst=" << tmp_type << " field=" << field_type << ")";
2379 failure = VERIFY_ERROR_GENERIC;
2380 break;
2381 }
2382
2383 SetRegisterType(work_line, dec_insn.vA_, tmp_type);
2384 }
2385 break;
2386 case Instruction::IGET_WIDE:
2387 {
2388 RegType dst_type;
2389 Field* inst_field;
2390 RegType obj_type;
2391
2392 obj_type = GetRegisterType(work_line, dec_insn.vB_);
2393 inst_field = GetInstField(vdata, obj_type, dec_insn.vC_, &failure);
2394 Class* inst_field_class = inst_field->GetDeclaringClass();
2395 if (failure != VERIFY_ERROR_NONE)
2396 break;
2397 /* check the type, which should be prim */
2398 switch (inst_field->GetType()->GetPrimitiveType()) {
2399 case Class::kPrimDouble:
2400 dst_type = kRegTypeDoubleLo;
2401 break;
2402 case Class::kPrimLong:
2403 dst_type = kRegTypeLongLo;
2404 break;
2405 default:
2406 LOG(ERROR) << "VFY: invalid iget-wide of "
2407 << inst_field_class->GetDescriptor()->ToModifiedUtf8()
2408 << "." << inst_field->GetName()->ToModifiedUtf8();
2409 dst_type = kRegTypeUnknown;
2410 failure = VERIFY_ERROR_GENERIC;
2411 break;
2412 }
2413 if (failure == VERIFY_ERROR_NONE) {
2414 SetRegisterType(work_line, dec_insn.vA_, dst_type);
2415 }
2416 }
2417 break;
2418 case Instruction::IGET_OBJECT:
2419 {
2420 Class* field_class;
2421 Field* inst_field;
2422 RegType obj_type;
2423
2424 obj_type = GetRegisterType(work_line, dec_insn.vB_);
2425 inst_field = GetInstField(vdata, obj_type, dec_insn.vC_, &failure);
2426 if (failure != VERIFY_ERROR_NONE)
2427 break;
2428 field_class = inst_field->GetType();
2429 if (field_class == NULL) {
2430 /* class not found or primitive type */
2431 LOG(ERROR) << "VFY: unable to recover field class from "
2432 << inst_field->GetName()->ToModifiedUtf8();
2433 failure = VERIFY_ERROR_GENERIC;
2434 break;
2435 }
2436 if (failure == VERIFY_ERROR_NONE) {
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07002437 DCHECK(!field_class->IsPrimitive()) << PrettyClass(field_class);
jeffhaobdb76512011-09-07 11:43:16 -07002438 SetRegisterType(work_line, dec_insn.vA_,
2439 RegTypeFromClass(field_class));
2440 }
2441 }
2442 break;
2443 case Instruction::IPUT:
2444 tmp_type = kRegTypeInteger;
2445 goto iput_1nr_common;
2446 case Instruction::IPUT_BOOLEAN:
2447 tmp_type = kRegTypeBoolean;
2448 goto iput_1nr_common;
2449 case Instruction::IPUT_BYTE:
2450 tmp_type = kRegTypeByte;
2451 goto iput_1nr_common;
2452 case Instruction::IPUT_CHAR:
2453 tmp_type = kRegTypeChar;
2454 goto iput_1nr_common;
2455 case Instruction::IPUT_SHORT:
2456 tmp_type = kRegTypeShort;
2457 goto iput_1nr_common;
2458iput_1nr_common:
2459 {
2460 RegType src_type, field_type, obj_type;
2461 Field* inst_field;
2462
2463 obj_type = GetRegisterType(work_line, dec_insn.vB_);
2464 inst_field = GetInstField(vdata, obj_type, dec_insn.vC_, &failure);
2465 if (failure != VERIFY_ERROR_NONE)
2466 break;
2467 CheckFinalFieldAccess(method, inst_field, &failure);
2468 if (failure != VERIFY_ERROR_NONE)
2469 break;
2470
2471 /* get type of field we're storing into */
2472 field_type =
2473 PrimitiveTypeToRegType(inst_field->GetType()->GetPrimitiveType());
2474 src_type = GetRegisterType(work_line, dec_insn.vA_);
2475
2476 /* correct if float */
2477 if (field_type == kRegTypeFloat)
2478 tmp_type = kRegTypeFloat;
2479
2480 /*
2481 * compiler can generate synthetic functions that write byte values
2482 * into boolean fields.
2483 */
2484 if (tmp_type == kRegTypeBoolean && src_type == kRegTypeByte)
2485 tmp_type = kRegTypeByte;
2486 if (field_type == kRegTypeBoolean && src_type == kRegTypeByte)
2487 field_type = kRegTypeByte;
2488
2489 /* make sure the source register has the correct type */
2490 if (!CanConvertTo1nr(src_type, tmp_type)) {
2491 LOG(ERROR) << "VFY: invalid reg type " << src_type
2492 << " on iput instr (need " << tmp_type << ")",
2493 failure = VERIFY_ERROR_GENERIC;
2494 break;
2495 }
2496
2497 VerifyRegisterType(work_line, dec_insn.vA_, field_type, &failure);
2498
2499 if (failure != VERIFY_ERROR_NONE || field_type == kRegTypeUnknown ||
2500 tmp_type != field_type) {
2501 Class* inst_field_class = inst_field->GetDeclaringClass();
2502 LOG(ERROR) << "VFY: invalid iput-1nr of "
2503 << inst_field_class->GetDescriptor()->ToModifiedUtf8()
2504 << "." << inst_field->GetName()->ToModifiedUtf8()
2505 << " (inst=" << tmp_type << " field=" << field_type << ")";
2506 failure = VERIFY_ERROR_GENERIC;
2507 break;
2508 }
2509 }
2510 break;
2511 case Instruction::IPUT_WIDE:
2512 Field* inst_field;
2513 RegType obj_type;
2514
2515 obj_type = GetRegisterType(work_line, dec_insn.vB_);
2516 inst_field = GetInstField(vdata, obj_type, dec_insn.vC_, &failure);
2517 if (failure != VERIFY_ERROR_NONE)
2518 break;
2519 CheckFinalFieldAccess(method, inst_field, &failure);
2520 if (failure != VERIFY_ERROR_NONE)
2521 break;
2522
2523 /* check the type, which should be prim */
2524 switch (inst_field->GetType()->GetPrimitiveType()) {
2525 case Class::kPrimDouble:
2526 VerifyRegisterType(work_line, dec_insn.vA_, kRegTypeDoubleLo,
2527 &failure);
2528 break;
2529 case Class::kPrimLong:
2530 VerifyRegisterType(work_line, dec_insn.vA_, kRegTypeLongLo, &failure);
2531 break;
2532 default:
2533 LOG(ERROR) << "VFY: invalid iput-wide of "
2534 << inst_field->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8()
2535 << "." << inst_field->GetName()->ToModifiedUtf8();
2536 failure = VERIFY_ERROR_GENERIC;
2537 break;
2538 }
2539 break;
2540 case Instruction::IPUT_OBJECT:
2541 {
2542 Class* field_class;
2543 Class* value_class;
2544 Field* inst_field;
2545 RegType obj_type, value_type;
2546
2547 obj_type = GetRegisterType(work_line, dec_insn.vB_);
2548 inst_field = GetInstField(vdata, obj_type, dec_insn.vC_, &failure);
2549 if (failure != VERIFY_ERROR_NONE)
2550 break;
Brian Carlstrom65ca0772011-09-24 16:03:08 -07002551 DCHECK(inst_field != NULL);
jeffhaobdb76512011-09-07 11:43:16 -07002552 CheckFinalFieldAccess(method, inst_field, &failure);
2553 if (failure != VERIFY_ERROR_NONE)
2554 break;
2555
2556 field_class = inst_field->GetType();
2557 if (field_class == NULL) {
2558 LOG(ERROR) << "VFY: unable to recover field class from '"
2559 << inst_field->GetName()->ToModifiedUtf8() << "'";
2560 failure = VERIFY_ERROR_GENERIC;
2561 break;
2562 }
2563
2564 value_type = GetRegisterType(work_line, dec_insn.vA_);
2565 if (!RegTypeIsReference(value_type)) {
2566 LOG(ERROR) << "VFY: storing non-ref v" << dec_insn.vA_
2567 << " into ref field '"
2568 << inst_field->GetName()->ToModifiedUtf8() << "' ("
2569 << field_class->GetDescriptor()->ToModifiedUtf8() << ")";
2570 failure = VERIFY_ERROR_GENERIC;
2571 break;
2572 }
2573 if (value_type != kRegTypeZero) {
2574 value_class = RegTypeInitializedReferenceToClass(value_type);
2575 if (value_class == NULL) {
2576 LOG(ERROR) << "VFY: storing uninit ref v" << dec_insn.vA_
2577 << " into ref field";
2578 failure = VERIFY_ERROR_GENERIC;
2579 break;
2580 }
2581 /* allow if field is any interface or field is base class */
2582 if (!field_class->IsInterface() &&
2583 !field_class->IsAssignableFrom(value_class)) {
2584 Class* inst_field_class = inst_field->GetDeclaringClass();
2585 LOG(ERROR) << "VFY: storing type '"
2586 << value_class->GetDescriptor()->ToModifiedUtf8()
2587 << "' into field type '"
2588 << field_class->GetDescriptor()->ToModifiedUtf8()
2589 << "' ("
2590 << inst_field_class->GetDescriptor()->ToModifiedUtf8()
2591 << "." << inst_field->GetName()->ToModifiedUtf8() << ")";
2592 failure = VERIFY_ERROR_GENERIC;
2593 break;
2594 }
2595 }
2596 }
2597 break;
2598
2599 case Instruction::SGET:
2600 tmp_type = kRegTypeInteger;
2601 goto sget_1nr_common;
2602 case Instruction::SGET_BOOLEAN:
2603 tmp_type = kRegTypeBoolean;
2604 goto sget_1nr_common;
2605 case Instruction::SGET_BYTE:
2606 tmp_type = kRegTypeByte;
2607 goto sget_1nr_common;
2608 case Instruction::SGET_CHAR:
2609 tmp_type = kRegTypeChar;
2610 goto sget_1nr_common;
2611 case Instruction::SGET_SHORT:
2612 tmp_type = kRegTypeShort;
2613 goto sget_1nr_common;
2614sget_1nr_common:
2615 {
2616 Field* static_field;
2617 RegType field_type;
2618
2619 static_field = GetStaticField(vdata, dec_insn.vB_, &failure);
2620 if (failure != VERIFY_ERROR_NONE)
2621 break;
2622
2623 /*
2624 * Make sure the field's type is compatible with expectation.
2625 * We can get ourselves into trouble if we mix & match loads
2626 * and stores with different widths, so rather than just checking
2627 * "CanConvertTo1nr" we require that the field types have equal
2628 * widths.
2629 */
2630 field_type =
2631 PrimitiveTypeToRegType(static_field->GetType()->GetPrimitiveType());
2632
2633 /* correct if float */
2634 if (field_type == kRegTypeFloat)
2635 tmp_type = kRegTypeFloat;
2636
2637 if (tmp_type != field_type) {
2638 Class* static_field_class = static_field->GetDeclaringClass();
2639 LOG(ERROR) << "VFY: invalid sget-1nr of "
2640 << static_field_class->GetDescriptor()->ToModifiedUtf8()
2641 << "." << static_field->GetName()->ToModifiedUtf8()
2642 << " (inst=" << tmp_type << " actual=" << field_type
2643 << ")";
2644 failure = VERIFY_ERROR_GENERIC;
2645 break;
2646 }
2647
2648 SetRegisterType(work_line, dec_insn.vA_, tmp_type);
2649 }
2650 break;
2651 case Instruction::SGET_WIDE:
2652 {
2653 Field* static_field;
2654 RegType dst_type;
2655
2656 static_field = GetStaticField(vdata, dec_insn.vB_, &failure);
2657 Class* static_field_class = static_field->GetDeclaringClass();
2658 if (failure != VERIFY_ERROR_NONE)
2659 break;
2660 /* check the type, which should be prim */
2661 switch (static_field->GetType()->GetPrimitiveType()) {
2662 case Class::kPrimDouble:
2663 dst_type = kRegTypeDoubleLo;
2664 break;
2665 case Class::kPrimLong:
2666 dst_type = kRegTypeLongLo;
2667 break;
2668 default:
2669 LOG(ERROR) << "VFY: invalid sget-wide of "
2670 << static_field_class->GetDescriptor()->ToModifiedUtf8()
2671 << "." << static_field->GetName()->ToModifiedUtf8();
2672 dst_type = kRegTypeUnknown;
2673 failure = VERIFY_ERROR_GENERIC;
2674 break;
2675 }
2676 if (failure == VERIFY_ERROR_NONE) {
2677 SetRegisterType(work_line, dec_insn.vA_, dst_type);
2678 }
2679 }
2680 break;
2681 case Instruction::SGET_OBJECT:
2682 {
2683 Field* static_field;
2684 Class* field_class;
2685
2686 static_field = GetStaticField(vdata, dec_insn.vB_, &failure);
2687 if (failure != VERIFY_ERROR_NONE)
2688 break;
2689 field_class = static_field->GetType();
2690 if (field_class == NULL) {
2691 LOG(ERROR) << "VFY: unable to recover field class from '"
2692 << static_field->GetName()->ToModifiedUtf8() << "'";
2693 failure = VERIFY_ERROR_GENERIC;
2694 break;
2695 }
2696 if (field_class->IsPrimitive()) {
2697 LOG(ERROR) << "VFY: attempt to get prim field with sget-object";
2698 failure = VERIFY_ERROR_GENERIC;
2699 break;
2700 }
2701 SetRegisterType(work_line, dec_insn.vA_, RegTypeFromClass(field_class));
2702 }
2703 break;
2704 case Instruction::SPUT:
2705 tmp_type = kRegTypeInteger;
2706 goto sput_1nr_common;
2707 case Instruction::SPUT_BOOLEAN:
2708 tmp_type = kRegTypeBoolean;
2709 goto sput_1nr_common;
2710 case Instruction::SPUT_BYTE:
2711 tmp_type = kRegTypeByte;
2712 goto sput_1nr_common;
2713 case Instruction::SPUT_CHAR:
2714 tmp_type = kRegTypeChar;
2715 goto sput_1nr_common;
2716 case Instruction::SPUT_SHORT:
2717 tmp_type = kRegTypeShort;
2718 goto sput_1nr_common;
2719sput_1nr_common:
2720 {
2721 RegType src_type, field_type;
2722 Field* static_field;
2723
2724 static_field = GetStaticField(vdata, dec_insn.vB_, &failure);
2725 if (failure != VERIFY_ERROR_NONE)
2726 break;
2727 CheckFinalFieldAccess(method, static_field, &failure);
2728 if (failure != VERIFY_ERROR_NONE)
2729 break;
2730
2731 /*
jeffhaod1f0fde2011-09-08 17:25:33 -07002732 * Get type of field we're storing into. We know that the
jeffhaobdb76512011-09-07 11:43:16 -07002733 * contents of the register match the instruction, but we also
2734 * need to ensure that the instruction matches the field type.
2735 * Using e.g. sput-short to write into a 32-bit integer field
2736 * can lead to trouble if we do 16-bit writes.
2737 */
2738 field_type =
2739 PrimitiveTypeToRegType(static_field->GetType()->GetPrimitiveType());
2740 src_type = GetRegisterType(work_line, dec_insn.vA_);
2741
2742 /* correct if float */
2743 if (field_type == kRegTypeFloat)
2744 tmp_type = kRegTypeFloat;
2745
2746 /*
2747 * compiler can generate synthetic functions that write byte values
2748 * into boolean fields.
2749 */
2750 if (tmp_type == kRegTypeBoolean && src_type == kRegTypeByte)
2751 tmp_type = kRegTypeByte;
2752 if (field_type == kRegTypeBoolean && src_type == kRegTypeByte)
2753 field_type = kRegTypeByte;
2754
2755 /* make sure the source register has the correct type */
2756 if (!CanConvertTo1nr(src_type, tmp_type)) {
2757 LOG(ERROR) << "VFY: invalid reg type " << src_type
2758 << " on sput instr (need " << tmp_type << ")";
2759 failure = VERIFY_ERROR_GENERIC;
2760 break;
2761 }
2762
2763 VerifyRegisterType(work_line, dec_insn.vA_, field_type, &failure);
2764
2765 if (failure != VERIFY_ERROR_NONE || field_type == kRegTypeUnknown ||
2766 tmp_type != field_type) {
2767 Class* static_field_class = static_field->GetDeclaringClass();
2768 LOG(ERROR) << "VFY: invalid sput-1nr of "
2769 << static_field_class->GetDescriptor()->ToModifiedUtf8()
2770 << "." << static_field->GetName()->ToModifiedUtf8()
2771 << " (inst=" << tmp_type << " actual=" << field_type
2772 << ")";
2773 failure = VERIFY_ERROR_GENERIC;
2774 break;
2775 }
2776 }
2777 break;
2778 case Instruction::SPUT_WIDE:
2779 Field* static_field;
2780
2781 static_field = GetStaticField(vdata, dec_insn.vB_, &failure);
2782 if (failure != VERIFY_ERROR_NONE)
2783 break;
2784 CheckFinalFieldAccess(method, static_field, &failure);
2785 if (failure != VERIFY_ERROR_NONE)
2786 break;
2787
2788 /* check the type, which should be prim */
2789 switch (static_field->GetType()->GetPrimitiveType()) {
2790 case Class::kPrimDouble:
2791 VerifyRegisterType(work_line, dec_insn.vA_, kRegTypeDoubleLo,
2792 &failure);
2793 break;
2794 case Class::kPrimLong:
2795 VerifyRegisterType(work_line, dec_insn.vA_, kRegTypeLongLo, &failure);
2796 break;
2797 default:
2798 LOG(ERROR) << "VFY: invalid sput-wide of "
2799 << static_field->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8()
2800 << "." << static_field->GetName()->ToModifiedUtf8();
2801 failure = VERIFY_ERROR_GENERIC;
2802 break;
2803 }
2804 break;
2805 case Instruction::SPUT_OBJECT:
2806 {
2807 Class* field_class;
2808 Class* value_class;
2809 Field* static_field;
2810 RegType value_type;
2811
2812 static_field = GetStaticField(vdata, dec_insn.vB_, &failure);
2813 if (failure != VERIFY_ERROR_NONE)
2814 break;
2815 CheckFinalFieldAccess(method, static_field, &failure);
2816 if (failure != VERIFY_ERROR_NONE)
2817 break;
2818
2819 field_class = static_field->GetType();
2820 if (field_class == NULL) {
2821 LOG(ERROR) << "VFY: unable to recover field class from '"
2822 << static_field->GetName()->ToModifiedUtf8() << "'";
2823 failure = VERIFY_ERROR_GENERIC;
2824 break;
2825 }
2826
2827 value_type = GetRegisterType(work_line, dec_insn.vA_);
2828 if (!RegTypeIsReference(value_type)) {
2829 LOG(ERROR) << "VFY: storing non-ref v" << dec_insn.vA_
2830 << " into ref field '"
2831 << static_field->GetName()->ToModifiedUtf8() << "' ("
2832 << field_class->GetDescriptor()->ToModifiedUtf8() << ")",
2833 failure = VERIFY_ERROR_GENERIC;
2834 break;
2835 }
2836 if (value_type != kRegTypeZero) {
2837 value_class = RegTypeInitializedReferenceToClass(value_type);
2838 if (value_class == NULL) {
2839 LOG(ERROR) << "VFY: storing uninit ref v" << dec_insn.vA_
2840 << " into ref field";
2841 failure = VERIFY_ERROR_GENERIC;
2842 break;
2843 }
2844 /* allow if field is any interface or field is base class */
2845 if (!field_class->IsInterface() &&
2846 !field_class->IsAssignableFrom(value_class)) {
2847 Class* static_field_class = static_field->GetDeclaringClass();
2848 LOG(ERROR) << "VFY: storing type '"
2849 << value_class->GetDescriptor()->ToModifiedUtf8()
2850 << "' into field type '"
2851 << field_class->GetDescriptor()->ToModifiedUtf8()
2852 << "' ("
2853 << static_field_class->GetDescriptor()->ToModifiedUtf8()
2854 << "." << static_field->GetName()->ToModifiedUtf8()
2855 << ")",
2856 failure = VERIFY_ERROR_GENERIC;
2857 break;
2858 }
2859 }
2860 }
2861 break;
2862
2863 case Instruction::INVOKE_VIRTUAL:
2864 case Instruction::INVOKE_VIRTUAL_RANGE:
2865 case Instruction::INVOKE_SUPER:
2866 case Instruction::INVOKE_SUPER_RANGE:
2867 {
2868 Method* called_method;
2869 RegType return_type;
2870 bool is_range;
2871 bool is_super;
2872
2873 is_range = (dec_insn.opcode_ == Instruction::INVOKE_VIRTUAL_RANGE ||
2874 dec_insn.opcode_ == Instruction::INVOKE_SUPER_RANGE);
2875 is_super = (dec_insn.opcode_ == Instruction::INVOKE_SUPER ||
2876 dec_insn.opcode_ == Instruction::INVOKE_SUPER_RANGE);
2877
2878 called_method = VerifyInvocationArgs(vdata, work_line, registers_size,
2879 &dec_insn, METHOD_VIRTUAL, is_range, is_super, &failure);
2880 if (failure != VERIFY_ERROR_NONE)
2881 break;
2882 return_type = GetMethodReturnType(dex_file, called_method);
2883 SetResultRegisterType(work_line, registers_size, return_type);
2884 just_set_result = true;
2885 }
2886 break;
2887 case Instruction::INVOKE_DIRECT:
2888 case Instruction::INVOKE_DIRECT_RANGE:
2889 {
2890 RegType return_type;
2891 Method* called_method;
2892 bool is_range;
2893
2894 is_range = (dec_insn.opcode_ == Instruction::INVOKE_DIRECT_RANGE);
2895 called_method = VerifyInvocationArgs(vdata, work_line, registers_size,
2896 &dec_insn, METHOD_DIRECT, is_range, false, &failure);
2897 if (failure != VERIFY_ERROR_NONE)
2898 break;
2899
2900 /*
jeffhaod1f0fde2011-09-08 17:25:33 -07002901 * Some additional checks when calling <init>. We know from
jeffhaobdb76512011-09-07 11:43:16 -07002902 * the invocation arg check that the "this" argument is an
jeffhaod1f0fde2011-09-08 17:25:33 -07002903 * instance of called_method->klass. Now we further restrict
jeffhaobdb76512011-09-07 11:43:16 -07002904 * that to require that called_method->klass is the same as
2905 * this->klass or this->super, allowing the latter only if
2906 * the "this" argument is the same as the "this" argument to
2907 * this method (which implies that we're in <init> ourselves).
2908 */
2909 if (IsInitMethod(called_method)) {
2910 RegType this_type;
2911 this_type = GetInvocationThis(work_line, &dec_insn, &failure);
2912 if (failure != VERIFY_ERROR_NONE)
2913 break;
2914
2915 /* no null refs allowed (?) */
2916 if (this_type == kRegTypeZero) {
2917 LOG(ERROR) << "VFY: unable to initialize null ref";
2918 failure = VERIFY_ERROR_GENERIC;
2919 break;
2920 }
2921
2922 Class* this_class;
2923
2924 this_class = RegTypeReferenceToClass(this_type, uninit_map);
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07002925 DCHECK(this_class != NULL);
jeffhaobdb76512011-09-07 11:43:16 -07002926
2927 /* must be in same class or in superclass */
2928 if (called_method->GetDeclaringClass() == this_class->GetSuperClass())
2929 {
2930 if (this_class != method->GetDeclaringClass()) {
2931 LOG(ERROR) << "VFY: invoke-direct <init> on super only "
2932 << "allowed for 'this' in <init>";
2933 failure = VERIFY_ERROR_GENERIC;
2934 break;
2935 }
2936 } else if (called_method->GetDeclaringClass() != this_class) {
2937 LOG(ERROR) << "VFY: invoke-direct <init> must be on current "
2938 << "class or super";
2939 failure = VERIFY_ERROR_GENERIC;
2940 break;
2941 }
2942
2943 /* arg must be an uninitialized reference */
2944 if (!RegTypeIsUninitReference(this_type)) {
2945 LOG(ERROR) << "VFY: can only initialize the uninitialized";
2946 failure = VERIFY_ERROR_GENERIC;
2947 break;
2948 }
2949
2950 /*
2951 * Replace the uninitialized reference with an initialized
jeffhaod1f0fde2011-09-08 17:25:33 -07002952 * one, and clear the entry in the uninit map. We need to
jeffhaobdb76512011-09-07 11:43:16 -07002953 * do this for all registers that have the same object
2954 * instance in them, not just the "this" register.
2955 */
2956 MarkRefsAsInitialized(work_line, registers_size, uninit_map,
2957 this_type, &failure);
2958 if (failure != VERIFY_ERROR_NONE)
2959 break;
2960 }
2961 return_type = GetMethodReturnType(dex_file, called_method);
2962 SetResultRegisterType(work_line, registers_size, return_type);
2963 just_set_result = true;
2964 }
2965 break;
2966 case Instruction::INVOKE_STATIC:
2967 case Instruction::INVOKE_STATIC_RANGE:
2968 {
2969 RegType return_type;
2970 Method* called_method;
2971 bool is_range;
2972
2973 is_range = (dec_insn.opcode_ == Instruction::INVOKE_STATIC_RANGE);
2974 called_method = VerifyInvocationArgs(vdata, work_line, registers_size,
2975 &dec_insn, METHOD_STATIC, is_range, false, &failure);
2976 if (failure != VERIFY_ERROR_NONE)
2977 break;
2978
2979 return_type = GetMethodReturnType(dex_file, called_method);
2980 SetResultRegisterType(work_line, registers_size, return_type);
2981 just_set_result = true;
2982 }
2983 break;
2984 case Instruction::INVOKE_INTERFACE:
2985 case Instruction::INVOKE_INTERFACE_RANGE:
2986 {
2987 RegType /*this_type,*/ return_type;
2988 Method* abs_method;
2989 bool is_range;
2990
2991 is_range = (dec_insn.opcode_ == Instruction::INVOKE_INTERFACE_RANGE);
2992 abs_method = VerifyInvocationArgs(vdata, work_line, registers_size,
2993 &dec_insn, METHOD_INTERFACE, is_range, false, &failure);
2994 if (failure != VERIFY_ERROR_NONE)
2995 break;
2996
2997#if 0 /* can't do this here, fails on dalvik test 052-verifier-fun */
2998 /*
2999 * Get the type of the "this" arg, which should always be an
jeffhaod1f0fde2011-09-08 17:25:33 -07003000 * interface class. Because we don't do a full merge on
jeffhaobdb76512011-09-07 11:43:16 -07003001 * interface classes, this might have reduced to Object.
3002 */
3003 this_type = GetInvocationThis(work_line, &dec_insn, &failure);
3004 if (failure != VERIFY_ERROR_NONE)
3005 break;
3006
3007 if (this_type == kRegTypeZero) {
3008 /* null pointer always passes (and always fails at runtime) */
3009 } else {
3010 Class* this_class;
3011
3012 this_class = RegTypeInitializedReferenceToClass(this_type);
3013 if (this_class == NULL) {
3014 LOG(ERROR) << "VFY: interface call on uninitialized";
3015 failure = VERIFY_ERROR_GENERIC;
3016 break;
3017 }
3018
3019 /*
3020 * Either "this_class" needs to be the interface class that
3021 * defined abs_method, or abs_method's class needs to be one
jeffhaod1f0fde2011-09-08 17:25:33 -07003022 * of the interfaces implemented by "this_class". (Or, if
jeffhaobdb76512011-09-07 11:43:16 -07003023 * we couldn't complete the merge, this will be Object.)
3024 */
3025 if (this_class != abs_method->GetDeclaringClass() &&
3026 this_class != class_linker->FindSystemClass("Ljava/lang/Object;") &&
3027 !this_class->Implements(abs_method->GetDeclaringClass())) {
3028 LOG(ERROR) << "VFY: unable to match abs_method '"
3029 << abs_method->GetName()->ToModifiedUtf8() << "' with "
3030 << this_class->GetDescriptor()->ToModifiedUtf8()
3031 << " interfaces";
3032 failure = VERIFY_ERROR_GENERIC;
3033 break;
3034 }
3035 }
3036#endif
3037
3038 /*
3039 * We don't have an object instance, so we can't find the
jeffhaod1f0fde2011-09-08 17:25:33 -07003040 * concrete method. However, all of the type information is
jeffhaobdb76512011-09-07 11:43:16 -07003041 * in the abstract method, so we're good.
3042 */
3043 return_type = GetMethodReturnType(dex_file, abs_method);
3044 SetResultRegisterType(work_line, registers_size, return_type);
3045 just_set_result = true;
3046 }
3047 break;
3048
3049 case Instruction::NEG_INT:
3050 case Instruction::NOT_INT:
3051 CheckUnop(work_line, &dec_insn, kRegTypeInteger, kRegTypeInteger,
3052 &failure);
3053 break;
3054 case Instruction::NEG_LONG:
3055 case Instruction::NOT_LONG:
3056 CheckUnop(work_line, &dec_insn, kRegTypeLongLo, kRegTypeLongLo, &failure);
3057 break;
3058 case Instruction::NEG_FLOAT:
3059 CheckUnop(work_line, &dec_insn, kRegTypeFloat, kRegTypeFloat, &failure);
3060 break;
3061 case Instruction::NEG_DOUBLE:
3062 CheckUnop(work_line, &dec_insn, kRegTypeDoubleLo, kRegTypeDoubleLo,
3063 &failure);
3064 break;
3065 case Instruction::INT_TO_LONG:
3066 CheckUnop(work_line, &dec_insn, kRegTypeLongLo, kRegTypeInteger,
3067 &failure);
3068 break;
3069 case Instruction::INT_TO_FLOAT:
3070 CheckUnop(work_line, &dec_insn, kRegTypeFloat, kRegTypeInteger, &failure);
3071 break;
3072 case Instruction::INT_TO_DOUBLE:
3073 CheckUnop(work_line, &dec_insn, kRegTypeDoubleLo, kRegTypeInteger,
3074 &failure);
3075 break;
3076 case Instruction::LONG_TO_INT:
3077 CheckUnop(work_line, &dec_insn, kRegTypeInteger, kRegTypeLongLo,
3078 &failure);
3079 break;
3080 case Instruction::LONG_TO_FLOAT:
3081 CheckUnop(work_line, &dec_insn, kRegTypeFloat, kRegTypeLongLo, &failure);
3082 break;
3083 case Instruction::LONG_TO_DOUBLE:
3084 CheckUnop(work_line, &dec_insn, kRegTypeDoubleLo, kRegTypeLongLo,
3085 &failure);
3086 break;
3087 case Instruction::FLOAT_TO_INT:
3088 CheckUnop(work_line, &dec_insn, kRegTypeInteger, kRegTypeFloat, &failure);
3089 break;
3090 case Instruction::FLOAT_TO_LONG:
3091 CheckUnop(work_line, &dec_insn, kRegTypeLongLo, kRegTypeFloat, &failure);
3092 break;
3093 case Instruction::FLOAT_TO_DOUBLE:
3094 CheckUnop(work_line, &dec_insn, kRegTypeDoubleLo, kRegTypeFloat,
3095 &failure);
3096 break;
3097 case Instruction::DOUBLE_TO_INT:
3098 CheckUnop(work_line, &dec_insn, kRegTypeInteger, kRegTypeDoubleLo,
3099 &failure);
3100 break;
3101 case Instruction::DOUBLE_TO_LONG:
3102 CheckUnop(work_line, &dec_insn, kRegTypeLongLo, kRegTypeDoubleLo,
3103 &failure);
3104 break;
3105 case Instruction::DOUBLE_TO_FLOAT:
3106 CheckUnop(work_line, &dec_insn, kRegTypeFloat, kRegTypeDoubleLo,
3107 &failure);
3108 break;
3109 case Instruction::INT_TO_BYTE:
3110 CheckUnop(work_line, &dec_insn, kRegTypeByte, kRegTypeInteger, &failure);
3111 break;
3112 case Instruction::INT_TO_CHAR:
3113 CheckUnop(work_line, &dec_insn, kRegTypeChar, kRegTypeInteger, &failure);
3114 break;
3115 case Instruction::INT_TO_SHORT:
3116 CheckUnop(work_line, &dec_insn, kRegTypeShort, kRegTypeInteger, &failure);
3117 break;
3118
3119 case Instruction::ADD_INT:
3120 case Instruction::SUB_INT:
3121 case Instruction::MUL_INT:
3122 case Instruction::REM_INT:
3123 case Instruction::DIV_INT:
3124 case Instruction::SHL_INT:
3125 case Instruction::SHR_INT:
3126 case Instruction::USHR_INT:
3127 CheckBinop(work_line, &dec_insn, kRegTypeInteger, kRegTypeInteger,
3128 kRegTypeInteger, false, &failure);
3129 break;
3130 case Instruction::AND_INT:
3131 case Instruction::OR_INT:
3132 case Instruction::XOR_INT:
3133 CheckBinop(work_line, &dec_insn, kRegTypeInteger, kRegTypeInteger,
3134 kRegTypeInteger, true, &failure);
3135 break;
3136 case Instruction::ADD_LONG:
3137 case Instruction::SUB_LONG:
3138 case Instruction::MUL_LONG:
3139 case Instruction::DIV_LONG:
3140 case Instruction::REM_LONG:
3141 case Instruction::AND_LONG:
3142 case Instruction::OR_LONG:
3143 case Instruction::XOR_LONG:
3144 CheckBinop(work_line, &dec_insn, kRegTypeLongLo, kRegTypeLongLo,
3145 kRegTypeLongLo, false, &failure);
3146 break;
3147 case Instruction::SHL_LONG:
3148 case Instruction::SHR_LONG:
3149 case Instruction::USHR_LONG:
3150 /* shift distance is Int, making these different from other binops */
3151 CheckBinop(work_line, &dec_insn, kRegTypeLongLo, kRegTypeLongLo,
3152 kRegTypeInteger, false, &failure);
3153 break;
3154 case Instruction::ADD_FLOAT:
3155 case Instruction::SUB_FLOAT:
3156 case Instruction::MUL_FLOAT:
3157 case Instruction::DIV_FLOAT:
3158 case Instruction::REM_FLOAT:
3159 CheckBinop(work_line, &dec_insn, kRegTypeFloat, kRegTypeFloat,
3160 kRegTypeFloat, false, &failure);
3161 break;
3162 case Instruction::ADD_DOUBLE:
3163 case Instruction::SUB_DOUBLE:
3164 case Instruction::MUL_DOUBLE:
3165 case Instruction::DIV_DOUBLE:
3166 case Instruction::REM_DOUBLE:
3167 CheckBinop(work_line, &dec_insn, kRegTypeDoubleLo, kRegTypeDoubleLo,
3168 kRegTypeDoubleLo, false, &failure);
3169 break;
3170 case Instruction::ADD_INT_2ADDR:
3171 case Instruction::SUB_INT_2ADDR:
3172 case Instruction::MUL_INT_2ADDR:
3173 case Instruction::REM_INT_2ADDR:
3174 case Instruction::SHL_INT_2ADDR:
3175 case Instruction::SHR_INT_2ADDR:
3176 case Instruction::USHR_INT_2ADDR:
3177 CheckBinop2addr(work_line, &dec_insn, kRegTypeInteger, kRegTypeInteger,
3178 kRegTypeInteger, false, &failure);
3179 break;
3180 case Instruction::AND_INT_2ADDR:
3181 case Instruction::OR_INT_2ADDR:
3182 case Instruction::XOR_INT_2ADDR:
3183 CheckBinop2addr(work_line, &dec_insn, kRegTypeInteger, kRegTypeInteger,
3184 kRegTypeInteger, true, &failure);
3185 break;
3186 case Instruction::DIV_INT_2ADDR:
3187 CheckBinop2addr(work_line, &dec_insn, kRegTypeInteger, kRegTypeInteger,
3188 kRegTypeInteger, false, &failure);
3189 break;
3190 case Instruction::ADD_LONG_2ADDR:
3191 case Instruction::SUB_LONG_2ADDR:
3192 case Instruction::MUL_LONG_2ADDR:
3193 case Instruction::DIV_LONG_2ADDR:
3194 case Instruction::REM_LONG_2ADDR:
3195 case Instruction::AND_LONG_2ADDR:
3196 case Instruction::OR_LONG_2ADDR:
3197 case Instruction::XOR_LONG_2ADDR:
3198 CheckBinop2addr(work_line, &dec_insn, kRegTypeLongLo, kRegTypeLongLo,
3199 kRegTypeLongLo, false, &failure);
3200 break;
3201 case Instruction::SHL_LONG_2ADDR:
3202 case Instruction::SHR_LONG_2ADDR:
3203 case Instruction::USHR_LONG_2ADDR:
3204 CheckBinop2addr(work_line, &dec_insn, kRegTypeLongLo, kRegTypeLongLo,
3205 kRegTypeInteger, false, &failure);
3206 break;
3207 case Instruction::ADD_FLOAT_2ADDR:
3208 case Instruction::SUB_FLOAT_2ADDR:
3209 case Instruction::MUL_FLOAT_2ADDR:
3210 case Instruction::DIV_FLOAT_2ADDR:
3211 case Instruction::REM_FLOAT_2ADDR:
3212 CheckBinop2addr(work_line, &dec_insn, kRegTypeFloat, kRegTypeFloat,
3213 kRegTypeFloat, false, &failure);
3214 break;
3215 case Instruction::ADD_DOUBLE_2ADDR:
3216 case Instruction::SUB_DOUBLE_2ADDR:
3217 case Instruction::MUL_DOUBLE_2ADDR:
3218 case Instruction::DIV_DOUBLE_2ADDR:
3219 case Instruction::REM_DOUBLE_2ADDR:
3220 CheckBinop2addr(work_line, &dec_insn, kRegTypeDoubleLo, kRegTypeDoubleLo,
3221 kRegTypeDoubleLo, false, &failure);
3222 break;
3223 case Instruction::ADD_INT_LIT16:
3224 case Instruction::RSUB_INT:
3225 case Instruction::MUL_INT_LIT16:
3226 case Instruction::DIV_INT_LIT16:
3227 case Instruction::REM_INT_LIT16:
3228 CheckLitop(work_line, &dec_insn, kRegTypeInteger, kRegTypeInteger, false,
3229 &failure);
3230 break;
3231 case Instruction::AND_INT_LIT16:
3232 case Instruction::OR_INT_LIT16:
3233 case Instruction::XOR_INT_LIT16:
3234 CheckLitop(work_line, &dec_insn, kRegTypeInteger, kRegTypeInteger, true,
3235 &failure);
3236 break;
3237 case Instruction::ADD_INT_LIT8:
3238 case Instruction::RSUB_INT_LIT8:
3239 case Instruction::MUL_INT_LIT8:
3240 case Instruction::DIV_INT_LIT8:
3241 case Instruction::REM_INT_LIT8:
3242 case Instruction::SHL_INT_LIT8:
3243 CheckLitop(work_line, &dec_insn, kRegTypeInteger, kRegTypeInteger, false,
3244 &failure);
3245 break;
3246 case Instruction::SHR_INT_LIT8:
3247 tmp_type = AdjustForRightShift(work_line, dec_insn.vB_, dec_insn.vC_,
jeffhaob4df5142011-09-19 20:25:32 -07003248 false);
jeffhaobdb76512011-09-07 11:43:16 -07003249 CheckLitop(work_line, &dec_insn, tmp_type, kRegTypeInteger, false,
3250 &failure);
3251 break;
3252 case Instruction::USHR_INT_LIT8:
3253 tmp_type = AdjustForRightShift(work_line, dec_insn.vB_, dec_insn.vC_,
jeffhaob4df5142011-09-19 20:25:32 -07003254 true);
jeffhaobdb76512011-09-07 11:43:16 -07003255 CheckLitop(work_line, &dec_insn, tmp_type, kRegTypeInteger, false,
3256 &failure);
3257 break;
3258 case Instruction::AND_INT_LIT8:
3259 case Instruction::OR_INT_LIT8:
3260 case Instruction::XOR_INT_LIT8:
3261 CheckLitop(work_line, &dec_insn, kRegTypeInteger, kRegTypeInteger, true,
3262 &failure);
3263 break;
3264
3265 /*
3266 * This falls into the general category of "optimized" instructions,
jeffhaod1f0fde2011-09-08 17:25:33 -07003267 * which don't generally appear during verification. Because it's
jeffhaobdb76512011-09-07 11:43:16 -07003268 * inserted in the course of verification, we can expect to see it here.
3269 */
jeffhaob4df5142011-09-19 20:25:32 -07003270 case Instruction::THROW_VERIFICATION_ERROR:
jeffhaobdb76512011-09-07 11:43:16 -07003271 break;
3272
3273 /*
3274 * Verifying "quickened" instructions is tricky, because we have
jeffhaod1f0fde2011-09-08 17:25:33 -07003275 * discarded the original field/method information. The byte offsets
jeffhaobdb76512011-09-07 11:43:16 -07003276 * and vtable indices only have meaning in the context of an object
3277 * instance.
3278 *
3279 * If a piece of code declares a local reference variable, assigns
3280 * null to it, and then issues a virtual method call on it, we
jeffhaod1f0fde2011-09-08 17:25:33 -07003281 * cannot evaluate the method call during verification. This situation
jeffhaobdb76512011-09-07 11:43:16 -07003282 * isn't hard to handle, since we know the call will always result in an
jeffhaod1f0fde2011-09-08 17:25:33 -07003283 * NPE, and the arguments and return value don't matter. Any code that
jeffhaobdb76512011-09-07 11:43:16 -07003284 * depends on the result of the method call is inaccessible, so the
3285 * fact that we can't fully verify anything that comes after the bad
3286 * call is not a problem.
3287 *
3288 * We must also consider the case of multiple code paths, only some of
jeffhaod1f0fde2011-09-08 17:25:33 -07003289 * which involve a null reference. We can completely verify the method
jeffhaobdb76512011-09-07 11:43:16 -07003290 * if we sidestep the results of executing with a null reference.
3291 * For example, if on the first pass through the code we try to do a
3292 * virtual method invocation through a null ref, we have to skip the
3293 * method checks and have the method return a "wildcard" type (which
jeffhaod1f0fde2011-09-08 17:25:33 -07003294 * merges with anything to become that other thing). The move-result
jeffhaobdb76512011-09-07 11:43:16 -07003295 * will tell us if it's a reference, single-word numeric, or double-word
jeffhaod1f0fde2011-09-08 17:25:33 -07003296 * value. We continue to perform the verification, and at the end of
jeffhaobdb76512011-09-07 11:43:16 -07003297 * the function any invocations that were never fully exercised are
3298 * marked as null-only.
3299 *
jeffhaod1f0fde2011-09-08 17:25:33 -07003300 * We would do something similar for the field accesses. The field's
jeffhaobdb76512011-09-07 11:43:16 -07003301 * type, once known, can be used to recover the width of short integers.
3302 * If the object reference was null, the field-get returns the "wildcard"
3303 * type, which is acceptable for any operation.
3304 */
3305 case Instruction::UNUSED_EE:
3306 case Instruction::UNUSED_EF:
3307 case Instruction::UNUSED_F2:
3308 case Instruction::UNUSED_F3:
3309 case Instruction::UNUSED_F4:
3310 case Instruction::UNUSED_F5:
3311 case Instruction::UNUSED_F6:
3312 case Instruction::UNUSED_F7:
3313 case Instruction::UNUSED_F8:
3314 case Instruction::UNUSED_F9:
3315 case Instruction::UNUSED_FA:
3316 case Instruction::UNUSED_FB:
3317 //case Instruction::EXECUTE_INLINE:
3318 //case Instruction::EXECUTE_INLINE_RANGE:
3319 //case Instruction::IGET_QUICK:
3320 //case Instruction::IGET_WIDE_QUICK:
3321 //case Instruction::IGET_OBJECT_QUICK:
3322 //case Instruction::IPUT_QUICK:
3323 //case Instruction::IPUT_WIDE_QUICK:
3324 //case Instruction::IPUT_OBJECT_QUICK:
3325 //case Instruction::INVOKE_VIRTUAL_QUICK:
3326 //case Instruction::INVOKE_VIRTUAL_QUICK_RANGE:
3327 //case Instruction::INVOKE_SUPER_QUICK:
3328 //case Instruction::INVOKE_SUPER_QUICK_RANGE:
3329 /* fall through to failure */
3330
3331 /*
3332 * These instructions are equivalent (from the verifier's point of view)
jeffhaod1f0fde2011-09-08 17:25:33 -07003333 * to the original form. The change was made for correctness rather
jeffhaobdb76512011-09-07 11:43:16 -07003334 * than improved performance (except for invoke-object-init, which
jeffhaod1f0fde2011-09-08 17:25:33 -07003335 * provides both). The substitution takes place after verification
jeffhaobdb76512011-09-07 11:43:16 -07003336 * completes, though, so we don't expect to see them here.
3337 */
3338 case Instruction::UNUSED_F0:
3339 case Instruction::UNUSED_F1:
3340 case Instruction::UNUSED_E3:
3341 case Instruction::UNUSED_E8:
3342 case Instruction::UNUSED_E7:
3343 case Instruction::UNUSED_E4:
3344 case Instruction::UNUSED_E9:
3345 case Instruction::UNUSED_FC:
3346 case Instruction::UNUSED_E5:
3347 case Instruction::UNUSED_EA:
3348 case Instruction::UNUSED_FD:
3349 case Instruction::UNUSED_E6:
3350 case Instruction::UNUSED_EB:
3351 case Instruction::UNUSED_FE:
3352 //case Instruction::INVOKE_OBJECT_INIT_RANGE:
3353 //case Instruction::RETURN_VOID_BARRIER:
3354 //case Instruction::IGET_VOLATILE:
3355 //case Instruction::IGET_WIDE_VOLATILE:
3356 //case Instruction::IGET_OBJECT_VOLATILE:
3357 //case Instruction::IPUT_VOLATILE:
3358 //case Instruction::IPUT_WIDE_VOLATILE:
3359 //case Instruction::IPUT_OBJECT_VOLATILE:
3360 //case Instruction::SGET_VOLATILE:
3361 //case Instruction::SGET_WIDE_VOLATILE:
3362 //case Instruction::SGET_OBJECT_VOLATILE:
3363 //case Instruction::SPUT_VOLATILE:
3364 //case Instruction::SPUT_WIDE_VOLATILE:
3365 //case Instruction::SPUT_OBJECT_VOLATILE:
3366 /* fall through to failure */
3367
3368 /* These should never appear during verification. */
3369 case Instruction::UNUSED_3E:
3370 case Instruction::UNUSED_3F:
3371 case Instruction::UNUSED_40:
3372 case Instruction::UNUSED_41:
3373 case Instruction::UNUSED_42:
3374 case Instruction::UNUSED_43:
3375 case Instruction::UNUSED_73:
3376 case Instruction::UNUSED_79:
3377 case Instruction::UNUSED_7A:
3378 case Instruction::UNUSED_EC:
3379 case Instruction::UNUSED_FF:
3380 //case Instruction::BREAKPOINT:
3381 //case Instruction::DISPATCH_FF:
3382 failure = VERIFY_ERROR_GENERIC;
3383 break;
3384
3385 /*
jeffhaod1f0fde2011-09-08 17:25:33 -07003386 * DO NOT add a "default" clause here. Without it the compiler will
jeffhaobdb76512011-09-07 11:43:16 -07003387 * complain if an instruction is missing (which is desirable).
3388 */
3389 }
3390
3391 if (failure != VERIFY_ERROR_NONE) {
jeffhaobdb76512011-09-07 11:43:16 -07003392 if (failure == VERIFY_ERROR_GENERIC) {
3393 /* immediate failure, reject class */
3394 LOG(ERROR) << "VFY: rejecting opcode 0x" << std::hex
3395 << (int) dec_insn.opcode_ << " at 0x" << insn_idx << std::dec;
3396 return false;
3397 } else {
3398 /* replace opcode and continue on */
3399 LOG(ERROR) << "VFY: replacing opcode 0x" << std::hex
3400 << (int) dec_insn.opcode_ << " at 0x" << insn_idx << std::dec;
jeffhaob4df5142011-09-19 20:25:32 -07003401 if (!ReplaceFailingInstruction(code_item, insn_idx, failure)) {
jeffhaobdb76512011-09-07 11:43:16 -07003402 LOG(ERROR) << "VFY: rejecting opcode 0x" << std::hex
3403 << (int) dec_insn.opcode_ << " at 0x" << insn_idx
3404 << std::dec;
3405 return false;
3406 }
3407 /* IMPORTANT: method->insns may have been changed */
3408 insns = code_item->insns_ + insn_idx;
3409
3410 /* continue on as if we just handled a throw-verification-error */
3411 failure = VERIFY_ERROR_NONE;
3412 opcode_flag = Instruction::kThrow;
3413 }
3414 }
3415
3416 /*
jeffhaod1f0fde2011-09-08 17:25:33 -07003417 * If we didn't just set the result register, clear it out. This
jeffhaobdb76512011-09-07 11:43:16 -07003418 * ensures that you can only use "move-result" immediately after the
jeffhaod1f0fde2011-09-08 17:25:33 -07003419 * result is set. (We could check this statically, but it's not
jeffhaobdb76512011-09-07 11:43:16 -07003420 * expensive and it makes our debugging output cleaner.)
3421 */
3422 if (!just_set_result) {
3423 int reg = RESULT_REGISTER(registers_size);
3424 SetRegisterType(work_line, reg, kRegTypeUnknown);
3425 SetRegisterType(work_line, reg + 1, kRegTypeUnknown);
3426 }
3427
jeffhaoa0a764a2011-09-16 10:43:38 -07003428 /* Handle "continue". Tag the next consecutive instruction. */
jeffhaobdb76512011-09-07 11:43:16 -07003429 if ((opcode_flag & Instruction::kContinue) != 0) {
3430 size_t insn_width = InsnGetWidth(insn_flags, insn_idx);
3431 if (insn_idx + insn_width >= insns_size) {
3432 LOG(ERROR) << "VFY: execution can walk off end of code area (from 0x"
3433 << std::hex << insn_idx << std::dec << ")";
3434 return false;
3435 }
3436
3437 /*
3438 * The only way to get to a move-exception instruction is to get
jeffhaod1f0fde2011-09-08 17:25:33 -07003439 * thrown there. Make sure the next instruction isn't one.
jeffhaobdb76512011-09-07 11:43:16 -07003440 */
3441 if (!CheckMoveException(code_item->insns_, insn_idx + insn_width))
3442 return false;
3443
Elliott Hughes5fe594f2011-09-08 12:33:17 -07003444 if (GetRegisterLine(reg_table, insn_idx + insn_width)->reg_types_.get() != NULL) {
jeffhaobdb76512011-09-07 11:43:16 -07003445 /*
3446 * Merge registers into what we have for the next instruction,
3447 * and set the "changed" flag if needed.
3448 */
3449 if (!UpdateRegisters(insn_flags, reg_table, insn_idx + insn_width,
3450 work_line))
3451 return false;
3452 } else {
3453 /*
3454 * We're not recording register data for the next instruction,
jeffhaod1f0fde2011-09-08 17:25:33 -07003455 * so we don't know what the prior state was. We have to
jeffhaobdb76512011-09-07 11:43:16 -07003456 * assume that something has changed and re-evaluate it.
3457 */
3458 InsnSetChanged(insn_flags, insn_idx + insn_width, true);
3459 }
3460 }
3461
3462 /*
jeffhaod1f0fde2011-09-08 17:25:33 -07003463 * Handle "branch". Tag the branch target.
jeffhaobdb76512011-09-07 11:43:16 -07003464 *
3465 * NOTE: instructions like Instruction::EQZ provide information about the
jeffhaod1f0fde2011-09-08 17:25:33 -07003466 * state of the register when the branch is taken or not taken. For example,
jeffhaobdb76512011-09-07 11:43:16 -07003467 * somebody could get a reference field, check it for zero, and if the
3468 * branch is taken immediately store that register in a boolean field
jeffhaod1f0fde2011-09-08 17:25:33 -07003469 * since the value is known to be zero. We do not currently account for
jeffhaobdb76512011-09-07 11:43:16 -07003470 * that, and will reject the code.
3471 *
3472 * TODO: avoid re-fetching the branch target
3473 */
3474 if ((opcode_flag & Instruction::kBranch) != 0) {
3475 bool isConditional, selfOkay;
3476
3477 if (!GetBranchOffset(code_item, insn_flags, insn_idx, &branch_target,
3478 &isConditional, &selfOkay)) {
3479 /* should never happen after static verification */
3480 LOG(ERROR) << "VFY: bad branch at 0x" << std::hex << insn_idx << std::dec;
3481 return false;
3482 }
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07003483 DCHECK_EQ(isConditional, (opcode_flag & Instruction::kContinue) != 0);
jeffhaobdb76512011-09-07 11:43:16 -07003484
3485 if (!CheckMoveException(code_item->insns_, insn_idx + branch_target))
3486 return false;
3487
3488 /* update branch target, set "changed" if appropriate */
3489 if (!UpdateRegisters(insn_flags, reg_table, insn_idx + branch_target,
3490 work_line))
3491 return false;
3492 }
3493
3494 /*
jeffhaod1f0fde2011-09-08 17:25:33 -07003495 * Handle "switch". Tag all possible branch targets.
jeffhaobdb76512011-09-07 11:43:16 -07003496 *
3497 * We've already verified that the table is structurally sound, so we
3498 * just need to walk through and tag the targets.
3499 */
3500 if ((opcode_flag & Instruction::kSwitch) != 0) {
3501 int offset_to_switch = insns[1] | (((int32_t) insns[2]) << 16);
3502 const uint16_t* switch_insns = insns + offset_to_switch;
3503 int switch_count = switch_insns[1];
3504 int offset_to_targets, targ;
3505
3506 if ((*insns & 0xff) == Instruction::PACKED_SWITCH) {
3507 /* 0 = sig, 1 = count, 2/3 = first key */
3508 offset_to_targets = 4;
3509 } else {
3510 /* 0 = sig, 1 = count, 2..count * 2 = keys */
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07003511 DCHECK((*insns & 0xff) == Instruction::SPARSE_SWITCH);
jeffhaobdb76512011-09-07 11:43:16 -07003512 offset_to_targets = 2 + 2 * switch_count;
3513 }
3514
3515 /* verify each switch target */
3516 for (targ = 0; targ < switch_count; targ++) {
3517 int offset;
3518 uint32_t abs_offset;
3519
3520 /* offsets are 32-bit, and only partly endian-swapped */
3521 offset = switch_insns[offset_to_targets + targ * 2] |
3522 (((int32_t) switch_insns[offset_to_targets + targ * 2 + 1]) << 16);
3523 abs_offset = insn_idx + offset;
3524
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07003525 DCHECK_LT(abs_offset, insns_size);
jeffhaobdb76512011-09-07 11:43:16 -07003526
3527 if (!CheckMoveException(code_item->insns_, abs_offset))
3528 return false;
3529
3530 if (!UpdateRegisters(insn_flags, reg_table, abs_offset, work_line))
3531 return false;
3532 }
3533 }
3534
3535 /*
3536 * Handle instructions that can throw and that are sitting in a
jeffhaod1f0fde2011-09-08 17:25:33 -07003537 * "try" block. (If they're not in a "try" block when they throw,
jeffhaobdb76512011-09-07 11:43:16 -07003538 * control transfers out of the method.)
3539 */
3540 if ((opcode_flag & Instruction::kThrow) != 0 &&
3541 InsnIsInTry(insn_flags, insn_idx)) {
3542 bool has_catch_all = false;
3543 DexFile::CatchHandlerIterator iterator = DexFile::dexFindCatchHandler(
3544 *code_item, insn_idx);
3545
3546 for (; !iterator.HasNext(); iterator.Next()) {
3547 if (iterator.Get().type_idx_ == DexFile::kDexNoIndex)
3548 has_catch_all = true;
3549
3550 /*
jeffhaod1f0fde2011-09-08 17:25:33 -07003551 * Merge registers into the "catch" block. We want to use the
3552 * "savedRegs" rather than "work_regs", because at runtime the
3553 * exception will be thrown before the instruction modifies any
3554 * registers.
jeffhaobdb76512011-09-07 11:43:16 -07003555 */
3556 if (!UpdateRegisters(insn_flags, reg_table, iterator.Get().address_,
3557 &reg_table->saved_line_))
3558 return false;
3559 }
3560
3561 /*
3562 * If the monitor stack depth is nonzero, there must be a "catch all"
jeffhaod1f0fde2011-09-08 17:25:33 -07003563 * handler for this instruction. This does apply to monitor-exit
jeffhaobdb76512011-09-07 11:43:16 -07003564 * because of async exception handling.
3565 */
3566 if (work_line->monitor_stack_top_ != 0 && !has_catch_all) {
3567 /*
3568 * The state in work_line reflects the post-execution state.
3569 * If the current instruction is a monitor-enter and the monitor
3570 * stack was empty, we don't need a catch-all (if it throws,
3571 * it will do so before grabbing the lock).
3572 */
3573 if (!(dec_insn.opcode_ == Instruction::MONITOR_ENTER &&
3574 work_line->monitor_stack_top_ == 1))
3575 {
3576 LOG(ERROR) << "VFY: no catch-all for instruction at 0x" << std::hex
3577 << insn_idx << std::dec;
3578 return false;
3579 }
3580 }
3581 }
3582
jeffhaod1f0fde2011-09-08 17:25:33 -07003583 /* If we're returning from the method, make sure monitor stack is empty. */
jeffhaobdb76512011-09-07 11:43:16 -07003584 if ((opcode_flag & Instruction::kReturn) != 0 &&
3585 work_line->monitor_stack_top_ != 0) {
3586 LOG(ERROR) << "VFY: return with stack depth="
3587 << work_line->monitor_stack_top_ << " at 0x" << std::hex
3588 << insn_idx << std::dec;
3589 return false;
3590 }
3591
3592 /*
jeffhaod1f0fde2011-09-08 17:25:33 -07003593 * Update start_guess. Advance to the next instruction of that's
3594 * possible, otherwise use the branch target if one was found. If
jeffhaobdb76512011-09-07 11:43:16 -07003595 * neither of those exists we're in a return or throw; leave start_guess
3596 * alone and let the caller sort it out.
3597 */
3598 if ((opcode_flag & Instruction::kContinue) != 0) {
3599 *start_guess = insn_idx + InsnGetWidth(insn_flags, insn_idx);
3600 } else if ((opcode_flag & Instruction::kBranch) != 0) {
3601 /* we're still okay if branch_target is zero */
3602 *start_guess = insn_idx + branch_target;
3603 }
3604
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07003605 DCHECK_LT(*start_guess, insns_size);
Brian Carlstrom03c99df2011-09-18 10:52:00 -07003606 DCHECK_NE(InsnGetWidth(insn_flags, *start_guess), 0);
jeffhaobdb76512011-09-07 11:43:16 -07003607
3608 return true;
3609}
3610
3611bool DexVerifier::ReplaceFailingInstruction(const DexFile::CodeItem* code_item,
jeffhaob4df5142011-09-19 20:25:32 -07003612 int insn_idx, VerifyError failure) {
jeffhaobdb76512011-09-07 11:43:16 -07003613 const uint16_t* insns = code_item->insns_ + insn_idx;
3614 const byte* ptr = reinterpret_cast<const byte*>(insns);
3615 const Instruction* inst = Instruction::At(ptr);
3616 Instruction::Code opcode = inst->Opcode();
3617 VerifyErrorRefType ref_type;
3618
3619 /*
3620 * Generate the new instruction out of the old.
3621 *
3622 * First, make sure this is an instruction we're expecting to stomp on.
3623 */
3624 switch (opcode) {
3625 case Instruction::CONST_CLASS: // insn[1] == class ref, 2 bytes
3626 case Instruction::CHECK_CAST:
3627 case Instruction::INSTANCE_OF:
3628 case Instruction::NEW_INSTANCE:
3629 case Instruction::NEW_ARRAY:
3630 case Instruction::FILLED_NEW_ARRAY: // insn[1] == class ref, 3 bytes
3631 case Instruction::FILLED_NEW_ARRAY_RANGE:
3632 ref_type = VERIFY_ERROR_REF_CLASS;
3633 break;
3634
3635 case Instruction::IGET: // insn[1] == field ref, 2 bytes
3636 case Instruction::IGET_BOOLEAN:
3637 case Instruction::IGET_BYTE:
3638 case Instruction::IGET_CHAR:
3639 case Instruction::IGET_SHORT:
3640 case Instruction::IGET_WIDE:
3641 case Instruction::IGET_OBJECT:
3642 case Instruction::IPUT:
3643 case Instruction::IPUT_BOOLEAN:
3644 case Instruction::IPUT_BYTE:
3645 case Instruction::IPUT_CHAR:
3646 case Instruction::IPUT_SHORT:
3647 case Instruction::IPUT_WIDE:
3648 case Instruction::IPUT_OBJECT:
3649 case Instruction::SGET:
3650 case Instruction::SGET_BOOLEAN:
3651 case Instruction::SGET_BYTE:
3652 case Instruction::SGET_CHAR:
3653 case Instruction::SGET_SHORT:
3654 case Instruction::SGET_WIDE:
3655 case Instruction::SGET_OBJECT:
3656 case Instruction::SPUT:
3657 case Instruction::SPUT_BOOLEAN:
3658 case Instruction::SPUT_BYTE:
3659 case Instruction::SPUT_CHAR:
3660 case Instruction::SPUT_SHORT:
3661 case Instruction::SPUT_WIDE:
3662 case Instruction::SPUT_OBJECT:
3663 ref_type = VERIFY_ERROR_REF_FIELD;
3664 break;
3665
3666 case Instruction::INVOKE_VIRTUAL: // insn[1] == method ref, 3 bytes
3667 case Instruction::INVOKE_VIRTUAL_RANGE:
3668 case Instruction::INVOKE_SUPER:
3669 case Instruction::INVOKE_SUPER_RANGE:
3670 case Instruction::INVOKE_DIRECT:
3671 case Instruction::INVOKE_DIRECT_RANGE:
3672 case Instruction::INVOKE_STATIC:
3673 case Instruction::INVOKE_STATIC_RANGE:
3674 case Instruction::INVOKE_INTERFACE:
3675 case Instruction::INVOKE_INTERFACE_RANGE:
3676 ref_type = VERIFY_ERROR_REF_METHOD;
3677 break;
3678
3679 default:
3680 /* could handle this in a generic way, but this is probably safer */
3681 LOG(ERROR) << "GLITCH: verifier asked to replace opcode 0x" << std::hex
3682 << (int) opcode << std::dec;
3683 return false;
3684 }
3685
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07003686 DCHECK(inst->IsThrow());
jeffhaobdb76512011-09-07 11:43:16 -07003687
3688 /* write a NOP over the third code unit, if necessary */
jeffhaob4df5142011-09-19 20:25:32 -07003689 int width = inst->Size();
jeffhaobdb76512011-09-07 11:43:16 -07003690 switch (width) {
3691 case 2:
3692 /* nothing to do */
3693 break;
3694 case 3:
jeffhaob4df5142011-09-19 20:25:32 -07003695 UpdateCodeUnit(insns + 2, Instruction::NOP);
jeffhaobdb76512011-09-07 11:43:16 -07003696 break;
3697 default:
3698 /* whoops */
3699 LOG(FATAL) << "ERROR: stomped a " << width
3700 << "-unit instruction with a verifier error";
3701 }
3702
3703 /* encode the opcode, with the failure code in the high byte */
jeffhaob4df5142011-09-19 20:25:32 -07003704 DCHECK(width == 2 || width == 3);
3705 uint16_t new_val = Instruction::THROW_VERIFICATION_ERROR |
3706 (failure << 8) | (ref_type << (8 + kVerifyErrorRefTypeShift));
3707 UpdateCodeUnit(insns, new_val);
jeffhaobdb76512011-09-07 11:43:16 -07003708
3709 return true;
3710}
3711
jeffhaob4df5142011-09-19 20:25:32 -07003712void DexVerifier::UpdateCodeUnit(const uint16_t* ptr, uint16_t new_val) {
3713 *(uint16_t*) ptr = new_val;
3714}
3715
jeffhaobdb76512011-09-07 11:43:16 -07003716void DexVerifier::HandleMonitorEnter(RegisterLine* work_line, uint32_t reg_idx,
3717 uint32_t insn_idx, VerifyError* failure) {
3718 if (!RegTypeIsReference(GetRegisterType(work_line, reg_idx))) {
3719 LOG(ERROR) << "VFY: monitor-enter on non-object";
3720 *failure = VERIFY_ERROR_GENERIC;
3721 return;
3722 }
3723
Elliott Hughes5fe594f2011-09-08 12:33:17 -07003724 if (work_line->monitor_entries_.get() == NULL) {
jeffhaobdb76512011-09-07 11:43:16 -07003725 return;
3726 }
3727
3728 if (work_line->monitor_stack_top_ == kMaxMonitorStackDepth) {
3729 LOG(ERROR) << "VFY: monitor-enter stack overflow (" << kMaxMonitorStackDepth
3730 << ")";
3731 *failure = VERIFY_ERROR_GENERIC;
3732 return;
3733 }
3734
3735 /*
3736 * Push an entry on the stack, and set a bit in the register flags to
3737 * indicate that it's associated with this register.
3738 */
3739 work_line->monitor_entries_[reg_idx] |= 1 << work_line->monitor_stack_top_;
3740 work_line->monitor_stack_[work_line->monitor_stack_top_++] = insn_idx;
3741}
3742
jeffhaobdb76512011-09-07 11:43:16 -07003743void DexVerifier::HandleMonitorExit(RegisterLine* work_line, uint32_t reg_idx,
3744 uint32_t insn_idx, VerifyError* failure) {
3745 if (!RegTypeIsReference(GetRegisterType(work_line, reg_idx))) {
3746 LOG(ERROR) << "VFY: monitor-exit on non-object";
3747 *failure = VERIFY_ERROR_GENERIC;
3748 return;
3749 }
3750
Elliott Hughes5fe594f2011-09-08 12:33:17 -07003751 if (work_line->monitor_entries_.get() == NULL) {
jeffhaobdb76512011-09-07 11:43:16 -07003752 return;
3753 }
3754
3755 if (work_line->monitor_stack_top_ == 0) {
3756 LOG(ERROR) << "VFY: monitor-exit stack underflow";
3757 *failure = VERIFY_ERROR_GENERIC;
3758 return;
3759 }
3760
3761 /*
3762 * Confirm that the entry at the top of the stack is associated with
jeffhaod1f0fde2011-09-08 17:25:33 -07003763 * the register. Pop the top entry off.
jeffhaobdb76512011-09-07 11:43:16 -07003764 */
3765 work_line->monitor_stack_top_--;
3766#ifdef BUG_3215458_FIXED
3767 /*
3768 * TODO: This code can safely be enabled if know we are working on
3769 * a dex file of format version 036 or later. (That is, we'll need to
3770 * add a check for the version number.)
3771 */
3772 if ((work_line->monitor_entries_[reg_idx] &
3773 (1 << work_line->monitor_stack_top_)) == 0) {
3774 LOG(ERROR) << "VFY: monitor-exit bit " << work_line->monitor_stack_top_
3775 << " not set: addr=0x" << std::hex << insn_idx << std::dec
3776 << " (bits[" << reg_idx << "]=" << std::hex
3777 << work_line->monitor_entries_[reg_idx] << std::dec << ")";
3778 *failure = VERIFY_ERROR_GENERIC;
3779 return;
3780 }
3781#endif
3782 work_line->monitor_stack_[work_line->monitor_stack_top_] = 0;
3783
3784 /* Clear the bit from the register flags. */
3785 work_line->monitor_entries_[reg_idx] &= ~(1 << work_line->monitor_stack_top_);
3786}
3787
3788Field* DexVerifier::GetInstField(VerifierData* vdata, RegType obj_type,
3789 int field_idx, VerifyError* failure) {
3790 Method* method = vdata->method_;
3791 const DexFile* dex_file = vdata->dex_file_;
Elliott Hughes5fe594f2011-09-08 12:33:17 -07003792 UninitInstanceMap* uninit_map = vdata->uninit_map_.get();
jeffhaobdb76512011-09-07 11:43:16 -07003793 bool must_be_local = false;
3794
3795 if (!RegTypeIsReference(obj_type)) {
3796 LOG(ERROR) << "VFY: attempt to access field in non-reference type "
3797 << obj_type;
3798 *failure = VERIFY_ERROR_GENERIC;
jeffhaob4df5142011-09-19 20:25:32 -07003799 return NULL;
jeffhaobdb76512011-09-07 11:43:16 -07003800 }
3801
jeffhaob4df5142011-09-19 20:25:32 -07003802 Field* field = ResolveFieldAndCheckAccess(dex_file, field_idx,
3803 method->GetDeclaringClass(), failure, false);
jeffhaobdb76512011-09-07 11:43:16 -07003804 if (field == NULL) {
3805 LOG(ERROR) << "VFY: unable to resolve instance field " << field_idx;
Brian Carlstrom65ca0772011-09-24 16:03:08 -07003806 *failure = VERIFY_ERROR_GENERIC;
jeffhaobdb76512011-09-07 11:43:16 -07003807 return field;
3808 }
3809
3810 if (obj_type == kRegTypeZero)
3811 return field;
3812
3813 /*
3814 * Access to fields in uninitialized objects is allowed if this is
3815 * the <init> method for the object and the field in question is
3816 * declared by this class.
3817 */
jeffhaob4df5142011-09-19 20:25:32 -07003818 Class* obj_class = RegTypeReferenceToClass(obj_type, uninit_map);
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07003819 DCHECK(obj_class != NULL);
jeffhaobdb76512011-09-07 11:43:16 -07003820 if (RegTypeIsUninitReference(obj_type)) {
3821 if (!IsInitMethod(method) || method->GetDeclaringClass() != obj_class) {
3822 LOG(ERROR) << "VFY: attempt to access field via uninitialized ref";
3823 *failure = VERIFY_ERROR_GENERIC;
3824 return field;
3825 }
3826 must_be_local = true;
3827 }
3828
jeffhaobdb76512011-09-07 11:43:16 -07003829 if (!field->GetDeclaringClass()->IsAssignableFrom(obj_class)) {
3830 LOG(ERROR) << "VFY: invalid field access (field "
3831 << field->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8()
3832 << "." << field->GetName()->ToModifiedUtf8() << ", through "
3833 << obj_class->GetDescriptor()->ToModifiedUtf8() << " ref)";
3834 *failure = VERIFY_ERROR_NO_FIELD;
3835 return field;
3836 }
3837
3838 if (must_be_local) {
3839 bool found = false;
3840 /* for uninit ref, make sure it's defined by this class, not super */
3841 for (uint32_t i = 0; i < obj_class->NumInstanceFields(); i++) {
3842 found |= (field == obj_class->GetInstanceField(i));
3843 }
3844 if (!found) {
3845 LOG(ERROR) << "VFY: invalid constructor field access (field "
3846 << field->GetName()->ToModifiedUtf8() << " in "
3847 << obj_class->GetDescriptor()->ToModifiedUtf8() << ")";
3848 *failure = VERIFY_ERROR_GENERIC;
3849 return field;
3850 }
3851 }
3852
3853 return field;
3854}
3855
3856Field* DexVerifier::GetStaticField(VerifierData* vdata, int field_idx,
3857 VerifyError* failure) {
3858 Method* method = vdata->method_;
3859 const DexFile* dex_file = vdata->dex_file_;
jeffhaob4df5142011-09-19 20:25:32 -07003860 Field* field = ResolveFieldAndCheckAccess(dex_file, field_idx,
3861 method->GetDeclaringClass(), failure, true);
jeffhaobdb76512011-09-07 11:43:16 -07003862 if (field == NULL) {
jeffhaob4df5142011-09-19 20:25:32 -07003863 const DexFile::FieldId& field_id = dex_file->GetFieldId(field_idx);
3864 LOG(ERROR) << "VFY: unable to resolve static field " << field_idx << " ("
3865 << dex_file->GetFieldName(field_id) << ") in "
3866 << dex_file->GetFieldClassDescriptor(field_id);
3867 *failure = VERIFY_ERROR_NO_FIELD;
jeffhaobdb76512011-09-07 11:43:16 -07003868 }
3869
3870 return field;
3871}
3872
3873Class* DexVerifier::GetCaughtExceptionType(VerifierData* vdata, int insn_idx,
3874 VerifyError* failure) {
3875 const DexFile* dex_file = vdata->dex_file_;
3876 const DexFile::CodeItem* code_item = vdata->code_item_;
3877 Method* method = vdata->method_;
3878 Class* common_super = NULL;
3879 uint32_t handlers_size;
jeffhaoba5ebb92011-08-25 17:24:37 -07003880 const byte* handlers_ptr = DexFile::dexGetCatchHandlerData(*code_item, 0);
jeffhaobdb76512011-09-07 11:43:16 -07003881
3882 if (code_item->tries_size_ != 0) {
3883 handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
3884 } else {
3885 handlers_size = 0;
3886 }
3887
3888 for (uint32_t i = 0; i < handlers_size; i++) {
jeffhaoba5ebb92011-08-25 17:24:37 -07003889 DexFile::CatchHandlerIterator iterator(handlers_ptr);
3890
3891 for (; !iterator.HasNext(); iterator.Next()) {
jeffhaobdb76512011-09-07 11:43:16 -07003892 DexFile::CatchHandlerItem handler = iterator.Get();
3893 if (handler.address_ == (uint32_t) insn_idx) {
3894 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
3895 Class* klass;
jeffhaoba5ebb92011-08-25 17:24:37 -07003896
jeffhaobdb76512011-09-07 11:43:16 -07003897 if (handler.type_idx_ == DexFile::kDexNoIndex) {
3898 klass = class_linker->FindSystemClass("Ljava/lang/Throwable;");
3899 } else {
jeffhao98eacac2011-09-14 16:11:53 -07003900 klass = ResolveClassAndCheckAccess(dex_file, handler.type_idx_,
3901 method->GetDeclaringClass(), failure);
jeffhaobdb76512011-09-07 11:43:16 -07003902 }
3903
3904 if (klass == NULL) {
3905 LOG(ERROR) << "VFY: unable to resolve exception class "
3906 << handler.type_idx_ << " ("
3907 << dex_file->dexStringByTypeIdx(handler.type_idx_) << ")";
jeffhaod1f0fde2011-09-08 17:25:33 -07003908 /* TODO: do we want to keep going? If we don't fail this we run
3909 * the risk of having a non-Throwable introduced at runtime.
3910 * However, that won't pass an instanceof test, so is essentially
3911 * harmless.
jeffhaobdb76512011-09-07 11:43:16 -07003912 */
3913 } else {
3914 if (common_super == NULL)
3915 common_super = klass;
3916 else
3917 common_super = FindCommonSuperclass(klass, common_super);
3918 }
3919 }
jeffhaoba5ebb92011-08-25 17:24:37 -07003920 }
3921
3922 handlers_ptr = iterator.GetData();
3923 }
3924
jeffhaobdb76512011-09-07 11:43:16 -07003925 if (common_super == NULL) {
3926 /* no catch blocks, or no catches with classes we can find */
3927 LOG(ERROR) << "VFY: unable to find exception handler at addr 0x" << std::hex
3928 << insn_idx << std::dec;
3929 *failure = VERIFY_ERROR_GENERIC;
3930 }
3931
3932 return common_super;
jeffhaoba5ebb92011-08-25 17:24:37 -07003933}
3934
jeffhaobdb76512011-09-07 11:43:16 -07003935DexVerifier::RegType DexVerifier::GetMethodReturnType(const DexFile* dex_file,
3936 const Method* method) {
3937 Class* klass = method->GetReturnType();
3938 if (klass->IsPrimitive())
3939 return PrimitiveTypeToRegType(klass->GetPrimitiveType());
3940 else
3941 return RegTypeFromClass(klass);
Carl Shapiro0e5d75d2011-07-06 18:28:37 -07003942}
3943
jeffhaobdb76512011-09-07 11:43:16 -07003944Class* DexVerifier::GetClassFromRegister(const RegisterLine* register_line,
3945 uint32_t vsrc, VerifyError* failure) {
3946 /* get the element type of the array held in vsrc */
3947 RegType type = GetRegisterType(register_line, vsrc);
jeffhaoba5ebb92011-08-25 17:24:37 -07003948
jeffhaobdb76512011-09-07 11:43:16 -07003949 /* if "always zero", we allow it to fail at runtime */
3950 if (type == kRegTypeZero)
3951 return NULL;
3952
3953 if (!RegTypeIsReference(type)) {
3954 LOG(ERROR) << "VFY: tried to get class from non-ref register v" << vsrc
3955 << " (type=" << type << ")",
3956 *failure = VERIFY_ERROR_GENERIC;
3957 return NULL;
3958 }
3959 if (RegTypeIsUninitReference(type)) {
3960 LOG(ERROR) << "VFY: register " << vsrc << " holds uninitialized reference";
3961 *failure = VERIFY_ERROR_GENERIC;
3962 return NULL;
jeffhaoba5ebb92011-08-25 17:24:37 -07003963 }
3964
jeffhaobdb76512011-09-07 11:43:16 -07003965 return RegTypeInitializedReferenceToClass(type);
Carl Shapiro0e5d75d2011-07-06 18:28:37 -07003966}
3967
jeffhaobdb76512011-09-07 11:43:16 -07003968DexVerifier::RegType DexVerifier::GetInvocationThis(
3969 const RegisterLine* register_line,
3970 const Instruction::DecodedInstruction* dec_insn, VerifyError* failure) {
3971 if (dec_insn->vA_ < 1) {
3972 LOG(ERROR) << "VFY: invoke lacks 'this'";
3973 *failure = VERIFY_ERROR_GENERIC;
3974 return kRegTypeUnknown;
jeffhaoba5ebb92011-08-25 17:24:37 -07003975 }
jeffhaobdb76512011-09-07 11:43:16 -07003976
3977 /* get the element type of the array held in vsrc */
3978 RegType this_type = GetRegisterType(register_line, dec_insn->vC_);
3979 if (!RegTypeIsReference(this_type)) {
3980 LOG(ERROR) << "VFY: tried to get class from non-ref register v"
3981 << dec_insn->vC_ << " (type=" << this_type << ")";
3982 *failure = VERIFY_ERROR_GENERIC;
3983 return kRegTypeUnknown;
3984 }
3985
3986 return this_type;
jeffhaoba5ebb92011-08-25 17:24:37 -07003987}
3988
jeffhaobdb76512011-09-07 11:43:16 -07003989void DexVerifier::SetRegisterType(RegisterLine* register_line, uint32_t vdst,
3990 RegType new_type) {
Elliott Hughes5fe594f2011-09-08 12:33:17 -07003991 RegType* insn_regs = register_line->reg_types_.get();
jeffhaoba5ebb92011-08-25 17:24:37 -07003992
jeffhaobdb76512011-09-07 11:43:16 -07003993 switch (new_type) {
3994 case kRegTypeUnknown:
3995 case kRegTypeBoolean:
3996 case kRegTypeOne:
3997 case kRegTypeConstByte:
3998 case kRegTypeConstPosByte:
3999 case kRegTypeConstShort:
4000 case kRegTypeConstPosShort:
4001 case kRegTypeConstChar:
4002 case kRegTypeConstInteger:
4003 case kRegTypeByte:
4004 case kRegTypePosByte:
4005 case kRegTypeShort:
4006 case kRegTypePosShort:
4007 case kRegTypeChar:
4008 case kRegTypeInteger:
4009 case kRegTypeFloat:
4010 case kRegTypeZero:
4011 case kRegTypeUninit:
4012 insn_regs[vdst] = new_type;
jeffhaoba5ebb92011-08-25 17:24:37 -07004013 break;
jeffhaobdb76512011-09-07 11:43:16 -07004014 case kRegTypeConstLo:
4015 case kRegTypeLongLo:
4016 case kRegTypeDoubleLo:
4017 insn_regs[vdst] = new_type;
4018 insn_regs[vdst + 1] = new_type + 1;
4019 break;
4020 case kRegTypeConstHi:
4021 case kRegTypeLongHi:
4022 case kRegTypeDoubleHi:
4023 /* should never set these explicitly */
4024 LOG(FATAL) << "BUG: explicit set of high register type";
4025 break;
4026
4027 default:
4028 /* can't switch for ref types, so we check explicitly */
4029 if (RegTypeIsReference(new_type)) {
4030 insn_regs[vdst] = new_type;
4031
4032 /*
4033 * In most circumstances we won't see a reference to a primitive
4034 * class here (e.g. "D"), since that would mean the object in the
jeffhaod1f0fde2011-09-08 17:25:33 -07004035 * register is actually a primitive type. It can happen as the
jeffhaobdb76512011-09-07 11:43:16 -07004036 * result of an assumed-successful check-cast instruction in
jeffhaod1f0fde2011-09-08 17:25:33 -07004037 * which the second argument refers to a primitive class. (In
jeffhaobdb76512011-09-07 11:43:16 -07004038 * practice, such an instruction will always throw an exception.)
4039 *
4040 * This is not an issue for instructions like const-class, where
4041 * the object in the register is a java.lang.Class instance.
4042 */
4043 break;
4044 }
4045 /* bad type - fall through */
4046
4047 case kRegTypeConflict: // should only be set during a merge
4048 LOG(FATAL) << "BUG: set register to unknown type " << new_type;
jeffhaoba5ebb92011-08-25 17:24:37 -07004049 break;
4050 }
4051
jeffhaobdb76512011-09-07 11:43:16 -07004052 /*
4053 * Clear the monitor entry bits for this register.
4054 */
Elliott Hughes5fe594f2011-09-08 12:33:17 -07004055 if (register_line->monitor_entries_.get() != NULL)
jeffhaobdb76512011-09-07 11:43:16 -07004056 register_line->monitor_entries_[vdst] = 0;
4057}
4058
4059void DexVerifier::VerifyRegisterType(RegisterLine* register_line, uint32_t vsrc,
4060 RegType check_type, VerifyError* failure) {
Elliott Hughes5fe594f2011-09-08 12:33:17 -07004061 const RegType* insn_regs = register_line->reg_types_.get();
jeffhaobdb76512011-09-07 11:43:16 -07004062 RegType src_type = insn_regs[vsrc];
4063
4064 switch (check_type) {
4065 case kRegTypeFloat:
4066 case kRegTypeBoolean:
4067 case kRegTypePosByte:
4068 case kRegTypeByte:
4069 case kRegTypePosShort:
4070 case kRegTypeShort:
4071 case kRegTypeChar:
4072 case kRegTypeInteger:
4073 if (!CanConvertTo1nr(src_type, check_type)) {
4074 LOG(ERROR) << "VFY: register1 v" << vsrc << " type " << src_type
4075 << ", wanted " << check_type;
4076 *failure = VERIFY_ERROR_GENERIC;
4077 }
4078 /* Update type if result is float */
4079 if (check_type == kRegTypeFloat) {
4080 SetRegisterType(register_line, vsrc, check_type);
4081 } else {
4082 /* Update const type to actual type after use */
4083 SetRegisterType(register_line, vsrc, ConstTypeToRegType(src_type));
4084 }
jeffhaoba5ebb92011-08-25 17:24:37 -07004085 break;
jeffhaobdb76512011-09-07 11:43:16 -07004086 case kRegTypeLongLo:
4087 case kRegTypeDoubleLo:
4088 if (insn_regs[vsrc + 1] != src_type + 1) {
4089 LOG(ERROR) << "VFY: register2 v" << vsrc << "-" << vsrc + 1
4090 << " values " << insn_regs[vsrc] << ","
4091 << insn_regs[vsrc + 1];
4092 *failure = VERIFY_ERROR_GENERIC;
4093 } else if (!CanConvertTo2(src_type, check_type)) {
4094 LOG(ERROR) << "VFY: register2 v" << vsrc << " type " << src_type
4095 << ", wanted " << check_type;
4096 *failure = VERIFY_ERROR_GENERIC;
4097 }
4098 /* Update type if source is from const */
4099 if (src_type == kRegTypeConstLo) {
4100 SetRegisterType(register_line, vsrc, check_type);
4101 }
jeffhaoba5ebb92011-08-25 17:24:37 -07004102 break;
jeffhaobdb76512011-09-07 11:43:16 -07004103 case kRegTypeConstLo:
4104 case kRegTypeConstHi:
4105 case kRegTypeLongHi:
4106 case kRegTypeDoubleHi:
4107 case kRegTypeZero:
4108 case kRegTypeOne:
4109 case kRegTypeUnknown:
4110 case kRegTypeConflict:
4111 /* should never be checking for these explicitly */
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07004112 DCHECK(false);
jeffhaobdb76512011-09-07 11:43:16 -07004113 *failure = VERIFY_ERROR_GENERIC;
4114 return;
4115 case kRegTypeUninit:
4116 default:
4117 /* make sure check_type is initialized reference */
4118 if (!RegTypeIsReference(check_type)) {
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07004119 LOG(FATAL) << "VFY: unexpected check type " << check_type;
jeffhaobdb76512011-09-07 11:43:16 -07004120 *failure = VERIFY_ERROR_GENERIC;
4121 break;
4122 }
4123 if (RegTypeIsUninitReference(check_type)) {
4124 LOG(ERROR) << "VFY: uninitialized ref not expected as reg check";
4125 *failure = VERIFY_ERROR_GENERIC;
4126 break;
4127 }
4128 /* make sure src_type is initialized reference or always-NULL */
4129 if (!RegTypeIsReference(src_type)) {
4130 LOG(ERROR) << "VFY: register1 v" << vsrc << " type " << src_type
4131 << ", wanted ref";
4132 *failure = VERIFY_ERROR_GENERIC;
4133 break;
4134 }
4135 if (RegTypeIsUninitReference(src_type)) {
4136 LOG(ERROR) << "VFY: register1 v" << vsrc << " holds uninitialized ref";
4137 *failure = VERIFY_ERROR_GENERIC;
4138 break;
4139 }
4140 /* if the register isn't Zero, make sure it's an instance of check */
4141 if (src_type != kRegTypeZero) {
4142 Class* src_class = RegTypeInitializedReferenceToClass(src_type);
4143 Class* check_class = RegTypeInitializedReferenceToClass(check_type);
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07004144 DCHECK(src_class != NULL);
4145 DCHECK(check_class != NULL);
jeffhaobdb76512011-09-07 11:43:16 -07004146
jeffhaoe0cfb6f2011-09-22 16:42:56 -07004147 if (check_class->IsInterface()) {
4148 /*
4149 * All objects implement all interfaces as far as the verifier is
4150 * concerned. The runtime has to sort it out. See coments above
4151 * FindCommonSuperclass.
4152 */
4153 } else {
4154 if (!check_class->IsAssignableFrom(src_class)) {
4155 LOG(ERROR) << "VFY: " << src_class->GetDescriptor()->ToModifiedUtf8()
4156 << " is not instance of "
4157 << check_class->GetDescriptor()->ToModifiedUtf8();
4158 *failure = VERIFY_ERROR_GENERIC;
4159 }
jeffhaobdb76512011-09-07 11:43:16 -07004160 }
4161 }
jeffhaoba5ebb92011-08-25 17:24:37 -07004162 break;
4163 }
jeffhaobdb76512011-09-07 11:43:16 -07004164}
jeffhaoba5ebb92011-08-25 17:24:37 -07004165
jeffhaobdb76512011-09-07 11:43:16 -07004166void DexVerifier::SetResultRegisterType(RegisterLine* register_line,
4167 const int insn_reg_count, RegType new_type) {
4168 SetRegisterType(register_line, RESULT_REGISTER(insn_reg_count), new_type);
4169}
4170
4171void DexVerifier::MarkRefsAsInitialized(RegisterLine* register_line,
4172 int insn_reg_count, UninitInstanceMap* uninit_map, RegType uninit_type,
4173 VerifyError* failure) {
Elliott Hughes5fe594f2011-09-08 12:33:17 -07004174 RegType* insn_regs = register_line->reg_types_.get();
jeffhaobdb76512011-09-07 11:43:16 -07004175 Class* klass = GetUninitInstance(uninit_map,
4176 RegTypeToUninitIndex(uninit_type));
4177
4178 if (klass == NULL) {
4179 LOG(ERROR) << "VFY: unable to find type=" << std::hex << uninit_type
4180 << std::dec << " (idx=" << RegTypeToUninitIndex(uninit_type)
4181 << ")";
4182 *failure = VERIFY_ERROR_GENERIC;
4183 return;
jeffhaoba5ebb92011-08-25 17:24:37 -07004184 }
4185
jeffhaobdb76512011-09-07 11:43:16 -07004186 RegType init_type = RegTypeFromClass(klass);
4187 int changed = 0;
4188 for (int i = 0; i < insn_reg_count; i++) {
4189 if (insn_regs[i] == uninit_type) {
4190 insn_regs[i] = init_type;
4191 changed++;
4192 }
4193 }
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07004194 DCHECK_GT(changed, 0);
jeffhaobdb76512011-09-07 11:43:16 -07004195
4196 return;
4197}
4198
4199void DexVerifier::MarkUninitRefsAsInvalid(RegisterLine* register_line,
4200 int insn_reg_count, UninitInstanceMap* uninit_map, RegType uninit_type) {
Elliott Hughes5fe594f2011-09-08 12:33:17 -07004201 RegType* insn_regs = register_line->reg_types_.get();
jeffhaobdb76512011-09-07 11:43:16 -07004202
4203 for (int i = 0; i < insn_reg_count; i++) {
4204 if (insn_regs[i] == uninit_type) {
4205 insn_regs[i] = kRegTypeConflict;
Elliott Hughes5fe594f2011-09-08 12:33:17 -07004206 if (register_line->monitor_entries_.get() != NULL)
jeffhaobdb76512011-09-07 11:43:16 -07004207 register_line->monitor_entries_[i] = 0;
4208 }
4209 }
4210}
4211
4212void DexVerifier::CopyRegister1(RegisterLine* register_line, uint32_t vdst,
4213 uint32_t vsrc, TypeCategory cat, VerifyError* failure) {
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07004214 DCHECK(cat == kTypeCategory1nr || cat == kTypeCategoryRef);
jeffhaobdb76512011-09-07 11:43:16 -07004215 RegType type = GetRegisterType(register_line, vsrc);
4216 CheckTypeCategory(type, cat, failure);
4217 if (*failure != VERIFY_ERROR_NONE) {
4218 LOG(ERROR) << "VFY: copy1 v" << vdst << "<-v" << vsrc << " type=" << type
4219 << " cat=" << (int) cat;
4220 } else {
4221 SetRegisterType(register_line, vdst, type);
Elliott Hughes5fe594f2011-09-08 12:33:17 -07004222 if (cat == kTypeCategoryRef && register_line->monitor_entries_.get() != NULL) {
jeffhaobdb76512011-09-07 11:43:16 -07004223 register_line->monitor_entries_[vdst] =
4224 register_line->monitor_entries_[vsrc];
4225 }
4226 }
4227}
4228
4229void DexVerifier::CopyRegister2(RegisterLine* register_line, uint32_t vdst,
4230 uint32_t vsrc, VerifyError* failure) {
4231 RegType type_l = GetRegisterType(register_line, vsrc);
4232 RegType type_h = GetRegisterType(register_line, vsrc + 1);
4233
4234 CheckTypeCategory(type_l, kTypeCategory2, failure);
4235 CheckWidePair(type_l, type_h, failure);
4236 if (*failure != VERIFY_ERROR_NONE) {
4237 LOG(ERROR) << "VFY: copy2 v" << vdst << "<-v" << vsrc << " type=" << type_l
4238 << "/" << type_h;
4239 } else {
4240 SetRegisterType(register_line, vdst, type_l);
4241 }
4242}
4243
4244void DexVerifier::CopyResultRegister1(RegisterLine* register_line,
4245 const int insn_reg_count, uint32_t vdst, TypeCategory cat,
4246 VerifyError* failure) {
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07004247 DCHECK_LT(vdst, static_cast<uint32_t>(insn_reg_count));
jeffhaobdb76512011-09-07 11:43:16 -07004248
4249 uint32_t vsrc = RESULT_REGISTER(insn_reg_count);
4250 RegType type = GetRegisterType(register_line, vsrc);
4251 CheckTypeCategory(type, cat, failure);
4252 if (*failure != VERIFY_ERROR_NONE) {
4253 LOG(ERROR) << "VFY: copyRes1 v" << vdst << "<-v" << vsrc << " cat="
4254 << (int) cat << " type=" << type;
4255 } else {
4256 SetRegisterType(register_line, vdst, type);
4257 SetRegisterType(register_line, vsrc, kRegTypeUnknown);
4258 }
4259}
4260
4261/*
jeffhaod1f0fde2011-09-08 17:25:33 -07004262 * Implement "move-result-wide". Copy the category-2 value from the result
jeffhaobdb76512011-09-07 11:43:16 -07004263 * register to another register, and reset the result register.
4264 */
4265void DexVerifier::CopyResultRegister2(RegisterLine* register_line,
4266 const int insn_reg_count, uint32_t vdst, VerifyError* failure) {
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07004267 DCHECK_LT(vdst, static_cast<uint32_t>(insn_reg_count));
jeffhaobdb76512011-09-07 11:43:16 -07004268
4269 uint32_t vsrc = RESULT_REGISTER(insn_reg_count);
4270 RegType type_l = GetRegisterType(register_line, vsrc);
4271 RegType type_h = GetRegisterType(register_line, vsrc + 1);
4272 CheckTypeCategory(type_l, kTypeCategory2, failure);
4273 CheckWidePair(type_l, type_h, failure);
4274 if (*failure != VERIFY_ERROR_NONE) {
4275 LOG(ERROR) << "VFY: copyRes2 v" << vdst << "<-v" << vsrc << " type="
4276 << type_l << "/" << type_h;
4277 } else {
4278 SetRegisterType(register_line, vdst, type_l);
4279 SetRegisterType(register_line, vsrc, kRegTypeUnknown);
4280 SetRegisterType(register_line, vsrc + 1, kRegTypeUnknown);
4281 }
4282}
4283
4284int DexVerifier::GetClassDepth(Class* klass) {
4285 int depth = 0;
4286 while (klass->GetSuperClass() != NULL) {
4287 klass = klass->GetSuperClass();
4288 depth++;
4289 }
4290 return depth;
4291}
4292
4293Class* DexVerifier::DigForSuperclass(Class* c1, Class* c2) {
4294 int depth1, depth2;
4295
4296 depth1 = GetClassDepth(c1);
4297 depth2 = GetClassDepth(c2);
4298
4299 /* pull the deepest one up */
4300 if (depth1 > depth2) {
4301 while (depth1 > depth2) {
4302 c1 = c1->GetSuperClass();
4303 depth1--;
4304 }
4305 } else {
4306 while (depth2 > depth1) {
4307 c2 = c2->GetSuperClass();
4308 depth2--;
4309 }
jeffhaoba5ebb92011-08-25 17:24:37 -07004310 }
4311
jeffhaobdb76512011-09-07 11:43:16 -07004312 /* walk up in lock-step */
4313 while (c1 != c2) {
4314 c1 = c1->GetSuperClass();
4315 c2 = c2->GetSuperClass();
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07004316 DCHECK(c1 != NULL);
4317 DCHECK(c2 != NULL);
jeffhaobdb76512011-09-07 11:43:16 -07004318 }
4319
4320 return c1;
4321}
4322
4323Class* DexVerifier::FindCommonArraySuperclass(Class* c1, Class* c2) {
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07004324 DCHECK(c1->IsArrayClass());
4325 DCHECK(c2->IsArrayClass());
4326 Class* e1 = c1->GetComponentType();
4327 Class* e2 = c2->GetComponentType();
4328 if (e1->IsPrimitive() || e2->IsPrimitive()) {
4329 return c1->GetSuperClass(); // == java.lang.Object
jeffhaobdb76512011-09-07 11:43:16 -07004330 }
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07004331 Class* common_elem = FindCommonSuperclass(c1->GetComponentType(), c2->GetComponentType());
4332 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
4333 const ClassLoader* class_loader = c1->GetClassLoader();
4334 std::string descriptor = "[" + common_elem->GetDescriptor()->ToModifiedUtf8();
4335 Class* array_class = class_linker->FindClass(descriptor.c_str(), class_loader);
4336 DCHECK(array_class != NULL);
jeffhaobdb76512011-09-07 11:43:16 -07004337 return array_class;
4338}
4339
4340Class* DexVerifier::FindCommonSuperclass(Class* c1, Class* c2) {
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07004341 DCHECK(!c1->IsPrimitive()) << PrettyClass(c1);
4342 DCHECK(!c2->IsPrimitive()) << PrettyClass(c2);
jeffhaobdb76512011-09-07 11:43:16 -07004343
4344 if (c1 == c2)
4345 return c1;
4346
jeffhao5dbddee2011-09-07 16:38:26 -07004347 if (c1->IsInterface() && c1->IsAssignableFrom(c2)) {
jeffhaobdb76512011-09-07 11:43:16 -07004348 return c1;
4349 }
jeffhao5dbddee2011-09-07 16:38:26 -07004350 if (c2->IsInterface() && c2->IsAssignableFrom(c1)) {
jeffhaobdb76512011-09-07 11:43:16 -07004351 return c2;
4352 }
4353 if (c1->IsArrayClass() && c2->IsArrayClass()) {
4354 return FindCommonArraySuperclass(c1, c2);
4355 }
4356
4357 return DigForSuperclass(c1, c2);
4358}
4359
jeffhao98eacac2011-09-14 16:11:53 -07004360Class* DexVerifier::ResolveClassAndCheckAccess(const DexFile* dex_file,
jeffhaob4df5142011-09-19 20:25:32 -07004361 uint32_t class_idx, const Class* referrer, VerifyError* failure) {
jeffhao98eacac2011-09-14 16:11:53 -07004362 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
4363 Class* res_class = class_linker->ResolveType(*dex_file, class_idx, referrer);
4364
4365 if (res_class == NULL) {
jeffhaoe0cfb6f2011-09-22 16:42:56 -07004366 //*failure = VERIFY_ERROR_NO_CLASS;
buzbeec0ecd652011-09-25 18:11:54 -07004367#if 1
4368 // FIXME - is this correct? Inserted as a workaround?
4369 Thread::Current()->ClearException();
4370#endif
jeffhaoe0cfb6f2011-09-22 16:42:56 -07004371 LOG(ERROR) << "VFY: can't find class with index 0x" << std::hex << class_idx << std::dec;
jeffhao98eacac2011-09-14 16:11:53 -07004372 return NULL;
4373 }
4374
4375 /* Check if access is allowed. */
4376 if (!referrer->CanAccess(res_class)) {
4377 LOG(ERROR) << "VFY: illegal class access: "
4378 << referrer->GetDescriptor()->ToModifiedUtf8() << " -> "
4379 << res_class->GetDescriptor()->ToModifiedUtf8();
4380 *failure = VERIFY_ERROR_ACCESS_CLASS;
4381 return NULL;
4382 }
4383
4384 return res_class;
4385}
4386
jeffhaob4df5142011-09-19 20:25:32 -07004387Method* DexVerifier::ResolveMethodAndCheckAccess(const DexFile* dex_file,
4388 uint32_t method_idx, const Class* referrer, VerifyError* failure,
4389 bool is_direct) {
4390 DexCache* dex_cache = referrer->GetDexCache();
4391 Method* res_method = dex_cache->GetResolvedMethod(method_idx);
4392
4393 if (res_method == NULL) {
4394 const DexFile::MethodId& method_id = dex_file->GetMethodId(method_idx);
4395 Class* klass = ResolveClassAndCheckAccess(dex_file, method_id.class_idx_, referrer, failure);
4396 if (klass == NULL) {
4397 DCHECK(*failure != VERIFY_ERROR_NONE);
4398 return NULL;
4399 }
4400
4401 const char* name = dex_file->dexStringById(method_id.name_idx_);
4402 std::string signature(dex_file->CreateMethodDescriptor(method_id.proto_idx_, NULL));
4403 if (is_direct) {
4404 res_method = klass->FindDirectMethod(name, signature);
4405 } else if (klass->IsInterface()) {
4406 res_method = klass->FindInterfaceMethod(name, signature);
4407 } else {
4408 res_method = klass->FindVirtualMethod(name, signature);
4409 }
4410 if (res_method != NULL) {
4411 dex_cache->SetResolvedMethod(method_idx, res_method);
4412 } else {
4413 LOG(ERROR) << "VFY: couldn't find method "
4414 << klass->GetDescriptor()->ToModifiedUtf8() << "." << name
4415 << " " << signature;
4416 *failure = VERIFY_ERROR_NO_METHOD;
4417 return NULL;
4418 }
4419 }
4420
4421 /* Check if access is allowed. */
jeffhao4a801a42011-09-23 13:53:40 -07004422 if (!referrer->CanAccessMember(res_method->GetDeclaringClass(), res_method->GetAccessFlags())) {
jeffhaob4df5142011-09-19 20:25:32 -07004423 LOG(ERROR) << "VFY: illegal method access (call "
4424 << res_method->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8()
jeffhaoe0cfb6f2011-09-22 16:42:56 -07004425 << "." << res_method->GetName()->ToModifiedUtf8() << " "
4426 << res_method->GetSignature()->ToModifiedUtf8() << " from "
jeffhaob4df5142011-09-19 20:25:32 -07004427 << referrer->GetDescriptor()->ToModifiedUtf8() << ")";
4428 *failure = VERIFY_ERROR_ACCESS_METHOD;
4429 return NULL;
4430 }
4431
4432 return res_method;
4433}
4434
4435Field* DexVerifier::ResolveFieldAndCheckAccess(const DexFile* dex_file,
4436 uint32_t field_idx, const Class* referrer, VerifyError* failure,
4437 bool is_static) {
4438 DexCache* dex_cache = referrer->GetDexCache();
4439 Field* res_field = dex_cache->GetResolvedField(field_idx);
4440
4441 if (res_field == NULL) {
4442 const DexFile::FieldId& field_id = dex_file->GetFieldId(field_idx);
4443 Class* klass = ResolveClassAndCheckAccess(dex_file, field_id.class_idx_, referrer, failure);
4444 if (klass == NULL) {
Brian Carlstrom65ca0772011-09-24 16:03:08 -07004445 DCHECK(*failure != VERIFY_ERROR_NONE) << PrettyClass(referrer);
jeffhaob4df5142011-09-19 20:25:32 -07004446 return NULL;
4447 }
4448
4449 Class* field_type = ResolveClassAndCheckAccess(dex_file, field_id.type_idx_, referrer, failure);
4450 if (field_type == NULL) {
Brian Carlstrom65ca0772011-09-24 16:03:08 -07004451 // TODO: restore this assert?
4452 // DCHECK(*failure != VERIFY_ERROR_NONE) << PrettyClass(referrer) << " " << PrettyClass(klass);
jeffhaob4df5142011-09-19 20:25:32 -07004453 return NULL;
4454 }
4455
4456 const char* name = dex_file->dexStringById(field_id.name_idx_);
4457 if (is_static) {
4458 res_field = klass->FindStaticField(name, field_type);
4459 } else {
4460 res_field = klass->FindInstanceField(name, field_type);
4461 }
4462 if (res_field != NULL) {
Elliott Hughes4a2b4172011-09-20 17:08:25 -07004463 dex_cache->SetResolvedField(field_idx, res_field);
jeffhaob4df5142011-09-19 20:25:32 -07004464 } else {
4465 LOG(ERROR) << "VFY: couldn't find field "
4466 << klass->GetDescriptor()->ToModifiedUtf8() << "." << name;
4467 *failure = VERIFY_ERROR_NO_FIELD;
4468 return NULL;
4469 }
4470 }
4471
4472 /* Check if access is allowed. */
jeffhao4a801a42011-09-23 13:53:40 -07004473 if (!referrer->CanAccessMember(res_field->GetDeclaringClass(), res_field->GetAccessFlags())) {
jeffhaob4df5142011-09-19 20:25:32 -07004474 LOG(ERROR) << "VFY: access denied from "
4475 << referrer->GetDescriptor()->ToModifiedUtf8() << " to field "
4476 << res_field->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8()
4477 << "." << res_field->GetName()->ToModifiedUtf8();
4478 *failure = VERIFY_ERROR_ACCESS_FIELD;
4479 return NULL;
4480 }
4481
4482 return res_field;
4483}
4484
jeffhaobdb76512011-09-07 11:43:16 -07004485DexVerifier::RegType DexVerifier::MergeTypes(RegType type1, RegType type2,
4486 bool* changed) {
4487 RegType result;
4488
jeffhao98eacac2011-09-14 16:11:53 -07004489 /* Check for trivial case so we don't have to hit memory. */
jeffhaobdb76512011-09-07 11:43:16 -07004490 if (type1 == type2)
4491 return type1;
4492
4493 /*
4494 * Use the table if we can, and reject any attempts to merge something
4495 * from the table with a reference type.
4496 *
4497 * Uninitialized references are composed of the enum ORed with an
jeffhaod1f0fde2011-09-08 17:25:33 -07004498 * index value. The uninitialized table entry at index zero *will*
4499 * show up as a simple kRegTypeUninit value. Since this cannot be
jeffhaobdb76512011-09-07 11:43:16 -07004500 * merged with anything but itself, the rules do the right thing.
4501 */
4502 if (type1 < kRegTypeMAX) {
4503 if (type2 < kRegTypeMAX) {
4504 result = merge_table_[type1][type2];
4505 } else {
4506 /* simple + reference == conflict, usually */
4507 if (type1 == kRegTypeZero)
4508 result = type2;
4509 else
4510 result = kRegTypeConflict;
4511 }
4512 } else {
4513 if (type2 < kRegTypeMAX) {
4514 /* reference + simple == conflict, usually */
4515 if (type2 == kRegTypeZero)
4516 result = type1;
4517 else
4518 result = kRegTypeConflict;
4519 } else {
4520 /* merging two references */
4521 if (RegTypeIsUninitReference(type1) ||
4522 RegTypeIsUninitReference(type2))
4523 {
4524 /* can't merge uninit with anything but self */
4525 result = kRegTypeConflict;
4526 } else {
4527 Class* klass1 = RegTypeInitializedReferenceToClass(type1);
4528 Class* klass2 = RegTypeInitializedReferenceToClass(type2);
4529 Class* merged_class = FindCommonSuperclass(klass1, klass2);
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07004530 DCHECK(merged_class != NULL);
jeffhaobdb76512011-09-07 11:43:16 -07004531 result = RegTypeFromClass(merged_class);
4532 }
4533 }
4534 }
4535
4536 if (result != type1)
4537 *changed = true;
jeffhaoba5ebb92011-08-25 17:24:37 -07004538 return result;
jeffhaobdb76512011-09-07 11:43:16 -07004539}
4540
4541DexVerifier::MonitorEntries DexVerifier::MergeMonitorEntries(
4542 MonitorEntries ents1, MonitorEntries ents2, bool* changed) {
4543 MonitorEntries result = ents1 & ents2;
4544 if (result != ents1)
4545 *changed = true;
4546 return result;
4547}
4548
4549bool DexVerifier::UpdateRegisters(InsnFlags* insn_flags,
4550 RegisterTable* reg_table, int next_insn, const RegisterLine* work_line) {
4551 const size_t insn_reg_count_plus = reg_table->insn_reg_count_plus_;
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07004552 DCHECK(work_line != NULL);
Elliott Hughes5fe594f2011-09-08 12:33:17 -07004553 const RegType* work_regs = work_line->reg_types_.get();
jeffhaobdb76512011-09-07 11:43:16 -07004554
4555 if (!InsnIsVisitedOrChanged(insn_flags, next_insn)) {
4556 /*
4557 * We haven't processed this instruction before, and we haven't
jeffhaod1f0fde2011-09-08 17:25:33 -07004558 * touched the registers here, so there's nothing to "merge". Copy
4559 * the registers over and mark it as changed. (This is the only
jeffhaobdb76512011-09-07 11:43:16 -07004560 * way a register can transition out of "unknown", so this is not
4561 * just an optimization.)
4562 */
4563 CopyLineToTable(reg_table, next_insn, work_line);
4564 InsnSetChanged(insn_flags, next_insn, true);
4565 } else {
4566 /* Merge registers, set Changed only if different */
4567 RegisterLine* target_line = GetRegisterLine(reg_table, next_insn);
Elliott Hughes5fe594f2011-09-08 12:33:17 -07004568 RegType* target_regs = target_line->reg_types_.get();
4569 MonitorEntries* work_mon_ents = work_line->monitor_entries_.get();
4570 MonitorEntries* target_mon_ents = target_line->monitor_entries_.get();
jeffhaobdb76512011-09-07 11:43:16 -07004571 bool changed = false;
4572 unsigned int idx;
4573
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07004574 DCHECK(target_regs != NULL);
jeffhaobdb76512011-09-07 11:43:16 -07004575 if (target_mon_ents != NULL) {
4576 /* Monitor stacks must be identical. */
4577 if (target_line->monitor_stack_top_ != work_line->monitor_stack_top_) {
4578 LOG(ERROR) << "VFY: mismatched stack depth "
4579 << target_line->monitor_stack_top_ << " vs. "
4580 << work_line->monitor_stack_top_ << " at 0x"
4581 << std::hex << next_insn << std::dec;
4582 return false;
4583 }
Elliott Hughes5fe594f2011-09-08 12:33:17 -07004584 if (memcmp(target_line->monitor_stack_.get(), work_line->monitor_stack_.get(),
jeffhaobdb76512011-09-07 11:43:16 -07004585 target_line->monitor_stack_top_ * sizeof(uint32_t)) != 0) {
4586 LOG(ERROR) << "VFY: mismatched monitor stacks at 0x" << std::hex
4587 << next_insn << std::dec;
4588 return false;
4589 }
4590 }
4591
4592 for (idx = 0; idx < insn_reg_count_plus; idx++) {
4593 target_regs[idx] = MergeTypes(target_regs[idx], work_regs[idx], &changed);
4594
4595 if (target_mon_ents != NULL) {
4596 target_mon_ents[idx] = MergeMonitorEntries(target_mon_ents[idx],
4597 work_mon_ents[idx], &changed);
4598 }
4599 }
4600
4601 if (changed) {
4602 InsnSetChanged(insn_flags, next_insn, true);
4603 }
4604 }
4605
4606 return true;
4607}
4608
4609bool DexVerifier::CanConvertTo1nr(RegType src_type, RegType check_type) {
4610 static const char conv_tab[kRegType1nrEND - kRegType1nrSTART + 1]
4611 [kRegType1nrEND - kRegType1nrSTART + 1] =
4612 {
4613 /* chk: 0 1 Z y Y h H c i b B s S C I F */
4614 { /*0*/ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
4615 { /*1*/ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
4616 { /*Z*/ 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 },
4617 { /*y*/ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
4618 { /*Y*/ 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1 },
4619 { /*h*/ 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1 },
4620 { /*H*/ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1 },
4621 { /*c*/ 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1 },
4622 { /*i*/ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1 },
4623 { /*b*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0 },
4624 { /*B*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0 },
4625 { /*s*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0 },
4626 { /*S*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0 },
4627 { /*C*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0 },
4628 { /*I*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 },
4629 { /*F*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
4630 };
4631
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07004632 DCHECK(check_type >= kRegType1nrSTART);
4633 DCHECK(check_type <= kRegType1nrEND);
jeffhaobdb76512011-09-07 11:43:16 -07004634
4635 if (src_type >= kRegType1nrSTART && src_type <= kRegType1nrEND)
4636 return (bool) conv_tab[src_type - kRegType1nrSTART]
4637 [check_type - kRegType1nrSTART];
4638
4639 return false;
4640}
4641
4642bool DexVerifier::CanConvertTo2(RegType src_type, RegType check_type) {
4643 return ((src_type == kRegTypeConstLo || src_type == check_type) &&
4644 (check_type == kRegTypeLongLo || check_type == kRegTypeDoubleLo));
4645}
4646
4647DexVerifier::RegType DexVerifier::PrimitiveTypeToRegType(
4648 Class::PrimitiveType prim_type) {
4649 switch (prim_type) {
4650 case Class::kPrimBoolean: return kRegTypeBoolean;
4651 case Class::kPrimByte: return kRegTypeByte;
4652 case Class::kPrimShort: return kRegTypeShort;
4653 case Class::kPrimChar: return kRegTypeChar;
4654 case Class::kPrimInt: return kRegTypeInteger;
4655 case Class::kPrimLong: return kRegTypeLongLo;
4656 case Class::kPrimFloat: return kRegTypeFloat;
4657 case Class::kPrimDouble: return kRegTypeDoubleLo;
4658 case Class::kPrimVoid:
4659 default: {
4660 return kRegTypeUnknown;
4661 }
4662 }
4663}
4664
4665DexVerifier::RegType DexVerifier::ConstTypeToRegType(RegType const_type) {
4666 switch (const_type) {
4667 case kRegTypeConstPosByte: return kRegTypePosByte;
4668 case kRegTypeConstByte: return kRegTypeByte;
4669 case kRegTypeConstPosShort: return kRegTypePosShort;
4670 case kRegTypeConstShort: return kRegTypeShort;
4671 case kRegTypeConstChar: return kRegTypeChar;
4672 case kRegTypeConstInteger: return kRegTypeInteger;
4673 default: {
4674 return const_type;
4675 }
4676 }
4677}
4678
4679char DexVerifier::DetermineCat1Const(int32_t value) {
4680 if (value < -32768)
4681 return kRegTypeConstInteger;
4682 else if (value < -128)
4683 return kRegTypeConstShort;
4684 else if (value < 0)
4685 return kRegTypeConstByte;
4686 else if (value == 0)
4687 return kRegTypeZero;
4688 else if (value == 1)
4689 return kRegTypeOne;
4690 else if (value < 128)
4691 return kRegTypeConstPosByte;
4692 else if (value < 32768)
4693 return kRegTypeConstPosShort;
4694 else if (value < 65536)
4695 return kRegTypeConstChar;
4696 else
4697 return kRegTypeConstInteger;
4698}
4699
4700void DexVerifier::CheckFinalFieldAccess(const Method* method,
4701 const Field* field, VerifyError* failure) {
Brian Carlstrom65ca0772011-09-24 16:03:08 -07004702 DCHECK(field != NULL);
4703 if (!field->IsFinal()) {
jeffhaobdb76512011-09-07 11:43:16 -07004704 return;
Brian Carlstrom65ca0772011-09-24 16:03:08 -07004705 }
jeffhaobdb76512011-09-07 11:43:16 -07004706
4707 /* make sure we're in the same class */
4708 if (method->GetDeclaringClass() != field->GetDeclaringClass()) {
4709 LOG(ERROR) << "VFY: can't modify final field "
4710 << field->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8()
4711 << "." << field->GetName()->ToModifiedUtf8();
4712 *failure = VERIFY_ERROR_ACCESS_FIELD;
4713 return;
4714 }
4715}
4716
4717void DexVerifier::CheckArrayIndexType(const Method* method, RegType reg_type,
4718 VerifyError* failure) {
4719 if (*failure == VERIFY_ERROR_NONE) {
4720 /*
jeffhaod1f0fde2011-09-08 17:25:33 -07004721 * The 1nr types are interchangeable at this level. We could
jeffhaobdb76512011-09-07 11:43:16 -07004722 * do something special if we can definitively identify it as a
4723 * float, but there's no real value in doing so.
4724 */
4725 CheckTypeCategory(reg_type, kTypeCategory1nr, failure);
4726 if (*failure != VERIFY_ERROR_NONE) {
4727 LOG(ERROR) << "Invalid reg type for array index (" << reg_type << ")";
4728 }
4729 }
4730}
4731
4732bool DexVerifier::CheckConstructorReturn(const Method* method,
4733 const RegisterLine* register_line, const int insn_reg_count) {
Elliott Hughes5fe594f2011-09-08 12:33:17 -07004734 const RegType* insn_regs = register_line->reg_types_.get();
jeffhaobdb76512011-09-07 11:43:16 -07004735
4736 if (!IsInitMethod(method))
4737 return true;
4738
4739 RegType uninit_this = RegTypeFromUninitIndex(kUninitThisArgSlot);
4740
4741 for (int i = 0; i < insn_reg_count; i++) {
4742 if (insn_regs[i] == uninit_this) {
4743 LOG(ERROR) << "VFY: <init> returning without calling superclass init";
4744 return false;
4745 }
4746 }
4747 return true;
4748}
4749
4750bool DexVerifier::CheckMoveException(const uint16_t* insns, int insn_idx) {
4751 if ((insns[insn_idx] & 0xff) == Instruction::MOVE_EXCEPTION) {
4752 LOG(ERROR) << "VFY: invalid use of move-exception";
4753 return false;
4754 }
4755 return true;
4756}
4757
4758void DexVerifier::CheckTypeCategory(RegType type, TypeCategory cat,
4759 VerifyError* failure) {
4760 switch (cat) {
4761 case kTypeCategory1nr:
4762 switch (type) {
4763 case kRegTypeZero:
4764 case kRegTypeOne:
4765 case kRegTypeBoolean:
4766 case kRegTypeConstPosByte:
4767 case kRegTypeConstByte:
4768 case kRegTypeConstPosShort:
4769 case kRegTypeConstShort:
4770 case kRegTypeConstChar:
4771 case kRegTypeConstInteger:
4772 case kRegTypePosByte:
4773 case kRegTypeByte:
4774 case kRegTypePosShort:
4775 case kRegTypeShort:
4776 case kRegTypeChar:
4777 case kRegTypeInteger:
4778 case kRegTypeFloat:
4779 break;
4780 default:
4781 *failure = VERIFY_ERROR_GENERIC;
4782 break;
4783 }
4784 break;
4785 case kTypeCategory2:
4786 switch (type) {
4787 case kRegTypeConstLo:
4788 case kRegTypeLongLo:
4789 case kRegTypeDoubleLo:
4790 break;
4791 default:
4792 *failure = VERIFY_ERROR_GENERIC;
4793 break;
4794 }
4795 break;
4796 case kTypeCategoryRef:
4797 if (type != kRegTypeZero && !RegTypeIsReference(type))
4798 *failure = VERIFY_ERROR_GENERIC;
4799 break;
4800 default:
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07004801 DCHECK(false);
jeffhaobdb76512011-09-07 11:43:16 -07004802 *failure = VERIFY_ERROR_GENERIC;
4803 break;
4804 }
4805}
4806
4807void DexVerifier::CheckWidePair(RegType type_l, RegType type_h,
4808 VerifyError* failure) {
4809 if ((type_h != type_l + 1))
4810 *failure = VERIFY_ERROR_GENERIC;
4811}
4812
4813void DexVerifier::CheckUnop(RegisterLine* register_line,
4814 Instruction::DecodedInstruction* dec_insn, RegType dst_type,
4815 RegType src_type, VerifyError* failure) {
4816 VerifyRegisterType(register_line, dec_insn->vB_, src_type, failure);
4817 SetRegisterType(register_line, dec_insn->vA_, dst_type);
4818}
4819
4820bool DexVerifier::UpcastBooleanOp(RegisterLine* register_line, uint32_t reg1,
4821 uint32_t reg2) {
4822 RegType type1, type2;
4823
4824 type1 = GetRegisterType(register_line, reg1);
4825 type2 = GetRegisterType(register_line, reg2);
4826
4827 if ((type1 == kRegTypeBoolean || type1 == kRegTypeZero || type1 == kRegTypeOne) &&
4828 (type2 == kRegTypeBoolean || type2 == kRegTypeZero || type2 == kRegTypeOne)) {
4829 return true;
4830 }
4831 return false;
4832}
4833
4834void DexVerifier::CheckLitop(RegisterLine* register_line,
4835 Instruction::DecodedInstruction* dec_insn, RegType dst_type,
4836 RegType src_type, bool check_boolean_op, VerifyError* failure) {
4837 VerifyRegisterType(register_line, dec_insn->vB_, src_type, failure);
4838
4839 if ((*failure == VERIFY_ERROR_NONE) && check_boolean_op) {
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07004840 DCHECK(dst_type == kRegTypeInteger);
jeffhaobdb76512011-09-07 11:43:16 -07004841
4842 /* check vB with the call, then check the constant manually */
4843 if (UpcastBooleanOp(register_line, dec_insn->vB_, dec_insn->vB_)
4844 && (dec_insn->vC_ == 0 || dec_insn->vC_ == 1)) {
4845 dst_type = kRegTypeBoolean;
4846 }
4847 }
4848
4849 SetRegisterType(register_line, dec_insn->vA_, dst_type);
4850}
4851
4852void DexVerifier::CheckBinop(RegisterLine* register_line,
4853 Instruction::DecodedInstruction* dec_insn, RegType dst_type,
4854 RegType src_type1, RegType src_type2, bool check_boolean_op,
4855 VerifyError* failure) {
4856 VerifyRegisterType(register_line, dec_insn->vB_, src_type1, failure);
4857 VerifyRegisterType(register_line, dec_insn->vC_, src_type2, failure);
4858
4859 if ((*failure == VERIFY_ERROR_NONE) && check_boolean_op) {
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07004860 DCHECK(dst_type == kRegTypeInteger);
jeffhaobdb76512011-09-07 11:43:16 -07004861 if (UpcastBooleanOp(register_line, dec_insn->vB_, dec_insn->vC_))
4862 dst_type = kRegTypeBoolean;
4863 }
4864
4865 SetRegisterType(register_line, dec_insn->vA_, dst_type);
4866}
4867
4868void DexVerifier::CheckBinop2addr(RegisterLine* register_line,
4869 Instruction::DecodedInstruction* dec_insn, RegType dst_type,
4870 RegType src_type1, RegType src_type2, bool check_boolean_op,
4871 VerifyError* failure) {
4872 VerifyRegisterType(register_line, dec_insn->vA_, src_type1, failure);
4873 VerifyRegisterType(register_line, dec_insn->vB_, src_type2, failure);
4874
4875 if ((*failure == VERIFY_ERROR_NONE) && check_boolean_op) {
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07004876 DCHECK(dst_type == kRegTypeInteger);
jeffhaobdb76512011-09-07 11:43:16 -07004877 if (UpcastBooleanOp(register_line, dec_insn->vA_, dec_insn->vB_))
4878 dst_type = kRegTypeBoolean;
4879 }
4880
4881 SetRegisterType(register_line, dec_insn->vA_, dst_type);
4882}
4883
4884DexVerifier::RegType DexVerifier::AdjustForRightShift(
4885 RegisterLine* register_line, int reg, unsigned int shift_count,
jeffhaob4df5142011-09-19 20:25:32 -07004886 bool is_unsigned_shift) {
jeffhaobdb76512011-09-07 11:43:16 -07004887 RegType src_type = GetRegisterType(register_line, reg);
4888 RegType new_type;
4889
4890 /* convert const derived types to their actual types */
4891 src_type = ConstTypeToRegType(src_type);
4892
4893 /* no-op */
4894 if (shift_count == 0)
4895 return src_type;
4896
4897 /* safe defaults */
4898 if (is_unsigned_shift)
4899 new_type = kRegTypeInteger;
4900 else
4901 new_type = src_type;
4902
4903 if (shift_count >= 32) {
4904 LOG(ERROR) << "Got unexpectedly large shift count " << shift_count;
4905 /* fail? */
4906 return new_type;
4907 }
4908
4909 switch (src_type) {
4910 case kRegTypeInteger: /* 32-bit signed value */
4911 if (is_unsigned_shift) {
4912 if (shift_count > 24)
4913 new_type = kRegTypePosByte;
4914 else if (shift_count >= 16)
4915 new_type = kRegTypeChar;
4916 } else {
4917 if (shift_count >= 24)
4918 new_type = kRegTypeByte;
4919 else if (shift_count >= 16)
4920 new_type = kRegTypeShort;
4921 }
4922 break;
4923 case kRegTypeShort: /* 16-bit signed value */
4924 if (is_unsigned_shift) {
4925 /* default (kRegTypeInteger) is correct */
4926 } else {
4927 if (shift_count >= 8)
4928 new_type = kRegTypeByte;
4929 }
4930 break;
4931 case kRegTypePosShort: /* 15-bit unsigned value */
4932 if (shift_count >= 8)
4933 new_type = kRegTypePosByte;
4934 break;
4935 case kRegTypeChar: /* 16-bit unsigned value */
4936 if (shift_count > 8)
4937 new_type = kRegTypePosByte;
4938 break;
4939 case kRegTypeByte: /* 8-bit signed value */
4940 /* defaults (u=kRegTypeInteger / s=src_type) are correct */
4941 break;
4942 case kRegTypePosByte: /* 7-bit unsigned value */
4943 /* always use new_type=src_type */
4944 new_type = src_type;
4945 break;
4946 case kRegTypeZero: /* 1-bit unsigned value */
4947 case kRegTypeOne:
4948 case kRegTypeBoolean:
4949 /* unnecessary? */
4950 new_type = kRegTypeZero;
4951 break;
4952 default:
4953 /* long, double, references; shouldn't be here! */
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07004954 DCHECK(false);
jeffhaobdb76512011-09-07 11:43:16 -07004955 break;
4956 }
4957
4958 return new_type;
4959}
4960
4961void DexVerifier::VerifyFilledNewArrayRegs(const Method* method,
4962 RegisterLine* register_line,
4963 const Instruction::DecodedInstruction* dec_insn, Class* res_class,
4964 bool is_range, VerifyError* failure) {
4965 uint32_t arg_count = dec_insn->vA_;
4966 RegType expected_type;
4967 Class::PrimitiveType elem_type;
4968 unsigned int ui;
4969
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07004970 DCHECK(res_class->IsArrayClass()) << PrettyClass(res_class);
jeffhaobdb76512011-09-07 11:43:16 -07004971 elem_type = res_class->GetComponentType()->GetPrimitiveType();
4972 if (elem_type == Class::kPrimNot) {
4973 expected_type = RegTypeFromClass(res_class->GetComponentType());
4974 } else {
4975 expected_type = PrimitiveTypeToRegType(elem_type);
4976 }
4977
4978 /*
jeffhaod1f0fde2011-09-08 17:25:33 -07004979 * Verify each register. If "arg_count" is bad, VerifyRegisterType()
4980 * will run off the end of the list and fail. It's legal, if silly,
jeffhaobdb76512011-09-07 11:43:16 -07004981 * for arg_count to be zero.
4982 */
4983 for (ui = 0; ui < arg_count; ui++) {
4984 uint32_t get_reg;
4985
4986 if (is_range)
4987 get_reg = dec_insn->vC_ + ui;
4988 else
4989 get_reg = dec_insn->arg_[ui];
4990
4991 VerifyRegisterType(register_line, get_reg, expected_type, failure);
4992 if (*failure != VERIFY_ERROR_NONE) {
4993 LOG(ERROR) << "VFY: filled-new-array arg " << ui << "(" << get_reg
4994 << ") not valid";
4995 return;
4996 }
4997 }
4998}
4999
5000bool DexVerifier::IsCorrectInvokeKind(MethodType method_type,
5001 Method* res_method) {
5002 switch (method_type) {
5003 case METHOD_DIRECT:
5004 return res_method->IsDirect();
5005 case METHOD_STATIC:
5006 return res_method->IsStatic();
5007 case METHOD_VIRTUAL:
5008 case METHOD_INTERFACE:
5009 return !res_method->IsDirect();
5010 default:
5011 return false;
5012 }
5013}
5014
5015Method* DexVerifier::VerifyInvocationArgs(VerifierData* vdata,
5016 RegisterLine* register_line, const int insn_reg_count,
5017 const Instruction::DecodedInstruction* dec_insn, MethodType method_type,
5018 bool is_range, bool is_super, VerifyError* failure) {
5019 Method* method = vdata->method_;
5020 const DexFile* dex_file = vdata->dex_file_;
5021 const DexFile::CodeItem* code_item = vdata->code_item_;
Elliott Hughes5fe594f2011-09-08 12:33:17 -07005022 UninitInstanceMap* uninit_map = vdata->uninit_map_.get();
jeffhaobdb76512011-09-07 11:43:16 -07005023
5024 Method* res_method;
5025 std::string sig;
5026 size_t sig_offset;
5027 int expected_args;
5028 int actual_args;
5029
5030 /*
jeffhaod1f0fde2011-09-08 17:25:33 -07005031 * Resolve the method. This could be an abstract or concrete method
jeffhaobdb76512011-09-07 11:43:16 -07005032 * depending on what sort of call we're making.
5033 */
jeffhaob4df5142011-09-19 20:25:32 -07005034 res_method = ResolveMethodAndCheckAccess(dex_file, dec_insn->vB_, method->GetDeclaringClass(),
5035 failure, (method_type == METHOD_DIRECT || method_type == METHOD_STATIC));
jeffhaobdb76512011-09-07 11:43:16 -07005036
jeffhaobdb76512011-09-07 11:43:16 -07005037 if (res_method == NULL) {
jeffhao98eacac2011-09-14 16:11:53 -07005038 const DexFile::MethodId& method_id = dex_file->GetMethodId(dec_insn->vB_);
5039 const char* method_name = dex_file->GetMethodName(method_id);
5040 const char* method_proto = dex_file->GetMethodPrototype(method_id);
5041 const char* class_descriptor = dex_file->GetMethodClassDescriptor(method_id);
5042
5043 LOG(ERROR) << "VFY: unable to resolve method " << dec_insn->vB_ << ": "
5044 << class_descriptor << "." << method_name << " " << method_proto;
jeffhaobdb76512011-09-07 11:43:16 -07005045 *failure = VERIFY_ERROR_NO_METHOD;
5046 return NULL;
5047 }
jeffhaobdb76512011-09-07 11:43:16 -07005048
5049 /*
5050 * Only time you can explicitly call a method starting with '<' is when
jeffhaod1f0fde2011-09-08 17:25:33 -07005051 * making a "direct" invocation on "<init>". There are additional
jeffhaobdb76512011-09-07 11:43:16 -07005052 * restrictions but we don't enforce them here.
5053 */
5054 if (res_method->GetName()->Equals("<init>")) {
5055 if (method_type != METHOD_DIRECT || !IsInitMethod(res_method)) {
5056 LOG(ERROR) << "VFY: invalid call to "
jeffhao98eacac2011-09-14 16:11:53 -07005057 << res_method->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8()
jeffhaobdb76512011-09-07 11:43:16 -07005058 << "." << res_method->GetName();
5059 goto bad_sig;
5060 }
5061 }
5062
5063 /*
5064 * See if the method type implied by the invoke instruction matches the
5065 * access flags for the target method.
5066 */
5067 if (!IsCorrectInvokeKind(method_type, res_method)) {
5068 LOG(ERROR) << "VFY: invoke type does not match method type of "
jeffhao98eacac2011-09-14 16:11:53 -07005069 << res_method->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8()
jeffhaobdb76512011-09-07 11:43:16 -07005070 << "." << res_method->GetName()->ToModifiedUtf8();
5071
5072 *failure = VERIFY_ERROR_GENERIC;
5073 return NULL;
5074 }
5075
5076 /*
5077 * If we're using invoke-super(method), make sure that the executing
5078 * method's class' superclass has a vtable entry for the target method.
5079 */
5080 if (is_super) {
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07005081 DCHECK(method_type == METHOD_VIRTUAL);
jeffhaobdb76512011-09-07 11:43:16 -07005082 Class* super = method->GetDeclaringClass()->GetSuperClass();
5083 if (super == NULL || res_method->GetMethodIndex() > super->GetVTable()->GetLength()) {
5084 if (super == NULL) {
5085 LOG(ERROR) << "VFY: invalid invoke-super from "
5086 << method->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8()
5087 << "." << method->GetName()->ToModifiedUtf8() << " to super -."
5088 << res_method->GetName()->ToModifiedUtf8()
5089 << " " << res_method->GetSignature()->ToModifiedUtf8();
5090 } else {
5091 LOG(ERROR) << "VFY: invalid invoke-super from "
5092 << method->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8()
5093 << "." << method->GetName()->ToModifiedUtf8() << " to super "
5094 << super->GetDescriptor()->ToModifiedUtf8()
5095 << "." << res_method->GetName()->ToModifiedUtf8()
5096 << " " << res_method->GetSignature()->ToModifiedUtf8();
5097 }
5098 *failure = VERIFY_ERROR_NO_METHOD;
5099 return NULL;
5100 }
5101 }
5102
5103 /*
5104 * We use vAA as our expected arg count, rather than res_method->insSize,
jeffhaod1f0fde2011-09-08 17:25:33 -07005105 * because we need to match the call to the signature. Also, we might
jeffhaobdb76512011-09-07 11:43:16 -07005106 * might be calling through an abstract method definition (which doesn't
5107 * have register count values).
5108 */
5109 expected_args = dec_insn->vA_;
5110 actual_args = 0;
5111
5112 /* caught by static verifier */
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07005113 DCHECK(is_range || expected_args <= 5);
jeffhaobdb76512011-09-07 11:43:16 -07005114
5115 if (expected_args > code_item->outs_size_) {
5116 LOG(ERROR) << "VFY: invalid arg count (" << expected_args
5117 << ") exceeds outsSize (" << code_item->outs_size_ << ")";
5118 *failure = VERIFY_ERROR_GENERIC;
5119 return NULL;
5120 }
5121
5122 sig = res_method->GetSignature()->ToModifiedUtf8();
5123 if (sig[0] != '(') {
5124 LOG(ERROR) << "VFY: descriptor doesn't start with '(': " << sig;
5125 goto bad_sig;
5126 }
5127
5128 /*
5129 * Check the "this" argument, which must be an instance of the class
jeffhaod1f0fde2011-09-08 17:25:33 -07005130 * that declared the method. For an interface class, we don't do the
jeffhaobdb76512011-09-07 11:43:16 -07005131 * full interface merge, so we can't do a rigorous check here (which
5132 * is okay since we have to do it at runtime).
5133 */
5134 if (!res_method->IsStatic()) {
5135 Class* actual_this_ref;
5136 RegType actual_arg_type;
5137
5138 actual_arg_type = GetInvocationThis(register_line, dec_insn, failure);
5139 if (*failure != VERIFY_ERROR_NONE)
5140 return NULL;
5141
5142 if (RegTypeIsUninitReference(actual_arg_type) &&
5143 !res_method->GetName()->Equals("<init>")) {
5144 LOG(ERROR) << "VFY: 'this' arg must be initialized";
5145 *failure = VERIFY_ERROR_GENERIC;
5146 return NULL;
5147 }
5148 if (method_type != METHOD_INTERFACE && actual_arg_type != kRegTypeZero) {
5149 actual_this_ref = RegTypeReferenceToClass(actual_arg_type, uninit_map);
5150 if (!res_method->GetDeclaringClass()->IsAssignableFrom(actual_this_ref)) {
5151 LOG(ERROR) << "VFY: 'this' arg '"
5152 << actual_this_ref->GetDescriptor()->ToModifiedUtf8()
5153 << "' not instance of '"
5154 << res_method->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8()
5155 << "'";
5156 *failure = VERIFY_ERROR_GENERIC;
5157 return NULL;
5158 }
5159 }
5160 actual_args++;
5161 }
5162
5163 /*
jeffhaod1f0fde2011-09-08 17:25:33 -07005164 * Process the target method's signature. This signature may or may not
jeffhaobdb76512011-09-07 11:43:16 -07005165 * have been verified, so we can't assume it's properly formed.
5166 */
5167 for (sig_offset = 1; sig_offset < sig.size(); sig_offset++) {
jeffhaobdb76512011-09-07 11:43:16 -07005168 if (sig[sig_offset] == ')')
5169 break;
5170
5171 if (actual_args >= expected_args) {
5172 LOG(ERROR) << "VFY: expected " << expected_args << " args, found more ("
5173 << sig.substr(sig_offset) << ")";
5174 goto bad_sig;
5175 }
5176
5177 uint32_t get_reg;
5178 if (is_range)
5179 get_reg = dec_insn->vC_ + actual_args;
5180 else
5181 get_reg = dec_insn->arg_[actual_args];
5182
5183 switch (sig[sig_offset]) {
5184 case 'L':
5185 {
5186 Class* klass = LookupSignatureClass(method, sig.substr(sig_offset),
5187 failure);
5188 if (*failure != VERIFY_ERROR_NONE)
5189 goto bad_sig;
5190 VerifyRegisterType(register_line, get_reg, RegTypeFromClass(klass),
5191 failure);
5192 if (*failure != VERIFY_ERROR_NONE) {
5193 LOG(ERROR) << "VFY: bad arg " << actual_args << " (into "
5194 << klass->GetDescriptor()->ToModifiedUtf8() << ")";
5195 goto bad_sig;
5196 }
5197 sig_offset += sig.substr(sig_offset).find(';');
5198 }
5199 actual_args++;
5200 break;
5201 case '[':
5202 {
5203 Class* klass = LookupSignatureArrayClass(method,
5204 sig.substr(sig_offset), failure);
5205 if (*failure != VERIFY_ERROR_NONE)
5206 goto bad_sig;
5207 VerifyRegisterType(register_line, get_reg, RegTypeFromClass(klass),
5208 failure);
5209 if (*failure != VERIFY_ERROR_NONE) {
5210 LOG(ERROR) << "VFY: bad arg " << actual_args << " (into "
5211 << klass->GetDescriptor()->ToModifiedUtf8() << ")";
5212 goto bad_sig;
5213 }
5214 while (sig[sig_offset] == '[')
5215 sig_offset++;
5216 if (sig[sig_offset] == 'L')
5217 sig_offset += sig.substr(sig_offset).find(';');
5218 }
5219 actual_args++;
5220 break;
5221 case 'Z':
5222 VerifyRegisterType(register_line, get_reg, kRegTypeBoolean, failure);
5223 actual_args++;
5224 break;
5225 case 'C':
5226 VerifyRegisterType(register_line, get_reg, kRegTypeChar, failure);
5227 actual_args++;
5228 break;
5229 case 'B':
5230 VerifyRegisterType(register_line, get_reg, kRegTypeByte, failure);
5231 actual_args++;
5232 break;
5233 case 'I':
5234 VerifyRegisterType(register_line, get_reg, kRegTypeInteger, failure);
5235 actual_args++;
5236 break;
5237 case 'S':
5238 VerifyRegisterType(register_line, get_reg, kRegTypeShort, failure);
5239 actual_args++;
5240 break;
5241 case 'F':
5242 VerifyRegisterType(register_line, get_reg, kRegTypeFloat, failure);
5243 actual_args++;
5244 break;
5245 case 'D':
5246 VerifyRegisterType(register_line, get_reg, kRegTypeDoubleLo, failure);
5247 actual_args += 2;
5248 break;
5249 case 'J':
5250 VerifyRegisterType(register_line, get_reg, kRegTypeLongLo, failure);
5251 actual_args += 2;
5252 break;
5253 default:
5254 LOG(ERROR) << "VFY: invocation target: bad signature type char '"
5255 << sig << "'";
5256 goto bad_sig;
5257 }
5258 }
5259 if (sig[sig_offset] != ')') {
5260 LOG(ERROR) << "VFY: invocation target: bad signature '"
5261 << res_method->GetSignature()->ToModifiedUtf8() << "'";
5262 goto bad_sig;
5263 }
5264
5265 if (actual_args != expected_args) {
5266 LOG(ERROR) << "VFY: expected " << expected_args << " args, found "
5267 << actual_args;
5268 goto bad_sig;
5269 }
5270
5271 return res_method;
5272
5273bad_sig:
5274 if (res_method != NULL) {
5275 LOG(ERROR) << "VFY: rejecting call to "
5276 << res_method->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8()
5277 << "." << res_method->GetName()->ToModifiedUtf8() << " "
5278 << res_method->GetSignature()->ToModifiedUtf8();
5279 }
5280
5281 if (*failure == VERIFY_ERROR_NONE)
5282 *failure = VERIFY_ERROR_GENERIC;
5283 return NULL;
5284}
jeffhaoba5ebb92011-08-25 17:24:37 -07005285
jeffhaod1f0fde2011-09-08 17:25:33 -07005286DexVerifier::RegisterMap* DexVerifier::GenerateRegisterMapV(VerifierData* vdata)
5287{
5288 const DexFile::CodeItem* code_item = vdata->code_item_;
5289 int i, bytes_for_addr, gc_point_count;
5290
5291 if (code_item->registers_size_ >= 2048) {
5292 LOG(ERROR) << "ERROR: register map can't handle "
5293 << code_item->registers_size_ << " registers";
5294 return NULL;
5295 }
5296 uint8_t reg_width = (code_item->registers_size_ + 7) / 8;
5297
5298 /*
5299 * Decide if we need 8 or 16 bits to hold the address. Strictly speaking
5300 * we only need 16 bits if we actually encode an address >= 256 -- if
5301 * the method has a section at the end without GC points (e.g. array
5302 * data) we don't need to count it. The situation is unusual, and
5303 * detecting it requires scanning the entire method, so we don't bother.
5304 */
5305 RegisterMapFormat format;
5306 if (code_item->insns_size_ < 256) {
5307 format = kRegMapFormatCompact8;
5308 bytes_for_addr = 1;
5309 } else {
5310 format = kRegMapFormatCompact16;
5311 bytes_for_addr = 2;
5312 }
5313
5314 /*
5315 * Count up the number of GC point instructions.
5316 *
5317 * NOTE: this does not automatically include the first instruction,
5318 * since we don't count method entry as a GC point.
5319 */
5320 gc_point_count = 0;
5321 for (i = 0; i < (int) code_item->insns_size_; i++) {
5322 if (InsnIsGcPoint(vdata->insn_flags_.get(), i))
5323 gc_point_count++;
5324 }
5325 if (gc_point_count >= 65536) {
5326 /* We could handle this, but in practice we don't get near this. */
5327 LOG(ERROR) << "ERROR: register map can't handle " << gc_point_count
5328 << " gc points in one method";
5329 return NULL;
5330 }
5331
5332 /* Calculate size of buffer to hold the map data. */
5333 uint32_t data_size = gc_point_count * (bytes_for_addr + reg_width);
5334
5335 RegisterMap* map = new RegisterMap(format, reg_width, gc_point_count,
jeffhaoa0a764a2011-09-16 10:43:38 -07005336 data_size);
jeffhaod1f0fde2011-09-08 17:25:33 -07005337
5338 /* Populate it. */
jeffhaoe23d93c2011-09-15 14:48:43 -07005339 uint8_t* map_data = map->data_;
jeffhaod1f0fde2011-09-08 17:25:33 -07005340 for (i = 0; i < (int) vdata->code_item_->insns_size_; i++) {
5341 if (InsnIsGcPoint(vdata->insn_flags_.get(), i)) {
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07005342 DCHECK(vdata->register_lines_[i].reg_types_.get() != NULL);
jeffhaod1f0fde2011-09-08 17:25:33 -07005343 if (format == kRegMapFormatCompact8) {
5344 *map_data++ = i;
5345 } else /*kRegMapFormatCompact16*/ {
5346 *map_data++ = i & 0xff;
5347 *map_data++ = i >> 8;
5348 }
5349 OutputTypeVector(vdata->register_lines_[i].reg_types_.get(),
5350 code_item->registers_size_, map_data);
5351 map_data += reg_width;
5352 }
5353 }
5354
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07005355 DCHECK_EQ((uint32_t) map_data - (uint32_t) map->data_, data_size);
jeffhaod1f0fde2011-09-08 17:25:33 -07005356
5357 // TODO: Remove this check when it's really running...
5358#if 1
5359 if (!VerifyMap(vdata, map)) {
5360 LOG(ERROR) << "Map failed to verify";
5361 return NULL;
5362 }
5363#endif
5364
5365 /* Try to compress the map. */
5366 RegisterMap* compress_map = CompressMapDifferential(map);
5367 if (compress_map != NULL) {
5368 // TODO: Remove this check when it's really running...
5369#if 1
5370 /*
5371 * Expand the compressed map we just created, and compare it
5372 * to the original. Abort the VM if it doesn't match up.
5373 */
5374 UniquePtr<RegisterMap> uncompressed_map(UncompressMapDifferential(compress_map));
5375 if (uncompressed_map.get() == NULL) {
5376 LOG(ERROR) << "Map failed to uncompress - "
5377 << vdata->method_->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8()
5378 << "." << vdata->method_->GetName()->ToModifiedUtf8();
5379 delete map;
5380 delete compress_map;
5381 /* bad - compression is broken or we're out of memory */
5382 return NULL;
5383 } else {
5384 if (!CompareMaps(map, uncompressed_map.get())) {
5385 LOG(ERROR) << "Map comparison failed - "
5386 << vdata->method_->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8()
5387 << "." << vdata->method_->GetName()->ToModifiedUtf8();
5388 delete map;
5389 delete compress_map;
5390 /* bad - compression is broken */
5391 return NULL;
5392 }
5393 }
5394#endif
5395 delete map;
5396 map = compress_map;
5397 }
5398
5399 return map;
5400}
5401
jeffhaoa0a764a2011-09-16 10:43:38 -07005402DexVerifier::RegisterMap* DexVerifier::GetExpandedRegisterMapHelper(
5403 Method* method, RegisterMap* map) {
5404 RegisterMap* new_map;
5405
5406 if (map == NULL)
5407 return NULL;
5408
5409 /* TODO: sanity check to ensure this isn't called w/o external locking */
5410
5411 uint8_t format = map->header_->format_;
5412 switch (format) {
5413 case kRegMapFormatCompact8:
5414 case kRegMapFormatCompact16:
5415 /* already expanded */
5416 return map;
5417 case kRegMapFormatDifferential:
5418 new_map = UncompressMapDifferential(map);
5419 break;
5420 default:
5421 LOG(ERROR) << "Unknown format " << format
5422 << " in dvmGetExpandedRegisterMap";
5423 return NULL;
5424 }
5425
5426 if (new_map == NULL) {
5427 LOG(ERROR) << "Map failed to uncompress (fmt=" << format << ") "
5428 << method->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8()
5429 << "." << method->GetName();
5430 return NULL;
5431 }
5432
5433 /* Update method, and free compressed map if it was sitting on the heap. */
5434 ByteArray* header = ByteArray::Alloc(sizeof(RegisterMapHeader));
5435 ByteArray* data = ByteArray::Alloc(ComputeRegisterMapSize(map));
5436
5437 memcpy(header->GetData(), map->header_, sizeof(RegisterMapHeader));
5438 memcpy(data->GetData(), map->data_, ComputeRegisterMapSize(map));
5439
5440 method->SetRegisterMapHeader(header);
5441 method->SetRegisterMapData(data);
5442
5443 delete map;
5444 return new_map;
5445}
5446
5447const uint8_t* DexVerifier::RegisterMapGetLine(const RegisterMap* map, int addr) {
5448 int addr_width, line_width;
5449 uint8_t format = map->header_->format_;
5450 uint16_t num_entries = map->header_->num_entries_;
5451
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07005452 DCHECK_GT(num_entries, 0);
jeffhaoa0a764a2011-09-16 10:43:38 -07005453
5454 switch (format) {
5455 case kRegMapFormatNone:
5456 return NULL;
5457 case kRegMapFormatCompact8:
5458 addr_width = 1;
5459 break;
5460 case kRegMapFormatCompact16:
5461 addr_width = 2;
5462 break;
5463 default:
5464 LOG(ERROR) << "Unknown format " << format;
5465 return NULL;
5466 }
5467
5468 line_width = addr_width + map->header_->reg_width_;
5469
5470 /*
5471 * Find the appropriate entry. Many maps are very small, some are very large.
5472 */
5473 static const int kSearchThreshold = 8;
5474 const uint8_t* data = NULL;
5475 int line_addr;
5476
5477 if (num_entries < kSearchThreshold) {
5478 int i;
5479 data = map->data_;
5480 for (i = num_entries; i > 0; i--) {
5481 line_addr = data[0];
5482 if (addr_width > 1)
5483 line_addr |= data[1] << 8;
5484 if (line_addr == addr)
5485 return data + addr_width;
5486
5487 data += line_width;
5488 }
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07005489 DCHECK_EQ(data, map->data_ + line_width * num_entries);
jeffhaoa0a764a2011-09-16 10:43:38 -07005490 } else {
5491 int hi, lo, mid;
5492
5493 lo = 0;
5494 hi = num_entries -1;
5495
5496 while (hi >= lo) {
5497 mid = (hi + lo) / 2;
5498 data = map->data_ + line_width * mid;
5499
5500 line_addr = data[0];
5501 if (addr_width > 1)
5502 line_addr |= data[1] << 8;
5503
5504 if (addr > line_addr) {
5505 lo = mid + 1;
5506 } else if (addr < line_addr) {
5507 hi = mid - 1;
5508 } else {
5509 return data + addr_width;
5510 }
5511 }
5512 }
5513
5514 return NULL;
5515}
5516
jeffhaod1f0fde2011-09-08 17:25:33 -07005517void DexVerifier::OutputTypeVector(const RegType* regs, int insn_reg_count,
5518 uint8_t* data) {
5519 uint8_t val = 0;
5520 int i;
5521
5522 for (i = 0; i < insn_reg_count; i++) {
5523 RegType type = *regs++;
5524 val >>= 1;
5525 if (IsReferenceType(type))
5526 val |= 0x80; /* set hi bit */
5527
5528 if ((i & 0x07) == 7)
5529 *data++ = val;
5530 }
5531 if ((i & 0x07) != 0) {
5532 /* Flush bits from last byte. */
5533 val >>= 8 - (i & 0x07);
5534 *data++ = val;
5535 }
5536}
5537
5538bool DexVerifier::VerifyMap(VerifierData* vdata, const RegisterMap* map) {
jeffhaoe23d93c2011-09-15 14:48:43 -07005539 const uint8_t* raw_map = map->data_;
5540 uint8_t format = map->header_->format_;
5541 const int num_entries = map->header_->num_entries_;
jeffhaod1f0fde2011-09-08 17:25:33 -07005542 int ent;
5543
jeffhaoe23d93c2011-09-15 14:48:43 -07005544 if ((vdata->code_item_->registers_size_ + 7) / 8 != map->header_->reg_width_) {
jeffhaod1f0fde2011-09-08 17:25:33 -07005545 LOG(ERROR) << "GLITCH: registersSize=" << vdata->code_item_->registers_size_
jeffhaoe23d93c2011-09-15 14:48:43 -07005546 << ", reg_width=" << map->header_->reg_width_;
jeffhaod1f0fde2011-09-08 17:25:33 -07005547 return false;
5548 }
5549
5550 for (ent = 0; ent < num_entries; ent++) {
5551 int addr;
5552
5553 switch (format) {
5554 case kRegMapFormatCompact8:
5555 addr = *raw_map++;
5556 break;
5557 case kRegMapFormatCompact16:
5558 addr = *raw_map++;
5559 addr |= (*raw_map++) << 8;
5560 break;
5561 default:
5562 LOG(FATAL) << "GLITCH: bad format (" << format << ")";
5563 return false;
5564 }
5565
5566 const RegType* regs = vdata->register_lines_[addr].reg_types_.get();
5567 if (regs == NULL) {
5568 LOG(ERROR) << "GLITCH: addr " << addr << " has no data";
5569 return false;
5570 }
5571
5572 uint8_t val = 0;
5573 int i;
5574
5575 for (i = 0; i < vdata->code_item_->registers_size_; i++) {
5576 bool bit_is_ref, reg_is_ref;
5577
5578 val >>= 1;
5579 if ((i & 0x07) == 0) {
5580 /* Load next byte of data. */
5581 val = *raw_map++;
5582 }
5583
5584 bit_is_ref = val & 0x01;
5585
5586 RegType type = regs[i];
5587 reg_is_ref = IsReferenceType(type);
5588
5589 if (bit_is_ref != reg_is_ref) {
5590 LOG(ERROR) << "GLITCH: addr " << addr << " reg " << i << ": bit="
5591 << bit_is_ref << " reg=" << reg_is_ref << "(" << type << ")";
5592 return false;
5593 }
5594 }
5595 /* Raw_map now points to the address field of the next entry. */
5596 }
5597
5598 return true;
5599}
5600
5601bool DexVerifier::CompareMaps(const RegisterMap* map1, const RegisterMap* map2)
5602{
5603 size_t size1, size2;
5604
5605 size1 = ComputeRegisterMapSize(map1);
5606 size2 = ComputeRegisterMapSize(map2);
5607 if (size1 != size2) {
5608 LOG(ERROR) << "CompareMaps: size mismatch (" << size1 << " vs " << size2
5609 << ")";
5610 return false;
5611 }
5612
jeffhaoe23d93c2011-09-15 14:48:43 -07005613 if (map1->header_->format_ != map2->header_->format_ ||
5614 map1->header_->reg_width_ != map2->header_->reg_width_ ||
jeffhaoa0a764a2011-09-16 10:43:38 -07005615 map1->header_->num_entries_ != map2->header_->num_entries_) {
jeffhaod1f0fde2011-09-08 17:25:33 -07005616 LOG(ERROR) << "CompareMaps: fields mismatch";
5617 }
jeffhaoe23d93c2011-09-15 14:48:43 -07005618 if (memcmp(map1->data_, map2->data_, size1) != 0) {
jeffhaod1f0fde2011-09-08 17:25:33 -07005619 LOG(ERROR) << "CompareMaps: data mismatch";
5620 return false;
5621 }
5622
5623 return true;
5624}
5625
5626size_t DexVerifier::ComputeRegisterMapSize(const RegisterMap* map) {
jeffhaoe23d93c2011-09-15 14:48:43 -07005627 uint8_t format = map->header_->format_;
5628 uint16_t num_entries = map->header_->num_entries_;
jeffhaod1f0fde2011-09-08 17:25:33 -07005629
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07005630 DCHECK(map != NULL);
jeffhaod1f0fde2011-09-08 17:25:33 -07005631
5632 switch (format) {
5633 case kRegMapFormatNone:
5634 return 1;
5635 case kRegMapFormatCompact8:
jeffhaoe23d93c2011-09-15 14:48:43 -07005636 return (1 + map->header_->reg_width_) * num_entries;
jeffhaod1f0fde2011-09-08 17:25:33 -07005637 case kRegMapFormatCompact16:
jeffhaoe23d93c2011-09-15 14:48:43 -07005638 return (2 + map->header_->reg_width_) * num_entries;
jeffhaod1f0fde2011-09-08 17:25:33 -07005639 case kRegMapFormatDifferential:
5640 {
5641 /* Decoded ULEB128 length. */
jeffhaoe23d93c2011-09-15 14:48:43 -07005642 const uint8_t* ptr = map->data_;
jeffhaod1f0fde2011-09-08 17:25:33 -07005643 return DecodeUnsignedLeb128(&ptr);
5644 }
5645 default:
5646 LOG(FATAL) << "Bad register map format " << format;
5647 return 0;
5648 }
5649}
5650
5651int DexVerifier::ComputeBitDiff(const uint8_t* bits1, const uint8_t* bits2,
5652 int byte_width, int* first_bit_changed_ptr, int* num_bits_changed_ptr,
5653 uint8_t* leb_out_buf) {
5654 int num_bits_changed = 0;
5655 int first_bit_changed = -1;
5656 int leb_size = 0;
5657 int byte_num;
5658
5659 /*
5660 * Run through the vectors, first comparing them at the byte level. This
5661 * will yield a fairly quick result if nothing has changed between them.
5662 */
5663 for (byte_num = 0; byte_num < byte_width; byte_num++) {
5664 uint8_t byte1 = *bits1++;
5665 uint8_t byte2 = *bits2++;
5666 if (byte1 != byte2) {
5667 /* Walk through the byte, identifying the changed bits. */
5668 int bit_num;
5669 for (bit_num = 0; bit_num < 8; bit_num++) {
5670 if (((byte1 >> bit_num) & 0x01) != ((byte2 >> bit_num) & 0x01)) {
5671 int bit_offset = (byte_num << 3) + bit_num;
5672
5673 if (first_bit_changed < 0)
5674 first_bit_changed = bit_offset;
5675 num_bits_changed++;
5676
5677 if (leb_out_buf == NULL) {
5678 leb_size += UnsignedLeb128Size(bit_offset);
5679 } else {
5680 uint8_t* cur_buf = leb_out_buf;
5681 leb_out_buf = WriteUnsignedLeb128(leb_out_buf, bit_offset);
5682 leb_size += leb_out_buf - cur_buf;
5683 }
5684 }
5685 }
5686 }
5687 }
5688
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07005689 if (num_bits_changed > 0) {
5690 DCHECK_GE(first_bit_changed, 0);
5691 }
jeffhaod1f0fde2011-09-08 17:25:33 -07005692
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07005693 if (first_bit_changed_ptr != NULL) {
jeffhaod1f0fde2011-09-08 17:25:33 -07005694 *first_bit_changed_ptr = first_bit_changed;
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07005695 }
5696
5697 if (num_bits_changed_ptr != NULL) {
jeffhaod1f0fde2011-09-08 17:25:33 -07005698 *num_bits_changed_ptr = num_bits_changed;
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07005699 }
jeffhaod1f0fde2011-09-08 17:25:33 -07005700
5701 return leb_size;
5702}
5703
5704DexVerifier::RegisterMap* DexVerifier::CompressMapDifferential(
5705 const RegisterMap* map) {
5706 int orig_size = ComputeRegisterMapSize(map);
5707 uint8_t* tmp_ptr;
5708 int addr_width;
5709
jeffhaoe23d93c2011-09-15 14:48:43 -07005710 uint8_t format = map->header_->format_;
jeffhaod1f0fde2011-09-08 17:25:33 -07005711 switch (format) {
5712 case kRegMapFormatCompact8:
5713 addr_width = 1;
5714 break;
5715 case kRegMapFormatCompact16:
5716 addr_width = 2;
5717 break;
5718 default:
5719 LOG(ERROR) << "ERROR: can't compress map with format=" << format;
5720 return NULL;
5721 }
5722
jeffhaoe23d93c2011-09-15 14:48:43 -07005723 int reg_width = map->header_->reg_width_;
5724 int num_entries = map->header_->num_entries_;
jeffhaod1f0fde2011-09-08 17:25:33 -07005725
5726 if (num_entries <= 1) {
5727 return NULL;
5728 }
5729
5730 /*
5731 * We don't know how large the compressed data will be. It's possible
5732 * for it to expand and become larger than the original. The header
5733 * itself is variable-sized, so we generate everything into a temporary
5734 * buffer and then copy it to form-fitting storage once we know how big
5735 * it will be (and that it's smaller than the original).
5736 *
5737 * If we use a size that is equal to the size of the input map plus
5738 * a value longer than a single entry can possibly expand to, we need
5739 * only check for overflow at the end of each entry. The worst case
5740 * for a single line is (1 + <ULEB8 address> + <full copy of vector>).
5741 * Addresses are 16 bits, so that's (1 + 3 + reg_width).
5742 *
5743 * The initial address offset and bit vector will take up less than
5744 * or equal to the amount of space required when uncompressed -- large
5745 * initial offsets are rejected.
5746 */
5747 UniquePtr<uint8_t[]> tmp_buf(new uint8_t[orig_size + (1 + 3 + reg_width)]);
5748
5749 tmp_ptr = tmp_buf.get();
5750
jeffhaoe23d93c2011-09-15 14:48:43 -07005751 const uint8_t* map_data = map->data_;
jeffhaod1f0fde2011-09-08 17:25:33 -07005752 const uint8_t* prev_bits;
5753 uint16_t addr, prev_addr;
5754
5755 addr = *map_data++;
5756 if (addr_width > 1)
5757 addr |= (*map_data++) << 8;
5758
5759 if (addr >= 128) {
5760 LOG(ERROR) << "Can't compress map with starting address >= 128";
5761 return NULL;
5762 }
5763
5764 /*
5765 * Start by writing the initial address and bit vector data. The high
5766 * bit of the initial address is used to indicate the required address
5767 * width (which the decoder can't otherwise determine without parsing
5768 * the compressed data).
5769 */
5770 *tmp_ptr++ = addr | (addr_width > 1 ? 0x80 : 0x00);
5771 memcpy(tmp_ptr, map_data, reg_width);
5772
5773 prev_bits = map_data;
5774 prev_addr = addr;
5775
5776 tmp_ptr += reg_width;
5777 map_data += reg_width;
5778
5779 /* Loop over all following entries. */
5780 for (int entry = 1; entry < num_entries; entry++) {
5781 int addr_diff;
5782 uint8_t key;
5783
5784 /* Pull out the address and figure out how to encode it. */
5785 addr = *map_data++;
5786 if (addr_width > 1)
5787 addr |= (*map_data++) << 8;
5788
5789 addr_diff = addr - prev_addr;
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07005790 DCHECK_GT(addr_diff, 0);
jeffhaod1f0fde2011-09-08 17:25:33 -07005791 if (addr_diff < 8) {
5792 /* Small difference, encode in 3 bits. */
5793 key = addr_diff -1; /* set 00000AAA */
5794 } else {
5795 /* Large difference, output escape code. */
5796 key = 0x07; /* escape code for AAA */
5797 }
5798
5799 int num_bits_changed, first_bit_changed, leb_size;
5800
5801 leb_size = ComputeBitDiff(prev_bits, map_data, reg_width,
5802 &first_bit_changed, &num_bits_changed, NULL);
5803
5804 if (num_bits_changed == 0) {
5805 /* set B to 1 and CCCC to zero to indicate no bits were changed */
5806 key |= 0x08;
5807 } else if (num_bits_changed == 1 && first_bit_changed < 16) {
5808 /* set B to 0 and CCCC to the index of the changed bit */
5809 key |= first_bit_changed << 4;
5810 } else if (num_bits_changed < 15 && leb_size < reg_width) {
5811 /* set B to 1 and CCCC to the number of bits */
5812 key |= 0x08 | (num_bits_changed << 4);
5813 } else {
5814 /* set B to 1 and CCCC to 0x0f so we store the entire vector */
5815 key |= 0x08 | 0xf0;
5816 }
5817
5818 /*
5819 * Encode output. Start with the key, follow with the address
5820 * diff (if it didn't fit in 3 bits), then the changed bit info.
5821 */
5822 *tmp_ptr++ = key;
5823 if ((key & 0x07) == 0x07)
5824 tmp_ptr = WriteUnsignedLeb128(tmp_ptr, addr_diff);
5825
5826 if ((key & 0x08) != 0) {
5827 int bit_count = key >> 4;
5828 if (bit_count == 0) {
5829 /* nothing changed, no additional output required */
5830 } else if (bit_count == 15) {
5831 /* full vector is most compact representation */
5832 memcpy(tmp_ptr, map_data, reg_width);
5833 tmp_ptr += reg_width;
5834 } else {
5835 /* write bit indices in ULEB128 format */
5836 (void) ComputeBitDiff(prev_bits, map_data, reg_width,
5837 NULL, NULL, tmp_ptr);
5838 tmp_ptr += leb_size;
5839 }
5840 } else {
5841 /* single-bit changed, value encoded in key byte */
5842 }
5843
5844 prev_bits = map_data;
5845 prev_addr = addr;
5846 map_data += reg_width;
5847
5848 /* See if we've run past the original size. */
5849 if (tmp_ptr - tmp_buf.get() >= orig_size) {
5850 return NULL;
5851 }
5852 }
5853
5854 /*
5855 * Create a RegisterMap with the contents.
5856 *
5857 * TODO: consider using a threshold other than merely ">=". We would
5858 * get poorer compression but potentially use less native heap space.
5859 */
5860 int new_data_size = tmp_ptr - tmp_buf.get();
5861 int new_map_size = new_data_size + UnsignedLeb128Size(new_data_size);
5862
5863 if (new_map_size >= orig_size) {
5864 return NULL;
5865 }
5866
5867 RegisterMap* new_map = new RegisterMap(kRegMapFormatDifferential, reg_width,
jeffhaoa0a764a2011-09-16 10:43:38 -07005868 num_entries, new_map_size);
jeffhaod1f0fde2011-09-08 17:25:33 -07005869
jeffhaoe23d93c2011-09-15 14:48:43 -07005870 tmp_ptr = new_map->data_;
jeffhaod1f0fde2011-09-08 17:25:33 -07005871 tmp_ptr = WriteUnsignedLeb128(tmp_ptr, new_data_size);
5872 memcpy(tmp_ptr, tmp_buf.get(), new_data_size);
5873
5874 return new_map;
5875}
5876
5877DexVerifier::RegisterMap* DexVerifier::UncompressMapDifferential(
5878 const RegisterMap* map) {
jeffhaoe23d93c2011-09-15 14:48:43 -07005879 uint8_t format = map->header_->format_;
jeffhaod1f0fde2011-09-08 17:25:33 -07005880 RegisterMapFormat new_format;
5881 int reg_width, num_entries, new_addr_width, new_data_size;
5882
5883 if (format != kRegMapFormatDifferential) {
5884 LOG(ERROR) << "Not differential (" << format << ")";
5885 return NULL;
5886 }
5887
jeffhaoe23d93c2011-09-15 14:48:43 -07005888 reg_width = map->header_->reg_width_;
5889 num_entries = map->header_->num_entries_;
jeffhaod1f0fde2011-09-08 17:25:33 -07005890
5891 /* Get the data size; we can check this at the end. */
jeffhaoe23d93c2011-09-15 14:48:43 -07005892 const uint8_t* src_ptr = map->data_;
jeffhaod1f0fde2011-09-08 17:25:33 -07005893 int expected_src_len = DecodeUnsignedLeb128(&src_ptr);
5894 const uint8_t* src_start = src_ptr;
5895
5896 /* Get the initial address and the 16-bit address flag. */
5897 int addr = *src_ptr & 0x7f;
5898 if ((*src_ptr & 0x80) == 0) {
5899 new_format = kRegMapFormatCompact8;
5900 new_addr_width = 1;
5901 } else {
5902 new_format = kRegMapFormatCompact16;
5903 new_addr_width = 2;
5904 }
5905 src_ptr++;
5906
5907 /* Now we know enough to allocate the new map. */
5908 new_data_size = (new_addr_width + reg_width) * num_entries;
5909 RegisterMap* new_map = new RegisterMap(new_format, reg_width, num_entries,
jeffhaoa0a764a2011-09-16 10:43:38 -07005910 new_data_size);
jeffhaod1f0fde2011-09-08 17:25:33 -07005911
5912 /* Write the start address and initial bits to the new map. */
jeffhaoe23d93c2011-09-15 14:48:43 -07005913 uint8_t* dst_ptr = new_map->data_;
jeffhaod1f0fde2011-09-08 17:25:33 -07005914
5915 *dst_ptr++ = addr & 0xff;
5916 if (new_addr_width > 1)
5917 *dst_ptr++ = (uint8_t) (addr >> 8);
5918
5919 memcpy(dst_ptr, src_ptr, reg_width);
5920
5921 int prev_addr = addr;
5922 const uint8_t* prev_bits = dst_ptr; /* point at uncompressed data */
5923
5924 dst_ptr += reg_width;
5925 src_ptr += reg_width;
5926
5927 /* Walk through, uncompressing one line at a time. */
5928 int entry;
5929 for (entry = 1; entry < num_entries; entry++) {
5930 int addr_diff;
5931 uint8_t key;
5932
5933 key = *src_ptr++;
5934
5935 /* Get the address. */
5936 if ((key & 0x07) == 7) {
5937 /* Address diff follows in ULEB128. */
5938 addr_diff = DecodeUnsignedLeb128(&src_ptr);
5939 } else {
5940 addr_diff = (key & 0x07) +1;
5941 }
5942
5943 addr = prev_addr + addr_diff;
5944 *dst_ptr++ = addr & 0xff;
5945 if (new_addr_width > 1)
5946 *dst_ptr++ = (uint8_t) (addr >> 8);
5947
5948 /* Unpack the bits. */
5949 if ((key & 0x08) != 0) {
5950 int bit_count = (key >> 4);
5951 if (bit_count == 0) {
5952 /* No bits changed, just copy previous. */
5953 memcpy(dst_ptr, prev_bits, reg_width);
5954 } else if (bit_count == 15) {
5955 /* Full copy of bit vector is present; ignore prev_bits. */
5956 memcpy(dst_ptr, src_ptr, reg_width);
5957 src_ptr += reg_width;
5958 } else {
5959 /* Copy previous bits and modify listed indices. */
5960 memcpy(dst_ptr, prev_bits, reg_width);
5961 while (bit_count--) {
5962 int bit_index = DecodeUnsignedLeb128(&src_ptr);
5963 ToggleBit(dst_ptr, bit_index);
5964 }
5965 }
5966 } else {
5967 /* Copy previous bits and modify the specified one. */
5968 memcpy(dst_ptr, prev_bits, reg_width);
5969
5970 /* One bit, from 0-15 inclusive, was changed. */
5971 ToggleBit(dst_ptr, key >> 4);
5972 }
5973
5974 prev_addr = addr;
5975 prev_bits = dst_ptr;
5976 dst_ptr += reg_width;
5977 }
5978
jeffhaoe23d93c2011-09-15 14:48:43 -07005979 if (dst_ptr - new_map->data_ != new_data_size) {
5980 LOG(ERROR) << "ERROR: output " << dst_ptr - new_map->data_
jeffhaod1f0fde2011-09-08 17:25:33 -07005981 << " bytes, expected " << new_data_size;
5982 free(new_map);
5983 return NULL;
5984 }
5985
5986 if (src_ptr - src_start != expected_src_len) {
5987 LOG(ERROR) << "ERROR: consumed " << src_ptr - src_start
5988 << " bytes, expected " << expected_src_len;
5989 free(new_map);
5990 return NULL;
5991 }
5992
5993 return new_map;
5994}
5995
jeffhaoe0cfb6f2011-09-22 16:42:56 -07005996/* Dump the register types for the specifed address to the log file. */
5997void DexVerifier::DumpRegTypes(const VerifierData* vdata,
5998 const RegisterLine* register_line, int addr, const char* addr_name,
5999 const UninitInstanceMap* uninit_map) {
6000 const DexFile::CodeItem* code_item = vdata->code_item_;
6001 uint16_t reg_count = code_item->registers_size_;
6002 uint32_t insns_size = code_item->insns_size_;
6003 const InsnFlags* insn_flags = vdata->insn_flags_.get();
6004 const RegType* addr_regs = register_line->reg_types_.get();
6005 int full_reg_count = reg_count + kExtraRegs;
6006 bool branch_target = InsnIsBranchTarget(insn_flags, addr);
6007 int i;
6008
6009 CHECK(addr >= 0 && addr < (int) insns_size);
6010
6011 int reg_char_size = full_reg_count + (full_reg_count - 1) / 4 + 2 + 1;
6012 char reg_chars[reg_char_size + 1];
6013 memset(reg_chars, ' ', reg_char_size);
6014 reg_chars[0] = '[';
6015 if (reg_count == 0)
6016 reg_chars[1] = ']';
6017 else
6018 reg_chars[1 + (reg_count - 1) + (reg_count -1 ) / 4 + 1] = ']';
6019 reg_chars[reg_char_size] = '\0';
6020
6021 for (i = 0; i < reg_count + kExtraRegs; i++) {
6022 char tch;
6023
6024 switch (addr_regs[i]) {
6025 case kRegTypeUnknown: tch = '.'; break;
6026 case kRegTypeConflict: tch = 'X'; break;
6027 case kRegTypeZero: tch = '0'; break;
6028 case kRegTypeOne: tch = '1'; break;
6029 case kRegTypeBoolean: tch = 'Z'; break;
6030 case kRegTypeConstPosByte: tch = 'y'; break;
6031 case kRegTypeConstByte: tch = 'Y'; break;
6032 case kRegTypeConstPosShort: tch = 'h'; break;
6033 case kRegTypeConstShort: tch = 'H'; break;
6034 case kRegTypeConstChar: tch = 'c'; break;
6035 case kRegTypeConstInteger: tch = 'i'; break;
6036 case kRegTypePosByte: tch = 'b'; break;
6037 case kRegTypeByte: tch = 'B'; break;
6038 case kRegTypePosShort: tch = 's'; break;
6039 case kRegTypeShort: tch = 'S'; break;
6040 case kRegTypeChar: tch = 'C'; break;
6041 case kRegTypeInteger: tch = 'I'; break;
6042 case kRegTypeFloat: tch = 'F'; break;
6043 case kRegTypeConstLo: tch = 'N'; break;
6044 case kRegTypeConstHi: tch = 'n'; break;
6045 case kRegTypeLongLo: tch = 'J'; break;
6046 case kRegTypeLongHi: tch = 'j'; break;
6047 case kRegTypeDoubleLo: tch = 'D'; break;
6048 case kRegTypeDoubleHi: tch = 'd'; break;
6049 default:
6050 if (RegTypeIsReference(addr_regs[i])) {
6051 if (RegTypeIsUninitReference(addr_regs[i]))
6052 tch = 'U';
6053 else
6054 tch = 'L';
6055 } else {
6056 tch = '*';
6057 CHECK(false);
6058 }
6059 break;
6060 }
6061
6062 if (i < reg_count)
6063 reg_chars[1 + i + (i / 4)] = tch;
6064 else
6065 reg_chars[1 + i + (i / 4) + 2] = tch;
6066 }
6067
6068 if (addr == 0 && addr_name != NULL) {
6069 char start = branch_target ? '>' : ' ';
6070 LOG(INFO) << start << addr_name << " " << reg_chars << " mst="
6071 << register_line->monitor_stack_top_;
6072 } else {
6073 char start = branch_target ? '>' : ' ';
6074 LOG(INFO) << start << "0x" << std::hex << addr << std::dec << " "
6075 << reg_chars << " mst=" << register_line->monitor_stack_top_;
6076 }
6077
6078 for (i = 0; i < reg_count + kExtraRegs; i++) {
6079 if (RegTypeIsReference(addr_regs[i]) && addr_regs[i] != kRegTypeZero) {
6080 Class* klass = RegTypeReferenceToClass(addr_regs[i], uninit_map);
6081 if (i < reg_count) {
6082 const char* undef = RegTypeIsUninitReference(addr_regs[i]) ? "[U]" : "";
6083 LOG(INFO) << " " << i << ": 0x" << std::hex << addr_regs[i] << std::dec
6084 << " " << undef << klass->GetDescriptor()->ToModifiedUtf8();
6085 } else {
6086 const char* undef = RegTypeIsUninitReference(addr_regs[i]) ? "[U]" : "";
6087 LOG(INFO) << " RS: 0x" << std::hex << addr_regs[i] << std::dec
6088 << " " << undef << klass->GetDescriptor()->ToModifiedUtf8();
6089 }
6090 }
6091 }
6092}
6093
Carl Shapiro0e5d75d2011-07-06 18:28:37 -07006094} // namespace art