Refactor TaskMemory initialization

Currently, TaskMemory implements the ProcessMemory interface almost
exactly; however, it's initialized using a constructor instead of an
Initialize method which makes it incompatible with a number of
ProcessMemory tests. Change its initialization to match the other
ProcessMemory classes.

Bug: crashpad:263
Change-Id: I8022dc3e1827a5bb398aace0058ce9494b6b6eb6
Reviewed-on: https://chromium-review.googlesource.com/c/1384447
Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org>
Reviewed-by: Mark Mentovai <mark@chromium.org>
diff --git a/snapshot/mac/process_reader_mac.cc b/snapshot/mac/process_reader_mac.cc
index e142fd2..4850bba 100644
--- a/snapshot/mac/process_reader_mac.cc
+++ b/snapshot/mac/process_reader_mac.cc
@@ -113,9 +113,11 @@
     return false;
   }
 
-  is_64_bit_ = process_info_.Is64Bit();
+  if (!task_memory_.Initialize(task)) {
+    return false;
+  }
 
-  task_memory_.reset(new TaskMemory(task));
+  is_64_bit_ = process_info_.Is64Bit();
   task_ = task;
 
   INITIALIZATION_STATE_SET_VALID(initialized_);
@@ -441,7 +443,7 @@
     Module module;
     module.timestamp = image_info.imageFileModDate;
 
-    if (!task_memory_->ReadCString(image_info.imageFilePath, &module.name)) {
+    if (!task_memory_.ReadCString(image_info.imageFilePath, &module.name)) {
       LOG(WARNING) << "could not read dyld_image_info::imageFilePath";
       // Proceed anyway with an empty module name.
     }
diff --git a/snapshot/mac/process_reader_mac.h b/snapshot/mac/process_reader_mac.h
index 91836db..8a5b2c8 100644
--- a/snapshot/mac/process_reader_mac.h
+++ b/snapshot/mac/process_reader_mac.h
@@ -138,7 +138,7 @@
   bool CPUTimes(timeval* user_time, timeval* system_time) const;
 
   //! \return Accesses the memory of the target task.
-  TaskMemory* Memory() { return task_memory_.get(); }
+  TaskMemory* Memory() { return &task_memory_; }
 
   //! \return The threads that are in the task (process). The first element (at
   //!     index `0`) corresponds to the main thread.
@@ -232,7 +232,7 @@
   std::vector<Thread> threads_;  // owns send rights
   std::vector<Module> modules_;
   std::vector<std::unique_ptr<MachOImageReader>> module_readers_;
-  std::unique_ptr<TaskMemory> task_memory_;
+  TaskMemory task_memory_;
   task_t task_;  // weak
   InitializationStateDcheck initialized_;
 
diff --git a/util/mach/task_memory.cc b/util/mach/task_memory.cc
index ad4c8c3..14069dd 100644
--- a/util/mach/task_memory.cc
+++ b/util/mach/task_memory.cc
@@ -64,10 +64,18 @@
   DCHECK_LE(user_end, vm_end);
 }
 
-TaskMemory::TaskMemory(task_t task) : task_(task) {
+TaskMemory::TaskMemory() : task_(TASK_NULL), initialized_() {}
+
+bool TaskMemory::Initialize(task_t task) {
+  INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
+  task_ = task;
+  INITIALIZATION_STATE_SET_VALID(initialized_);
+  return true;
 }
 
 bool TaskMemory::Read(mach_vm_address_t address, size_t size, void* buffer) {
+  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+
   std::unique_ptr<MappedMemory> memory = ReadMapped(address, size);
   if (!memory) {
     return false;
@@ -80,6 +88,8 @@
 std::unique_ptr<TaskMemory::MappedMemory> TaskMemory::ReadMapped(
     mach_vm_address_t address,
     size_t size) {
+  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+
   if (size == 0) {
     return std::unique_ptr<MappedMemory>(new MappedMemory(0, 0, 0, 0));
   }
@@ -104,12 +114,16 @@
 }
 
 bool TaskMemory::ReadCString(mach_vm_address_t address, std::string* string) {
+  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+
   return ReadCStringInternal(address, false, 0, string);
 }
 
 bool TaskMemory::ReadCStringSizeLimited(mach_vm_address_t address,
                                         mach_vm_size_t size,
                                         std::string* string) {
+  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+
   return ReadCStringInternal(address, true, size, string);
 }
 
@@ -117,6 +131,8 @@
                                      bool has_size,
                                      mach_vm_size_t size,
                                      std::string* string) {
+  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+
   if (!has_size) {
     size = PAGE_SIZE;
   }
diff --git a/util/mach/task_memory.h b/util/mach/task_memory.h
index c8caf85..118ff0b 100644
--- a/util/mach/task_memory.h
+++ b/util/mach/task_memory.h
@@ -23,6 +23,7 @@
 
 #include "base/mac/scoped_mach_vm.h"
 #include "base/macros.h"
+#include "util/misc/initialization_state_dcheck.h"
 
 namespace crashpad {
 
@@ -87,12 +88,21 @@
     DISALLOW_COPY_AND_ASSIGN(MappedMemory);
   };
 
-  //! \param[in] task A send right to the target task’s task port. This object
-  //!     does not take ownership of the send right.
-  explicit TaskMemory(task_t task);
-
+  TaskMemory();
   ~TaskMemory() {}
 
+  //! \brief Initializes this object to read the memory of a task with the
+  //!     provided task port.
+  //!
+  //! This method must be called successfully prior to calling any other method
+  //! in this class.
+  //!
+  //! \param[in] task A send right to the target task's task port. This object
+  //!     does not take ownership of the send right.
+  //!
+  //! \return `true` on success, `false` on failure with a message logged.
+  bool Initialize(task_t task);
+
   //! \brief Copies memory from the target task into a caller-provided buffer in
   //!     the current task.
   //!
@@ -170,6 +180,7 @@
                            std::string* string);
 
   task_t task_;  // weak
+  InitializationStateDcheck initialized_;
 
   DISALLOW_COPY_AND_ASSIGN(TaskMemory);
 };
diff --git a/util/mach/task_memory_test.cc b/util/mach/task_memory_test.cc
index e3ef760..904dfca 100644
--- a/util/mach/task_memory_test.cc
+++ b/util/mach/task_memory_test.cc
@@ -44,7 +44,8 @@
     region[index] = (index % 256) ^ ((index >> 8) % 256);
   }
 
