From 87315e9d2fdf6c7a6d876e63f844299f982a5b75 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Wed, 20 Mar 2019 16:02:54 -0700 Subject: [PATCH] Catch SIGBUS in HeapWalker SIGBUS shouldn't happen, since all of the regions being walked were previously read out of /prod/pid/maps, but it seems to happen rarely. Catch it so it can produce a better log message. Bug: 128983715 Test: atest memunreachable_test Change-Id: I82d3941a382a0451c0dda12f5eb849ad8d697bc9 --- libmemunreachable/HeapWalker.cpp | 2 +- libmemunreachable/HeapWalker.h | 12 +++++++--- libmemunreachable/ScopedSignalHandler.h | 30 +++++++++++++++++++------ 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/libmemunreachable/HeapWalker.cpp b/libmemunreachable/HeapWalker.cpp index e11f0798a..7cae04869 100644 --- a/libmemunreachable/HeapWalker.cpp +++ b/libmemunreachable/HeapWalker.cpp @@ -207,6 +207,6 @@ void HeapWalker::HandleSegFault(ScopedSignalHandler& handler, int signal, siginf } } -ScopedSignalHandler::SignalFn ScopedSignalHandler::handler_; +Allocator::unique_ptr ScopedSignalHandler::handler_map_; } // namespace android diff --git a/libmemunreachable/HeapWalker.h b/libmemunreachable/HeapWalker.h index 9e3db080d..f00bccaaa 100644 --- a/libmemunreachable/HeapWalker.h +++ b/libmemunreachable/HeapWalker.h @@ -52,7 +52,8 @@ class HeapWalker { allocation_bytes_(0), roots_(allocator), root_vals_(allocator), - segv_handler_(), + sigsegv_handler_(allocator), + sigbus_handler_(allocator), walking_ptr_(0), walking_range_{0, 0}, segv_logged_(false), @@ -62,10 +63,14 @@ class HeapWalker { valid_mappings_range_.end = 0; valid_mappings_range_.begin = ~valid_allocations_range_.end; - segv_handler_.install( + sigsegv_handler_.install( SIGSEGV, [=](ScopedSignalHandler& handler, int signal, siginfo_t* siginfo, void* uctx) { this->HandleSegFault(handler, signal, siginfo, uctx); }); + sigbus_handler_.install( + SIGBUS, [=](ScopedSignalHandler& handler, int signal, siginfo_t* siginfo, void* uctx) { + this->HandleSegFault(handler, signal, siginfo, uctx); + }); } ~HeapWalker() {} @@ -106,7 +111,8 @@ class HeapWalker { allocator::vector roots_; allocator::vector root_vals_; - ScopedSignalHandler segv_handler_; + ScopedSignalHandler sigsegv_handler_; + ScopedSignalHandler sigbus_handler_; volatile uintptr_t walking_ptr_; Range walking_range_; bool segv_logged_; diff --git a/libmemunreachable/ScopedSignalHandler.h b/libmemunreachable/ScopedSignalHandler.h index 9e08a8ecc..ef4473f7a 100644 --- a/libmemunreachable/ScopedSignalHandler.h +++ b/libmemunreachable/ScopedSignalHandler.h @@ -24,6 +24,7 @@ #include "android-base/macros.h" +#include "Allocator.h" #include "log.h" namespace android { @@ -32,17 +33,29 @@ class ScopedSignalHandler { public: using Fn = std::function; - explicit ScopedSignalHandler() : signal_(-1) {} + explicit ScopedSignalHandler(Allocator allocator) : signal_(-1) { + if (handler_map_ == nullptr) { + Allocator map_allocator = allocator; + handler_map_ = map_allocator.make_unique(allocator); + } + } ~ScopedSignalHandler() { reset(); } template void install(int signal, F&& f) { if (signal_ != -1) MEM_LOG_ALWAYS_FATAL("ScopedSignalHandler already installed"); - handler_ = SignalFn([=](int signal, siginfo_t* si, void* uctx) { f(*this, signal, si, uctx); }); + if (handler_map_->find(signal) != handler_map_->end()) { + MEM_LOG_ALWAYS_FATAL("ScopedSignalHandler already installed for %d", signal); + } + + (*handler_map_)[signal] = + SignalFn([=](int signal, siginfo_t* si, void* uctx) { f(*this, signal, si, uctx); }); struct sigaction act {}; - act.sa_sigaction = [](int signal, siginfo_t* si, void* uctx) { handler_(signal, si, uctx); }; + act.sa_sigaction = [](int signal, siginfo_t* si, void* uctx) { + ((*handler_map_)[signal])(signal, si, uctx); + }; act.sa_flags = SA_SIGINFO; int ret = sigaction(signal, &act, &old_act_); @@ -59,19 +72,22 @@ class ScopedSignalHandler { if (ret < 0) { MEM_ALOGE("failed to uninstall segfault handler"); } - handler_ = SignalFn{}; + + handler_map_->erase(signal_); + if (handler_map_->empty()) { + handler_map_.reset(); + } signal_ = -1; } } private: using SignalFn = std::function; + using SignalFnMap = allocator::unordered_map; DISALLOW_COPY_AND_ASSIGN(ScopedSignalHandler); int signal_; struct sigaction old_act_; - // TODO(ccross): to support multiple ScopedSignalHandlers handler_ would need - // to be a static map of signals to handlers, but allocated with Allocator. - static SignalFn handler_; + static Allocator::unique_ptr handler_map_; }; } // namespace android