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 dvmThrowException("Ljava/lang/IllegalAccessError;",
134 "cross-loader access from pre-verified class");
135 return NULL;
136 }
137 }
138
139 LOGVV("##### +ResolveClass(%s): referrer=%s dex=%p ldr=%p ref=%d\n",
140 resClass->descriptor, referrer->descriptor, referrer->pDvmDex,
141 referrer->classLoader, classIdx);
142
143 /*
144 * Add what we found to the list so we can skip the class search
145 * next time through.
146 *
147 * TODO: should we be doing this when fromUnverifiedConstant==true?
148 * (see comments at top of oo/Class.c)
149 */
150 dvmDexSetResolvedClass(pDvmDex, classIdx, resClass);
151 } else {
152 /* not found, exception should be raised */
153 LOGVV("Class not found: %s\n",
154 dexStringByTypeIdx(pDvmDex->pDexFile, classIdx));
155 assert(dvmCheckException(dvmThreadSelf()));
156 }
157
158 return resClass;
159 }
160
161
162 /*
163 * Find the method corresponding to "methodRef".
164 *
165 * We use "referrer" to find the DexFile with the constant pool that
166 * "methodRef" is an index into. We also use its class loader. The method
167 * being resolved may very well be in a different DEX file.
168 *
169 * If this is a static method, we ensure that the method's class is
170 * initialized.
171 */
dvmResolveMethod(const ClassObject * referrer,u4 methodIdx,MethodType methodType)172 Method* dvmResolveMethod(const ClassObject* referrer, u4 methodIdx,
173 MethodType methodType)
174 {
175 DvmDex* pDvmDex = referrer->pDvmDex;
176 ClassObject* resClass;
177 const DexMethodId* pMethodId;
178 Method* resMethod;
179
180 assert(methodType != METHOD_INTERFACE);
181
182 LOGVV("--- resolving method %u (referrer=%s)\n", methodIdx,
183 referrer->descriptor);
184 pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
185
186 resClass = dvmResolveClass(referrer, pMethodId->classIdx, false);
187 if (resClass == NULL) {
188 /* can't find the class that the method is a part of */
189 assert(dvmCheckException(dvmThreadSelf()));
190 return NULL;
191 }
192 if (dvmIsInterfaceClass(resClass)) {
193 /* method is part of an interface */
194 dvmThrowExceptionWithClassMessage(
195 "Ljava/lang/IncompatibleClassChangeError;",
196 resClass->descriptor);
197 return NULL;
198 }
199
200 const char* name = dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
201 DexProto proto;
202 dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
203
204 /*
205 * We need to chase up the class hierarchy to find methods defined
206 * in super-classes. (We only want to check the current class
207 * if we're looking for a constructor; since DIRECT calls are only
208 * for constructors and private methods, we don't want to walk up.)
209 */
210 if (methodType == METHOD_DIRECT) {
211 resMethod = dvmFindDirectMethod(resClass, name, &proto);
212 } else if (methodType == METHOD_STATIC) {
213 resMethod = dvmFindDirectMethodHier(resClass, name, &proto);
214 } else {
215 resMethod = dvmFindVirtualMethodHier(resClass, name, &proto);
216 }
217
218 if (resMethod == NULL) {
219 dvmThrowException("Ljava/lang/NoSuchMethodError;", name);
220 return NULL;
221 }
222
223 LOGVV("--- found method %d (%s.%s)\n",
224 methodIdx, resClass->descriptor, resMethod->name);
225
226 /* see if this is a pure-abstract method */
227 if (dvmIsAbstractMethod(resMethod) && !dvmIsAbstractClass(resClass)) {
228 dvmThrowException("Ljava/lang/AbstractMethodError;", name);
229 return NULL;
230 }
231
232 /*
233 * If we're the first to resolve this class, we need to initialize
234 * it now. Only necessary for METHOD_STATIC.
235 */
236 if (methodType == METHOD_STATIC) {
237 if (!dvmIsClassInitialized(resMethod->clazz) &&
238 !dvmInitClass(resMethod->clazz))
239 {
240 assert(dvmCheckException(dvmThreadSelf()));
241 return NULL;
242 } else {
243 assert(!dvmCheckException(dvmThreadSelf()));
244 }
245 } else {
246 /*
247 * Edge case: if the <clinit> for a class creates an instance
248 * of itself, we will call <init> on a class that is still being
249 * initialized by us.
250 */
251 assert(dvmIsClassInitialized(resMethod->clazz) ||
252 dvmIsClassInitializing(resMethod->clazz));
253 }
254
255 /*
256 * The class is initialized, the method has been found. Add a pointer
257 * to our data structure so we don't have to jump through the hoops again.
258 */
259 dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
260
261 return resMethod;
262 }
263
264 /*
265 * Resolve an interface method reference.
266 *
267 * Returns NULL with an exception raised on failure.
268 */
dvmResolveInterfaceMethod(const ClassObject * referrer,u4 methodIdx)269 Method* dvmResolveInterfaceMethod(const ClassObject* referrer, u4 methodIdx)
270 {
271 DvmDex* pDvmDex = referrer->pDvmDex;
272 ClassObject* resClass;
273 const DexMethodId* pMethodId;
274 Method* resMethod;
275 int i;
276
277 LOGVV("--- resolving interface method %d (referrer=%s)\n",
278 methodIdx, referrer->descriptor);
279 pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
280
281 resClass = dvmResolveClass(referrer, pMethodId->classIdx, false);
282 if (resClass == NULL) {
283 /* can't find the class that the method is a part of */
284 assert(dvmCheckException(dvmThreadSelf()));
285 return NULL;
286 }
287 if (!dvmIsInterfaceClass(resClass)) {
288 /* whoops */
289 dvmThrowExceptionWithClassMessage(
290 "Ljava/lang/IncompatibleClassChangeError;",
291 resClass->descriptor);
292 return NULL;
293 }
294
295 /*
296 * This is the first time the method has been resolved. Set it in our
297 * resolved-method structure. It always resolves to the same thing,
298 * so looking it up and storing it doesn't create a race condition.
299 *
300 * If we scan into the interface's superclass -- which is always
301 * java/lang/Object -- we will catch things like:
302 * interface I ...
303 * I myobj = (something that implements I)
304 * myobj.hashCode()
305 * However, the Method->methodIndex will be an offset into clazz->vtable,
306 * rather than an offset into clazz->iftable. The invoke-interface
307 * code can test to see if the method returned is abstract or concrete,
308 * and use methodIndex accordingly. I'm not doing this yet because
309 * (a) we waste time in an unusual case, and (b) we're probably going
310 * to fix it in the DEX optimizer.
311 *
312 * We do need to scan the superinterfaces, in case we're invoking a
313 * superinterface method on an interface reference. The class in the
314 * DexTypeId is for the static type of the object, not the class in
315 * which the method is first defined. We have the full, flattened
316 * list in "iftable".
317 */
318 const char* methodName =
319 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
320
321 DexProto proto;
322 dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
323
324 LOGVV("+++ looking for '%s' '%s' in resClass='%s'\n",
325 methodName, methodSig, resClass->descriptor);
326 resMethod = dvmFindVirtualMethod(resClass, methodName, &proto);
327 if (resMethod == NULL) {
328 LOGVV("+++ did not resolve immediately\n");
329 for (i = 0; i < resClass->iftableCount; i++) {
330 resMethod = dvmFindVirtualMethod(resClass->iftable[i].clazz,
331 methodName, &proto);
332 if (resMethod != NULL)
333 break;
334 }
335
336 if (resMethod == NULL) {
337 dvmThrowException("Ljava/lang/NoSuchMethodError;", methodName);
338 return NULL;
339 }
340 } else {
341 LOGVV("+++ resolved immediately: %s (%s %d)\n", resMethod->name,
342 resMethod->clazz->descriptor, (u4) resMethod->methodIndex);
343 }
344
345 LOGVV("--- found interface method %d (%s.%s)\n",
346 methodIdx, resClass->descriptor, resMethod->name);
347
348 /* we're expecting this to be abstract */
349 assert(dvmIsAbstractMethod(resMethod));
350
351 /* interface methods are always public; no need to check access */
352
353 /*
354 * The interface class *may* be initialized. According to VM spec
355 * v2 2.17.4, the interfaces a class refers to "need not" be initialized
356 * when the class is initialized.
357 *
358 * It isn't necessary for an interface class to be initialized before
359 * we resolve methods on that interface.
360 *
361 * We choose not to do the initialization now.
362 */
363 //assert(dvmIsClassInitialized(resMethod->clazz));
364
365 /*
366 * The class is initialized, the method has been found. Add a pointer
367 * to our data structure so we don't have to jump through the hoops again.
368 */
369 dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
370
371 return resMethod;
372 }
373
374 /*
375 * Resolve an instance field reference.
376 *
377 * Returns NULL and throws an exception on error (no such field, illegal
378 * access).
379 */
dvmResolveInstField(const ClassObject * referrer,u4 ifieldIdx)380 InstField* dvmResolveInstField(const ClassObject* referrer, u4 ifieldIdx)
381 {
382 DvmDex* pDvmDex = referrer->pDvmDex;
383 ClassObject* resClass;
384 const DexFieldId* pFieldId;
385 InstField* resField;
386
387 LOGVV("--- resolving field %u (referrer=%s cl=%p)\n",
388 ifieldIdx, referrer->descriptor, referrer->classLoader);
389
390 pFieldId = dexGetFieldId(pDvmDex->pDexFile, ifieldIdx);
391
392 /*
393 * Find the field's class.
394 */
395 resClass = dvmResolveClass(referrer, pFieldId->classIdx, false);
396 if (resClass == NULL) {
397 assert(dvmCheckException(dvmThreadSelf()));
398 return NULL;
399 }
400
401 resField = dvmFindInstanceFieldHier(resClass,
402 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
403 dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
404 if (resField == NULL) {
405 dvmThrowException("Ljava/lang/NoSuchFieldError;",
406 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
407 return NULL;
408 }
409
410 /*
411 * Class must be initialized by now (unless verifier is buggy). We
412 * could still be in the process of initializing it if the field
413 * access is from a static initializer.
414 */
415 assert(dvmIsClassInitialized(resField->field.clazz) ||
416 dvmIsClassInitializing(resField->field.clazz));
417
418 /*
419 * The class is initialized, the method has been found. Add a pointer
420 * to our data structure so we don't have to jump through the hoops again.
421 */
422 dvmDexSetResolvedField(pDvmDex, ifieldIdx, (Field*)resField);
423 LOGVV(" field %u is %s.%s\n",
424 ifieldIdx, resField->field.clazz->descriptor, resField->field.name);
425
426 return resField;
427 }
428
429 /*
430 * Resolve a static field reference. The DexFile format doesn't distinguish
431 * between static and instance field references, so the "resolved" pointer
432 * in the Dex struct will have the wrong type. We trivially cast it here.
433 *
434 * Causes the field's class to be initialized.
435 */
dvmResolveStaticField(const ClassObject * referrer,u4 sfieldIdx)436 StaticField* dvmResolveStaticField(const ClassObject* referrer, u4 sfieldIdx)
437 {
438 DvmDex* pDvmDex = referrer->pDvmDex;
439 ClassObject* resClass;
440 const DexFieldId* pFieldId;
441 StaticField* resField;
442
443 pFieldId = dexGetFieldId(pDvmDex->pDexFile, sfieldIdx);
444
445 /*
446 * Find the field's class.
447 */
448 resClass = dvmResolveClass(referrer, pFieldId->classIdx, false);
449 if (resClass == NULL) {
450 assert(dvmCheckException(dvmThreadSelf()));
451 return NULL;
452 }
453
454 resField = dvmFindStaticFieldHier(resClass,
455 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
456 dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
457 if (resField == NULL) {
458 dvmThrowException("Ljava/lang/NoSuchFieldError;",
459 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
460 return NULL;
461 }
462
463 /*
464 * If we're the first to resolve the field in which this class resides,
465 * we need to do it now. Note that, if the field was inherited from
466 * a superclass, it is not necessarily the same as "resClass".
467 */
468 if (!dvmIsClassInitialized(resField->field.clazz) &&
469 !dvmInitClass(resField->field.clazz))
470 {
471 assert(dvmCheckException(dvmThreadSelf()));
472 return NULL;
473 }
474
475 /*
476 * The class is initialized, the method has been found. Add a pointer
477 * to our data structure so we don't have to jump through the hoops again.
478 */
479 dvmDexSetResolvedField(pDvmDex, sfieldIdx, (Field*) resField);
480
481 return resField;
482 }
483
484
485 /*
486 * Resolve a string reference.
487 *
488 * Finding the string is easy. We need to return a reference to a
489 * java/lang/String object, not a bunch of characters, which means the
490 * first time we get here we need to create an interned string.
491 */
dvmResolveString(const ClassObject * referrer,u4 stringIdx)492 StringObject* dvmResolveString(const ClassObject* referrer, u4 stringIdx)
493 {
494 DvmDex* pDvmDex = referrer->pDvmDex;
495 StringObject* strObj;
496 StringObject* internStrObj;
497 const char* utf8;
498 u4 utf16Size;
499
500 LOGVV("+++ resolving string, referrer is %s\n", referrer->descriptor);
501
502 /*
503 * Create a UTF-16 version so we can trivially compare it to what's
504 * already interned.
505 */
506 utf8 = dexStringAndSizeById(pDvmDex->pDexFile, stringIdx, &utf16Size);
507 strObj = dvmCreateStringFromCstrAndLength(utf8, utf16Size,
508 ALLOC_DEFAULT);
509 if (strObj == NULL) {
510 /* ran out of space in GC heap? */
511 assert(dvmCheckException(dvmThreadSelf()));
512 goto bail;
513 }
514
515 /*
516 * Add it to the intern list. The return value is the one in the
517 * intern list, which (due to race conditions) may or may not be
518 * the one we just created. The intern list is synchronized, so
519 * there will be only one "live" version.
520 *
521 * By requesting an immortal interned string, we guarantee that
522 * the returned object will never be collected by the GC.
523 *
524 * A NULL return here indicates some sort of hashing failure.
525 */
526 internStrObj = dvmLookupImmortalInternedString(strObj);
527 dvmReleaseTrackedAlloc((Object*) strObj, NULL);
528 strObj = internStrObj;
529 if (strObj == NULL) {
530 assert(dvmCheckException(dvmThreadSelf()));
531 goto bail;
532 }
533
534 /* save a reference so we can go straight to the object next time */
535 dvmDexSetResolvedString(pDvmDex, stringIdx, strObj);
536
537 bail:
538 return strObj;
539 }
540
541 /*
542 * For debugging: return a string representing the methodType.
543 */
dvmMethodTypeStr(MethodType methodType)544 const char* dvmMethodTypeStr(MethodType methodType)
545 {
546 switch (methodType) {
547 case METHOD_DIRECT: return "direct";
548 case METHOD_STATIC: return "static";
549 case METHOD_VIRTUAL: return "virtual";
550 case METHOD_INTERFACE: return "interface";
551 case METHOD_UNKNOWN: return "UNKNOWN";
552 }
553 assert(false);
554 return "BOGUS";
555 }
556