| 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(),
|
|
|