More robust GC verification and corruption dumping

Added a test for GC heap corruption dumping, added more info to the
dump like adjacent bytes and card table.

Added heap corruption detection in
ConcurrentCopying::MarkNonMoving().

Bug: 37187694
Bug: 12687968

Test: mm test-art-host-gtest-verification_test -j20

Change-Id: I8c90e45796d0784265aa091b2f8082f0cfb62719
diff --git a/runtime/gc/verification.cc b/runtime/gc/verification.cc
new file mode 100644
index 0000000..9e79cb4
--- /dev/null
+++ b/runtime/gc/verification.cc
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "verification.h"
+
+#include <iomanip>
+#include <sstream>
+
+#include "mirror/class-inl.h"
+
+namespace art {
+namespace gc {
+
+std::string Verification::DumpObjectInfo(const void* addr, const char* tag) const {
+  std::ostringstream oss;
+  oss << tag << "=" << addr;
+  if (IsValidHeapObjectAddress(addr)) {
+    mirror::Object* obj = reinterpret_cast<mirror::Object*>(const_cast<void*>(addr));
+    mirror::Class* klass = obj->GetClass<kVerifyNone, kWithoutReadBarrier>();
+    oss << " klass=" << klass;
+    if (IsValidClass(klass)) {
+      oss << "(" << klass->PrettyClass() << ")";
+      if (klass->IsArrayClass<kVerifyNone, kWithoutReadBarrier>()) {
+        oss << " length=" << obj->AsArray<kVerifyNone, kWithoutReadBarrier>()->GetLength();
+      }
+    } else {
+      oss << " <invalid address>";
+    }
+    space::Space* const space = heap_->FindSpaceFromAddress(addr);
+    if (space != nullptr) {
+      oss << " space=" << *space;
+    }
+    accounting::CardTable* card_table = heap_->GetCardTable();
+    if (card_table->AddrIsInCardTable(addr)) {
+      oss << " card=" << static_cast<size_t>(
+          card_table->GetCard(reinterpret_cast<const mirror::Object*>(addr)));
+    }
+    // Dump adjacent RAM.
+    const uintptr_t uint_addr = reinterpret_cast<uintptr_t>(addr);
+    static constexpr size_t kBytesBeforeAfter = 2 * kObjectAlignment;
+    const uintptr_t dump_start = uint_addr - kBytesBeforeAfter;
+    const uintptr_t dump_end = uint_addr + kBytesBeforeAfter;
+    if (dump_start < dump_end &&
+        IsValidHeapObjectAddress(reinterpret_cast<const void*>(dump_start)) &&
+        IsValidHeapObjectAddress(reinterpret_cast<const void*>(dump_end - kObjectAlignment))) {
+      oss << " adjacent_ram=";
+      for (uintptr_t p = dump_start; p < dump_end; ++p) {
+        if (p == uint_addr) {
+          // Marker of where the object is.
+          oss << "|";
+        }
+        uint8_t* ptr = reinterpret_cast<uint8_t*>(p);
+        oss << std::hex << std::setfill('0') << std::setw(2) << static_cast<uintptr_t>(*ptr);
+      }
+    }
+  } else {
+    oss << " <invalid address>";
+  }
+  return oss.str();
+}
+
+void Verification::LogHeapCorruption(ObjPtr<mirror::Object> holder,
+                                     MemberOffset offset,
+                                     mirror::Object* ref,
+                                     bool fatal) const {
+  // Lowest priority logging first:
+  PrintFileToLog("/proc/self/maps", LogSeverity::FATAL_WITHOUT_ABORT);
+  MemMap::DumpMaps(LOG_STREAM(FATAL_WITHOUT_ABORT), true);
+  // Buffer the output in the string stream since it is more important than the stack traces
+  // and we want it to have log priority. The stack traces are printed from Runtime::Abort
+  // which is called from LOG(FATAL) but before the abort message.
+  std::ostringstream oss;
+  oss << "GC tried to mark invalid reference " << ref << std::endl;
+  oss << DumpObjectInfo(ref, "ref") << "\n";
+  if (holder != nullptr) {
+    oss << DumpObjectInfo(holder.Ptr(), "holder");
+    mirror::Class* holder_klass = holder->GetClass<kVerifyNone, kWithoutReadBarrier>();
+    if (IsValidClass(holder_klass)) {
+      oss << "field_offset=" << offset.Uint32Value();
+      ArtField* field = holder->FindFieldByOffset(offset);
+      if (field != nullptr) {
+        oss << " name=" << field->GetName();
+      }
+    }
+  }
+
+  if (fatal) {
+    LOG(FATAL) << oss.str();
+  } else {
+    LOG(FATAL_WITHOUT_ABORT) << oss.str();
+  }
+}
+
+bool Verification::IsValidHeapObjectAddress(const void* addr, space::Space** out_space) const {
+  if (!IsAligned<kObjectAlignment>(addr)) {
+    return false;
+  }
+  space::Space* const space = heap_->FindSpaceFromAddress(addr);
+  if (space != nullptr) {
+    if (out_space != nullptr) {
+      *out_space = space;
+    }
+    return true;
+  }
+  return false;
+}
+
+bool Verification::IsValidClass(const void* addr) const {
+  if (!IsValidHeapObjectAddress(addr)) {
+    return false;
+  }
+  mirror::Class* klass = reinterpret_cast<mirror::Class*>(const_cast<void*>(addr));
+  mirror::Class* k1 = klass->GetClass<kVerifyNone, kWithoutReadBarrier>();
+  if (!IsValidHeapObjectAddress(k1)) {
+    return false;
+  }
+  // k should be class class, take the class again to verify.
+  // Note that this check may not be valid for the no image space since the class class might move
+  // around from moving GC.
+  mirror::Class* k2 = k1->GetClass<kVerifyNone, kWithoutReadBarrier>();
+  if (!IsValidHeapObjectAddress(k2)) {
+    return false;
+  }
+  return k1 == k2;
+}
+
+}  // namespace gc
+}  // namespace art