Fix deadlock from dl_iterate_phdr() callback.

Avoid allocating any memory from within the callback.

Test: m test-art-host-gtest
Test: testrunner.py --host
Test: aosp_taimen-userdebug boots.
Test: run-gtests.sh
Test: testrunner.py --target --optimizing --64
Bug: 156312036
Change-Id: I1e89a0f5b1d5185d80856cf7b805f53fff605bbb
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index a7054d3..d8fd1ea 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -1232,6 +1232,11 @@
   LOG(FATAL) << "Should not reach here.";
   UNREACHABLE();
 #else
+  struct DummyMapData {
+    const char* name;
+    uint8_t* vaddr;
+    size_t memsz;
+  };
   struct dl_iterate_context {
     static int callback(dl_phdr_info* info, size_t size ATTRIBUTE_UNUSED, void* data) {
       auto* context = reinterpret_cast<dl_iterate_context*>(data);
@@ -1266,8 +1271,18 @@
             uint8_t* vaddr = reinterpret_cast<uint8_t*>(info->dlpi_addr +
                 info->dlpi_phdr[i].p_vaddr);
             size_t memsz = info->dlpi_phdr[i].p_memsz;
-            MemMap mmap = MemMap::MapDummy(info->dlpi_name, vaddr, memsz);
-            context->dlopen_mmaps_->push_back(std::move(mmap));
+            size_t name_size = strlen(info->dlpi_name) + 1u;
+            std::vector<char>* dummy_maps_names = context->dummy_maps_names_;
+            // We must not allocate any memory in the callback, see b/156312036 .
+            if (name_size < dummy_maps_names->capacity() - dummy_maps_names->size() &&
+                context->dummy_maps_data_->size() < context->dummy_maps_data_->capacity()) {
+              dummy_maps_names->insert(
+                  dummy_maps_names->end(), info->dlpi_name, info->dlpi_name + name_size);
+              const char* name = &(*dummy_maps_names)[dummy_maps_names->size() - name_size];
+              context->dummy_maps_data_->push_back({ name, vaddr, memsz });
+            }
+            context->num_dummy_maps_ += 1u;
+            context->dummy_maps_names_size_ += name_size;
           }
         }
         return 1;  // Stop iteration and return 1 from dl_iterate_phdr.
@@ -1275,24 +1290,71 @@
       return 0;  // Continue iteration and return 0 from dl_iterate_phdr when finished.
     }
     const uint8_t* const begin_;
-    std::vector<MemMap>* const dlopen_mmaps_;
-    const size_t shared_objects_before;
+    std::vector<DummyMapData>* dummy_maps_data_;
+    size_t num_dummy_maps_;
+    std::vector<char>* dummy_maps_names_;
+    size_t dummy_maps_names_size_;
+    size_t shared_objects_before;
     size_t shared_objects_seen;
   };
-  dl_iterate_context context = { Begin(), &dlopen_mmaps_, shared_objects_before_, 0};
+
+  // We must not allocate any memory in the callback, see b/156312036 .
+  // Therefore we pre-allocate storage for the data we need for creating the dummy maps.
+  std::vector<DummyMapData> dummy_maps_data;
+  dummy_maps_data.reserve(32);  // 32 should be enough. If not, we'll retry.
+  std::vector<char> dummy_maps_names;
+  dummy_maps_names.reserve(4 * KB);  // 4KiB should be enough. If not, we'll retry.
+
+  dl_iterate_context context = {
+      Begin(),
+      &dummy_maps_data,
+      /*num_dummy_maps_*/ 0u,
+      &dummy_maps_names,
+      /*dummy_maps_names_size_*/ 0u,
+      shared_objects_before_,
+      /*shared_objects_seen*/ 0u
+  };
 
   if (dl_iterate_phdr(dl_iterate_context::callback, &context) == 0) {
     // Hm. Maybe our optimization went wrong. Try another time with shared_objects_before == 0
     // before giving up. This should be unusual.
     VLOG(oat) << "Need a second run in PreSetup, didn't find with shared_objects_before="
               << shared_objects_before_;
-    dl_iterate_context context0 = { Begin(), &dlopen_mmaps_, 0, 0};
-    if (dl_iterate_phdr(dl_iterate_context::callback, &context0) == 0) {
+    DCHECK(dummy_maps_data.empty());
+    DCHECK_EQ(context.num_dummy_maps_, 0u);
+    DCHECK(dummy_maps_names.empty());
+    DCHECK_EQ(context.dummy_maps_names_size_, 0u);
+    context.shared_objects_before = 0u;
+    context.shared_objects_seen = 0u;
+    if (dl_iterate_phdr(dl_iterate_context::callback, &context) == 0) {
       // OK, give up and print an error.
       PrintFileToLog("/proc/self/maps", android::base::LogSeverity::WARNING);
       LOG(ERROR) << "File " << elf_filename << " loaded with dlopen but cannot find its mmaps.";
     }
   }
+
+  if (dummy_maps_data.size() < context.num_dummy_maps_) {
+    // Insufficient capacity. Reserve more space and retry.
+    dummy_maps_data.clear();
+    dummy_maps_data.reserve(context.num_dummy_maps_);
+    context.num_dummy_maps_ = 0u;
+    dummy_maps_names.clear();
+    dummy_maps_names.reserve(context.dummy_maps_names_size_);
+    context.dummy_maps_names_size_ = 0u;
+    context.shared_objects_before = 0u;
+    context.shared_objects_seen = 0u;
+    bool success = (dl_iterate_phdr(dl_iterate_context::callback, &context) != 0);
+    CHECK(success);
+  }
+
+  CHECK_EQ(dummy_maps_data.size(), context.num_dummy_maps_);
+  CHECK_EQ(dummy_maps_names.size(), context.dummy_maps_names_size_);
+  DCHECK_EQ(static_cast<size_t>(std::count(dummy_maps_names.begin(), dummy_maps_names.end(), '\0')),
+            context.num_dummy_maps_);
+  for (const DummyMapData& data : dummy_maps_data) {
+    MemMap mmap = MemMap::MapDummy(data.name, data.vaddr, data.memsz);
+    dlopen_mmaps_.push_back(std::move(mmap));
+  }
 #endif
 }