Merge "ART: Add object-readbarrier-inl.h"
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index ed34a8d..11af1c0 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -125,6 +125,7 @@
 ART_GTEST_transaction_test_DEX_DEPS := Transaction
 ART_GTEST_type_lookup_table_test_DEX_DEPS := Lookup
 ART_GTEST_unstarted_runtime_test_DEX_DEPS := Nested
+ART_GTEST_heap_verification_test_DEX_DEPS := ProtoCompare ProtoCompare2 StaticsFromCode XandY
 ART_GTEST_verifier_deps_test_DEX_DEPS := VerifierDeps VerifierDepsMulti MultiDex
 ART_GTEST_dex_to_dex_decompiler_test_DEX_DEPS := VerifierDeps DexToDexDecompiler
 
@@ -655,6 +656,7 @@
 ART_GTEST_stub_test_DEX_DEPS :=
 ART_GTEST_transaction_test_DEX_DEPS :=
 ART_GTEST_dex2oat_environment_tests_DEX_DEPS :=
+ART_GTEST_heap_verification_test_DEX_DEPS :=
 ART_GTEST_verifier_deps_test_DEX_DEPS :=
 ART_VALGRIND_DEPENDENCIES :=
 ART_VALGRIND_TARGET_DEPENDENCIES :=
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 011ef65..0860b2e 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -93,6 +93,7 @@
         "gc/space/space.cc",
         "gc/space/zygote_space.cc",
         "gc/task_processor.cc",
+        "gc/verification.cc",
         "hprof/hprof.cc",
         "image.cc",
         "indirect_reference_table.cc",
@@ -547,6 +548,7 @@
         "gc/accounting/space_bitmap_test.cc",
         "gc/collector/immune_spaces_test.cc",
         "gc/heap_test.cc",
+        "gc/heap_verification_test.cc",
         "gc/reference_queue_test.cc",
         "gc/space/dlmalloc_space_static_test.cc",
         "gc/space/dlmalloc_space_random_test.cc",
diff --git a/runtime/gc/collector/concurrent_copying-inl.h b/runtime/gc/collector/concurrent_copying-inl.h
index 8a9b11d..dd449f9 100644
--- a/runtime/gc/collector/concurrent_copying-inl.h
+++ b/runtime/gc/collector/concurrent_copying-inl.h
@@ -96,7 +96,9 @@
 }
 
 template<bool kGrayImmuneObject, bool kFromGCThread>
-inline mirror::Object* ConcurrentCopying::Mark(mirror::Object* from_ref) {
+inline mirror::Object* ConcurrentCopying::Mark(mirror::Object* from_ref,
+                                               mirror::Object* holder,
+                                               MemberOffset offset) {
   if (from_ref == nullptr) {
     return nullptr;
   }
@@ -141,7 +143,7 @@
       if (immune_spaces_.ContainsObject(from_ref)) {
         return MarkImmuneSpace<kGrayImmuneObject>(from_ref);
       } else {
-        return MarkNonMoving(from_ref);
+        return MarkNonMoving(from_ref, holder, offset);
       }
     default:
       UNREACHABLE();
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index a091fce..80b569a 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -29,6 +29,7 @@
 #include "gc/reference_processor.h"
 #include "gc/space/image_space.h"
 #include "gc/space/space-inl.h"
+#include "gc/verification.h"
 #include "image-inl.h"
 #include "intern_table.h"
 #include "mirror/class-inl.h"
@@ -2362,7 +2363,9 @@
   return alloc_stack->Contains(ref);
 }
 
-mirror::Object* ConcurrentCopying::MarkNonMoving(mirror::Object* ref) {
+mirror::Object* ConcurrentCopying::MarkNonMoving(mirror::Object* ref,
+                                                 mirror::Object* holder,
+                                                 MemberOffset offset) {
   // ref is in a non-moving space (from_ref == to_ref).
   DCHECK(!region_space_->HasAddress(ref)) << ref;
   DCHECK(!immune_spaces_.ContainsObject(ref));
@@ -2408,6 +2411,11 @@
           return ref;
         }
       }
+      if (is_los && !IsAligned<kPageSize>(ref)) {
+        // Ref is a large object that is not aligned, it must be heap corruption. Dump data before
+        // AtomicSetReadBarrierState since it will fault if the address is not valid.
+        heap_->GetVerification()->LogHeapCorruption(ref, offset, holder, /* fatal */ true);
+      }
       // Not marked or on the allocation stack. Try to mark it.
       // This may or may not succeed, which is ok.
       bool cas_success = false;
diff --git a/runtime/gc/collector/concurrent_copying.h b/runtime/gc/collector/concurrent_copying.h
index 398a7e2..c21520d 100644
--- a/runtime/gc/collector/concurrent_copying.h
+++ b/runtime/gc/collector/concurrent_copying.h
@@ -106,7 +106,9 @@
     return IsMarked(ref) == ref;
   }
   template<bool kGrayImmuneObject = true, bool kFromGCThread = false>
