aboutsummaryrefslogtreecommitdiff
path: root/src/client/linux
diff options
context:
space:
mode:
authorEric Holk <eholk@chromium.org>2017-06-19 10:06:28 -0700
committerMark Mentovai <mark@chromium.org>2017-06-19 18:23:41 +0000
commit1628d99f7b21b6920ac8bf197b2acd38021f1df9 (patch)
tree2f20240353ae3028cfe6f83f7d90bddf854a2dbb /src/client/linux
parentroll lss deps (diff)
downloadbreakpad-1628d99f7b21b6920ac8bf197b2acd38021f1df9.tar.xz
Add first chance exception handler API
This change adds the option for Breakpad hosts to register a callback that gets the first chance to handle an exception. The handler will return true if it handled the exception and false otherwise. The primary use case is V8's trap-based bounds checking support for WebAssembly. Bug: Change-Id: I5aa5b87d1229f1cef905a00404fa2027ee86be56 Reviewed-on: https://chromium-review.googlesource.com/509994 Reviewed-by: Mark Mentovai <mark@chromium.org>
Diffstat (limited to 'src/client/linux')
-rw-r--r--src/client/linux/handler/exception_handler.cc17
-rw-r--r--src/client/linux/handler/exception_handler.h4
-rw-r--r--src/client/linux/handler/exception_handler_unittest.cc23
3 files changed, 44 insertions, 0 deletions
diff --git a/src/client/linux/handler/exception_handler.cc b/src/client/linux/handler/exception_handler.cc
index e9ec2bad..586d84e9 100644
--- a/src/client/linux/handler/exception_handler.cc
+++ b/src/client/linux/handler/exception_handler.cc
@@ -218,6 +218,7 @@ pthread_mutex_t g_handler_stack_mutex_ = PTHREAD_MUTEX_INITIALIZER;
// time can use |g_crash_context_|.
ExceptionHandler::CrashContext g_crash_context_;
+FirstChanceHandler g_first_chance_handler_ = nullptr;
} // namespace
// Runs before crashing: normal context.
@@ -331,6 +332,18 @@ void ExceptionHandler::RestoreHandlersLocked() {
// Runs on the crashing thread.
// static
void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) {
+
+ // Give the first chance handler a chance to recover from this signal
+ //
+ // This is primarily used by V8. V8 uses guard regions to guarantee memory
+ // safety in WebAssembly. This means some signals might be expected if they
+ // originate from Wasm code while accessing the guard region. We give V8 the
+ // chance to handle and recover from these signals first.
+ if (g_first_chance_handler_ != nullptr &&
+ g_first_chance_handler_(sig, info, uc)) {
+ return;
+ }
+
// All the exception signals are blocked at this point.
pthread_mutex_lock(&g_handler_stack_mutex_);
@@ -782,4 +795,8 @@ bool ExceptionHandler::WriteMinidumpForChild(pid_t child,
return callback ? callback(descriptor, callback_context, true) : true;
}
+void SetFirstChanceExceptionHandler(FirstChanceHandler callback) {
+ g_first_chance_handler_ = callback;
+}
+
} // namespace google_breakpad
diff --git a/src/client/linux/handler/exception_handler.h b/src/client/linux/handler/exception_handler.h
index 591c3108..daba57e0 100644
--- a/src/client/linux/handler/exception_handler.h
+++ b/src/client/linux/handler/exception_handler.h
@@ -273,6 +273,10 @@ class ExceptionHandler {
AppMemoryList app_memory_list_;
};
+
+typedef bool (*FirstChanceHandler)(int, void*, void*);
+void SetFirstChanceExceptionHandler(FirstChanceHandler callback);
+
} // namespace google_breakpad
#endif // CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_
diff --git a/src/client/linux/handler/exception_handler_unittest.cc b/src/client/linux/handler/exception_handler_unittest.cc
index 17d84cf7..cede40bd 100644
--- a/src/client/linux/handler/exception_handler_unittest.cc
+++ b/src/client/linux/handler/exception_handler_unittest.cc
@@ -1177,3 +1177,26 @@ TEST(ExceptionHandlerTest, WriteMinidumpForChild) {
close(fds[1]);
unlink(minidump_filename.c_str());
}
+
+namespace {
+const int kSimpleFirstChanceReturnStatus = 42;
+bool SimpleFirstChanceHandler(int, void*, void*) {
+ exit(kSimpleFirstChanceReturnStatus);
+}
+}
+
+TEST(ExceptionHandlerTest, FirstChanceHandlerRuns) {
+ AutoTempDir temp_dir;
+
+ const pid_t child = fork();
+ if (child == 0) {
+ ExceptionHandler handler(
+ MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1);
+ google_breakpad::SetFirstChanceExceptionHandler(SimpleFirstChanceHandler);
+ DoNullPointerDereference();
+ }
+ int status;
+ ASSERT_NE(HANDLE_EINTR(waitpid(child, &status, 0)), -1);
+ ASSERT_TRUE(WIFEXITED(status));
+ ASSERT_EQ(kSimpleFirstChanceReturnStatus, WEXITSTATUS(status));
+}