diff options
author | 2017-03-18 02:51:37 +0000 | |
---|---|---|
committer | 2017-03-18 02:51:37 +0000 | |
commit | 33dca562d5ed9f52f63ced2334c066333ca073e9 (patch) | |
tree | b13ca4ec329595953d3aa3b04b0323f2dee173ca /runtime/fault_handler.cc | |
parent | 7600fa9234e02cf5108a3a82babf3d3ab82fcddd (diff) |
Revert "Make sigchain actually own the signal chain."
This reverts commit 7600fa9234e02cf5108a3a82babf3d3ab82fcddd.
Change-Id: Ia46db2a7df0c0ac07107a8db06f42ff1afd4a97e
Diffstat (limited to 'runtime/fault_handler.cc')
-rw-r--r-- | runtime/fault_handler.cc | 131 |
1 files changed, 108 insertions, 23 deletions
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc index 4220250c38..64128cc61e 100644 --- a/runtime/fault_handler.cc +++ b/runtime/fault_handler.cc @@ -38,8 +38,8 @@ extern "C" __attribute__((visibility("default"))) void art_sigsegv_fault() { } // Signal handler called on SIGSEGV. -static bool art_fault_handler(int sig, siginfo_t* info, void* context) { - return fault_manager.HandleFault(sig, info, context); +static void art_fault_handler(int sig, siginfo_t* info, void* context) { + fault_manager.HandleFault(sig, info, context); } FaultManager::FaultManager() : initialized_(false) { @@ -49,15 +49,43 @@ FaultManager::FaultManager() : initialized_(false) { FaultManager::~FaultManager() { } +static void SetUpArtAction(struct sigaction* action) { + action->sa_sigaction = art_fault_handler; + sigemptyset(&action->sa_mask); + action->sa_flags = SA_SIGINFO | SA_ONSTACK; +#if !defined(__APPLE__) && !defined(__mips__) + action->sa_restorer = nullptr; +#endif +} + +void FaultManager::EnsureArtActionInFrontOfSignalChain() { + if (initialized_) { + struct sigaction action; + SetUpArtAction(&action); + EnsureFrontOfChain(SIGSEGV, &action); + } else { + LOG(WARNING) << "Can't call " << __FUNCTION__ << " due to unitialized fault manager"; + } +} + void FaultManager::Init() { CHECK(!initialized_); - AddSpecialSignalHandlerFn(SIGSEGV, art_fault_handler); + struct sigaction action; + SetUpArtAction(&action); + + // Set our signal handler now. + int e = sigaction(SIGSEGV, &action, &oldaction_); + if (e != 0) { + VLOG(signals) << "Failed to claim SEGV: " << strerror(errno); + } + // Make sure our signal handler is called before any user handlers. + ClaimSignalChain(SIGSEGV, &oldaction_); initialized_ = true; } void FaultManager::Release() { if (initialized_) { - RemoveSpecialSignalHandlerFn(SIGSEGV, art_fault_handler); + UnclaimSignalChain(SIGSEGV); initialized_ = false; } } @@ -90,36 +118,93 @@ bool FaultManager::HandleFaultByOtherHandlers(int sig, siginfo_t* info, void* co return false; } -bool FaultManager::HandleFault(int sig, siginfo_t* info, void* context) { - VLOG(signals) << "Handling fault"; +class ScopedSignalUnblocker { + public: + explicit ScopedSignalUnblocker(const std::initializer_list<int>& signals) { + sigset_t new_mask; + sigemptyset(&new_mask); + for (int signal : signals) { + sigaddset(&new_mask, signal); + } + if (sigprocmask(SIG_UNBLOCK, &new_mask, &previous_mask_) != 0) { + PLOG(FATAL) << "failed to unblock signals"; + } + } + + ~ScopedSignalUnblocker() { + if (sigprocmask(SIG_SETMASK, &previous_mask_, nullptr) != 0) { + PLOG(FATAL) << "failed to unblock signals"; + } + } + + private: + sigset_t previous_mask_; +}; + +class ScopedHandlingSignalSetter { + public: + explicit ScopedHandlingSignalSetter(Thread* thread) : thread_(thread) { + CHECK(!thread->HandlingSignal()); + thread_->SetHandlingSignal(true); + } + + ~ScopedHandlingSignalSetter() { + CHECK(thread_->HandlingSignal()); + thread_->SetHandlingSignal(false); + } + + private: + Thread* thread_; +}; + +void FaultManager::HandleFault(int sig, siginfo_t* info, void* context) { + // BE CAREFUL ALLOCATING HERE INCLUDING USING LOG(...) + // + // If malloc calls abort, it will be holding its lock. + // If the handler tries to call malloc, it will deadlock. + + // Use a thread local field to track whether we're recursing, and fall back. + // (e.g.. if one of our handlers crashed) + Thread* thread = Thread::Current(); + + if (thread != nullptr && !thread->HandlingSignal()) { + // Unblock some signals and set thread->handling_signal_ to true, + // so that we can catch crashes in our signal handler. + ScopedHandlingSignalSetter setter(thread); + ScopedSignalUnblocker unblocker { SIGABRT, SIGBUS, SIGSEGV }; // NOLINT + + VLOG(signals) << "Handling fault"; #ifdef TEST_NESTED_SIGNAL - // Simulate a crash in a handler. - raise(SIGSEGV); + // Simulate a crash in a handler. + raise(SIGSEGV); #endif - if (IsInGeneratedCode(info, context, true)) { - VLOG(signals) << "in generated code, looking for handler"; - for (const auto& handler : generated_code_handlers_) { - VLOG(signals) << "invoking Action on handler " << handler; - if (handler->Action(sig, info, context)) { - // We have handled a signal so it's time to return from the - // signal handler to the appropriate place. - return true; + if (IsInGeneratedCode(info, context, true)) { + VLOG(signals) << "in generated code, looking for handler"; + for (const auto& handler : generated_code_handlers_) { + VLOG(signals) << "invoking Action on handler " << handler; + if (handler->Action(sig, info, context)) { + // We have handled a signal so it's time to return from the + // signal handler to the appropriate place. + return; + } } - } - // We hit a signal we didn't handle. This might be something for which - // we can give more information about so call all registered handlers to - // see if it is. - if (HandleFaultByOtherHandlers(sig, info, context)) { - return true; + // We hit a signal we didn't handle. This might be something for which + // we can give more information about so call all registered handlers to + // see if it is. + if (HandleFaultByOtherHandlers(sig, info, context)) { + return; + } } } // Set a breakpoint in this function to catch unhandled signals. art_sigsegv_fault(); - return false; + + // Pass this on to the next handler in the chain, or the default if none. + InvokeUserSignalHandler(sig, info, context); } void FaultManager::AddHandler(FaultHandler* handler, bool generated_code) { |