-  TaskMemory memory(mach_task_self());
+  TaskMemory memory;
+  ASSERT_TRUE(memory.Initialize(mach_task_self()));
 
   // This tests using both the Read() and ReadMapped() interfaces.
   std::string result(kSize, '\0');
@@ -119,7 +120,8 @@
       mach_task_self(), address + PAGE_SIZE, PAGE_SIZE, FALSE, VM_PROT_NONE);
   ASSERT_EQ(kr, KERN_SUCCESS) << MachErrorMessage(kr, "vm_protect");
 
-  TaskMemory memory(mach_task_self());
+  TaskMemory memory;
+  ASSERT_TRUE(memory.Initialize(mach_task_self()));
   std::string result(kSize, '\0');
 
   EXPECT_FALSE(memory.Read(address, kSize, &result[0]));
@@ -171,7 +173,8 @@
 }
 
 TEST(TaskMemory, ReadCStringSelf) {
-  TaskMemory memory(mach_task_self());
+  TaskMemory memory;
+  ASSERT_TRUE(memory.Initialize(mach_task_self()));
   std::string result;
 
   const char kConstCharEmpty[] = "";
@@ -253,7 +256,8 @@
       mach_task_self(), address + PAGE_SIZE, PAGE_SIZE, FALSE, VM_PROT_NONE);
   ASSERT_EQ(kr, KERN_SUCCESS) << MachErrorMessage(kr, "vm_protect");
 
-  TaskMemory memory(mach_task_self());
+  TaskMemory memory;
+  ASSERT_TRUE(memory.Initialize(mach_task_self()));
   std::string result;
   EXPECT_FALSE(memory.ReadCString(address, &result));
 
@@ -298,7 +302,8 @@
 }
 
 TEST(TaskMemory, ReadCStringSizeLimited_ConstCharEmpty) {
-  TaskMemory memory(mach_task_self());
+  TaskMemory memory;
+  ASSERT_TRUE(memory.Initialize(mach_task_self()));
   std::string result;
 
   static constexpr char kConstCharEmpty[] = "";
@@ -319,7 +324,8 @@
 }
 
 TEST(TaskMemory, ReadCStringSizeLimited_ConstCharShort) {
-  TaskMemory memory(mach_task_self());
+  TaskMemory memory;
+  ASSERT_TRUE(memory.Initialize(mach_task_self()));
   std::string result;
 
   static constexpr char kConstCharShort[] = "A short const char[]";
@@ -339,7 +345,8 @@
 }
 
 TEST(TaskMemory, ReadCStringSizeLimited_StaticConstCharEmpty) {
-  TaskMemory memory(mach_task_self());
+  TaskMemory memory;
+  ASSERT_TRUE(memory.Initialize(mach_task_self()));
   std::string result;
 
   static constexpr char kStaticConstCharEmpty[] = "";
@@ -364,7 +371,8 @@
 }
 
 TEST(TaskMemory, ReadCStringSizeLimited_StaticConstCharShort) {
-  TaskMemory memory(mach_task_self());
+  TaskMemory memory;
+  ASSERT_TRUE(memory.Initialize(mach_task_self()));
   std::string result;
 
   static constexpr char kStaticConstCharShort[] =
@@ -391,7 +399,8 @@
 }
 
 TEST(TaskMemory, ReadCStringSizeLimited_StringShort) {
-  TaskMemory memory(mach_task_self());
+  TaskMemory memory;
+  ASSERT_TRUE(memory.Initialize(mach_task_self()));
   std::string result;
 
   std::string string_short("A short std::string in a function");
@@ -411,7 +420,8 @@
 }
 
 TEST(TaskMemory, ReadCStringSizeLimited_StringLong) {
-  TaskMemory memory(mach_task_self());
+  TaskMemory memory;
+  ASSERT_TRUE(memory.Initialize(mach_task_self()));
   std::string result;
 
   std::string string_long;
@@ -477,7 +487,8 @@
   // hopefully there are either no other threads or they’re all quiescent, so
   // nothing else should wind up mapped in the address.
 
-  TaskMemory memory(mach_task_self());
+  TaskMemory memory;
+  ASSERT_TRUE(memory.Initialize(mach_task_self()));
   std::unique_ptr<TaskMemory::MappedMemory> mapped;
 
   static constexpr char kTestBuffer[] = "hello!";
@@ -514,7 +525,8 @@
 
 TEST(TaskMemory, MappedMemoryReadCString) {
   // This tests the behavior of TaskMemory::MappedMemory::ReadCString().
-  TaskMemory memory(mach_task_self());
+  TaskMemory memory;
+  ASSERT_TRUE(memory.Initialize(mach_task_self()));
   std::unique_ptr<TaskMemory::MappedMemory> mapped;
 
   static constexpr char kTestBuffer[] = "0\0" "2\0" "45\0" "789";