From c2deabee5d424854cd60e1424d1eb6ece9e2723a Mon Sep 17 00:00:00 2001 From: optizone <42874998+optizone@users.noreply.github.com> Date: Tue, 9 Apr 2019 22:33:13 +0300 Subject: [PATCH] Use forked process to handle crashes (#1443) --- src/CutterApplication.cpp | 1 + src/Main.cpp | 7 ++ src/common/CrashHandler.cpp | 186 ++++++++++++++---------------------- src/common/CrashHandler.h | 3 + 4 files changed, 83 insertions(+), 114 deletions(-) diff --git a/src/CutterApplication.cpp b/src/CutterApplication.cpp index d435ce96..b2e361be 100644 --- a/src/CutterApplication.cpp +++ b/src/CutterApplication.cpp @@ -1,4 +1,5 @@ #include "common/PythonManager.h" +#include "common/CrashHandler.h" #include "CutterApplication.h" #include "plugins/PluginManager.h" #include "CutterConfig.h" diff --git a/src/Main.cpp b/src/Main.cpp index e177ca2b..f6496b08 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -21,6 +21,13 @@ static void migrateSettings(QSettings &newSettings) int main(int argc, char *argv[]) { + if (argc >= 3 && QString::fromLocal8Bit(argv[1]) == "--start-crash-handler") { + QApplication app(argc, argv); + QString dumpLocation = QString::fromLocal8Bit(argv[2]); + showCrashDialog(dumpLocation); + return 0; + } + initCrashHandler(); qRegisterMetaType>(); diff --git a/src/common/CrashHandler.cpp b/src/common/CrashHandler.cpp index c69cfccb..481de058 100644 --- a/src/common/CrashHandler.cpp +++ b/src/common/CrashHandler.cpp @@ -1,19 +1,20 @@ #include "CrashHandler.h" - -#ifdef CUTTER_ENABLE_CRASH_REPORTS #include "BugReporting.h" -#include -#include #include #include #include -#include -#include +#include #include + +#ifdef CUTTER_ENABLE_CRASH_REPORTS + +#include +#include #include #include #include +#include #if defined (Q_OS_LINUX) #include "client/linux/handler/exception_handler.h" @@ -23,41 +24,12 @@ #include "client/mac/handler/exception_handler.h" #endif // Q_OS +static google_breakpad::ExceptionHandler *exceptionHandler = nullptr; - -// Here will be placed crash dump at the first place -// and then moved if needed -#if defined (Q_OS_LINUX) || defined (Q_OS_MACOS) -static std::string tmpLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString(); -#else -static std::wstring tmpLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdWString(); -#endif - -static const QMap sigNumDescription = { - #ifdef SIGSEGV - { SIGSEGV, "SIGSEGV" }, - #endif // SIGSEGV - #ifdef SIGILL - { SIGILL, "SIGILL" }, - #endif // SIGILL - #ifdef SIGFPE - { SIGFPE, "SIGFPE" }, - #endif // SIGFPE - #ifdef SIGABRT - { SIGABRT, "SIGABRT" }, - #endif // SIGABRT - #ifdef SIGBUS - { SIGBUS, "SIGBUS" }, - #endif // SIGBUS - #ifdef SIGPIPE - { SIGPIPE, "SIGPIPE" }, - #endif // SIGPIPE - #ifdef SIGSYS - { SIGSYS, "SIGSYS" } - #endif // SIGSYS -}; - -static QString dumpFileFullPath = ""; +static void finishCrashHandler() +{ + delete exceptionHandler; +} #ifdef Q_OS_WIN32 // Called if crash dump was successfully created @@ -68,9 +40,11 @@ bool callback(const wchar_t *_dump_dir, MDRawAssertionInfo *assertion, bool success) { - QString dir = QString::fromWCharArray(_dump_dir); - QString id = QString::fromWCharArray(_minidump_id); - dumpFileFullPath = QDir(dir).filePath(id + ".dmp"); + const QDir dir = QString::fromWCharArray(_dump_dir); + const QString id = QString::fromWCharArray(_minidump_id); + QProcess::execute(QCoreApplication::applicationFilePath() + + " --start-crash-handler " + + dir.filePath(id + ".dmp")); return true; } #elif defined (Q_OS_LINUX) @@ -78,7 +52,9 @@ bool callback(const wchar_t *_dump_dir, // Saves path to file bool callback(const google_breakpad::MinidumpDescriptor &md, void *context, bool b) { - dumpFileFullPath = md.path(); + QProcess::execute(QCoreApplication::applicationFilePath() + + " --start-crash-handler " + + md.path()); return true; } #elif defined (Q_OS_MACOS) @@ -86,54 +62,72 @@ bool callback(const google_breakpad::MinidumpDescriptor &md, void *context, bool // Saves path to file bool callback(const char *dump_dir, const char *minidump_id, void *context, bool succeeded) { - QString dir = QString::fromUtf8(dump_dir); - QString id = QString::fromUtf8(minidump_id); - dumpFileFullPath = QDir(dir).filePath(id + ".dmp"); + const QDir dir = QString::fromUtf8(dump_dir); + const QString id = QString::fromUtf8(minidump_id); + QProcess::execute(QCoreApplication::applicationFilePath() + + " --start-crash-handler " + + dir.filePath(id + ".dmp")); return true; } #endif // Q_OS - -/** - * @brief Writes minidump and put its name in dumpFileFullPath. - * @return true on succes - */ -bool writeMinidump() +void initCrashHandler() { - bool ok; -#if defined (Q_OS_LINUX) || defined (Q_OS_MACOS) - ok = google_breakpad::ExceptionHandler::WriteMinidump(tmpLocation, - callback, - nullptr); -#elif defined (Q_OS_WIN32) - ok = google_breakpad::ExceptionHandler::WriteMinidump(tmpLocation, - callback, - nullptr); -#endif // Q_OS - return ok; + if (exceptionHandler) { + return; + } + // Here will be placed crash dump at the first place + // and then moved if needed + +#if defined (Q_OS_LINUX) + static std::string tmpLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString(); + exceptionHandler = new google_breakpad::ExceptionHandler(google_breakpad::MinidumpDescriptor(tmpLocation), + nullptr, + callback, + nullptr, + true, + -1); +#elif defined (Q_OS_MACOS) + static std::string tmpLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString(); + exceptionHandler = new google_breakpad::ExceptionHandler(tmpLocation, + nullptr, + callback, + nullptr, + true, + nullptr); +#else + static std::wstring tmpLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdWString(); + exceptionHandler = new google_breakpad::ExceptionHandler(tmpLocation, + nullptr, + callback, + nullptr, + google_breakpad::ExceptionHandler::HANDLER_ALL); +#endif + atexit(finishCrashHandler); } -[[noreturn]] void crashHandler(int signum) +#else // CUTTER_ENABLE_CRASH_REPORTS + +void initCrashHandler() { - // As soon as Cutter crashed, crash dump is created, so core and memory state - // is not changed by all stuff with user interation going on below. - bool ok = writeMinidump(); - QString err = sigNumDescription.contains(signum) ? - sigNumDescription[signum] : - QObject::tr("undefined"); +} + +#endif // CUTTER_ENABLE_CRASH_REPORTS +void showCrashDialog(const QString &dumpFile) +{ QMessageBox mb; mb.setWindowTitle(QObject::tr("Cutter encountered a problem")); - mb.setText(QObject::tr("Cutter received a %1 it can't handle and will close.
" - "Would you like to create a crash dump for bug report?" - ).arg(err)); + mb.setText(QObject::tr("Cutter received a signal it can't handle and will close.
" + "Would you like to create a crash dump for bug report?")); mb.setStandardButtons(QMessageBox::Yes | QMessageBox::No); mb.button(QMessageBox::Yes)->setText(QObject::tr("Create a crash dump")); mb.button(QMessageBox::No)->setText(QObject::tr("Do not report")); mb.setDefaultButton(QMessageBox::Yes); + bool ok = false; int ret = mb.exec(); if (ret == QMessageBox::Yes) { QString dumpSaveFileName; @@ -141,7 +135,6 @@ bool writeMinidump() do { placementFailCounter++; if (placementFailCounter == 4) { - ok = false; break; } dumpSaveFileName = QFileDialog::getSaveFileName(nullptr, @@ -154,9 +147,10 @@ bool writeMinidump() QObject::tr("Dump files (*.dmp)")); if (dumpSaveFileName.isEmpty()) { - exit(3); + return; } - if (QFile::rename(dumpFileFullPath, dumpSaveFileName)) { + if (QFile::rename(dumpFile, dumpSaveFileName)) { + ok = true; break; } QMessageBox::critical(nullptr, @@ -187,43 +181,7 @@ bool writeMinidump() QObject::tr("Error occured during crash dump creation.")); } } else { - QFile f(dumpFileFullPath); + QFile f(dumpFile); f.remove(); } - - _exit(3); } - -void initCrashHandler() -{ -#ifdef SIGSEGV - signal(SIGSEGV, crashHandler); -#endif // SIGSEGV -#ifdef SIGILL - signal(SIGILL, crashHandler); -#endif // SIGILL -#ifdef SIGFPE - signal(SIGFPE, crashHandler); -#endif // SIGFPE -#ifdef SIGABRT - signal(SIGABRT, crashHandler); -#endif // SIGABRT -#ifdef SIGBUS - signal(SIGBUS, crashHandler); -#endif // SIGBUS -#ifdef SIGPIPE - signal(SIGPIPE, crashHandler); -#endif // SIGPIPE -#ifdef SIGSYS - signal(SIGSYS, crashHandler); -#endif // SIGSYS -} - -#else // CUTTER_ENABLE_CRASH_REPORTS - -void initCrashHandler() -{ - -} - -#endif // CUTTER_ENABLE_CRASH_REPORTS diff --git a/src/common/CrashHandler.h b/src/common/CrashHandler.h index 4c62d903..be961be7 100644 --- a/src/common/CrashHandler.h +++ b/src/common/CrashHandler.h @@ -1,6 +1,8 @@ #ifndef CRASH_HANDLER_H #define CRASH_HANDLER_H +#include + /** * @fn void initCrashHandler() * @@ -9,5 +11,6 @@ */ void initCrashHandler(); +void showCrashDialog(const QString &dumpFile); #endif // CRASH_HANDLER_H