Verify method invocation type.

Dalvik provides five different ways to invoke a method (virtual, super,
direct, static, interface).  Using a virtual invoke instruction to call
a direct method will not produce the desired results.

This adds a test to the verifier that ensures the method targeted by
an invocation instruction is of an appropriate kind.

Bug 3082885.

Change-Id: Iacf14b9b3959a0894d89d727286e10e3ecf72680
diff --git a/vm/analysis/CodeVerify.c b/vm/analysis/CodeVerify.c
index 933c058..dcd8252 100644
--- a/vm/analysis/CodeVerify.c
+++ b/vm/analysis/CodeVerify.c
@@ -1002,6 +1002,24 @@
 }
 
 /*
+ * See if the method matches the MethodType.
+ */
+static bool isCorrectInvokeKind(MethodType methodType, Method* resMethod)
+{
+    switch (methodType) {
+    case METHOD_DIRECT:
+        return dvmIsDirectMethod(resMethod);
+    case METHOD_STATIC:
+        return dvmIsStaticMethod(resMethod);
+    case METHOD_VIRTUAL:
+    case METHOD_INTERFACE:
+        return !dvmIsDirectMethod(resMethod);
+    default:
+        return false;
+    }
+}
+
+/*
  * Verify the arguments to a method.  We're executing in "method", making
  * a call to the method reference in vB.
  *
@@ -1060,10 +1078,9 @@
             //char* curMethodDesc =
             //    dexProtoCopyMethodDescriptor(&meth->prototype);
 
-            LOGI("Could not find method %s.%s, referenced from "
-                 "method %s.%s\n",
-                 dotMissingClass, methodName/*, methodDesc*/,
-                 dotMethClass, meth->name/*, curMethodDesc*/);
+            LOGI("Could not find method %s.%s, referenced from method %s.%s\n",
+                dotMissingClass, methodName/*, methodDesc*/,
+                dotMethClass, meth->name/*, curMethodDesc*/);
 
             free(dotMissingClass);
             free(dotMethClass);
@@ -1093,6 +1110,16 @@
     }
 
     /*
+     * See if the method type implied by the invoke instruction matches the
+     * access flags for the target method.
+     */
+    if (!isCorrectInvokeKind(methodType, resMethod)) {
+        LOG_VFY("VFY: invoke type does not match method type of %s.%s\n",
+            resMethod->clazz->descriptor, resMethod->name);
+        goto fail;
+    }
+
+    /*
      * If we're using invoke-super(method), make sure that the executing
      * method's class' superclass has a vtable entry for the target method.
      */