Fix for issue 242, plus a redo of how old exception handlers are tracked, and called.

R=Craig.Schlenter, luly81



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@315 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
nealsid 2009-02-26 21:31:53 +00:00
parent 4af5fe0b59
commit 02c244f1b2
3 changed files with 59 additions and 22 deletions

View File

@ -1,7 +1,7 @@
CXX=g++ CXX=g++
CC=gcc CC=gcc
CXXFLAGS=-gstabs -I../../.. -Wall -D_REENTRANT CXXFLAGS=-gstabs+ -I../../.. -Wall -D_REENTRANT
LDFLAGS=-lpthread LDFLAGS=-lpthread
OBJ_DIR=. OBJ_DIR=.

View File

@ -81,6 +81,15 @@ ExceptionHandler::ExceptionHandler(const string &dump_path,
installed_handler_(install_handler) { installed_handler_(install_handler) {
set_dump_path(dump_path); 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) { if (install_handler) {
SetupHandler(); SetupHandler();
pthread_mutex_lock(&handler_stack_mutex_); pthread_mutex_lock(&handler_stack_mutex_);
@ -149,20 +158,26 @@ void ExceptionHandler::SetupHandler() {
} }
void ExceptionHandler::SetupHandler(int signo) { void ExceptionHandler::SetupHandler(int signo) {
struct sigaction act, old_act;
act.sa_handler = HandleException; // We're storing pointers to the old signal action
act.sa_flags = SA_ONSTACK; // structure, rather than copying the structure
if (sigaction(signo, &act, &old_act) < 0) // because we can't count on the sa_mask field to
return; // be scalar.
old_handlers_[signo] = old_act.sa_handler; struct sigaction *old_act = &old_actions_[signo];
if (sigaction(signo, &act_, old_act) < 0)
return;
} }
void ExceptionHandler::TeardownHandler(int signo) { void ExceptionHandler::TeardownHandler(int signo) {
if (old_handlers_.find(signo) != old_handlers_.end()) { TeardownHandler(signo, NULL);
struct sigaction act; }
act.sa_handler = old_handlers_[signo];
act.sa_flags = 0; void ExceptionHandler::TeardownHandler(int signo, struct sigaction *final_handler) {
sigaction(signo, &act, 0); 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_); pthread_mutex_unlock(&handler_stack_mutex_);
// Restore original handler. // Restore original handler.
current_handler->TeardownHandler(signo); struct sigaction old_action;
current_handler->TeardownHandler(signo, &old_action);
struct sigcontext *sig_ctx = NULL; struct sigcontext *sig_ctx = NULL;
if (current_handler->InternalWriteMinidump(signo, current_ebp, &sig_ctx)) { if (current_handler->InternalWriteMinidump(signo, current_ebp, &sig_ctx)) {
@ -202,11 +218,23 @@ void ExceptionHandler::HandleException(int signo) {
} else { } else {
// Exception not fully handled, will call the next handler in stack to // Exception not fully handled, will call the next handler in stack to
// process it. // process it.
typedef void (*SignalHandler)(int signo, struct sigcontext); if (old_action.sa_handler != NULL && sig_ctx != NULL) {
SignalHandler old_handler =
reinterpret_cast<SignalHandler>(current_handler->old_handlers_[signo]); // Have our own typedef, because of the comment above w.r.t signal
if (old_handler != NULL && sig_ctx != NULL) // 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); old_handler(signo, *sig_ctx);
sigprocmask(SIG_SETMASK, &old_set, NULL);
}
} }
pthread_mutex_lock(&handler_stack_mutex_); pthread_mutex_lock(&handler_stack_mutex_);
@ -247,7 +275,7 @@ bool ExceptionHandler::InternalWriteMinidump(int signo,
// Unblock the signals. // Unblock the signals.
if (blocked) { if (blocked) {
sigprocmask(SIG_SETMASK, &sig_old, &sig_old); sigprocmask(SIG_SETMASK, &sig_old, NULL);
} }
if (callback_) if (callback_)

View File

@ -36,6 +36,7 @@
#include <map> #include <map>
#include <string> #include <string>
#include <signal.h>
#include <vector> #include <vector>
#include "client/linux/handler/minidump_generator.h" #include "client/linux/handler/minidump_generator.h"
@ -146,6 +147,8 @@ class ExceptionHandler {
void SetupHandler(int signo); void SetupHandler(int signo);
// Teardown the handler for a signal. // Teardown the handler for a signal.
void TeardownHandler(int signo); void TeardownHandler(int signo);
// Teardown the handler for a signal.
void TeardownHandler(int signo, struct sigaction *old);
// Teardown all handlers. // Teardown all handlers.
void TeardownAllHandler(); void TeardownAllHandler();
@ -192,10 +195,6 @@ class ExceptionHandler {
// when created (with an install_handler parameter set to true). // when created (with an install_handler parameter set to true).
bool installed_handler_; bool installed_handler_;
// Keep the previous handlers for the signal.
typedef void (*sighandler_t)(int);
std::map<int, sighandler_t> old_handlers_;
// The global exception handler stack. This is need becuase there may exist // The global exception handler stack. This is need becuase there may exist
// multiple ExceptionHandler instances in a process. Each will have itself // multiple ExceptionHandler instances in a process. Each will have itself
// registered in this stack. // registered in this stack.
@ -210,6 +209,16 @@ class ExceptionHandler {
// disallow copy ctor and operator= // disallow copy ctor and operator=
explicit ExceptionHandler(const ExceptionHandler &); explicit ExceptionHandler(const ExceptionHandler &);
void operator=(const ExceptionHandler &); void operator=(const ExceptionHandler &);
// The sigactions structure we use for each signal
struct sigaction act_;
// Keep the previous handlers for the signal.
// We're wasting a bit of memory here since we only change
// the handler for some signals but i want to avoid allocating
// memory in the signal handler
struct sigaction old_actions_[NSIG];
}; };
} // namespace google_breakpad } // namespace google_breakpad