Index: third_party/crashpad/crashpad/handler/handler_main.cc |
diff --git a/third_party/crashpad/crashpad/handler/handler_main.cc b/third_party/crashpad/crashpad/handler/handler_main.cc |
index c7c2b29738bde496f39cd31c8594fc8946ff5456..9433a6af5186ec33ebf6c68fb17948adb227381d 100644 |
--- a/third_party/crashpad/crashpad/handler/handler_main.cc |
+++ b/third_party/crashpad/crashpad/handler/handler_main.cc |
@@ -24,10 +24,8 @@ |
#include <memory> |
#include <string> |
#include <utility> |
-#include <vector> |
#include "base/auto_reset.h" |
-#include "base/compiler_specific.h" |
#include "base/files/file_path.h" |
#include "base/files/scoped_file.h" |
#include "base/logging.h" |
@@ -66,7 +64,6 @@ |
#include "util/win/exception_handler_server.h" |
#include "util/win/handle.h" |
#include "util/win/initial_client_data.h" |
-#include "util/win/session_end_watcher.h" |
#endif // OS_MACOSX |
namespace crashpad { |
@@ -96,7 +93,6 @@ void Usage(const base::FilePath& me) { |
#endif // OS_MACOSX |
" --metrics-dir=DIR store metrics files in DIR (only in Chromium)\n" |
" --no-rate-limit don't rate limit crash uploads\n" |
-" --no-upload-gzip don't use gzip compression when uploading\n" |
#if defined(OS_MACOSX) |
" --reset-own-crash-exception-port-to-system-default\n" |
" reset the server's exception handler to default\n" |
@@ -111,65 +107,11 @@ void Usage(const base::FilePath& me) { |
ToolSupport::UsageTail(me); |
} |
-// Calls Metrics::HandlerLifetimeMilestone, but only on the first call. This is |
-// to prevent multiple exit events from inadvertently being recorded, which |
-// might happen if a crash occurs during destruction in what would otherwise be |
-// a normal exit, or if a CallMetricsRecordNormalExit object is destroyed after |
-// something else logs an exit event. |
-void MetricsRecordExit(Metrics::LifetimeMilestone milestone) { |
- static bool once = [](Metrics::LifetimeMilestone milestone) { |
- Metrics::HandlerLifetimeMilestone(milestone); |
- return true; |
- }(milestone); |
- ALLOW_UNUSED_LOCAL(once); |
-} |
- |
-// Calls MetricsRecordExit() to record a failure, and returns EXIT_FAILURE for |
-// the convenience of callers in main() which can simply write “return |
-// ExitFailure();”. |
-int ExitFailure() { |
- MetricsRecordExit(Metrics::LifetimeMilestone::kFailed); |
- return EXIT_FAILURE; |
-} |
- |
-class CallMetricsRecordNormalExit { |
- public: |
- CallMetricsRecordNormalExit() {} |
- ~CallMetricsRecordNormalExit() { |
- MetricsRecordExit(Metrics::LifetimeMilestone::kExitedNormally); |
- } |
- |
- private: |
- DISALLOW_COPY_AND_ASSIGN(CallMetricsRecordNormalExit); |
-}; |
- |
#if defined(OS_MACOSX) |
-void InstallSignalHandler(const std::vector<int>& signals, |
- void (*handler)(int, siginfo_t*, void*)) { |
- struct sigaction sa = {}; |
- sigemptyset(&sa.sa_mask); |
- sa.sa_flags = SA_SIGINFO; |
- sa.sa_sigaction = handler; |
- |
- for (int sig : signals) { |
- int rv = sigaction(sig, &sa, nullptr); |
- PCHECK(rv == 0) << "sigaction " << sig; |
- } |
-} |
- |
-void RestoreDefaultSignalHandler(int sig) { |
- struct sigaction sa = {}; |
- sigemptyset(&sa.sa_mask); |
- sa.sa_flags = 0; |
- sa.sa_handler = SIG_DFL; |
- int rv = sigaction(sig, &sa, nullptr); |
- DPLOG_IF(ERROR, rv != 0) << "sigaction " << sig; |
-} |
+struct sigaction g_original_crash_sigaction[NSIG]; |
void HandleCrashSignal(int sig, siginfo_t* siginfo, void* context) { |
- MetricsRecordExit(Metrics::LifetimeMilestone::kCrashed); |
- |
// Is siginfo->si_code useful? The only interesting values on macOS are 0 (not |
// useful, signals generated asynchronously such as by kill() or raise()) and |
// small positive numbers (useful, signal generated via a hardware fault). The |
@@ -201,17 +143,22 @@ void HandleCrashSignal(int sig, siginfo_t* siginfo, void* context) { |
} |
Metrics::HandlerCrashed(metrics_code); |
- RestoreDefaultSignalHandler(sig); |
+ // Restore the previous signal handler. |
+ DCHECK_GT(sig, 0); |
+ DCHECK_LT(static_cast<size_t>(sig), arraysize(g_original_crash_sigaction)); |
+ struct sigaction* osa = &g_original_crash_sigaction[sig]; |
+ int rv = sigaction(sig, osa, nullptr); |
+ DPLOG_IF(ERROR, rv != 0) << "sigaction " << sig; |
// If the signal was received synchronously resulting from a hardware fault, |
// returning from the signal handler will cause the kernel to re-raise it, |
// because this handler hasn’t done anything to alleviate the condition that |
- // caused the signal to be raised in the first place. With the default signal |
- // handler in place, it will cause the same behavior to be taken as though |
- // this signal handler had never been installed at all (expected to be a |
- // crash). This is ideal, because the signal is re-raised with the same |
- // properties and from the same context that initially triggered it, providing |
- // the best debugging experience. |
+ // caused the signal to be raised in the first place. With the old signal |
+ // handler in place (expected to be SIG_DFL), it will cause the same behavior |
+ // to be taken as though this signal handler had never been installed at all |
+ // (expected to be a crash). This is ideal, because the signal is re-raised |
+ // with the same properties and from the same context that initially triggered |
+ // it, providing the best debugging experience. |
if ((sig != SIGILL && sig != SIGFPE && sig != SIGBUS && sig != SIGSEGV) || |
!si_code_valid) { |
@@ -219,7 +166,8 @@ void HandleCrashSignal(int sig, siginfo_t* siginfo, void* context) { |
// asynchronously via kill() and raise(), and those arising via hardware |
// traps such as int3 (resulting in SIGTRAP but advancing the instruction |
// pointer), will not reoccur on their own when returning from the signal |
- // handler. Re-raise them. |
+ // handler. Re-raise them or call to the previous signal handler as |
+ // appropriate. |
// |
// Unfortunately, when SIGBUS is received asynchronously via kill(), |
// siginfo->si_code makes it appear as though it was actually received via a |
@@ -232,66 +180,49 @@ void HandleCrashSignal(int sig, siginfo_t* siginfo, void* context) { |
// very valuable for debugging and are visible to a Mach exception handler. |
// Since SIGBUS is normally received synchronously in response to a hardware |
// fault, don’t sweat the unexpected asynchronous case. |
- // |
- // Because this signal handler executes with the signal blocked, this |
- // raise() cannot immediately deliver the signal. Delivery is deferred until |
- // this signal handler returns and the signal becomes unblocked. The |
- // re-raised signal will appear with the same context as where it was |
- // initially triggered. |
- int rv = raise(sig); |
- DPLOG_IF(ERROR, rv != 0) << "raise"; |
+ if (osa->sa_handler == SIG_DFL) { |
+ // Because this signal handler executes with the signal blocked, this |
+ // raise() cannot immediately deliver the signal. Delivery is deferred |
+ // until this signal handler returns and the signal becomes unblocked. The |
+ // re-raised signal will appear with the same context as where it was |
+ // initially triggered. |
+ rv = raise(sig); |
+ DPLOG_IF(ERROR, rv != 0) << "raise"; |
+ } else if (osa->sa_handler != SIG_IGN) { |
+ if (osa->sa_flags & SA_SIGINFO) { |
+ osa->sa_sigaction(sig, siginfo, context); |
+ } else { |
+ osa->sa_handler(sig); |
+ } |
+ } |
} |
} |
-void HandleTerminateSignal(int sig, siginfo_t* siginfo, void* context) { |
- MetricsRecordExit(Metrics::LifetimeMilestone::kTerminated); |
- |
- RestoreDefaultSignalHandler(sig); |
- |
- // Re-raise the signal. See the explanation in HandleCrashSignal(). Note that |
- // no checks for signals arising from synchronous hardware faults are made |
- // because termination signals never originate in that way. |
- int rv = raise(sig); |
- DPLOG_IF(ERROR, rv != 0) << "raise"; |
-} |
- |
void InstallCrashHandler() { |
+ struct sigaction sa = {}; |
+ sigemptyset(&sa.sa_mask); |
+ sa.sa_flags = SA_SIGINFO; |
+ sa.sa_sigaction = HandleCrashSignal; |
+ |
// These are the core-generating signals from 10.12.3 |
// xnu-3789.41.3/bsd/sys/signalvar.h sigprop: entries with SA_CORE are in the |
// set. |
- const int kCrashSignals[] = {SIGQUIT, |
- SIGILL, |
- SIGTRAP, |
- SIGABRT, |
- SIGEMT, |
- SIGFPE, |
- SIGBUS, |
- SIGSEGV, |
- SIGSYS}; |
- InstallSignalHandler( |
- std::vector<int>(&kCrashSignals[0], |
- &kCrashSignals[arraysize(kCrashSignals)]), |
- HandleCrashSignal); |
- |
- // Not a crash handler, but close enough. These are non-core-generating but |
- // terminating signals from 10.12.3 xnu-3789.41.3/bsd/sys/signalvar.h sigprop: |
- // entries with SA_KILL but not SA_CORE are in the set. SIGKILL is excluded |
- // because it is uncatchable. |
- const int kTerminateSignals[] = {SIGHUP, |
- SIGINT, |
- SIGPIPE, |
- SIGALRM, |
- SIGTERM, |
- SIGXCPU, |
- SIGXFSZ, |
- SIGVTALRM, |
- SIGPROF, |
- SIGUSR1, |
- SIGUSR2}; |
- InstallSignalHandler( |
- std::vector<int>(&kTerminateSignals[0], |
- &kTerminateSignals[arraysize(kTerminateSignals)]), |
- HandleTerminateSignal); |
+ const int kSignals[] = {SIGQUIT, |
+ SIGILL, |
+ SIGTRAP, |
+ SIGABRT, |
+ SIGEMT, |
+ SIGFPE, |
+ SIGBUS, |
+ SIGSEGV, |
+ SIGSYS}; |
+ |
+ for (int sig : kSignals) { |
+ DCHECK_GT(sig, 0); |
+ DCHECK_LT(static_cast<size_t>(sig), arraysize(g_original_crash_sigaction)); |
+ int rv = sigaction(sig, &sa, &g_original_crash_sigaction[sig]); |
+ PCHECK(rv == 0) << "sigaction " << sig; |
+ } |
} |
struct ResetSIGTERMTraits { |
@@ -311,9 +242,6 @@ ExceptionHandlerServer* g_exception_handler_server; |
// This signal handler is only operative when being run from launchd. |
void HandleSIGTERM(int sig, siginfo_t* siginfo, void* context) { |
- // Don’t call MetricsRecordExit(). This is part of the normal exit path when |
- // running from launchd. |
- |
DCHECK(g_exception_handler_server); |
g_exception_handler_server->Stop(); |
} |
@@ -323,7 +251,6 @@ void HandleSIGTERM(int sig, siginfo_t* siginfo, void* context) { |
LONG(WINAPI* g_original_exception_filter)(EXCEPTION_POINTERS*) = nullptr; |
LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) { |
- MetricsRecordExit(Metrics::LifetimeMilestone::kCrashed); |
Metrics::HandlerCrashed(exception_pointers->ExceptionRecord->ExceptionCode); |
if (g_original_exception_filter) |
@@ -332,37 +259,9 @@ LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) { |
return EXCEPTION_CONTINUE_SEARCH; |
} |
-// Handles events like Control-C and Control-Break on a console. |
-BOOL WINAPI ConsoleHandler(DWORD console_event) { |
- MetricsRecordExit(Metrics::LifetimeMilestone::kTerminated); |
- return false; |
-} |
- |
-// Handles a WM_ENDSESSION message sent when the user session is ending. |
-class TerminateHandler final : public SessionEndWatcher { |
- public: |
- TerminateHandler() : SessionEndWatcher() {} |
- ~TerminateHandler() override {} |
- |
- private: |
- // SessionEndWatcher: |
- void SessionEnding() override { |
- MetricsRecordExit(Metrics::LifetimeMilestone::kTerminated); |
- } |
- |
- DISALLOW_COPY_AND_ASSIGN(TerminateHandler); |
-}; |
- |
void InstallCrashHandler() { |
g_original_exception_filter = |
SetUnhandledExceptionFilter(&UnhandledExceptionHandler); |
- |
- // These are termination handlers, not crash handlers, but that’s close |
- // enough. Note that destroying the TerminateHandler would wait for its thread |
- // to exit, which isn’t necessary or desirable. |
- SetConsoleCtrlHandler(ConsoleHandler, true); |
- static TerminateHandler* terminate_handler = new TerminateHandler(); |
- ALLOW_UNUSED_LOCAL(terminate_handler); |
} |
#endif // OS_MACOSX |
@@ -371,7 +270,6 @@ void InstallCrashHandler() { |
int HandlerMain(int argc, char* argv[]) { |
InstallCrashHandler(); |
- CallMetricsRecordNormalExit metrics_record_normal_exit; |
const base::FilePath argv0( |
ToolSupport::CommandLineArgumentToFilePathStringType(argv[0])); |
@@ -393,7 +291,6 @@ int HandlerMain(int argc, char* argv[]) { |
#endif // OS_MACOSX |
kOptionMetrics, |
kOptionNoRateLimit, |
- kOptionNoUploadGzip, |
#if defined(OS_MACOSX) |
kOptionResetOwnCrashExceptionPortToSystemDefault, |
#elif defined(OS_WIN) |
@@ -420,13 +317,11 @@ int HandlerMain(int argc, char* argv[]) { |
InitialClientData initial_client_data; |
#endif // OS_MACOSX |
bool rate_limit; |
- bool upload_gzip; |
} options = {}; |
#if defined(OS_MACOSX) |
options.handshake_fd = -1; |
#endif |
options.rate_limit = true; |
- options.upload_gzip = true; |
const option long_options[] = { |
{"annotation", required_argument, nullptr, kOptionAnnotation}, |
@@ -445,7 +340,6 @@ int HandlerMain(int argc, char* argv[]) { |
#endif // OS_MACOSX |
{"metrics-dir", required_argument, nullptr, kOptionMetrics}, |
{"no-rate-limit", no_argument, nullptr, kOptionNoRateLimit}, |
- {"no-upload-gzip", no_argument, nullptr, kOptionNoUploadGzip}, |
#if defined(OS_MACOSX) |
{"reset-own-crash-exception-port-to-system-default", |
no_argument, |
@@ -468,7 +362,7 @@ int HandlerMain(int argc, char* argv[]) { |
std::string value; |
if (!SplitStringFirst(optarg, '=', &key, &value)) { |
ToolSupport::UsageHint(me, "--annotation requires KEY=VALUE"); |
- return ExitFailure(); |
+ return EXIT_FAILURE; |
} |
std::string old_value; |
if (!MapInsertOrReplace(&options.annotations, key, value, &old_value)) { |
@@ -487,7 +381,7 @@ int HandlerMain(int argc, char* argv[]) { |
options.handshake_fd < 0) { |
ToolSupport::UsageHint(me, |
"--handshake-fd requires a file descriptor"); |
- return ExitFailure(); |
+ return EXIT_FAILURE; |
} |
break; |
} |
@@ -500,7 +394,7 @@ int HandlerMain(int argc, char* argv[]) { |
if (!options.initial_client_data.InitializeFromString(optarg)) { |
ToolSupport::UsageHint( |
me, "failed to parse --initial-client-data"); |
- return ExitFailure(); |
+ return EXIT_FAILURE; |
} |
break; |
} |
@@ -513,10 +407,6 @@ int HandlerMain(int argc, char* argv[]) { |
options.rate_limit = false; |
break; |
} |
- case kOptionNoUploadGzip: { |
- options.upload_gzip = false; |
- break; |
- } |
#if defined(OS_MACOSX) |
case kOptionResetOwnCrashExceptionPortToSystemDefault: { |
options.reset_own_crash_exception_port_to_system_default = true; |
@@ -534,17 +424,15 @@ int HandlerMain(int argc, char* argv[]) { |
} |
case kOptionHelp: { |
Usage(me); |
- MetricsRecordExit(Metrics::LifetimeMilestone::kExitedEarly); |
return EXIT_SUCCESS; |
} |
case kOptionVersion: { |
ToolSupport::Version(me); |
- MetricsRecordExit(Metrics::LifetimeMilestone::kExitedEarly); |
return EXIT_SUCCESS; |
} |
default: { |
ToolSupport::UsageHint(me, nullptr); |
- return ExitFailure(); |
+ return EXIT_FAILURE; |
} |
} |
} |
@@ -554,34 +442,34 @@ int HandlerMain(int argc, char* argv[]) { |
#if defined(OS_MACOSX) |
if (options.handshake_fd < 0 && options.mach_service.empty()) { |
ToolSupport::UsageHint(me, "--handshake-fd or --mach-service is required"); |
- return ExitFailure(); |
+ return EXIT_FAILURE; |
} |
if (options.handshake_fd >= 0 && !options.mach_service.empty()) { |
ToolSupport::UsageHint( |
me, "--handshake-fd and --mach-service are incompatible"); |
- return ExitFailure(); |
+ return EXIT_FAILURE; |
} |
#elif defined(OS_WIN) |
if (!options.initial_client_data.IsValid() && options.pipe_name.empty()) { |
ToolSupport::UsageHint(me, |
"--initial-client-data or --pipe-name is required"); |
- return ExitFailure(); |
+ return EXIT_FAILURE; |
} |
if (options.initial_client_data.IsValid() && !options.pipe_name.empty()) { |
ToolSupport::UsageHint( |
me, "--initial-client-data and --pipe-name are incompatible"); |
- return ExitFailure(); |
+ return EXIT_FAILURE; |
} |
#endif // OS_MACOSX |
if (!options.database) { |
ToolSupport::UsageHint(me, "--database is required"); |
- return ExitFailure(); |
+ return EXIT_FAILURE; |
} |
if (argc) { |
ToolSupport::UsageHint(me, nullptr); |
- return ExitFailure(); |
+ return EXIT_FAILURE; |
} |
#if defined(OS_MACOSX) |
@@ -606,7 +494,7 @@ int HandlerMain(int argc, char* argv[]) { |
} |
if (!receive_right.is_valid()) { |
- return ExitFailure(); |
+ return EXIT_FAILURE; |
} |
ExceptionHandlerServer exception_handler_server( |
@@ -623,7 +511,6 @@ int HandlerMain(int argc, char* argv[]) { |
// launchd.plist(5). |
// |
// Set up a SIGTERM handler that will call exception_handler_server.Stop(). |
- // This replaces the HandleTerminateSignal handler for SIGTERM. |
struct sigaction sa = {}; |
sigemptyset(&sa.sa_mask); |
sa.sa_flags = SA_SIGINFO; |
@@ -657,20 +544,18 @@ int HandlerMain(int argc, char* argv[]) { |
} |
} |
- Metrics::HandlerLifetimeMilestone(Metrics::LifetimeMilestone::kStarted); |
- |
std::unique_ptr<CrashReportDatabase> database(CrashReportDatabase::Initialize( |
base::FilePath(ToolSupport::CommandLineArgumentToFilePathStringType( |
options.database)))); |
if (!database) { |
- return ExitFailure(); |
+ return EXIT_FAILURE; |
} |
// TODO(scottmg): options.rate_limit should be removed when we have a |
// configurable database setting to control upload limiting. |
// See https://crashpad.chromium.org/bug/23. |
CrashReportUploadThread upload_thread( |
- database.get(), options.url, options.rate_limit, options.upload_gzip); |
+ database.get(), options.url, options.rate_limit); |
upload_thread.Start(); |
PruneCrashReportThread prune_thread(database.get(), |