OSDN Git Service

ART: Print maps directly to log
authorAndreas Gampe <agampe@google.com>
Tue, 24 Feb 2015 23:50:19 +0000 (15:50 -0800)
committerAndreas Gampe <agampe@google.com>
Wed, 25 Feb 2015 06:30:47 +0000 (22:30 -0800)
Do not read proc maps into a string before printing them later back
to the log. In low-memory situations this can cause a bad_alloc.

External bug: http://b.android.com/153990
Bug: 19494774

Change-Id: Ie63d8788afe8c9da65b30b2f89c50d3dbb820755

runtime/mem_map.cc
runtime/oat_file.cc
runtime/utils.cc
runtime/utils.h

index a722813..4b85469 100644 (file)
@@ -152,11 +152,9 @@ static bool ContainedWithinExistingMap(uintptr_t begin,
       return true;
     }
   }
-  std::string maps;
-  ReadFileToString("/proc/self/maps", &maps);
+  PrintFileToLog("/proc/self/maps", LogSeverity::WARNING);
   *error_msg = StringPrintf("Requested region 0x%08" PRIxPTR "-0x%08" PRIxPTR " does not overlap "
-                            "any existing map:\n%s\n",
-                            begin, end, maps.c_str());
+                            "any existing map. See process maps in the log.", begin, end);
   return false;
 }
 
