Handle segfaults while walking native heap

Vendor blobs on ryu mprotect heap pages, causing segfaults when dumping
unreachable memory.  Handle segfaults within HeapWalker by mapping a
zero page over any unreadable pages.  HeapWalker runs in the forked
process, so the mapping will not affect the original process.

Bug: 28269332
Change-Id: I16245af722123f2ad467cbc6f245a70666c55544
(cherry picked from commit ba5d9ff6d9674a0f1e985b49f53863045aff558d)
diff --git a/libmemunreachable/HeapWalker.h b/libmemunreachable/HeapWalker.h
index 7b851c4..140f3ea 100644
--- a/libmemunreachable/HeapWalker.h
+++ b/libmemunreachable/HeapWalker.h
@@ -17,9 +17,12 @@
 #ifndef LIBMEMUNREACHABLE_HEAP_WALKER_H_
 #define LIBMEMUNREACHABLE_HEAP_WALKER_H_
 
+#include <signal.h>
+
 #include "android-base/macros.h"
 
 #include "Allocator.h"
+#include "ScopedSignalHandler.h"
 #include "Tarjan.h"
 
 // A range [begin, end)
@@ -41,10 +44,17 @@
  public:
   HeapWalker(Allocator<HeapWalker> allocator) : allocator_(allocator),
     allocations_(allocator), allocation_bytes_(0),
-	roots_(allocator), root_vals_(allocator) {
+	roots_(allocator), root_vals_(allocator),
+	segv_handler_(allocator), walking_ptr_(0) {
     valid_allocations_range_.end = 0;
     valid_allocations_range_.begin = ~valid_allocations_range_.end;
+
+    segv_handler_.install(SIGSEGV,
+        [=](ScopedSignalHandler& handler, int signal, siginfo_t* siginfo, void* uctx) {
+          this->HandleSegFault(handler, signal, siginfo, uctx);
+      });
   }
+
   ~HeapWalker() {}
   bool Allocation(uintptr_t begin, uintptr_t end);
   void Root(uintptr_t begin, uintptr_t end);
@@ -70,7 +80,8 @@
  private:
 
   void RecurseRoot(const Range& root);
-  bool IsAllocationPtr(uintptr_t ptr, Range* range, AllocationInfo** info);
+  bool WordContainsAllocationPtr(uintptr_t ptr, Range* range, AllocationInfo** info);
+  void HandleSegFault(ScopedSignalHandler&, int, siginfo_t*, void*);
 
   DISALLOW_COPY_AND_ASSIGN(HeapWalker);
   Allocator<HeapWalker> allocator_;
@@ -81,6 +92,9 @@
 
   allocator::vector<Range> roots_;
   allocator::vector<uintptr_t> root_vals_;
+
+  ScopedSignalHandler segv_handler_;
+  uintptr_t walking_ptr_;
 };
 
 template<class F>
@@ -92,7 +106,7 @@
   for (uintptr_t i = begin; i < range.end; i += sizeof(uintptr_t)) {
     Range ref_range;
     AllocationInfo* ref_info;
-    if (IsAllocationPtr(*reinterpret_cast<uintptr_t*>(i), &ref_range, &ref_info)) {
+    if (WordContainsAllocationPtr(i, &ref_range, &ref_info)) {
       f(ref_range, ref_info);
     }
   }