Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 87315e9d authored by Colin Cross's avatar Colin Cross
Browse files

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
parent b4ef0beb
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -207,6 +207,6 @@ void HeapWalker::HandleSegFault(ScopedSignalHandler& handler, int signal, siginf
  }
}

ScopedSignalHandler::SignalFn ScopedSignalHandler::handler_;
Allocator<ScopedSignalHandler::SignalFnMap>::unique_ptr ScopedSignalHandler::handler_map_;

}  // namespace android
+9 −3
Original line number Diff line number Diff line
@@ -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<Range> roots_;
  allocator::vector<uintptr_t> root_vals_;

  ScopedSignalHandler segv_handler_;
  ScopedSignalHandler sigsegv_handler_;
  ScopedSignalHandler sigbus_handler_;
  volatile uintptr_t walking_ptr_;
  Range walking_range_;
  bool segv_logged_;
+23 −7
Original line number Diff line number Diff line
@@ -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<void(ScopedSignalHandler&, int, siginfo_t*, void*)>;

  explicit ScopedSignalHandler() : signal_(-1) {}
  explicit ScopedSignalHandler(Allocator<ScopedSignalHandler> allocator) : signal_(-1) {
    if (handler_map_ == nullptr) {
      Allocator<SignalFnMap> map_allocator = allocator;
      handler_map_ = map_allocator.make_unique(allocator);
    }
  }
  ~ScopedSignalHandler() { reset(); }

  template <class F>
  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<void(int, siginfo_t*, void*)>;
  using SignalFnMap = allocator::unordered_map<int, SignalFn>;
  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<SignalFnMap>::unique_ptr handler_map_;
};

}  // namespace android