Fix handling of unresolved references in verifier.

The verifier should not treat use of unresolved references as a reason to reject
the entire class. Instead, the verifier treats the instruction as a throw. If
that class is run, the interpreter with extra checks will throw an exception.

Bug: 10457426

Change-Id: I3799da843a7ffb3519bbf6dc13a6276519d9cb95
diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc
index d70b80e..018add3 100644
--- a/runtime/interpreter/interpreter_goto_table_impl.cc
+++ b/runtime/interpreter/interpreter_goto_table_impl.cc
@@ -74,6 +74,7 @@
 template<bool do_access_check>
 JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
                        ShadowFrame& shadow_frame, JValue result_register) {
+  bool do_assignability_check = do_access_check;
   if (UNLIKELY(!shadow_frame.HasReferenceArray())) {
     LOG(FATAL) << "Invalid shadow frame for interpreter use";
     return JValue();
@@ -264,11 +265,28 @@
 
   HANDLE_INSTRUCTION_START(RETURN_OBJECT) {
     JValue result;
+    Object* obj_result = shadow_frame.GetVRegReference(inst->VRegA_11x(inst_data));
     result.SetJ(0);
-    result.SetL(shadow_frame.GetVRegReference(inst->VRegA_11x(inst_data)));
+    result.SetL(obj_result);
     if (UNLIKELY(self->TestAllFlags())) {
       CheckSuspend(self);
     }
+    if (do_assignability_check && obj_result != NULL) {
+      Class* return_type = MethodHelper(shadow_frame.GetMethod()).GetReturnType();
+      if (return_type == NULL) {
+        // Return the pending exception.
+        HANDLE_PENDING_EXCEPTION();
+      }
+      if (!obj_result->VerifierInstanceOf(return_type)) {
+        // This should never happen.
+        self->ThrowNewExceptionF(self->GetCurrentLocationForThrow(),
+                                 "Ljava/lang/VirtualMachineError;",
+                                 "Returning '%s' that is not instance of return type '%s'",
+                                 ClassHelper(obj_result->GetClass()).GetDescriptor(),
+                                 ClassHelper(return_type).GetDescriptor());
+        HANDLE_PENDING_EXCEPTION();
+      }
+    }
     if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
       instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
                                        shadow_frame.GetMethod(), dex_pc,
@@ -512,6 +530,12 @@
     Object* exception = shadow_frame.GetVRegReference(inst->VRegA_11x(inst_data));
     if (UNLIKELY(exception == NULL)) {
       ThrowNullPointerException(NULL, "throw with null exception");
+    } else if (do_assignability_check && !exception->GetClass()->IsThrowableClass()) {
+      // This should never happen.
+      self->ThrowNewExceptionF(self->GetCurrentLocationForThrow(),
+                               "Ljava/lang/VirtualMachineError;",
+                               "Throwing '%s' that is not instance of Throwable",
+                               ClassHelper(exception->GetClass()).GetDescriptor());
     } else {
       self->SetException(shadow_frame.GetCurrentLocationForThrow(), exception->AsThrowable());
     }