Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1449)

Unified Diff: third_party/crashpad/crashpad/handler/handler_main.cc

Issue 2710663006: Update Crashpad to 4a2043ea65e2641ef1a921801c0aaa15ada02fc7 (Closed)
Patch Set: Update Crashpad to 4a2043ea65e2 Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 9433a6af5186ec33ebf6c68fb17948adb227381d..5006cf6723f6a59ffcc700d74ae652dc44a61f36 100644
--- a/third_party/crashpad/crashpad/handler/handler_main.cc
+++ b/third_party/crashpad/crashpad/handler/handler_main.cc
@@ -24,8 +24,10 @@
#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"
@@ -64,6 +66,7 @@
#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 {
@@ -93,6 +96,7 @@ 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"
@@ -107,11 +111,66 @@ 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)
-struct sigaction g_original_crash_sigaction[NSIG];
+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;
+ ALLOW_UNUSED_LOCAL(rv);
+}
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
@@ -143,22 +202,17 @@ void HandleCrashSignal(int sig, siginfo_t* siginfo, void* context) {
}
Metrics::HandlerCrashed(metrics_code);
- // 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;
+ RestoreDefaultSignalHandler(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 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.
+ // 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.
if ((sig != SIGILL && sig != SIGFPE && sig != SIGBUS && sig != SIGSEGV) ||
!si_code_valid) {
@@ -166,8 +220,7 @@ 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 or call to the previous signal handler as
- // appropriate.
+ // handler. Re-raise them.
//
// Unfortunately, when SIGBUS is received asynchronously via kill(),
// siginfo->si_code makes it appear as though it was actually received via a
@@ -180,49 +233,68 @@ 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.
- 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);
- }
- }
+ //
+ // 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";
+ ALLOW_UNUSED_LOCAL(rv);
}
}
-void InstallCrashHandler() {
- struct sigaction sa = {};
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_SIGINFO;
- sa.sa_sigaction = HandleCrashSignal;
+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";
+ ALLOW_UNUSED_LOCAL(rv);
+}
+
+void InstallCrashHandler() {
// 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 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;
- }
+ 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);
}
struct ResetSIGTERMTraits {
@@ -242,6 +314,9 @@ 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();
}
@@ -251,6 +326,7 @@ 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)
@@ -259,9 +335,37 @@ 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
@@ -270,6 +374,7 @@ void InstallCrashHandler() {
int HandlerMain(int argc, char* argv[]) {
InstallCrashHandler();
+ CallMetricsRecordNormalExit metrics_record_normal_exit;
const base::FilePath argv0(
ToolSupport::CommandLineArgumentToFilePathStringType(argv[0]));
@@ -291,6 +396,7 @@ int HandlerMain(int argc, char* argv[]) {
#endif // OS_MACOSX
kOptionMetrics,
kOptionNoRateLimit,
+ kOptionNoUploadGzip,
#if defined(OS_MACOSX)
kOptionResetOwnCrashExceptionPortToSystemDefault,
#elif defined(OS_WIN)
@@ -317,11 +423,13 @@ 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},
@@ -340,6 +448,7 @@ 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,
@@ -362,7 +471,7 @@ int HandlerMain(int argc, char* argv[]) {
std::string value;
if (!SplitStringFirst(optarg, '=', &key, &value)) {
ToolSupport::UsageHint(me, "--annotation requires KEY=VALUE");
- return EXIT_FAILURE;
+ return ExitFailure();
}
std::string old_value;
if (!MapInsertOrReplace(&options.annotations, key, value, &old_value)) {
@@ -381,7 +490,7 @@ int HandlerMain(int argc, char* argv[]) {
options.handshake_fd < 0) {
ToolSupport::UsageHint(me,
"--handshake-fd requires a file descriptor");
- return EXIT_FAILURE;
+ return ExitFailure();
}
break;
}
@@ -394,7 +503,7 @@ int HandlerMain(int argc, char* argv[]) {
if (!options.initial_client_data.InitializeFromString(optarg)) {
ToolSupport::UsageHint(
me, "failed to parse --initial-client-data");
- return EXIT_FAILURE;
+ return ExitFailure();
}
break;
}
@@ -407,6 +516,10 @@ 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;
@@ -424,15 +537,17 @@ 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 EXIT_FAILURE;
+ return ExitFailure();
}
}
}
@@ -442,34 +557,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 EXIT_FAILURE;
+ return ExitFailure();
}
if (options.handshake_fd >= 0 && !options.mach_service.empty()) {
ToolSupport::UsageHint(
me, "--handshake-fd and --mach-service are incompatible");
- return EXIT_FAILURE;
+ return ExitFailure();
}
#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 EXIT_FAILURE;
+ return ExitFailure();
}
if (options.initial_client_data.IsValid() && !options.pipe_name.empty()) {
ToolSupport::UsageHint(
me, "--initial-client-data and --pipe-name are incompatible");
- return EXIT_FAILURE;
+ return ExitFailure();
}
#endif // OS_MACOSX
if (!options.database) {
ToolSupport::UsageHint(me, "--database is required");
- return EXIT_FAILURE;
+ return ExitFailure();
}
if (argc) {
ToolSupport::UsageHint(me, nullptr);
- return EXIT_FAILURE;
+ return ExitFailure();
}
#if defined(OS_MACOSX)
@@ -494,7 +609,7 @@ int HandlerMain(int argc, char* argv[]) {
}
if (!receive_right.is_valid()) {
- return EXIT_FAILURE;
+ return ExitFailure();
}
ExceptionHandlerServer exception_handler_server(
@@ -511,6 +626,7 @@ 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;
@@ -544,18 +660,20 @@ 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 EXIT_FAILURE;
+ return ExitFailure();
}
// 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);
+ database.get(), options.url, options.rate_limit, options.upload_gzip);
upload_thread.Start();
PruneCrashReportThread prune_thread(database.get(),
« no previous file with comments | « third_party/crashpad/crashpad/handler/handler.gyp ('k') | third_party/crashpad/crashpad/minidump/minidump_context.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698