• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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