Reject classes implementing themselves as interface directly or transitively.

Also enforce class definition ordering with respect to
implemented interfaces within a Dex file.

Change-Id: I1cb991b1a976933f952d45ed08d8a189000ae4f5
diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc
index c76044dd5..d241f0c 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex_file_verifier.cc
@@ -1987,12 +1987,37 @@
     }
   }
 
+  // Check interfaces.
   const DexFile::TypeList* interfaces = dex_file_->GetInterfacesList(*item);
   if (interfaces != nullptr) {
     uint32_t size = interfaces->Size();
-
-    // Ensure that all interfaces refer to classes (not arrays or primitives).
     for (uint32_t i = 0; i < size; i++) {
+      // Check that a class does not implement itself directly (by having the
+      // same type idx as one of its immediate implemented interfaces).
+      if (UNLIKELY(interfaces->GetTypeItem(i).type_idx_ == item->class_idx_)) {
+        ErrorStringPrintf("Class with same type idx as implemented interface: '%d'",
+                          item->class_idx_);
+        return false;
+      }
+
+      // Check that a class is defined after the interfaces it implements
+      // (if they are defined in the same Dex file).
+      const DexFile::ClassDef* interface_def =
+          dex_file_->FindClassDef(interfaces->GetTypeItem(i).type_idx_);
+      if (interface_def != nullptr) {
+        // The interface is defined in this Dex file.
+        if (interface_def > item) {
+          // ClassDef item for interface appearing after the class' ClassDef item.
+          ErrorStringPrintf("Invalid class definition ordering:"
+                            " class with type idx: '%d' defined before"
+                            " implemented interface with type idx: '%d'",
+                            item->class_idx_,
+                            interfaces->GetTypeItem(i).type_idx_);
+          return false;
+        }
+      }
+
+      // Ensure that the interface refers to a class (not an array nor a primitive type).
       LOAD_STRING_BY_TYPE(inf_descriptor, interfaces->GetTypeItem(i).type_idx_,
                           "inter_class_def_item interface type_idx")
       if (UNLIKELY(!IsValidDescriptor(inf_descriptor) || inf_descriptor[0] != 'L')) {
diff --git a/runtime/dex_file_verifier_test.cc b/runtime/dex_file_verifier_test.cc
index fa6cfee..42c3e0d 100644
--- a/runtime/dex_file_verifier_test.cc
+++ b/runtime/dex_file_verifier_test.cc
@@ -1607,4 +1607,93 @@
       " superclass with type idx: '0'");
 }
 
+// Generated from:
+//
+//   .class public abstract interface LInterfaceImplementsItself;
+//   .super Ljava/lang/Object;
+//   .implements LInterfaceImplementsItself;
+
+static const char kInterfaceImplementsItselfTestDex[] =
+    "ZGV4CjAzNQBgK8ZUyZHMR7lmXBQ6uJSrndrDOAoPughEAQAAcAAAAHhWNBIAAAAAAAAAAOAAAAAC"
+    "AAAAcAAAAAIAAAB4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAIAAAACkAAAAoAAAAKAA"
+    "AAC9AAAAAAAAAAEAAAAAAAAAAQYAAAEAAADUAAAA/////wAAAAAAAAAAAAAAABtMSW50ZXJmYWNl"
+    "SW1wbGVtZW50c0l0c2VsZjsAEkxqYXZhL2xhbmcvT2JqZWN0OwAAAAABAAAAAAAAAAAAAAAIAAAA"
+    "AAAAAAEAAAAAAAAAAQAAAAIAAABwAAAAAgAAAAIAAAB4AAAABgAAAAEAAACAAAAAAiAAAAIAAACg"
+    "AAAAARAAAAEAAADUAAAAAxAAAAEAAADcAAAAABAAAAEAAADgAAAA";
+
+TEST_F(DexFileVerifierTest, InterfaceImplementsItself) {
+  VerifyModification(
+      kInterfaceImplementsItselfTestDex,
+      "interface_implements_itself",
+      [](DexFile* dex_file ATTRIBUTE_UNUSED) { /* empty */ },
+      "Class with same type idx as implemented interface: '0'");
+}
+
+// Generated from:
+//
+//   .class public abstract interface LPing;
+//   .super Ljava/lang/Object;
+//   .implements LPong;
+//
+// and:
+//
+//   .class public abstract interface LPong;
+//   .super Ljava/lang/Object;
+//   .implements LPing;
+
+static const char kInterfacesImplementOneAnotherTestDex[] =
+    "ZGV4CjAzNQC9LFtYXO2Se9koyKbznW5m5+lH2CaauJdkAQAAcAAAAHhWNBIAAAAAAAAAAAABAAAD"
+    "AAAAcAAAAAMAAAB8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAIgAAACcAAAAyAAAAMgA"
+    "AADQAAAA2AAAAAAAAAABAAAAAgAAAAEAAAABBgAAAgAAAOwAAAD/////AAAAAAAAAAAAAAAAAAAA"
+    "AAEGAAACAAAA9AAAAP////8AAAAAAAAAAAAAAAAGTFBpbmc7AAZMUG9uZzsAEkxqYXZhL2xhbmcv"
+    "T2JqZWN0OwABAAAAAAAAAAEAAAABAAAAAAAAAAgAAAAAAAAAAQAAAAAAAAABAAAAAwAAAHAAAAAC"
+    "AAAAAwAAAHwAAAAGAAAAAgAAAIgAAAACIAAAAwAAAMgAAAABEAAAAgAAAOwAAAADEAAAAQAAAPwA"
+    "AAAAEAAAAQAAAAABAAA=";
+
+TEST_F(DexFileVerifierTest, InterfacesImplementOneAnother) {
+  VerifyModification(
+      kInterfacesImplementOneAnotherTestDex,
+      "interfaces_implement_one_another",
+      [](DexFile* dex_file ATTRIBUTE_UNUSED) { /* empty */ },
+      "Invalid class definition ordering: class with type idx: '1' defined before"
+      " implemented interface with type idx: '0'");
+}
+
+// Generated from:
+//
+//   .class public abstract interface LA;
+//   .super Ljava/lang/Object;
+//   .implements LB;
+//
+// and:
+//
+//   .class public abstract interface LB;
+//   .super Ljava/lang/Object;
+//   .implements LC;
+//
+// and:
+//
+//   .class public abstract interface LC;
+//   .super Ljava/lang/Object;
+//   .implements LA;
+
+static const char kCircularInterfaceImplementationTestDex[] =
+    "ZGV4CjAzNQBqK5JDNvKFhgQE2DfycoggFIPHXp5VfdOUAQAAcAAAAHhWNBIAAAAAAAAAADABAAAE"
+    "AAAAcAAAAAQAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAJAAAACkAAAA8AAAAPAA"
+    "AAD1AAAA+gAAAP8AAAAAAAAAAQAAAAIAAAADAAAAAgAAAAEGAAADAAAAHAEAAP////8AAAAAAAAA"
+    "AAAAAAABAAAAAQYAAAMAAAAUAQAA/////wAAAAAAAAAAAAAAAAAAAAABBgAAAwAAACQBAAD/////"
+    "AAAAAAAAAAAAAAAAA0xBOwADTEI7AANMQzsAEkxqYXZhL2xhbmcvT2JqZWN0OwAAAQAAAAIAAAAB"
+    "AAAAAAAAAAEAAAABAAAAAAAAAAgAAAAAAAAAAQAAAAAAAAABAAAABAAAAHAAAAACAAAABAAAAIAA"
+    "AAAGAAAAAwAAAJAAAAACIAAABAAAAPAAAAABEAAAAwAAABQBAAADEAAAAQAAACwBAAAAEAAAAQAA"
+    "ADABAAA=";
+
+TEST_F(DexFileVerifierTest, CircularInterfaceImplementation) {
+  VerifyModification(
+      kCircularInterfaceImplementationTestDex,
+      "circular_interface_implementation",
+      [](DexFile* dex_file ATTRIBUTE_UNUSED) { /* empty */ },
+      "Invalid class definition ordering: class with type idx: '2' defined before"
+      " implemented interface with type idx: '0'");
+}
+
 }  // namespace art