@@ -375,12 +373,11 @@ MemMap* MemMap::MapAnonymous(const char* name, uint8_t* expected_ptr, size_t byt
 #endif
 
   if (actual == MAP_FAILED) {
-    std::string maps;
-    ReadFileToString("/proc/self/maps", &maps);
+    PrintFileToLog("/proc/self/maps", LogSeverity::WARNING);
 
-    *error_msg = StringPrintf("Failed anonymous mmap(%p, %zd, 0x%x, 0x%x, %d, 0): %s\n%s",
-                              expected_ptr, page_aligned_byte_count, prot, flags, fd.get(),
-                              strerror(saved_errno), maps.c_str());
+    *error_msg = StringPrintf("Failed anonymous mmap(%p, %zd, 0x%x, 0x%x, %d, 0): %s. See process "
+                              "maps in the log.", expected_ptr, page_aligned_byte_count, prot,
+                              flags, fd.get(), strerror(saved_errno));
     return nullptr;
   }
   std::ostringstream check_map_request_error_msg;
@@ -435,14 +432,13 @@ MemMap* MemMap::MapFileAtAddress(uint8_t* expected_ptr, size_t byte_count, int p
   if (actual == MAP_FAILED) {
     auto saved_errno = errno;
 
-    std::string maps;
-    ReadFileToString("/proc/self/maps", &maps);
+    PrintFileToLog("/proc/self/maps", LogSeverity::WARNING);
 
     *error_msg = StringPrintf("mmap(%p, %zd, 0x%x, 0x%x, %d, %" PRId64
-                              ") of file '%s' failed: %s\n%s",
+                              ") of file '%s' failed: %s. See process maps in the log.",
                               page_aligned_expected, page_aligned_byte_count, prot, flags, fd,
                               static_cast<int64_t>(page_aligned_offset), filename,
-                              strerror(saved_errno), maps.c_str());
+                              strerror(saved_errno));
     return nullptr;
   }
   std::ostringstream check_map_request_error_msg;
@@ -544,11 +540,9 @@ MemMap* MemMap::RemapAtEnd(uint8_t* new_end, const char* tail_name, int tail_pro
   // Unmap/map the tail region.
   int result = munmap(tail_base_begin, tail_base_size);
   if (result == -1) {
-    std::string maps;
-    ReadFileToString("/proc/self/maps", &maps);
-    *error_msg = StringPrintf("munmap(%p, %zd) failed for '%s'\n%s",
-                              tail_base_begin, tail_base_size, name_.c_str(),
-                              maps.c_str());
+    PrintFileToLog("/proc/self/maps", LogSeverity::WARNING);
+    *error_msg = StringPrintf("munmap(%p, %zd) failed for '%s'. See process maps in the log.",
+                              tail_base_begin, tail_base_size, name_.c_str());
     return nullptr;
   }
   // Don't cause memory allocation between the munmap and the mmap
@@ -558,11 +552,10 @@ MemMap* MemMap::RemapAtEnd(uint8_t* new_end, const char* tail_name, int tail_pro
   uint8_t* actual = reinterpret_cast<uint8_t*>(mmap(tail_base_begin, tail_base_size, tail_prot,
                                               flags, fd.get(), 0));
   if (actual == MAP_FAILED) {
-    std::string maps;
-    ReadFileToString("/proc/self/maps", &maps);
-    *error_msg = StringPrintf("anonymous mmap(%p, %zd, 0x%x, 0x%x, %d, 0) failed\n%s",
-                              tail_base_begin, tail_base_size, tail_prot, flags, fd.get(),
-                              maps.c_str());
+    PrintFileToLog("/proc/self/maps", LogSeverity::WARNING);
+    *error_msg = StringPrintf("anonymous mmap(%p, %zd, 0x%x, 0x%x, %d, 0) failed. See process "
+                              "maps in the log.", tail_base_begin, tail_base_size, tail_prot, flags,
+                              fd.get());
     return nullptr;
   }
   return new MemMap(tail_name, actual, tail_size, actual, tail_base_size, tail_prot, false);
index 9061bb3..ae09c6d 100644 (file)
@@ -171,10 +171,10 @@ bool OatFile::Dlopen(const std::string& elf_filename, uint8_t* requested_base,
     return false;
   }
   if (requested_base != NULL && begin_ != requested_base) {
+    PrintFileToLog("/proc/self/maps", LogSeverity::WARNING);
     *error_msg = StringPrintf("Failed to find oatdata symbol at expected address: "
-                              "oatdata=%p != expected=%p /proc/self/maps:\n",
+                              "oatdata=%p != expected=%p. See process maps in the log.",
                               begin_, requested_base);
-    ReadFileToString("/proc/self/maps", error_msg);
     return false;
   }
   end_ = reinterpret_cast<uint8_t*>(dlsym(dlopen_handle_, "oatlastword"));
@@ -209,10 +209,10 @@ bool OatFile::ElfFileOpen(File* file, uint8_t* requested_base, uint8_t* oat_file
     return false;
   }
   if (requested_base != NULL && begin_ != requested_base) {
+    PrintFileToLog("/proc/self/maps", LogSeverity::WARNING);
     *error_msg = StringPrintf("Failed to find oatdata symbol at expected address: "
-                              "oatdata=%p != expected=%p /proc/self/maps:\n",
+                              "oatdata=%p != expected=%p. See process maps in the log.",
                               begin_, requested_base);
-    ReadFileToString("/proc/self/maps", error_msg);
     return false;
   }
   end_ = elf_file_->FindDynamicSymbolAddress("oatlastword");
index 85c9340..2123753 100644 (file)
@@ -133,14 +133,14 @@ void GetThreadStack(pthread_t thread, void** stack_base, size_t* stack_size, siz
 }
 
 bool ReadFileToString(const std::string& file_name, std::string* result) {
-  std::unique_ptr<File> file(new File);
-  if (!file->Open(file_name, O_RDONLY)) {
+  File file;
+  if (!file.Open(file_name, O_RDONLY)) {
     return false;
   }
 
   std::vector<char> buf(8 * KB);
   while (true) {
-    int64_t n = TEMP_FAILURE_RETRY(read(file->Fd(), &buf[0], buf.size()));
+    int64_t n = TEMP_FAILURE_RETRY(read(file.Fd(), &buf[0], buf.size()));
     if (n == -1) {
       return false;
     }
@@ -151,6 +151,59 @@ bool ReadFileToString(const std::string& file_name, std::string* result) {
   }
 }
 
+bool PrintFileToLog(const std::string& file_name, LogSeverity level) {
+  File file;
+  if (!file.Open(file_name, O_RDONLY)) {
+    return false;
+  }
+
+  constexpr size_t kBufSize = 256;  // Small buffer. Avoid stack overflow and stack size warnings.
+  char buf[kBufSize + 1];           // +1 for terminator.
+  size_t filled_to = 0;
+  while (true) {
+    DCHECK_LT(filled_to, kBufSize);
+    int64_t n = TEMP_FAILURE_RETRY(read(file.Fd(), &buf[filled_to], kBufSize - filled_to));
+    if (n <= 0) {
+      // Print the rest of the buffer, if it exists.
+      if (filled_to > 0) {
+        buf[filled_to] = 0;
+        LOG(level) << buf;
+      }
+      return n == 0;
+    }
+    // Scan for '\n'.
+    size_t i = filled_to;
+    bool found_newline = false;
+    for (; i < filled_to + n; ++i) {
+      if (buf[i] == '\n') {
+        // Found a line break, that's something to print now.
+        buf[i] = 0;
+        LOG(level) << buf;
+        // Copy the rest to the front.
+        if (i + 1 < filled_to + n) {
+          memmove(&buf[0], &buf[i + 1], filled_to + n - i - 1);
+          filled_to = filled_to + n - i - 1;
+        } else {
+          filled_to = 0;
+        }
+        found_newline = true;
+        break;
+      }
+    }
+    if (found_newline) {
+      continue;
+    } else {
+      filled_to += n;
+      // Check if we must flush now.
+      if (filled_to == kBufSize) {
+        buf[kBufSize] = 0;
+        LOG(level) << buf;
+        filled_to = 0;
+      }
+    }
+  }
+}
+
 std::string GetIsoDate() {
   time_t now = time(NULL);
   tm tmbuf;
index 3191e7d..698d686 100644 (file)
@@ -410,6 +410,7 @@ std::string JniLongName(mirror::ArtMethod* m)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 bool ReadFileToString(const std::string& file_name, std::string* result);
+bool PrintFileToLog(const std::string& file_name, LogSeverity level);
 
 // Returns the current date in ISO yyyy-mm-dd hh:mm:ss format.
 std::string GetIsoDate();