Changed the way errors are propagated through the verifier.
Changed the boolean "okay" to a "failure" enumeration. Most failures are
"generic", but some are called out specially. Added a more detailed
failure result from resolver functions.
In theory, no behavior has changed.
diff --git a/vm/analysis/DexOptimize.c b/vm/analysis/DexOptimize.c
index 3ab6216..d420043 100644
--- a/vm/analysis/DexOptimize.c
+++ b/vm/analysis/DexOptimize.c
@@ -1658,8 +1658,11 @@
* file.
*
* Exceptions caused by failures are cleared before returning.
+ *
+ * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
*/
-ClassObject* dvmOptResolveClass(ClassObject* referrer, u4 classIdx)
+ClassObject* dvmOptResolveClass(ClassObject* referrer, u4 classIdx,
+ VerifyError* pFailure)
{
DvmDex* pDvmDex = referrer->pDvmDex;
ClassObject* resClass;
@@ -1682,6 +1685,8 @@
classIdx,
dexStringByTypeIdx(pDvmDex->pDexFile, classIdx));
dvmClearOptException(dvmThreadSelf());
+ if (pFailure != NULL)
+ *pFailure = VERIFY_ERROR_NO_CLASS;
return NULL;
}
@@ -1695,6 +1700,8 @@
if (IS_CLASS_FLAG_SET(resClass, CLASS_MULTIPLE_DEFS)) {
LOGI("DexOpt: not resolving ambiguous class '%s'\n",
resClass->descriptor);
+ if (pFailure != NULL)
+ *pFailure = VERIFY_ERROR_NO_CLASS;
return NULL;
}
@@ -1705,6 +1712,8 @@
if (!allowed) {
LOGW("DexOpt: resolve class illegal access: %s -> %s\n",
referrer->descriptor, resClass->descriptor);
+ if (pFailure != NULL)
+ *pFailure = VERIFY_ERROR_ACCESS;
return NULL;
}
@@ -1713,8 +1722,11 @@
/*
* Alternate version of dvmResolveInstField().
+ *
+ * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
*/
-InstField* dvmOptResolveInstField(ClassObject* referrer, u4 ifieldIdx)
+InstField* dvmOptResolveInstField(ClassObject* referrer, u4 ifieldIdx,
+ VerifyError* pFailure)
{
DvmDex* pDvmDex = referrer->pDvmDex;
InstField* resField;
@@ -1729,10 +1741,12 @@
/*
* Find the field's class.
*/
- resClass = dvmOptResolveClass(referrer, pFieldId->classIdx);
+ resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
if (resClass == NULL) {
//dvmClearOptException(dvmThreadSelf());
assert(!dvmCheckException(dvmThreadSelf()));
+ if (pFailure != NULL)
+ *pFailure = VERIFY_ERROR_NO_FIELD;
return NULL;
}
@@ -1743,6 +1757,8 @@
LOGD("DexOpt: couldn't find field %s.%s\n",
resClass->descriptor,
dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
+ if (pFailure != NULL)
+ *pFailure = VERIFY_ERROR_NO_FIELD;
return NULL;
}
@@ -1760,6 +1776,8 @@
LOGI("DexOpt: access denied from %s to field %s.%s\n",
referrer->descriptor, resField->field.clazz->descriptor,
resField->field.name);
+ if (pFailure != NULL)
+ *pFailure = VERIFY_ERROR_ACCESS;
return NULL;
}
@@ -1770,8 +1788,11 @@
* 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)
+StaticField* dvmOptResolveStaticField(ClassObject* referrer, u4 sfieldIdx,
+ VerifyError* pFailure)
{
DvmDex* pDvmDex = referrer->pDvmDex;
StaticField* resField;
@@ -1786,10 +1807,12 @@
/*
* Find the field's class.
*/
- resClass = dvmOptResolveClass(referrer, pFieldId->classIdx);
+ resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
if (resClass == NULL) {
//dvmClearOptException(dvmThreadSelf());
assert(!dvmCheckException(dvmThreadSelf()));
+ if (pFailure != NULL)
+ *pFailure = VERIFY_ERROR_NO_FIELD;
return NULL;
}
@@ -1798,6 +1821,8 @@
dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
if (resField == NULL) {
LOGD("DexOpt: couldn't find static field\n");
+ if (pFailure != NULL)
+ *pFailure = VERIFY_ERROR_NO_FIELD;
return NULL;
}
@@ -1820,6 +1845,8 @@
LOGI("DexOpt: access denied from %s to field %s.%s\n",
referrer->descriptor, resField->field.clazz->descriptor,
resField->field.name);
+ if (pFailure != NULL)
+ *pFailure = VERIFY_ERROR_ACCESS;
return NULL;
}
@@ -1845,7 +1872,7 @@
InstField* field;
int byteOffset;
- field = dvmOptResolveInstField(clazz, fieldIdx);
+ field = dvmOptResolveInstField(clazz, fieldIdx, NULL);
if (field == NULL) {
LOGI("DexOpt: unable to optimize field ref 0x%04x at 0x%02x in %s.%s\n",
fieldIdx, (int) (insns - method->insns), clazz->descriptor,
@@ -1869,9 +1896,11 @@
* Alternate version of dvmResolveMethod().
*
* Doesn't throw exceptions, and checks access on every lookup.
+ *
+ * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
*/
Method* dvmOptResolveMethod(ClassObject* referrer, u4 methodIdx,
- MethodType methodType)
+ MethodType methodType, VerifyError* pFailure)
{
DvmDex* pDvmDex = referrer->pDvmDex;
Method* resMethod;
@@ -1888,16 +1917,20 @@
pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
- resClass = dvmOptResolveClass(referrer, pMethodId->classIdx);
+ resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, pFailure);
if (resClass == NULL) {
/* can't find the class that the method is a part of */
LOGV("DexOpt: can't find called method's class (?.%s)\n",
dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
+ if (pFailure != NULL)
+ *pFailure = VERIFY_ERROR_NO_METHOD;
return NULL;
}
if (dvmIsInterfaceClass(resClass)) {
/* method is part of an interface; this is wrong method for that */
LOGW("DexOpt: method is in an interface\n");
+ if (pFailure != NULL)
+ *pFailure = VERIFY_ERROR_GENERIC;
return NULL;
}
@@ -1923,6 +1956,8 @@
if (resMethod == NULL) {
LOGV("DexOpt: couldn't find method '%s'\n",
dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
+ if (pFailure != NULL)
+ *pFailure = VERIFY_ERROR_NO_METHOD;
return NULL;
}
@@ -1931,6 +1966,8 @@
LOGW("DexOpt: pure-abstract method '%s' in %s\n",
dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx),
resClass->descriptor);
+ if (pFailure != NULL)
+ *pFailure = VERIFY_ERROR_GENERIC;
return NULL;
}
@@ -1961,6 +1998,8 @@
referrer->descriptor);
free(desc);
}
+ if (pFailure != NULL)
+ *pFailure = VERIFY_ERROR_ACCESS;
return NULL;
}
@@ -1981,7 +2020,7 @@
Method* baseMethod;
u2 methodIdx = insns[1];
- baseMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_VIRTUAL);
+ baseMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_VIRTUAL, NULL);
if (baseMethod == NULL) {
LOGD("DexOpt: unable to optimize virt call 0x%04x at 0x%02x in %s.%s\n",
methodIdx,
@@ -2025,7 +2064,7 @@
Method* calledMethod;
u2 methodIdx = insns[1];
- calledMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_DIRECT);
+ calledMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_DIRECT, NULL);
if (calledMethod == NULL) {
LOGD("DexOpt: unable to opt direct call 0x%04x at 0x%02x in %s.%s\n",
methodIdx,
@@ -2057,6 +2096,8 @@
/*
* Resolve an interface method reference.
*
+ * No method access check here -- interface methods are always public.
+ *
* Returns NULL if the method was not found. Does not throw an exception.
*/
Method* dvmOptResolveInterfaceMethod(ClassObject* referrer, u4 methodIdx)
@@ -2075,7 +2116,7 @@
pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
- resClass = dvmOptResolveClass(referrer, pMethodId->classIdx);
+ resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, NULL);
if (resClass == NULL) {
/* can't find the class that the method is a part of */
dvmClearOptException(dvmThreadSelf());
@@ -2151,7 +2192,7 @@
//return false;
- calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType);
+ calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
if (calledMethod == NULL) {
LOGV("+++ DexOpt inline: can't find %d\n", methodIdx);
return false;