Correct handling of certain incompatible class changes.
Tests 065 and 066 depened on the old behavior of the verifier. Updating
them to the new behavior wasn't enough, though, because they weren't
reporting the right error. The verifier's resolution code now examines
the exception to see if the load failure was caused by an incompatible
class change error.
I also updated the description of test 071 to note that it will fail on
the device if you don't have an sdcard.
Added a method to get the exception "cause" field. It handles the
"uninitialized" state, which I keep forgetting about.
Spruced up dvmDumpObject, which hadn't been used in a while. Fixed a
warning in Profile.c.
For internal bug 1866729.
diff --git a/vm/Exception.c b/vm/Exception.c
index 4881640..3a56cc3 100644
--- a/vm/Exception.c
+++ b/vm/Exception.c
@@ -102,6 +102,9 @@
/*
* Cache pointers to some of the exception classes we use locally.
+ *
+ * Note this is NOT called during dexopt optimization. Some of the fields
+ * are initialized by the verifier (dvmVerifyCodeFlow).
*/
bool dvmExceptionStartup(void)
{
@@ -377,6 +380,14 @@
}
}
+ if (cause != NULL) {
+ if (!dvmInstanceof(cause->clazz, gDvm.classJavaLangThrowable)) {
+ LOGE("Tried to init exception with cause '%s'\n",
+ cause->clazz->descriptor);
+ dvmAbort();
+ }
+ }
+
/*
* The Throwable class has four public constructors:
* (1) Throwable()
@@ -625,6 +636,28 @@
}
/*
+ * Get the "cause" field from an exception.
+ *
+ * The Throwable class initializes the "cause" field to "this" to
+ * differentiate between being initialized to null and never being
+ * initialized. We check for that here and convert it to NULL.
+ */
+Object* dvmGetExceptionCause(const Object* exception)
+{
+ if (!dvmInstanceof(exception->clazz, gDvm.classJavaLangThrowable)) {
+ LOGE("Tried to get cause from object of type '%s'\n",
+ exception->clazz->descriptor);
+ dvmAbort();
+ }
+ Object* cause =
+ dvmGetFieldObject(exception, gDvm.offJavaLangThrowable_cause);
+ if (cause == exception)
+ return NULL;
+ else
+ return cause;
+}
+
+/*
* Print the stack trace of the current exception on stderr. This is called
* from the JNI ExceptionDescribe call.
*
@@ -1208,9 +1241,8 @@
for (;;) {
logStackTraceOf(exception);
- cause = (Object*) dvmGetFieldObject(exception,
- gDvm.offJavaLangThrowable_cause);
- if ((cause == NULL) || (cause == exception)) {
+ cause = dvmGetExceptionCause(exception);
+ if (cause == NULL) {
break;
}
LOGI("Caused by:\n");