diff options
author | Andreas Gampe <agampe@google.com> | 2015-02-24 15:50:19 -0800 |
---|---|---|
committer | Andreas Gampe <agampe@google.com> | 2015-02-24 22:30:47 -0800 |
commit | a6dfdae1cffc78f9791348b2e1dc8f4c6c3f7128 (patch) | |
tree | 2b07c1cc94212963ec38a2c0a784a26fe1522194 | |
parent | 96ac49a260223dc00291116daa63d7489c52bb0f (diff) | |
download | art-a6dfdae1cffc78f9791348b2e1dc8f4c6c3f7128.tar.gz art-a6dfdae1cffc78f9791348b2e1dc8f4c6c3f7128.tar.bz2 art-a6dfdae1cffc78f9791348b2e1dc8f4c6c3f7128.zip |
ART: Print maps directly to log
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
-rw-r--r-- | runtime/mem_map.cc | 39 | ||||
-rw-r--r-- | runtime/oat_file.cc | 8 | ||||
-rw-r--r-- | runtime/utils.cc | 59 | ||||
-rw-r--r-- | runtime/utils.h | 1 |
4 files changed, 77 insertions, 30 deletions
diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc index a722813867..4b85469fdf 100644 --- a/runtime/mem_map.cc +++ b/runtime/mem_map.cc @@ -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); diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index 9061bb3d55..ae09c6d385 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -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"); diff --git a/runtime/utils.cc b/runtime/utils.cc index 85c9340d02..2123753de7 100644 --- a/runtime/utils.cc +++ b/runtime/utils.cc @@ -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; diff --git a/runtime/utils.h b/runtime/utils.h index 3191e7d305..698d686afd 100644 --- a/runtime/utils.h +++ b/runtime/utils.h @@ -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(); |