Don't try to handle nested SIGSEGV inside fault handler.
Trying to handle nested SIGSEGV in the fault handler leads to infinite signals
and retrying if the cause of the SIGSEGV was a lack of stack space. This can
lead to applications not chaining through to debuggerd and dying.
Bug: 18330119
Change-Id: Iadcffe0fa0e55d783b84a06504bbd9d181e641e4
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc
index c473684..ab3ec62 100644
--- a/runtime/fault_handler.cc
+++ b/runtime/fault_handler.cc
@@ -179,6 +179,10 @@
// Now set up the nested signal handler.
+ // TODO: add SIGSEGV back to the nested signals when we can handle running out stack gracefully.
+ static const int handled_nested_signals[] = {SIGABRT};
+ constexpr size_t num_handled_nested_signals = arraysize(handled_nested_signals);
+
// Release the fault manager so that it will remove the signal chain for
// SIGSEGV and we call the real sigaction.
fault_manager.Release();
@@ -188,33 +192,40 @@
// Unblock the signals we allow so that they can be delivered in the signal handler.
sigset_t sigset;
sigemptyset(&sigset);
- sigaddset(&sigset, SIGSEGV);
- sigaddset(&sigset, SIGABRT);
+ for (int signal : handled_nested_signals) {
+ sigaddset(&sigset, signal);
+ }
pthread_sigmask(SIG_UNBLOCK, &sigset, nullptr);
// If we get a signal in this code we want to invoke our nested signal
// handler.
- struct sigaction action, oldsegvaction, oldabortaction;
+ struct sigaction action;
+ struct sigaction oldactions[num_handled_nested_signals];
action.sa_sigaction = art_nested_signal_handler;
// Explicitly mask out SIGSEGV and SIGABRT from the nested signal handler. This
// should be the default but we definitely don't want these happening in our
// nested signal handler.
sigemptyset(&action.sa_mask);
- sigaddset(&action.sa_mask, SIGSEGV);
- sigaddset(&action.sa_mask, SIGABRT);
+ for (int signal : handled_nested_signals) {
+ sigaddset(&action.sa_mask, signal);
+ }
action.sa_flags = SA_SIGINFO | SA_ONSTACK;
#if !defined(__APPLE__) && !defined(__mips__)
action.sa_restorer = nullptr;
#endif
- // Catch SIGSEGV and SIGABRT to invoke our nested handler
- int e1 = sigaction(SIGSEGV, &action, &oldsegvaction);
- int e2 = sigaction(SIGABRT, &action, &oldabortaction);
- if (e1 != 0 || e2 != 0) {
- LOG(ERROR) << "Unable to set up nested signal handler";
- } else {
+ // Catch handled signals to invoke our nested handler.
+ bool success = true;
+ for (size_t i = 0; i < num_handled_nested_signals; ++i) {
+ success = sigaction(handled_nested_signals[i], &action, &oldactions[i]) == 0;
+ if (!success) {
+ PLOG(ERROR) << "Unable to set up nested signal handler";
+ break;
+ }
+ }
+ if (success) {
// Save the current state and call the handlers. If anything causes a signal
// our nested signal handler will be invoked and this will longjmp to the saved
// state.
@@ -223,8 +234,12 @@
if (handler->Action(sig, info, context)) {
// Restore the signal handlers, reinit the fault manager and return. Signal was
// handled.
- sigaction(SIGSEGV, &oldsegvaction, nullptr);
- sigaction(SIGABRT, &oldabortaction, nullptr);
+ for (size_t i = 0; i < num_handled_nested_signals; ++i) {
+ success = sigaction(handled_nested_signals[i], &oldactions[i], nullptr) == 0;
+ if (!success) {
+ PLOG(ERROR) << "Unable to restore signal handler";
+ }
+ }
fault_manager.Init();
return;
}
@@ -234,8 +249,12 @@
}
// Restore the signal handlers.
- sigaction(SIGSEGV, &oldsegvaction, nullptr);
- sigaction(SIGABRT, &oldabortaction, nullptr);
+ for (size_t i = 0; i < num_handled_nested_signals; ++i) {
+ success = sigaction(handled_nested_signals[i], &oldactions[i], nullptr) == 0;
+ if (!success) {
+ PLOG(ERROR) << "Unable to restore signal handler";
+ }
+ }
}
// Now put the fault manager back in place.