/* * Alternate version of dvmResolveStaticField(). * * Does not force initialization of the resolved field's class. * * On failure, returns NULL, and sets *pFailure if pFailure is not NULL. */ StaticField* dvmOptResolveStaticField(ClassObject* referrer, u4 sfieldIdx, VerifyError* pFailure) { DvmDex* pDvmDex = referrer->pDvmDex; StaticField* resField; resField = (StaticField*)dvmDexGetResolvedField(pDvmDex, sfieldIdx); if (resField == NULL) { const DexFieldId* pFieldId; ClassObject* resClass; pFieldId = dexGetFieldId(pDvmDex->pDexFile, sfieldIdx); /* * Find the field's class. */ resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure); if (resClass == NULL) { //dvmClearOptException(dvmThreadSelf()); assert(!dvmCheckException(dvmThreadSelf())); if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); } return NULL; } const char* fieldName = dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx); resField = (StaticField*)dvmFindFieldHier(resClass, fieldName, dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx)); if (resField == NULL) { ALOGD("DexOpt: couldn't find static field %s.%s", resClass->descriptor, fieldName); if (pFailure != NULL) *pFailure = VERIFY_ERROR_NO_FIELD; return NULL; } if (!dvmIsStaticField(resField)) { ALOGD("DexOpt: wanted static, got instance for field %s.%s", resClass->descriptor, fieldName); if (pFailure != NULL) *pFailure = VERIFY_ERROR_CLASS_CHANGE; return NULL; } /* * Add it to the resolved table so we're faster on the next lookup. * * We can only do this if we're in "dexopt", because the presence * of a valid value in the resolution table implies that the class * containing the static field has been initialized. */ if (gDvm.optimizing) dvmDexSetResolvedField(pDvmDex, sfieldIdx, (Field*) resField); } /* access allowed? */ tweakLoader(referrer, resField->clazz); bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField); untweakLoader(referrer, resField->clazz); if (!allowed) { ALOGI("DexOpt: access denied from %s to field %s.%s", referrer->descriptor, resField->clazz->descriptor, resField->name); if (pFailure != NULL) *pFailure = VERIFY_ERROR_ACCESS_FIELD; return NULL; } return resField; }
/* * Get the address of a field from an object. This can be used with "get" * or "set". * * "declaringClass" is the class in which the field was declared. For an * instance field, "obj" is the object that holds the field data; for a * static field its value is ignored. * * "If the underlying field is static, the class that declared the * field is initialized if it has not already been initialized." * * On failure, throws an exception and returns NULL. * * The documentation lists exceptional conditions and the exceptions that * should be thrown, but doesn't say which exception previals when two or * more exceptional conditions exist at the same time. For example, * attempting to set a protected field from an unrelated class causes an * IllegalAccessException, while passing in a data type that doesn't match * the field causes an IllegalArgumentException. If code does both at the * same time, we have to choose one or othe other. * * The expected order is: * (1) Check for illegal access. Throw IllegalAccessException. * (2) Make sure the object actually has the field. Throw * IllegalArgumentException. * (3) Make sure the field matches the expected type, e.g. if we issued * a "getInteger" call make sure the field is an integer or can be * converted to an int with a widening conversion. Throw * IllegalArgumentException. * (4) Make sure "obj" is not null. Throw NullPointerException. * * TODO: we're currently handling #3 after #4, because we don't check the * widening conversion until we're actually extracting the value from the * object (which won't work well if it's a null reference). */ static JValue* getFieldDataAddr(Object* obj, ClassObject* declaringClass, int slot, bool isSetOperation, bool noAccessCheck) { Field* field; JValue* result; field = dvmSlotToField(declaringClass, slot); assert(field != NULL); /* verify access */ if (!noAccessCheck) { if (isSetOperation && dvmIsFinalField(field)) { dvmThrowException("Ljava/lang/IllegalAccessException;", "field is marked 'final'"); return NULL; } ClassObject* callerClass = dvmGetCaller2Class(dvmThreadSelf()->curFrame); /* * We need to check two things: * (1) Would an instance of the calling class have access to the field? * (2) If the field is "protected", is the object an instance of the * calling class, or is the field's declaring class in the same * package as the calling class? * * #1 is basic access control. #2 ensures that, just because * you're a subclass of Foo, you can't mess with protected fields * in arbitrary Foo objects from other packages. */ if (!dvmCheckFieldAccess(callerClass, field)) { dvmThrowException("Ljava/lang/IllegalAccessException;", "access to field not allowed"); return NULL; } if (dvmIsProtectedField(field)) { bool isInstance, samePackage; if (obj != NULL) isInstance = dvmInstanceof(obj->clazz, callerClass); else isInstance = false; samePackage = dvmInSamePackage(declaringClass, callerClass); if (!isInstance && !samePackage) { dvmThrowException("Ljava/lang/IllegalAccessException;", "access to protected field not allowed"); return NULL; } } } if (dvmIsStaticField(field)) { /* init class if necessary, then return ptr to storage in "field" */ if (!dvmIsClassInitialized(declaringClass)) { if (!dvmInitClass(declaringClass)) { assert(dvmCheckException(dvmThreadSelf())); return NULL; } } result = dvmStaticFieldPtr((StaticField*) field); } else { /* * Verify object is of correct type (i.e. it actually has the * expected field in it), then grab a pointer to obj storage. * The call to dvmVerifyObjectInClass throws an NPE if "obj" is NULL. */ if (!dvmVerifyObjectInClass(obj, declaringClass)) { assert(dvmCheckException(dvmThreadSelf())); if (obj != NULL) { LOGD("Wrong type of object for field lookup: %s %s\n", obj->clazz->descriptor, declaringClass->descriptor); } return NULL; } result = dvmFieldPtr(obj, ((InstField*) field)->byteOffset); } return result; }
/* * Alternate version of dvmResolveInstField(). * * On failure, returns NULL, and sets *pFailure if pFailure is not NULL. */ InstField* dvmOptResolveInstField(ClassObject* referrer, u4 ifieldIdx, VerifyError* pFailure) { DvmDex* pDvmDex = referrer->pDvmDex; InstField* resField; resField = (InstField*) dvmDexGetResolvedField(pDvmDex, ifieldIdx); if (resField == NULL) { const DexFieldId* pFieldId; ClassObject* resClass; pFieldId = dexGetFieldId(pDvmDex->pDexFile, ifieldIdx); /* * Find the field's class. */ resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure); if (resClass == NULL) { //dvmClearOptException(dvmThreadSelf()); assert(!dvmCheckException(dvmThreadSelf())); if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); } return NULL; } resField = (InstField*)dvmFindFieldHier(resClass, dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx), dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx)); if (resField == NULL) { ALOGD("DexOpt: couldn't find field %s.%s", resClass->descriptor, dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx)); if (pFailure != NULL) *pFailure = VERIFY_ERROR_NO_FIELD; return NULL; } if (dvmIsStaticField(resField)) { ALOGD("DexOpt: wanted instance, got static for field %s.%s", resClass->descriptor, dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx)); if (pFailure != NULL) *pFailure = VERIFY_ERROR_CLASS_CHANGE; return NULL; } /* * Add it to the resolved table so we're faster on the next lookup. */ dvmDexSetResolvedField(pDvmDex, ifieldIdx, (Field*) resField); } /* access allowed? */ tweakLoader(referrer, resField->clazz); bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField); untweakLoader(referrer, resField->clazz); if (!allowed) { ALOGI("DexOpt: access denied from %s to field %s.%s", referrer->descriptor, resField->clazz->descriptor, resField->name); if (pFailure != NULL) *pFailure = VERIFY_ERROR_ACCESS_FIELD; return NULL; } return resField; }