1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 /*
17 * Resolve classes, methods, fields, and strings.
18 *
19 * According to the VM spec (v2 5.5), classes may be initialized by use
20 * of the "new", "getstatic", "putstatic", or "invokestatic" instructions.
21 * If we are resolving a static method or static field, we make the
22 * initialization check here.
23 *
24 * (NOTE: the verifier has its own resolve functions, which can be invoked
25 * if a class isn't pre-verified. Those functions must not update the
26 * "resolved stuff" tables for static fields and methods, because they do
27 * not perform initialization.)
28 */
29 #include "Dalvik.h"
30
31 #include <stdlib.h>
32
33
34 /*
35 * Find the class corresponding to "classIdx", which maps to a class name
36 * string. It might be in the same DEX file as "referrer", in a different
37 * DEX file, generated by a class loader, or generated by the VM (e.g.
38 * array classes).
39 *
40 * Because the DexTypeId is associated with the referring class' DEX file,
41 * we may have to resolve the same class more than once if it's referred
42 * to from classes in multiple DEX files. This is a necessary property for
43 * DEX files associated with different class loaders.
44 *
45 * We cache a copy of the lookup in the DexFile's "resolved class" table,
46 * so future references to "classIdx" are faster.
47 *
48 * Note that "referrer" may be in the process of being linked.
49 *
50 * Traditional VMs might do access checks here, but in Dalvik the class
51 * "constant pool" is shared between all classes in the DEX file. We rely
52 * on the verifier to do the checks for us.
53 *
54 * Does not initialize the class.
55 *
56 * "fromUnverifiedConstant" should only be set if this call is the direct
57 * result of executing a "const-class" or "instance-of" instruction, which
58 * use class constants not resolved by the bytecode verifier.
59 *
60 * Returns NULL with an exception raised on failure.
61 */
dvmResolveClass(const ClassObject * referrer,u4 classIdx,bool fromUnverifiedConstant)62 ClassObject* dvmResolveClass(const ClassObject* referrer, u4 classIdx,
63 bool fromUnverifiedConstant)
64 {
65 DvmDex* pDvmDex = referrer->pDvmDex;
66 ClassObject* resClass;
67 const char* className;
68
69 /*
70 * Check the table first -- this gets called from the other "resolve"
71 * methods.
72 */
73 resClass = dvmDexGetResolvedClass(pDvmDex, classIdx);
74 if (resClass != NULL)
75 return resClass;
76
77 LOGVV("--- resolving class %u (referrer=%s cl=%p)\n",
78 classIdx, referrer->descriptor, referrer->classLoader);
79
80 /*
81 * Class hasn't been loaded yet, or is in the process of being loaded
82 * and initialized now. Try to get a copy. If we find one, put the
83 * pointer in the DexTypeId. There isn't a race condition here --
84 * 32-bit writes are guaranteed atomic on all target platforms. Worst
85 * case we have two threads storing the same value.
86 *
87 * If this is an array class, we'll generate it here.
88 */
89 className = dexStringByTypeIdx(pDvmDex->pDexFile, classIdx);
90 if (className[0] != '\0' && className[1] == '\0') {
91 /* primitive type */
92 resClass = dvmFindPrimitiveClass(className[0]);
93 } else {
94 resClass = dvmFindClassNoInit(className, referrer->classLoader);
95 }
96
97 if (resClass != NULL) {
98 /*
99 * If the referrer was pre-verified, the resolved class must come
100 * from the same DEX or from a bootstrap class. The pre-verifier
101 * makes assumptions that could be invalidated by a wacky class
102 * loader. (See the notes at the top of oo/Class.c.)
103 *
104 * The verifier does *not* fail a class for using a const-class
105 * or instance-of instruction referring to an unresolveable class,
106 * because the result of the instruction is simply a Class object
107 * or boolean -- there's no need to resolve the class object during
108 * verification. Instance field and virtual method accesses can
109 * break dangerously if we get the wrong class, but const-class and
110 * instance-of are only interesting at execution time. So, if we
111 * we got here as part of executing one of the "unverified class"
112 * instructions, we skip the additional check.
113 *
114 * Ditto for class references from annotations and exception
115 * handler lists.
116 */
117 if (!fromUnverifiedConstant &&
118 IS_CLASS_FLAG_SET(referrer, CLASS_ISPREVERIFIED))
119 {
120 ClassObject* resClassCheck = resClass;
121 if (dvmIsArrayClass(resClassCheck))
122 resClassCheck = resClassCheck->elementClass;
123
124 if (referrer->pDvmDex != resClassCheck->pDvmDex &&
125 resClassCheck->classLoader != NULL)
126 {
127 LOGW("Class resolved by unexpected DEX:"
128 " %s(%p):%p ref [%s] %s(%p):%p\n",
129 referrer->descriptor, referrer->classLoader,
130 referrer->pDvmDex,
131 resClass->descriptor, resClassCheck->descriptor,
132 resClassCheck->classLoader, resClassCheck->pDvmDex);
133 LOGW("(%s had used a different %s during pre-verification)\n",
134 referrer->descriptor, resClass->descriptor);
135 dvmThrowException("Ljava/lang/IllegalAccessError;",
136 "Class ref in pre-verified class resolved to unexpected "
137 "implementation");
138 return NULL;
139 }
140 }
141
142 LOGVV("##### +ResolveClass(%s): referrer=%s dex=%p ldr=%p ref=%d\n",
143 resClass->descriptor, referrer->descriptor, referrer->pDvmDex,
144 referrer->classLoader, classIdx);
145
146 /*
147 * Add what we found to the list so we can skip the class search
148 * next time through.
149 *
150 * TODO: should we be doing this when fromUnverifiedConstant==true?
151 * (see comments at top of oo/Class.c)
152 */
153 dvmDexSetResolvedClass(pDvmDex, classIdx, resClass);
154 } else {
155 /* not found, exception should be raised */
156 LOGVV("Class not found: %s\n",
157 dexStringByTypeIdx(pDvmDex->pDexFile, classIdx));
158 assert(dvmCheckException(dvmThreadSelf()));
159 }
160
161 return resClass;
162 }
163
164
165 /*
166 * Find the method corresponding to "methodRef".
167 *
168 * We use "referrer" to find the DexFile with the constant pool that
169 * "methodRef" is an index into. We also use its class loader. The method
170 * being resolved may very well be in a different DEX file.
171 *
172 * If this is a static method, we ensure that the method's class is
173 * initialized.
174 */
dvmResolveMethod(const ClassObject * referrer,u4 methodIdx,MethodType methodType)175 Method* dvmResolveMethod(const ClassObject* referrer, u4 methodIdx,
176 MethodType methodType)
177 {
178 DvmDex* pDvmDex = referrer->pDvmDex;
179 ClassObject* resClass;
180 const DexMethodId* pMethodId;
181 Method* resMethod;
182
183 assert(methodType != METHOD_INTERFACE);
184
185 LOGVV("--- resolving method %u (referrer=%s)\n", methodIdx,
186 referrer->descriptor);
187 pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
188
189 resClass = dvmResolveClass(referrer, pMethodId->classIdx, false);
190 if (resClass == NULL) {
191 /* can't find the class that the method is a part of */
192 assert(dvmCheckException(dvmThreadSelf()));
193 return NULL;
194 }
195 if (dvmIsInterfaceClass(resClass)) {
196 /* method is part of an interface */
197 dvmThrowExceptionWithClassMessage(
198 "Ljava/lang/IncompatibleClassChangeError;",
199 resClass->descriptor);
200 return NULL;
201 }
202
203 const char* name = dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
204 DexProto proto;
205 dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
206
207 /*
208 * We need to chase up the class hierarchy to find methods defined
209 * in super-classes. (We only want to check the current class
210 * if we're looking for a constructor; since DIRECT calls are only
211 * for constructors and private methods, we don't want to walk up.)
212 */
213 if (methodType == METHOD_DIRECT) {
214 resMethod = dvmFindDirectMethod(resClass, name, &proto);
215 } else if (methodType == METHOD_STATIC) {
216 resMethod = dvmFindDirectMethodHier(resClass, name, &proto);
217 } else {
218 resMethod = dvmFindVirtualMethodHier(resClass, name, &proto);
219 }
220
221 if (resMethod == NULL) {
222 dvmThrowException("Ljava/lang/NoSuchMethodError;", name);
223 return NULL;
224 }
225
226 LOGVV("--- found method %d (%s.%s)\n",
227 methodIdx, resClass->descriptor, resMethod->name);
228
229 /* see if this is a pure-abstract method */
230 if (dvmIsAbstractMethod(resMethod) && !dvmIsAbstractClass(resClass)) {
231 dvmThrowException("Ljava/lang/AbstractMethodError;", name);
232 return NULL;
233 }
234
235 /*
236 * If we're the first to resolve this class, we need to initialize
237 * it now. Only necessary for METHOD_STATIC.
238 */
239 if (methodType == METHOD_STATIC) {
240 if (!dvmIsClassInitialized(resMethod->clazz) &&
241 !dvmInitClass(resMethod->clazz))
242 {
243 assert(dvmCheckException(dvmThreadSelf()));
244 return NULL;
245 } else {
246 assert(!dvmCheckException(dvmThreadSelf()));
247 }
248 } else {
249 /*
250 * Edge case: if the <clinit> for a class creates an instance
251 * of itself, we will call <init> on a class that is still being
252 * initialized by us.
253 */
254 assert(dvmIsClassInitialized(resMethod->clazz) ||
255 dvmIsClassInitializing(resMethod->clazz));
256 }
257
258 /*
259 * The class is initialized, the method has been found. Add a pointer
260 * to our data structure so we don't have to jump through the hoops again.
261 */
262 dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
263
264 return resMethod;
265 }
266
267 /*
268 * Resolve an interface method reference.
269 *
270 * Returns NULL with an exception raised on failure.
271 */
dvmResolveInterfaceMethod(const ClassObject * referrer,u4 methodIdx)272 Method* dvmResolveInterfaceMethod(const ClassObject* referrer, u4 methodIdx)
273 {
274 DvmDex* pDvmDex = referrer->pDvmDex;
275 ClassObject* resClass;
276 const DexMethodId* pMethodId;
277 Method* resMethod;
278 int i;
279
280 LOGVV("--- resolving interface method %d (referrer=%s)\n",
281 methodIdx, referrer->descriptor);
282 pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
283
284 resClass = dvmResolveClass(referrer, pMethodId->classIdx, false);
285 if (resClass == NULL) {
286 /* can't find the class that the method is a part of */
287 assert(dvmCheckException(dvmThreadSelf()));
288 return NULL;
289 }
290 if (!dvmIsInterfaceClass(resClass)) {
291 /* whoops */
292 dvmThrowExceptionWithClassMessage(
293 "Ljava/lang/IncompatibleClassChangeError;",
294 resClass->descriptor);
295 return NULL;
296 }
297
298 /*
299 * This is the first time the method has been resolved. Set it in our
300 * resolved-method structure. It always resolves to the same thing,
301 * so looking it up and storing it doesn't create a race condition.
302 *
303 * If we scan into the interface's superclass -- which is always
304 * java/lang/Object -- we will catch things like:
305 * interface I ...
306 * I myobj = (something that implements I)
307 * myobj.hashCode()
308 * However, the Method->methodIndex will be an offset into clazz->vtable,
309 * rather than an offset into clazz->iftable. The invoke-interface
310 * code can test to see if the method returned is abstract or concrete,
311 * and use methodIndex accordingly. I'm not doing this yet because
312 * (a) we waste time in an unusual case, and (b) we're probably going
313 * to fix it in the DEX optimizer.
314 *
315 * We do need to scan the superinterfaces, in case we're invoking a
316 * superinterface method on an interface reference. The class in the
317 * DexTypeId is for the static type of the object, not the class in
318 * which the method is first defined. We have the full, flattened
319 * list in "iftable".
320 */
321 const char* methodName =
322 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
323
324 DexProto proto;
325 dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
326
327 LOGVV("+++ looking for '%s' '%s' in resClass='%s'\n",
328 methodName, methodSig, resClass->descriptor);
329 resMethod = dvmFindVirtualMethod(resClass, methodName, &proto);
330 if (resMethod == NULL) {
331 LOGVV("+++ did not resolve immediately\n");
332 for (i = 0; i < resClass->iftableCount; i++) {
333 resMethod = dvmFindVirtualMethod(resClass->iftable[i].clazz,
334 methodName, &proto);
335 if (resMethod != NULL)
336 break;
337 }
338
339 if (resMethod == NULL) {
340 dvmThrowException("Ljava/lang/NoSuchMethodError;", methodName);
341 return NULL;
342 }
343 } else {
344 LOGVV("+++ resolved immediately: %s (%s %d)\n", resMethod->name,
345 resMethod->clazz->descriptor, (u4) resMethod->methodIndex);
346 }
347
348 LOGVV("--- found interface method %d (%s.%s)\n",
349 methodIdx, resClass->descriptor, resMethod->name);
350
351 /* we're expecting this to be abstract */
352 assert(dvmIsAbstractMethod(resMethod));
353
354 /* interface methods are always public; no need to check access */
355
356 /*
357 * The interface class *may* be initialized. According to VM spec
358 * v2 2.17.4, the interfaces a class refers to "need not" be initialized
359 * when the class is initialized.
360 *
361 * It isn't necessary for an interface class to be initialized before
362 * we resolve methods on that interface.
363 *
364 * We choose not to do the initialization now.
365 */
366 //assert(dvmIsClassInitialized(resMethod->clazz));
367
368 /*
369 * The class is initialized, the method has been found. Add a pointer
370 * to our data structure so we don't have to jump through the hoops again.
371 */
372 dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
373
374 return resMethod;
375 }
376
377 /*
378 * Resolve an instance field reference.
379 *
380 * Returns NULL and throws an exception on error (no such field, illegal
381 * access).
382 */
dvmResolveInstField(const ClassObject * referrer,u4 ifieldIdx)383 InstField* dvmResolveInstField(const ClassObject* referrer, u4 ifieldIdx)
384 {
385 DvmDex* pDvmDex = referrer->pDvmDex;
386 ClassObject* resClass;
387 const DexFieldId* pFieldId;
388 InstField* resField;
389
390 LOGVV("--- resolving field %u (referrer=%s cl=%p)\n",
391 ifieldIdx, referrer->descriptor, referrer->classLoader);
392
393 pFieldId = dexGetFieldId(pDvmDex->pDexFile, ifieldIdx);
394
395 /*
396 * Find the field's class.
397 */
398 resClass = dvmResolveClass(referrer, pFieldId->classIdx, false);
399 if (resClass == NULL) {
400 assert(dvmCheckException(dvmThreadSelf()));
401 return NULL;
402 }
403
404 resField = dvmFindInstanceFieldHier(resClass,
405 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
406 dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
407 if (resField == NULL) {
408 dvmThrowException("Ljava/lang/NoSuchFieldError;",
409 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
410 return NULL;
411 }
412
413 /*
414 * Class must be initialized by now (unless verifier is buggy). We
415 * could still be in the process of initializing it if the field
416 * access is from a static initializer.
417 */
418 assert(dvmIsClassInitialized(resField->field.clazz) ||
419 dvmIsClassInitializing(resField->field.clazz));
420
421 /*
422 * The class is initialized, the method has been found. Add a pointer
423 * to our data structure so we don't have to jump through the hoops again.
424 */
425 dvmDexSetResolvedField(pDvmDex, ifieldIdx, (Field*)resField);
426 LOGVV(" field %u is %s.%s\n",
427 ifieldIdx, resField->field.clazz->descriptor, resField->field.name);
428
429 return resField;
430 }
431
432 /*
433 * Resolve a static field reference. The DexFile format doesn't distinguish
434 * between static and instance field references, so the "resolved" pointer
435 * in the Dex struct will have the wrong type. We trivially cast it here.
436 *
437 * Causes the field's class to be initialized.
438 */
dvmResolveStaticField(const ClassObject * referrer,u4 sfieldIdx)439 StaticField* dvmResolveStaticField(const ClassObject* referrer, u4 sfieldIdx)
440 {
441 DvmDex* pDvmDex = referrer->pDvmDex;
442 ClassObject* resClass;
443 const DexFieldId* pFieldId;
444 StaticField* resField;
445
446 pFieldId = dexGetFieldId(pDvmDex->pDexFile, sfieldIdx);
447
448 /*
449 * Find the field's class.
450 */
451 resClass = dvmResolveClass(referrer, pFieldId->classIdx, false);
452 if (resClass == NULL) {
453 assert(dvmCheckException(dvmThreadSelf()));
454 return NULL;
455 }
456
457 resField = dvmFindStaticFieldHier(resClass,
458 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
459 dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
460 if (resField == NULL) {
461 dvmThrowException("Ljava/lang/NoSuchFieldError;",
462 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
463 return NULL;
464 }
465
466 /*
467 * If we're the first to resolve the field in which this class resides,
468 * we need to do it now. Note that, if the field was inherited from
469 * a superclass, it is not necessarily the same as "resClass".
470 */
471 if (!dvmIsClassInitialized(resField->field.clazz) &&
472 !dvmInitClass(resField->field.clazz))
473 {
474 assert(dvmCheckException(dvmThreadSelf()));
475 return NULL;
476 }
477
478 /*
479 * The class is initialized, the method has been found. Add a pointer
480 * to our data structure so we don't have to jump through the hoops again.
481 */
482 dvmDexSetResolvedField(pDvmDex, sfieldIdx, (Field*) resField);
483
484 return resField;
485 }
486
487
488 /*
489 * Resolve a string reference.
490 *
491 * Finding the string is easy. We need to return a reference to a
492 * java/lang/String object, not a bunch of characters, which means the
493 * first time we get here we need to create an interned string.
494 */
dvmResolveString(const ClassObject * referrer,u4 stringIdx)495 StringObject* dvmResolveString(const ClassObject* referrer, u4 stringIdx)
496 {
497 DvmDex* pDvmDex = referrer->pDvmDex;
498 StringObject* strObj;
499 StringObject* internStrObj;
500 const char* utf8;
501 u4 utf16Size;
502
503 LOGVV("+++ resolving string, referrer is %s\n", referrer->descriptor);
504
505 /*
506 * Create a UTF-16 version so we can trivially compare it to what's
507 * already interned.
508 */
509 utf8 = dexStringAndSizeById(pDvmDex->pDexFile, stringIdx, &utf16Size);
510 strObj = dvmCreateStringFromCstrAndLength(utf8, utf16Size,
511 ALLOC_DEFAULT);
512 if (strObj == NULL) {
513 /* ran out of space in GC heap? */
514 assert(dvmCheckException(dvmThreadSelf()));
515 goto bail;
516 }
517
518 /*
519 * Add it to the intern list. The return value is the one in the
520 * intern list, which (due to race conditions) may or may not be
521 * the one we just created. The intern list is synchronized, so
522 * there will be only one "live" version.
523 *
524 * By requesting an immortal interned string, we guarantee that
525 * the returned object will never be collected by the GC.
526 *
527 * A NULL return here indicates some sort of hashing failure.
528 */
529 internStrObj = dvmLookupImmortalInternedString(strObj);
530 dvmReleaseTrackedAlloc((Object*) strObj, NULL);
531 strObj = internStrObj;
532 if (strObj == NULL) {
533 assert(dvmCheckException(dvmThreadSelf()));
534 goto bail;
535 }
536
537 /* save a reference so we can go straight to the object next time */
538 dvmDexSetResolvedString(pDvmDex, stringIdx, strObj);
539
540 bail:
541 return strObj;
542 }
543
544 /*
545 * For debugging: return a string representing the methodType.
546 */
dvmMethodTypeStr(MethodType methodType)547 const char* dvmMethodTypeStr(MethodType methodType)
548 {
549 switch (methodType) {
550 case METHOD_DIRECT: return "direct";
551 case METHOD_STATIC: return "static";
552 case METHOD_VIRTUAL: return "virtual";
553 case METHOD_INTERFACE: return "interface";
554 case METHOD_UNKNOWN: return "UNKNOWN";
555 }
556 assert(false);
557 return "BOGUS";
558 }
559