aboutsummaryrefslogtreecommitdiff
path: root/src/client/linux/handler/exception_handler.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/linux/handler/exception_handler.cc')
-rw-r--r--src/client/linux/handler/exception_handler.cc62
1 files changed, 45 insertions, 17 deletions
diff --git a/src/client/linux/handler/exception_handler.cc b/src/client/linux/handler/exception_handler.cc
index b253cb39..26e09b7d 100644
--- a/src/client/linux/handler/exception_handler.cc
+++ b/src/client/linux/handler/exception_handler.cc
@@ -81,6 +81,15 @@ ExceptionHandler::ExceptionHandler(const string &dump_path,
installed_handler_(install_handler) {
set_dump_path(dump_path);
+ act_.sa_handler = HandleException;
+ act_.sa_flags = SA_ONSTACK;
+ sigemptyset(&act_.sa_mask);
+ // now, make sure we're blocking all the signals we are handling
+ // when we're handling any of them
+ for ( size_t i = 0; i < sizeof(SigTable) / sizeof(SigTable[0]); ++i) {
+ sigaddset(&act_.sa_mask, SigTable[i]);
+ }
+
if (install_handler) {
SetupHandler();
pthread_mutex_lock(&handler_stack_mutex_);
@@ -149,20 +158,26 @@ void ExceptionHandler::SetupHandler() {
}
void ExceptionHandler::SetupHandler(int signo) {
- struct sigaction act, old_act;
- act.sa_handler = HandleException;
- act.sa_flags = SA_ONSTACK;
- if (sigaction(signo, &act, &old_act) < 0)
- return;
- old_handlers_[signo] = old_act.sa_handler;
+
+ // We're storing pointers to the old signal action
+ // structure, rather than copying the structure
+ // because we can't count on the sa_mask field to
+ // be scalar.
+ struct sigaction *old_act = &old_actions_[signo];
+
+ if (sigaction(signo, &act_, old_act) < 0)
+ return;
}
void ExceptionHandler::TeardownHandler(int signo) {
- if (old_handlers_.find(signo) != old_handlers_.end()) {
- struct sigaction act;
- act.sa_handler = old_handlers_[signo];
- act.sa_flags = 0;
- sigaction(signo, &act, 0);
+ TeardownHandler(signo, NULL);
+}
+
+void ExceptionHandler::TeardownHandler(int signo, struct sigaction *final_handler) {
+ if (old_actions_[signo].sa_handler) {
+ struct sigaction *act = &old_actions_[signo];
+ sigaction(signo, act, final_handler);
+ memset(&old_actions_[signo], 0x0, sizeof(struct sigaction));
}
}
@@ -193,7 +208,8 @@ void ExceptionHandler::HandleException(int signo) {
pthread_mutex_unlock(&handler_stack_mutex_);
// Restore original handler.
- current_handler->TeardownHandler(signo);
+ struct sigaction old_action;
+ current_handler->TeardownHandler(signo, &old_action);
struct sigcontext *sig_ctx = NULL;
if (current_handler->InternalWriteMinidump(signo, current_ebp, &sig_ctx)) {
@@ -202,11 +218,23 @@ void ExceptionHandler::HandleException(int signo) {
} else {
// Exception not fully handled, will call the next handler in stack to
// process it.
- typedef void (*SignalHandler)(int signo, struct sigcontext);
- SignalHandler old_handler =
- reinterpret_cast<SignalHandler>(current_handler->old_handlers_[signo]);
- if (old_handler != NULL && sig_ctx != NULL)
+ if (old_action.sa_handler != NULL && sig_ctx != NULL) {
+
+ // Have our own typedef, because of the comment above w.r.t signal
+ // context on the stack
+ typedef void (*SignalHandler)(int signo, struct sigcontext);
+
+ SignalHandler old_handler =
+ reinterpret_cast<SignalHandler>(old_action.sa_handler);
+
+ sigset_t old_set;
+ // Use SIG_BLOCK here because we don't want to unblock a signal
+ // that the signal handler we're currently in needs to block
+ sigprocmask(SIG_BLOCK, &old_action.sa_mask, &old_set);
old_handler(signo, *sig_ctx);
+ sigprocmask(SIG_SETMASK, &old_set, NULL);
+ }
+
}
pthread_mutex_lock(&handler_stack_mutex_);
@@ -247,7 +275,7 @@ bool ExceptionHandler::InternalWriteMinidump(int signo,
// Unblock the signals.
if (blocked) {
- sigprocmask(SIG_SETMASK, &sig_old, &sig_old);
+ sigprocmask(SIG_SETMASK, &sig_old, NULL);
}
if (callback_)