diff options
author | Eric Holk <eholk@chromium.org> | 2017-06-19 10:06:28 -0700 |
---|---|---|
committer | Mark Mentovai <mark@chromium.org> | 2017-06-19 18:23:41 +0000 |
commit | 1628d99f7b21b6920ac8bf197b2acd38021f1df9 (patch) | |
tree | 2f20240353ae3028cfe6f83f7d90bddf854a2dbb /src | |
parent | roll lss deps (diff) | |
download | breakpad-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')
-rw-r--r-- | src/client/linux/handler/exception_handler.cc | 17 | ||||
-rw-r--r-- | src/client/linux/handler/exception_handler.h | 4 | ||||
-rw-r--r-- | src/client/linux/handler/exception_handler_unittest.cc | 23 |
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)); +} |