Fix a per-process dumpsys meminfo crash.

In the InvalidateAllocator() function, DlMallocSpace and RosAllocSpace
both null out the underlying allocator pointer at the zygote fork time
so that new allocations won't accidentally happen in the zygote space
after a zygote fork. However, nulling out the only allocator pointer
would cause crashes in non-allocation uses such as GetFootprint() in
this particular crash. Fix this by creating a second pointer just for
the allocation purpose that gets nulled upon a InvalidateAllocator()
call while the original pointer keeps pointing to the allocator.

Change-Id: Ie751d9380db39baace9e25712a3824eec9a9969a
diff --git a/runtime/gc/space/dlmalloc_space-inl.h b/runtime/gc/space/dlmalloc_space-inl.h
index fbbba1f..c14a4e1 100644
--- a/runtime/gc/space/dlmalloc_space-inl.h
+++ b/runtime/gc/space/dlmalloc_space-inl.h
@@ -40,7 +40,7 @@
 
 inline mirror::Object* DlMallocSpace::AllocWithoutGrowthLocked(Thread* /*self*/, size_t num_bytes,
                                                                size_t* bytes_allocated) {
-  mirror::Object* result = reinterpret_cast<mirror::Object*>(mspace_malloc(mspace_, num_bytes));
+  mirror::Object* result = reinterpret_cast<mirror::Object*>(mspace_malloc(mspace_for_alloc_, num_bytes));
   if (LIKELY(result != NULL)) {
     if (kDebugSpaces) {
       CHECK(Contains(result)) << "Allocation (" << reinterpret_cast<void*>(result)
diff --git a/runtime/gc/space/dlmalloc_space.cc b/runtime/gc/space/dlmalloc_space.cc
index fcac588..b067bbc 100644
--- a/runtime/gc/space/dlmalloc_space.cc
+++ b/runtime/gc/space/dlmalloc_space.cc
@@ -111,7 +111,7 @@
 DlMallocSpace::DlMallocSpace(const std::string& name, MemMap* mem_map, void* mspace, byte* begin,
                              byte* end, byte* limit, size_t growth_limit)
     : MallocSpace(name, mem_map, begin, end, limit, growth_limit),
-      total_bytes_freed_(0), total_objects_freed_(0), mspace_(mspace) {
+      total_bytes_freed_(0), total_objects_freed_(0), mspace_(mspace), mspace_for_alloc_(mspace) {
   CHECK(mspace != NULL);
 }
 
@@ -334,25 +334,17 @@
 }
 
 uint64_t DlMallocSpace::GetBytesAllocated() {
-  if (mspace_ != nullptr) {
-    MutexLock mu(Thread::Current(), lock_);
-    size_t bytes_allocated = 0;
-    mspace_inspect_all(mspace_, DlmallocBytesAllocatedCallback, &bytes_allocated);
-    return bytes_allocated;
-  } else {
-    return Size();
-  }
+  MutexLock mu(Thread::Current(), lock_);
+  size_t bytes_allocated = 0;
+  mspace_inspect_all(mspace_, DlmallocBytesAllocatedCallback, &bytes_allocated);
+  return bytes_allocated;
 }
 
 uint64_t DlMallocSpace::GetObjectsAllocated() {
-  if (mspace_ != nullptr) {
-    MutexLock mu(Thread::Current(), lock_);
-    size_t objects_allocated = 0;
-    mspace_inspect_all(mspace_, DlmallocObjectsAllocatedCallback, &objects_allocated);
-    return objects_allocated;
-  } else {
-    return 0;
-  }
+  MutexLock mu(Thread::Current(), lock_);
+  size_t objects_allocated = 0;
+  mspace_inspect_all(mspace_, DlmallocObjectsAllocatedCallback, &objects_allocated);
+  return objects_allocated;
 }
 
 #ifndef NDEBUG
diff --git a/runtime/gc/space/dlmalloc_space.h b/runtime/gc/space/dlmalloc_space.h
index 1cfee7a..d18d4ad 100644
--- a/runtime/gc/space/dlmalloc_space.h
+++ b/runtime/gc/space/dlmalloc_space.h
@@ -97,7 +97,7 @@
   mirror::Class* FindRecentFreedObject(const mirror::Object* obj);
 
   virtual void InvalidateAllocator() {
-    mspace_ = nullptr;
+    mspace_for_alloc_ = nullptr;
   }
 
   virtual bool IsDlMallocSpace() const {
@@ -130,7 +130,11 @@
   static const size_t kChunkOverhead = kWordSize;
 
   // Underlying malloc space
-  void* mspace_;
+  void* const mspace_;
+
+  // A mspace pointer used for allocation. Equals to what mspace_
+  // points to or nullptr after InvalidateAllocator() is called.
+  void* mspace_for_alloc_;
 
   friend class collector::MarkSweep;
 
diff --git a/runtime/gc/space/rosalloc_space-inl.h b/runtime/gc/space/rosalloc_space-inl.h
index 92c69af..0fe5dd7 100644
--- a/runtime/gc/space/rosalloc_space-inl.h
+++ b/runtime/gc/space/rosalloc_space-inl.h
@@ -35,8 +35,9 @@
 inline mirror::Object* RosAllocSpace::AllocWithoutGrowthLocked(Thread* self, size_t num_bytes,
                                                                size_t* bytes_allocated) {
   size_t rosalloc_size = 0;
-  mirror::Object* result = reinterpret_cast<mirror::Object*>(rosalloc_->Alloc(self, num_bytes,
-                                                                              &rosalloc_size));
+  mirror::Object* result = reinterpret_cast<mirror::Object*>(
+      rosalloc_for_alloc_->Alloc(self, num_bytes,
+                                 &rosalloc_size));
   if (LIKELY(result != NULL)) {
     if (kDebugSpaces) {
       CHECK(Contains(result)) << "Allocation (" << reinterpret_cast<void*>(result)
diff --git a/runtime/gc/space/rosalloc_space.cc b/runtime/gc/space/rosalloc_space.cc
index 72692d6..a3d2dfa 100644
--- a/runtime/gc/space/rosalloc_space.cc
+++ b/runtime/gc/space/rosalloc_space.cc
@@ -38,7 +38,8 @@
 RosAllocSpace::RosAllocSpace(const std::string& name, MemMap* mem_map,
                              art::gc::allocator::RosAlloc* rosalloc, byte* begin, byte* end,
                              byte* limit, size_t growth_limit)
-    : MallocSpace(name, mem_map, begin, end, limit, growth_limit), rosalloc_(rosalloc) {
+    : MallocSpace(name, mem_map, begin, end, limit, growth_limit), rosalloc_(rosalloc),
+      rosalloc_for_alloc_(rosalloc) {
   CHECK(rosalloc != NULL);
 }
 
@@ -252,23 +253,15 @@
 }
 
 uint64_t RosAllocSpace::GetBytesAllocated() {
-  if (rosalloc_ != NULL) {
-    size_t bytes_allocated = 0;
-    InspectAllRosAlloc(art::gc::allocator::RosAlloc::BytesAllocatedCallback, &bytes_allocated);
-    return bytes_allocated;
-  } else {
-    return Size();
-  }
+  size_t bytes_allocated = 0;
+  InspectAllRosAlloc(art::gc::allocator::RosAlloc::BytesAllocatedCallback, &bytes_allocated);
+  return bytes_allocated;
 }
 
 uint64_t RosAllocSpace::GetObjectsAllocated() {
-  if (rosalloc_ != NULL) {
-    size_t objects_allocated = 0;
-    InspectAllRosAlloc(art::gc::allocator::RosAlloc::ObjectsAllocatedCallback, &objects_allocated);
-    return objects_allocated;
-  } else {
-    return 0;
-  }
+  size_t objects_allocated = 0;
+  InspectAllRosAlloc(art::gc::allocator::RosAlloc::ObjectsAllocatedCallback, &objects_allocated);
+  return objects_allocated;
 }
 
 void RosAllocSpace::InspectAllRosAlloc(void (*callback)(void *start, void *end, size_t num_bytes, void* callback_arg),
diff --git a/runtime/gc/space/rosalloc_space.h b/runtime/gc/space/rosalloc_space.h
index 8191ffb..6311580 100644
--- a/runtime/gc/space/rosalloc_space.h
+++ b/runtime/gc/space/rosalloc_space.h
@@ -97,7 +97,7 @@
   mirror::Class* FindRecentFreedObject(const mirror::Object* obj);
 
   virtual void InvalidateAllocator() {
-    rosalloc_ = NULL;
+    rosalloc_for_alloc_ = NULL;
   }
 
   virtual bool IsRosAllocSpace() const {
@@ -130,7 +130,11 @@
   AtomicInteger total_objects_freed_atomic_;
 
   // Underlying rosalloc.
-  art::gc::allocator::RosAlloc* rosalloc_;
+  art::gc::allocator::RosAlloc* const rosalloc_;
+
+  // A rosalloc pointer used for allocation. Equals to what rosalloc_
+  // points to or nullptr after InvalidateAllocator() is called.
+  art::gc::allocator::RosAlloc* rosalloc_for_alloc_;
 
   friend class collector::MarkSweep;