OSDN Git Service

Fix divergence between interpreter and compiler.
authorAart Bik <ajcbik@google.com>
Wed, 29 Jun 2016 21:54:26 +0000 (14:54 -0700)
committerAart Bik <ajcbik@google.com>
Wed, 29 Jun 2016 21:54:26 +0000 (14:54 -0700)
Rationale:
Access checks on a method invocation should be performed
prior to checking null pointer for non-static method calls.

Test: 600-verifier-fails

BUG=29068831

Change-Id: I21874d96ff83e7e6c6cf7c239e65ce1b515b9729

runtime/entrypoints/entrypoint_utils-inl.h
test/600-verifier-fails/expected.txt
test/600-verifier-fails/src/Main.java

index fc62573..1b55d2f 100644 (file)
@@ -448,23 +448,10 @@ inline ArtMethod* FindMethodFromCode(uint32_t method_idx, mirror::Object** this_
                      : ClassLinker::kNoICCECheckForCache;
     resolved_method = class_linker->ResolveMethod<resolve_mode>(self, method_idx, referrer, type);
   }
+  // Resolution and access check.
   if (UNLIKELY(resolved_method == nullptr)) {
     DCHECK(self->IsExceptionPending());  // Throw exception and unwind.
     return nullptr;  // Failure.
-  } else if (UNLIKELY(*this_object == nullptr && type != kStatic)) {
-    if (UNLIKELY(resolved_method->GetDeclaringClass()->IsStringClass() &&
-                 resolved_method->IsConstructor())) {
-      // Hack for String init:
-      //
-      // We assume that the input of String.<init> in verified code is always
-      // an unitialized reference. If it is a null constant, it must have been
-      // optimized out by the compiler. Do not throw NullPointerException.
-    } else {
-      // Maintain interpreter-like semantics where NullPointerException is thrown
-      // after potential NoSuchMethodError from class linker.
-      ThrowNullPointerExceptionForMethodAccess(method_idx, type);
-      return nullptr;  // Failure.
-    }
   } else if (access_check) {
     mirror::Class* methods_class = resolved_method->GetDeclaringClass();
     bool can_access_resolved_method =
@@ -482,6 +469,22 @@ inline ArtMethod* FindMethodFromCode(uint32_t method_idx, mirror::Object** this_
       return nullptr;  // Failure.
     }
   }
+  // Next, null pointer check.
+  if (UNLIKELY(*this_object == nullptr && type != kStatic)) {
+    if (UNLIKELY(resolved_method->GetDeclaringClass()->IsStringClass() &&
+                 resolved_method->IsConstructor())) {
+      // Hack for String init:
+      //
+      // We assume that the input of String.<init> in verified code is always
+      // an unitialized reference. If it is a null constant, it must have been
+      // optimized out by the compiler. Do not throw NullPointerException.
+    } else {
+      // Maintain interpreter-like semantics where NullPointerException is thrown
+      // after potential NoSuchMethodError from class linker.
+      ThrowNullPointerExceptionForMethodAccess(method_idx, type);
+      return nullptr;  // Failure.
+    }
+  }
   switch (type) {
     case kStatic:
     case kDirect:
index 8399969..eaa0c93 100644 (file)
@@ -2,3 +2,4 @@ passed A
 passed B
 passed C
 passed D
+passed E
index 64c3d5c..fa25d58 100644 (file)
@@ -38,7 +38,6 @@ public class Main {
     test("B");
     test("C");
     test("D");
-    // TODO: enable again
-    // test("E");
+    test("E");
   }
 }