Extra OatDexFile checks when defining classes.

Add a check that the class def index from TypeLookupTable is
valid and checks that OatClass data is within the oat file.
Add a TODO for a check that we cannot do with the data
currently recorded in the oat file.

Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Bug: 148412019
Change-Id: Ie23a24cf72bb5a3cc432680db2c870a33d58b030
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 3c29480..b646eb1 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -2073,46 +2073,46 @@
   }
 
   uint32_t oat_class_offset = GetOatClassOffset(class_def_index);
+  CHECK_GE(oat_class_offset, sizeof(OatHeader)) << oat_file_->GetLocation();
+  CHECK_LT(oat_class_offset, oat_file_->Size()) << oat_file_->GetLocation();
+  CHECK_LE(/* status */ sizeof(uint16_t) + /* type */ sizeof(uint16_t),
+           oat_file_->Size() - oat_class_offset) << oat_file_->GetLocation();
+  const uint8_t* current_pointer = oat_file_->Begin() + oat_class_offset;
 
-  const uint8_t* oat_class_pointer = oat_file_->Begin() + oat_class_offset;
-  CHECK_LT(reinterpret_cast<const void*>(oat_class_pointer),
-           reinterpret_cast<const void*>(oat_file_->End())) << oat_file_->GetLocation();
-
-  const uint8_t* status_pointer = oat_class_pointer;
-  CHECK_LT(status_pointer, oat_file_->End()) << oat_file_->GetLocation();
-  ClassStatus status = enum_cast<ClassStatus>(*reinterpret_cast<const int16_t*>(status_pointer));
-  CHECK_LE(status, ClassStatus::kLast) << static_cast<uint32_t>(status)
-      << " at " << oat_file_->GetLocation();
-
-  const uint8_t* type_pointer = status_pointer + sizeof(uint16_t);
-  CHECK_LT(type_pointer, oat_file_->End()) << oat_file_->GetLocation();
-  OatClassType type = static_cast<OatClassType>(*reinterpret_cast<const uint16_t*>(type_pointer));
-  CHECK_LT(type, OatClassType::kOatClassMax) << oat_file_->GetLocation();
-
-  const uint8_t* after_type_pointer = type_pointer + sizeof(int16_t);
-  CHECK_LE(after_type_pointer, oat_file_->End()) << oat_file_->GetLocation();
+  uint16_t status_value = *reinterpret_cast<const uint16_t*>(current_pointer);
+  current_pointer += sizeof(uint16_t);
+  uint16_t type_value = *reinterpret_cast<const uint16_t*>(current_pointer);
+  current_pointer += sizeof(uint16_t);
+  CHECK_LE(status_value, enum_cast<uint8_t>(ClassStatus::kLast))
+      << static_cast<uint32_t>(status_value) << " at " << oat_file_->GetLocation();
+  CHECK_LT(type_value, enum_cast<uint8_t>(OatClassType::kOatClassMax)) << oat_file_->GetLocation();
+  ClassStatus status = enum_cast<ClassStatus>(status_value);
+  OatClassType type = enum_cast<OatClassType>(type_value);
 
   uint32_t bitmap_size = 0;
-  const uint8_t* bitmap_pointer = nullptr;
-  const uint8_t* methods_pointer = nullptr;
+  const uint32_t* bitmap_pointer = nullptr;
+  const OatMethodOffsets* methods_pointer = nullptr;
   if (type != OatClassType::kNoneCompiled) {
     if (type == OatClassType::kSomeCompiled) {
-      bitmap_size = static_cast<uint32_t>(*reinterpret_cast<const uint32_t*>(after_type_pointer));
-      bitmap_pointer = after_type_pointer + sizeof(bitmap_size);
-      CHECK_LE(bitmap_pointer, oat_file_->End()) << oat_file_->GetLocation();
-      methods_pointer = bitmap_pointer + bitmap_size;
+      CHECK_LE(sizeof(uint32_t), static_cast<size_t>(oat_file_->End() - current_pointer))
+          << oat_file_->GetLocation();
+      bitmap_size = *reinterpret_cast<const uint32_t*>(current_pointer);
+      current_pointer += sizeof(uint32_t);
+      CHECK_LE(bitmap_size, static_cast<size_t>(oat_file_->End() - current_pointer))
+          << oat_file_->GetLocation();
+      bitmap_pointer = reinterpret_cast<const uint32_t*>(current_pointer);
+      current_pointer += bitmap_size;
+      CHECK_LE(BitVector::NumSetBits(bitmap_pointer, bitmap_size * kBitsPerByte),
+               static_cast<size_t>(oat_file_->End() - current_pointer) / sizeof(OatMethodOffsets))
+          << oat_file_->GetLocation();
     } else {
-      methods_pointer = after_type_pointer;
+      // TODO: We do not have enough information here to check if the array extends beyond
+      // the end of the oat file. We should record the number of methods in the oat file.
     }
-    CHECK_LE(methods_pointer, oat_file_->End()) << oat_file_->GetLocation();
+    methods_pointer = reinterpret_cast<const OatMethodOffsets*>(current_pointer);
   }
 
-  return OatFile::OatClass(oat_file_,
-                           status,
-                           type,
-                           bitmap_size,
-                           reinterpret_cast<const uint32_t*>(bitmap_pointer),
-                           reinterpret_cast<const OatMethodOffsets*>(methods_pointer));
+  return OatFile::OatClass(oat_file_, status, type, bitmap_size, bitmap_pointer, methods_pointer);
 }
 
 const dex::ClassDef* OatDexFile::FindClassDef(const DexFile& dex_file,
@@ -2125,9 +2125,10 @@
   if (LIKELY((oat_dex_file != nullptr) && oat_dex_file->GetTypeLookupTable().Valid())) {
     used_lookup_table = true;
     const uint32_t class_def_idx = oat_dex_file->GetTypeLookupTable().Lookup(descriptor, hash);
-    lookup_table_classdef = (class_def_idx != dex::kDexNoIndex)
-        ? &dex_file.GetClassDef(class_def_idx)
-        : nullptr;
+    if (class_def_idx != dex::kDexNoIndex) {
+      CHECK_LT(class_def_idx, dex_file.NumClassDefs()) << oat_dex_file->GetOatFile()->GetLocation();
+      lookup_table_classdef = &dex_file.GetClassDef(class_def_idx);
+    }
     if (!kIsDebugBuild) {
       return lookup_table_classdef;
     }