-  ALWAYS_INLINE mirror::Object* Mark(mirror::Object* from_ref)
+  ALWAYS_INLINE mirror::Object* Mark(mirror::Object* from_ref,
+                                     mirror::Object* holder = nullptr,
+                                     MemberOffset offset = MemberOffset(0))
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!mark_stack_lock_, !skipped_blocks_lock_, !immune_gray_stack_lock_);
   ALWAYS_INLINE mirror::Object* MarkFromReadBarrier(mirror::Object* from_ref)
@@ -224,7 +226,10 @@
   void DisableMarking() REQUIRES_SHARED(Locks::mutator_lock_);
   void IssueDisableMarkingCheckpoint() REQUIRES_SHARED(Locks::mutator_lock_);
   void ExpandGcMarkStack() REQUIRES_SHARED(Locks::mutator_lock_);
-  mirror::Object* MarkNonMoving(mirror::Object* from_ref) REQUIRES_SHARED(Locks::mutator_lock_)
+  mirror::Object* MarkNonMoving(mirror::Object* from_ref,
+                                mirror::Object* holder = nullptr,
+                                MemberOffset offset = MemberOffset(0))
+      REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!mark_stack_lock_, !skipped_blocks_lock_);
   ALWAYS_INLINE mirror::Object* MarkUnevacFromSpaceRegion(mirror::Object* from_ref,
       accounting::SpaceBitmap<kObjectAlignment>* bitmap)
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index df12d87..64dce5f 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -60,6 +60,7 @@
 #include "gc/space/space-inl.h"
 #include "gc/space/zygote_space.h"
 #include "gc/task_processor.h"
+#include "gc/verification.h"
 #include "entrypoints/quick/quick_alloc_entrypoints.h"
 #include "gc_pause_listener.h"
 #include "heap-inl.h"
@@ -287,6 +288,7 @@
     CHECK_EQ(foreground_collector_type_, kCollectorTypeCC);
     CHECK_EQ(background_collector_type_, kCollectorTypeCCBackground);
   }
+  verification_.reset(new Verification(this));
   CHECK_GE(large_object_threshold, kMinLargeObjectThreshold);
   ScopedTrace trace(__FUNCTION__);
   Runtime* const runtime = Runtime::Current();
@@ -4268,5 +4270,9 @@
   return ret;
 }
 
+const Verification* Heap::GetVerification() const {
+  return verification_.get();
+}
+
 }  // namespace gc
 }  // namespace art
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 241d84c..aa123d8 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -64,6 +64,7 @@
 class GcPauseListener;
 class ReferenceProcessor;
 class TaskProcessor;
+class Verification;
 
 namespace accounting {
   class HeapBitmap;
@@ -821,6 +822,8 @@
   // reasons, we assume it stays valid when we read it (so that we don't require a lock).
   void RemoveGcPauseListener();
 
+  const Verification* GetVerification() const;
+
  private:
   class ConcurrentGCTask;
   class CollectorTransitionTask;
@@ -1433,6 +1436,8 @@
   // An installed GC Pause listener.
   Atomic<GcPauseListener*> gc_pause_listener_;
 
+  std::unique_ptr<Verification> verification_;
+
   friend class CollectorTransitionTask;
   friend class collector::GarbageCollector;
   friend class collector::MarkCompact;
diff --git a/runtime/gc/heap_verification_test.cc b/runtime/gc/heap_verification_test.cc
new file mode 100644
index 0000000..480ba2a
--- /dev/null
+++ b/runtime/gc/heap_verification_test.cc
@@ -0,0 +1,119 @@
+/*
+ * 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 "common_runtime_test.h"
+#include "verification.h"
+#include "mirror/string.h"
+#include "scoped_thread_state_change-inl.h"
+
+namespace art {
+namespace gc {
+
+class VerificationTest : public CommonRuntimeTest {
+ protected:
+  VerificationTest() {}
+
+  template <class T>
+  mirror::ObjectArray<T>* AllocObjectArray(Thread* self, size_t length)
+      REQUIRES_SHARED(Locks::mutator_lock_) {
+    ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
+    return mirror::ObjectArray<T>::Alloc(
+        self,
+        class_linker->GetClassRoot(ClassLinker::ClassRoot::kObjectArrayClass),
+        length);
+  }
+};
+
+TEST_F(VerificationTest, IsValidHeapObjectAddress) {
+  ScopedObjectAccess soa(Thread::Current());
+  const Verification* const v = Runtime::Current()->GetHeap()->GetVerification();
+  EXPECT_FALSE(v->IsValidHeapObjectAddress(reinterpret_cast<const void*>(1)));
+  EXPECT_FALSE(v->IsValidHeapObjectAddress(reinterpret_cast<const void*>(4)));
+  EXPECT_FALSE(v->IsValidHeapObjectAddress(nullptr));
+  VariableSizedHandleScope hs(soa.Self());
+  Handle<mirror::String> string(
+      hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "test")));
+  EXPECT_TRUE(v->IsValidHeapObjectAddress(string.Get()));
+  EXPECT_TRUE(v->IsValidHeapObjectAddress(string->GetClass()));
+  const uintptr_t uint_klass = reinterpret_cast<uintptr_t>(string->GetClass());
+  // Not actually a valid object but the verification can't know that. Guaranteed to be inside a
+  // heap space.
+  EXPECT_TRUE(v->IsValidHeapObjectAddress(
+      reinterpret_cast<const void*>(uint_klass + kObjectAlignment)));
+  EXPECT_FALSE(v->IsValidHeapObjectAddress(
+      reinterpret_cast<const void*>(&uint_klass)));
+}
+
+TEST_F(VerificationTest, IsValidClass) {
+  ScopedObjectAccess soa(Thread::Current());
+  VariableSizedHandleScope hs(soa.Self());
+  Handle<mirror::String> string(
+      hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "test")));
+  const Verification* const v = Runtime::Current()->GetHeap()->GetVerification();
+  EXPECT_FALSE(v->IsValidClass(reinterpret_cast<const void*>(1)));
+  EXPECT_FALSE(v->IsValidClass(reinterpret_cast<const void*>(4)));
+  EXPECT_FALSE(v->IsValidClass(nullptr));
+  EXPECT_FALSE(v->IsValidClass(string.Get()));
+  EXPECT_TRUE(v->IsValidClass(string->GetClass()));
+  const uintptr_t uint_klass = reinterpret_cast<uintptr_t>(string->GetClass());
+  EXPECT_FALSE(v->IsValidClass(reinterpret_cast<const void*>(uint_klass - kObjectAlignment)));
+  EXPECT_FALSE(v->IsValidClass(reinterpret_cast<const void*>(&uint_klass)));
+}
+
+TEST_F(VerificationTest, DumpObjectInfo) {
+  ScopedLogSeverity sls(LogSeverity::INFO);
+  ScopedObjectAccess soa(Thread::Current());
+  Runtime* const runtime = Runtime::Current();
+  VariableSizedHandleScope hs(soa.Self());
+  Handle<mirror::String> string(
+      hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "obj")));
+  Handle<mirror::ObjectArray<mirror::Object>> arr(
+      hs.NewHandle(AllocObjectArray<mirror::Object>(soa.Self(), 256)));
+  const Verification* const v = runtime->GetHeap()->GetVerification();
+  LOG(INFO) << v->DumpObjectInfo(reinterpret_cast<const void*>(1), "obj");
+  LOG(INFO) << v->DumpObjectInfo(reinterpret_cast<const void*>(4), "obj");
+  LOG(INFO) << v->DumpObjectInfo(nullptr, "obj");
+  LOG(INFO) << v->DumpObjectInfo(string.Get(), "test");
+  LOG(INFO) << v->DumpObjectInfo(string->GetClass(), "obj");
+  const uintptr_t uint_klass = reinterpret_cast<uintptr_t>(string->GetClass());
+  LOG(INFO) << v->DumpObjectInfo(reinterpret_cast<const void*>(uint_klass - kObjectAlignment),
+                                 "obj");
+  LOG(INFO) << v->DumpObjectInfo(reinterpret_cast<const void*>(&uint_klass), "obj");
+  LOG(INFO) << v->DumpObjectInfo(arr.Get(), "arr");
+}
+
+TEST_F(VerificationTest, LogHeapCorruption) {
+  ScopedLogSeverity sls(LogSeverity::INFO);
+  ScopedObjectAccess soa(Thread::Current());
+  Runtime* const runtime = Runtime::Current();
+  VariableSizedHandleScope hs(soa.Self());
+  Handle<mirror::String> string(
+      hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "obj")));
+  using ObjArray = mirror::ObjectArray<mirror::Object>;
+  Handle<ObjArray> arr(
+      hs.NewHandle(AllocObjectArray<mirror::Object>(soa.Self(), 256)));
+  const Verification* const v = runtime->GetHeap()->GetVerification();
+  arr->Set(0, string.Get());
+  // Test normal cases.
+  v->LogHeapCorruption(arr.Get(), ObjArray::DataOffset(kHeapReferenceSize), string.Get(), false);
+  v->LogHeapCorruption(string.Get(), mirror::Object::ClassOffset(), string->GetClass(), false);
+  // Test null holder cases.
+  v->LogHeapCorruption(nullptr, MemberOffset(0), string.Get(), false);
+  v->LogHeapCorruption(nullptr, MemberOffset(0), arr.Get(), false);
+}
+
+}  // namespace gc
+}  // namespace art
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
diff --git a/runtime/gc/verification.h b/runtime/gc/verification.h
new file mode 100644
index 0000000..3d95d93
--- /dev/null
+++ b/runtime/gc/verification.h
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+#ifndef ART_RUNTIME_GC_VERIFICATION_H_
+#define ART_RUNTIME_GC_VERIFICATION_H_
+
+#include "obj_ptr.h"
+#include "offsets.h"
+
+namespace art {
+
+namespace mirror {
+class Class;
+class Object;
+}  // namespace mirror
+
+namespace gc {
+
+namespace space {
+class Space;
+}  // namespace space
+
+class Heap;
+
+class Verification {
+ public:
+  explicit Verification(gc::Heap* heap) : heap_(heap) {}
+
+  // Dump some reveant to debugging info about an object.
+  std::string DumpObjectInfo(const void* obj, const char* tag) const
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
+  // Don't use ObjPtr for things that might not be aligned like the invalid reference.
+  void LogHeapCorruption(ObjPtr<mirror::Object> holder,
+                         MemberOffset offset,
+                         mirror::Object* ref,
+                         bool fatal) const REQUIRES_SHARED(Locks::mutator_lock_);
+
+
+  // Return true if the klass is likely to be a valid mirror::Class.
+  bool IsValidClass(const void* klass) const REQUIRES_SHARED(Locks::mutator_lock_);
+
+  // Does not allow null.
+  bool IsValidHeapObjectAddress(const void* addr, space::Space** out_space = nullptr) const
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
+ private:
+  gc::Heap* const heap_;
+};
+
+}  // namespace gc
+}  // namespace art
+
+#endif  // ART_RUNTIME_GC_VERIFICATION_H_
diff --git a/test/911-get-stack-trace/expected.txt b/test/911-get-stack-trace/expected.txt
index 2318414..fb5f71b 100644
--- a/test/911-get-stack-trace/expected.txt
+++ b/test/911-get-stack-trace/expected.txt
@@ -4,7 +4,7 @@
 From top
 ---------
  getStackTrace (Ljava/lang/Thread;II)[[Ljava/lang/String; -1 -2
- print (Ljava/lang/Thread;II)V 0 36
+ print (Ljava/lang/Thread;II)V 0 38
  printOrWait (IILart/ControlData;)V 6 41
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
@@ -22,10 +22,9 @@
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
  doTest ()V 38 25
- run ()V 20 26
- main ([Ljava/lang/String;)V 0 19
+ run ()V 0 30
 ---------
- print (Ljava/lang/Thread;II)V 0 36
+ print (Ljava/lang/Thread;II)V 0 38
  printOrWait (IILart/ControlData;)V 6 41
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
@@ -43,11 +42,10 @@
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
  doTest ()V 42 26
- run ()V 20 26
- main ([Ljava/lang/String;)V 0 19
+ run ()V 0 30
 ---------
  getStackTrace (Ljava/lang/Thread;II)[[Ljava/lang/String; -1 -2
- print (Ljava/lang/Thread;II)V 0 36
+ print (Ljava/lang/Thread;II)V 0 38
  printOrWait (IILart/ControlData;)V 6 41
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
@@ -59,19 +57,19 @@
  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
 From bottom
 ---------
- main ([Ljava/lang/String;)V 0 19
+ run ()V 0 30
 ---------
+ baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
  doTest ()V 65 32
- run ()V 20 26
- main ([Ljava/lang/String;)V 0 19
+ run ()V 0 30
 ---------
+ bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- doTest ()V 69 33
 
 ################################
 ### Other thread (suspended) ###
@@ -258,9 +256,12 @@
 Signal Catcher
 
 ---------
-main
+Test911
 
 ---------
+main
+<not printed>
+---------
 AllTraces Thread 0
  wait ()V -1 -2
  printOrWait (IILart/ControlData;)V 24 47
@@ -356,14 +357,16 @@
 Signal Catcher
 
 ---------
-main
+Test911
  getAllStackTraces (I)[[Ljava/lang/Object; -1 -2
  printAll (I)V 0 75
  doTest ()V 128 59
- run ()V 44 38
- main ([Ljava/lang/String;)V 0 19
+ run ()V 24 42
 
 ---------
+main
+<not printed>
+---------
 AllTraces Thread 0
  wait ()V -1 -2
  printOrWait (IILart/ControlData;)V 24 47
@@ -589,18 +592,23 @@
 Signal Catcher
 
 ---------
-main
+Test911
  getAllStackTraces (I)[[Ljava/lang/Object; -1 -2
  printAll (I)V 0 75
  doTest ()V 133 61
- run ()V 44 38
- main ([Ljava/lang/String;)V 0 19
+ run ()V 24 42
 
+---------
+main
+<not printed>
 
 ########################################
 ### Other select threads (suspended) ###
 ########################################
 ---------
+Test911
+
+---------
 ThreadListTraces Thread 0
 
 ---------
@@ -616,55 +624,58 @@
 ThreadListTraces Thread 8
 
 ---------
-main
-
----------
-ThreadListTraces Thread 0
- wait ()V -1 -2
- printOrWait (IILart/ControlData;)V 24 47
- baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
- bar (IIILart/ControlData;)J 0 26
- foo (IIILart/ControlData;)I 0 21
-
----------
-ThreadListTraces Thread 2
- wait ()V -1 -2
- printOrWait (IILart/ControlData;)V 24 47
- baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
- bar (IIILart/ControlData;)J 0 26
- foo (IIILart/ControlData;)I 0 21
-
----------
-ThreadListTraces Thread 4
- wait ()V -1 -2
- printOrWait (IILart/ControlData;)V 24 47
- baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
- bar (IIILart/ControlData;)J 0 26
- foo (IIILart/ControlData;)I 0 21
-
----------
-ThreadListTraces Thread 6
- wait ()V -1 -2
- printOrWait (IILart/ControlData;)V 24 47
- baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
- bar (IIILart/ControlData;)J 0 26
- foo (IIILart/ControlData;)I 0 21
-
----------
-ThreadListTraces Thread 8
- wait ()V -1 -2
- printOrWait (IILart/ControlData;)V 24 47
- baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
- bar (IIILart/ControlData;)J 0 26
- foo (IIILart/ControlData;)I 0 21
-
----------
-main
+Test911
  getThreadListStackTraces ([Ljava/lang/Thread;I)[[Ljava/lang/Object; -1 -2
  printList ([Ljava/lang/Thread;I)V 0 68
  doTest ()V 116 54
- run ()V 52 42
- main ([Ljava/lang/String;)V 0 19
+ run ()V 32 46
+
+---------
+ThreadListTraces Thread 0
+ wait ()V -1 -2
+ printOrWait (IILart/ControlData;)V 24 47
+ baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
+ bar (IIILart/ControlData;)J 0 26
+ foo (IIILart/ControlData;)I 0 21
+
+---------
+ThreadListTraces Thread 2
+ wait ()V -1 -2
+ printOrWait (IILart/ControlData;)V 24 47
+ baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
+ bar (IIILart/ControlData;)J 0 26
+ foo (IIILart/ControlData;)I 0 21
+
+---------
+ThreadListTraces Thread 4
+ wait ()V -1 -2
+ printOrWait (IILart/ControlData;)V 24 47
+ baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
+ bar (IIILart/ControlData;)J 0 26
+ foo (IIILart/ControlData;)I 0 21
+
+---------
+ThreadListTraces Thread 6
+ wait ()V -1 -2
+ printOrWait (IILart/ControlData;)V 24 47
+ baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
+ bar (IIILart/ControlData;)J 0 26
+ foo (IIILart/ControlData;)I 0 21
+
+---------
+ThreadListTraces Thread 8
+ wait ()V -1 -2
+ printOrWait (IILart/ControlData;)V 24 47
+ baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
+ bar (IIILart/ControlData;)J 0 26
+ foo (IIILart/ControlData;)I 0 21
+
+---------
+Test911
+ getThreadListStackTraces ([Ljava/lang/Thread;I)[[Ljava/lang/Object; -1 -2
+ printList ([Ljava/lang/Thread;I)V 0 68
+ doTest ()V 121 56
+ run ()V 32 46
 
 ---------
 ThreadListTraces Thread 0
@@ -771,25 +782,16 @@
  foo (IIILart/ControlData;)I 0 21
  run ()V 4 37
 
----------
-main
- getThreadListStackTraces ([Ljava/lang/Thread;I)[[Ljava/lang/Object; -1 -2
- printList ([Ljava/lang/Thread;I)V 0 68
- doTest ()V 121 56
- run ()V 52 42
- main ([Ljava/lang/String;)V 0 19
-
 
 ###################
 ### Same thread ###
 ###################
-5
+4
 JVMTI_ERROR_ILLEGAL_ARGUMENT
 [public static native java.lang.Object[] art.Frames.getFrameLocation(java.lang.Thread,int), ffffffff]
 [public static void art.Frames.doTestSameThread(), 38]
 [public static void art.Frames.doTest() throws java.lang.Exception, 0]
-[public static void art.Test911.run() throws java.lang.Exception, 3c]
-[public static void Main.main(java.lang.String[]) throws java.lang.Exception, 0]
+[public void art.Test911$1.run(), 28]
 JVMTI_ERROR_NO_MORE_FRAMES
 
 ################################
diff --git a/test/911-get-stack-trace/src/art/PrintThread.java b/test/911-get-stack-trace/src/art/PrintThread.java
index de1da9c..f50a66b 100644
--- a/test/911-get-stack-trace/src/art/PrintThread.java
+++ b/test/911-get-stack-trace/src/art/PrintThread.java
@@ -19,6 +19,8 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 public class PrintThread {
   public static void print(String[][] stack) {
@@ -36,6 +38,20 @@
     print(getStackTrace(t, start, max));
   }
 
+  // We have to ignore some threads when printing all stack traces. These are threads that may or
+  // may not exist depending on the environment.
+  public final static String IGNORE_THREAD_NAME_REGEX =
+      "Binder:|RenderThread|hwuiTask|Jit thread pool worker|Instr:|JDWP|Profile Saver|main";
+  public final static Matcher IGNORE_THREADS =
+      Pattern.compile(IGNORE_THREAD_NAME_REGEX).matcher("");
+
+  // We have to skip the stack of some threads when printing all stack traces. These are threads
+  // that may have a different call stack (e.g., when run as an app), or may be in a
+  // non-deterministic state.
+  public final static String CUT_STACK_THREAD_NAME_REGEX = "Daemon|main";
+  public final static Matcher CUT_STACK_THREADS =
+      Pattern.compile(CUT_STACK_THREAD_NAME_REGEX).matcher("");
+
   public static void printAll(Object[][] stacks) {
     List<String> stringified = new ArrayList<String>(stacks.length);
 
@@ -43,11 +59,11 @@
       Thread t = (Thread)stackInfo[0];
       String name = (t != null) ? t.getName() : "null";
       String stackSerialization;
-      if (name.contains("Daemon")) {
+      if (CUT_STACK_THREADS.reset(name).find()) {
         // Do not print daemon stacks, as they're non-deterministic.
         stackSerialization = "<not printed>";
-      } else if (name.startsWith("Jit thread pool worker")) {
-        // Skip JIT thread pool. It may or may not be there depending on configuration.
+      } else if (IGNORE_THREADS.reset(name).find()) {
+        // Skip IGNORE_THREADS.
         continue;
       } else {
         StringBuilder sb = new StringBuilder();
diff --git a/test/911-get-stack-trace/src/art/Test911.java b/test/911-get-stack-trace/src/art/Test911.java
index 71a5196..ee59368 100644
--- a/test/911-get-stack-trace/src/art/Test911.java
+++ b/test/911-get-stack-trace/src/art/Test911.java
@@ -23,27 +23,38 @@
     Main.bindAgentJNIForClass(PrintThread.class);
     Main.bindAgentJNIForClass(ThreadListTraces.class);
 
-    SameThread.doTest();
+    Thread t = new Thread("Test911") {
+      @Override
+      public void run() {
+        try {
+          SameThread.doTest();
 
-    System.out.println();
+          System.out.println();
 
-    OtherThread.doTestOtherThreadWait();
+          OtherThread.doTestOtherThreadWait();
 
-    System.out.println();
+          System.out.println();
 
-    OtherThread.doTestOtherThreadBusyLoop();
+          OtherThread.doTestOtherThreadBusyLoop();
 
-    System.out.println();
+          System.out.println();
 
-    AllTraces.doTest();
+          AllTraces.doTest();
 
-    System.out.println();
+          System.out.println();
 
-    ThreadListTraces.doTest();
+          ThreadListTraces.doTest();
 
-    System.out.println();
+          System.out.println();
 
-    Frames.doTest();
+          Frames.doTest();
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
+      }
+    };
+    t.start();
+    t.join();
 
     System.out.println("Done");
   }
diff --git a/test/testrunner/run_build_test_target.py b/test/testrunner/run_build_test_target.py
index 0ab50af..b1274c9 100755
--- a/test/testrunner/run_build_test_target.py
+++ b/test/testrunner/run_build_test_target.py
@@ -62,7 +62,7 @@
 print custom_env
 os.environ.update(custom_env)
 
-if target.get('make'):
+if target.has_key('make'):
   build_command = 'make'
   build_command += ' -j' + str(n_threads)
   build_command += ' -C ' + env.ANDROID_BUILD_TOP
@@ -74,7 +74,7 @@
   if subprocess.call(build_command.split()):
     sys.exit(1)
 
-if target.get('golem'):
+if target.has_key('golem'):
   machine_type = target.get('golem')
   # use art-opt-cc by default since it mimics the default preopt config.
   default_golem_config = 'art-opt-cc'
@@ -92,7 +92,7 @@
   if subprocess.call(cmd):
     sys.exit(1)
 
-if target.get('run-test'):
+if target.has_key('run-test'):
   run_test_command = [os.path.join(env.ANDROID_BUILD_TOP,
                                    'art/test/testrunner/testrunner.py')]
   run_test_command += target.get('run-test', [])
diff --git a/test/valgrind-suppressions.txt b/test/valgrind-suppressions.txt
index c775f98..086a856 100644
--- a/test/valgrind-suppressions.txt
+++ b/test/valgrind-suppressions.txt
@@ -69,3 +69,9 @@
    fun:_ZN12BacktraceMap6CreateEib
 }
 
+{
+   process_vm_readv
+   Memcheck:Param
+   process_vm_readv(lvec[...])
+   fun:process_vm_readv
+}
diff --git a/test/valgrind-target-suppressions.txt b/test/valgrind-target-suppressions.txt
index 452a174..0d63a1c 100644
--- a/test/valgrind-target-suppressions.txt
+++ b/test/valgrind-target-suppressions.txt
@@ -67,3 +67,10 @@
   fun:msync
   fun:_ZN3art6MemMap11MapInternalEPvmiiilb
 }
+
+{
+   process_vm_readv
+   Memcheck:Param
+   process_vm_readv(lvec[...])
+   fun:process_vm_readv
+}