diff --git a/Telegram/SourceFiles/core/crash_reports.cpp b/Telegram/SourceFiles/core/crash_reports.cpp index 232794298..f763fcd45 100644 --- a/Telegram/SourceFiles/core/crash_reports.cpp +++ b/Telegram/SourceFiles/core/crash_reports.cpp @@ -131,20 +131,98 @@ void InstallQtMessageHandler() { }); } -Qt::HANDLE ReportingThreadId = nullptr; -bool ReportingHeaderWritten = false; -QMutex ReportingMutex; +std::atomic ReportingThreadId/* = nullptr*/; +bool ReportingHeaderWritten/* = false*/; +const char *BreakpadDumpPath/* = nullptr*/; +const wchar_t *BreakpadDumpPathW/* = nullptr*/; -const char *BreakpadDumpPath = nullptr; -const wchar_t *BreakpadDumpPathW = nullptr; +const int HandledSignals[] = { + SIGSEGV, + SIGABRT, + SIGFPE, + SIGILL, +#ifdef Q_OS_UNIX + SIGBUS, + SIGTRAP, +#endif // Q_OS_UNIX +}; #ifdef Q_OS_UNIX -struct sigaction SIG_def[32]; +struct sigaction OldSigActions[32]/* = { 0 }*/; + +void RestoreSignalHandlers() { + for (const auto signal : HandledSignals) { + sigaction(signal, &OldSigActions[signal], nullptr); + } +} + +void InvokeOldSignalHandler(int signum, siginfo_t *info, void *ucontext) { + if (signum < 0 || signum > 31) { + return; + } else if (OldSigActions[signum].sa_flags & SA_SIGINFO) { + if (OldSigActions[signum].sa_sigaction) { + OldSigActions[signum].sa_sigaction(signum, info, ucontext); + } + } else { + if (OldSigActions[signum].sa_handler) { + OldSigActions[signum].sa_handler(signum); + } + } +} + +void WriteReportHeader() { + if (ReportingHeaderWritten) { + return; + } + ReportingHeaderWritten = true; + const auto dec2hex = [](int value) -> char { + if (value >= 0 && value < 10) { + return '0' + value; + } else if (value >= 10 && value < 16) { + return 'a' + (value - 10); + } + return '#'; + }; + for (const auto &i : ProcessAnnotationRefs) { + QByteArray utf8 = i.second->toUtf8(); + std::string wrapped; + wrapped.reserve(4 * utf8.size()); + for (auto ch : utf8) { + auto uch = static_cast(ch); + wrapped.append("\\x", 2).append(1, dec2hex(uch >> 4)).append(1, dec2hex(uch & 0x0F)); + } + ProcessAnnotations[i.first] = wrapped; + } + for (const auto &i : ProcessAnnotations) { + dump() << i.first.c_str() << ": " << i.second.c_str() << "\n"; + } + Platform::WriteCrashDumpDetails(); + dump() << "\n"; +} + +void WriteReportInfo(int signum, const char *name) { + WriteReportHeader(); + + const auto thread = ReportingThreadId.load(); + if (name) { + dump() << "Caught signal " << signum << " (" << name << ") in thread " << uint64(thread) << "\n"; + } else if (signum == -1) { + dump() << "Google Breakpad caught a crash, minidump written in thread " << uint64(thread) << "\n"; + if (BreakpadDumpPath) { + dump() << "Minidump: " << BreakpadDumpPath << "\n"; + } else if (BreakpadDumpPathW) { + dump() << "Minidump: " << BreakpadDumpPathW << "\n"; + } + } else { + dump() << "Caught signal " << signum << " in thread " << uint64(thread) << "\n"; + } + + dump() << "\nBacktrace omitted.\n"; + dump() << "\n"; +} void SignalHandler(int signum, siginfo_t *info, void *ucontext) { - if (signum > 0) { - sigaction(signum, &SIG_def[signum], 0); - } + RestoreSignalHandlers(); #else // Q_OS_UNIX void SignalHandler(int signum) { @@ -162,125 +240,17 @@ void SignalHandler(int signum) { #endif // !Q_OS_WIN } - Qt::HANDLE thread = QThread::currentThreadId(); - if (thread == ReportingThreadId) return; + auto expected = Qt::HANDLE(nullptr); + const auto thread = QThread::currentThreadId(); - QMutexLocker lock(&ReportingMutex); - ReportingThreadId = thread; - - if (!ReportingHeaderWritten) { - ReportingHeaderWritten = true; - auto dec2hex = [](int value) -> char { - if (value >= 0 && value < 10) { - return '0' + value; - } else if (value >= 10 && value < 16) { - return 'a' + (value - 10); - } - return '#'; - }; - - for (const auto &i : ProcessAnnotationRefs) { - QByteArray utf8 = i.second->toUtf8(); - std::string wrapped; - wrapped.reserve(4 * utf8.size()); - for (auto ch : utf8) { - auto uch = static_cast(ch); - wrapped.append("\\x", 2).append(1, dec2hex(uch >> 4)).append(1, dec2hex(uch & 0x0F)); - } - ProcessAnnotations[i.first] = wrapped; - } - - for (const auto &i : ProcessAnnotations) { - dump() << i.first.c_str() << ": " << i.second.c_str() << "\n"; - } - psWriteDump(); - dump() << "\n"; - } - if (name) { - dump() << "Caught signal " << signum << " (" << name << ") in thread " << uint64(thread) << "\n"; - } else if (signum == -1) { - dump() << "Google Breakpad caught a crash, minidump written in thread " << uint64(thread) << "\n"; - if (BreakpadDumpPath) { - dump() << "Minidump: " << BreakpadDumpPath << "\n"; - } else if (BreakpadDumpPathW) { - dump() << "Minidump: " << BreakpadDumpPathW << "\n"; - } - } else { - dump() << "Caught signal " << signum << " in thread " << uint64(thread) << "\n"; + if (ReportingThreadId.compare_exchange_strong(expected, thread)) { + WriteReportInfo(signum, name); + ReportingThreadId = nullptr; } - // see https://github.com/benbjohnson/bandicoot #ifdef Q_OS_UNIX - ucontext_t *uc = (ucontext_t*)ucontext; - - void *caller = 0; - if (uc) { -#if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6) - /* OSX < 10.6 */ -#if defined(__x86_64__) - caller = (void*)uc->uc_mcontext->__ss.__rip; -#elif defined(__i386__) - caller = (void*)uc->uc_mcontext->__ss.__eip; -#else - caller = (void*)uc->uc_mcontext->__ss.__srr0; -#endif -#elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6) - /* OSX >= 10.6 */ -#if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__) - caller = (void*)uc->uc_mcontext->__ss.__rip; -#else - caller = (void*)uc->uc_mcontext->__ss.__eip; -#endif -#elif defined(__linux__) - /* Linux */ -#if defined(__i386__) - caller = (void*)uc->uc_mcontext.gregs[14]; /* Linux 32 */ -#elif defined(__X86_64__) || defined(__x86_64__) - caller = (void*)uc->uc_mcontext.gregs[16]; /* Linux 64 */ -#elif defined(__ia64__) /* Linux IA64 */ - caller = (void*)uc->uc_mcontext.sc_ip; -#endif - -#endif - } - - void *addresses[132] = { 0 }; - size_t size = backtrace(addresses, 128); - - /* overwrite sigaction with caller's address */ - if (caller) { - for (int i = size; i > 1; --i) { - addresses[i + 3] = addresses[i]; - } - addresses[2] = (void*)0x1; - addresses[3] = caller; - addresses[4] = (void*)0x1; - } - -#ifdef Q_OS_MAC - dump() << "\nBase image addresses:\n"; - for (size_t i = 0; i < size; ++i) { - Dl_info info; - dump() << i << " "; - if (dladdr(addresses[i], &info)) { - dump() << uint64(info.dli_fbase) << " (" << info.dli_fname << ")\n"; - } else { - dump() << "_unknown_module_\n"; - } - } -#endif // Q_OS_MAC - - dump() << "\nBacktrace:\n"; - - backtrace_symbols_fd(addresses, size, ReportFileNo); - -#else // Q_OS_UNIX - dump() << "\nBacktrace omitted.\n"; -#endif // else for Q_OS_UNIX - - dump() << "\n"; - - ReportingThreadId = nullptr; + InvokeOldSignalHandler(signum, info, ucontext); +#endif // Q_OS_UNIX } bool SetSignalHandlers = true; @@ -475,17 +445,13 @@ Status Restart() { sigemptyset(&sigact.sa_mask); sigact.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO; - sigaction(SIGABRT, &sigact, &SIG_def[SIGABRT]); - sigaction(SIGSEGV, &sigact, &SIG_def[SIGSEGV]); - sigaction(SIGILL, &sigact, &SIG_def[SIGILL]); - sigaction(SIGFPE, &sigact, &SIG_def[SIGFPE]); - sigaction(SIGBUS, &sigact, &SIG_def[SIGBUS]); - sigaction(SIGSYS, &sigact, &SIG_def[SIGSYS]); + for (const auto signal : HandledSignals) { + sigaction(signal, &sigact, &OldSigActions[signal]); + } #else // !Q_OS_WIN - signal(SIGABRT, SignalHandler); - signal(SIGSEGV, SignalHandler); - signal(SIGILL, SignalHandler); - signal(SIGFPE, SignalHandler); + for (const auto signal : HandledSignals) { + signal(signal, SignalHandler); + } #endif // else for !Q_OS_WIN } diff --git a/Telegram/SourceFiles/core/update_checker.cpp b/Telegram/SourceFiles/core/update_checker.cpp index f96d85f58..5f42cfb75 100644 --- a/Telegram/SourceFiles/core/update_checker.cpp +++ b/Telegram/SourceFiles/core/update_checker.cpp @@ -1559,20 +1559,27 @@ bool checkReadyUpdate() { #elif defined Q_OS_UNIX // Q_OS_MAC // if the files in the directory are owned by user, while the directory is not, // update will still fail since it's not possible to remove files - if (unlink(QFile::encodeName(curUpdater).constData())) { + if (QFile::exists(curUpdater) + && unlink(QFile::encodeName(curUpdater).constData())) { if (errno == EACCES) { + DEBUG_LOG(("Update Info: " + "could not unlink current Updater, access denied.")); cSetWriteProtected(true); return true; } else { + DEBUG_LOG(("Update Error: could not unlink current Updater.")); ClearAll(); return false; } } if (!linuxMoveFile(QFile::encodeName(updater.absoluteFilePath()).constData(), QFile::encodeName(curUpdater).constData())) { if (errno == EACCES) { + DEBUG_LOG(("Update Info: " + "could not copy new Updater, access denied.")); cSetWriteProtected(true); return true; } else { + DEBUG_LOG(("Update Error: could not copy new Updater.")); ClearAll(); return false; } diff --git a/Telegram/SourceFiles/platform/linux/specific_linux.cpp b/Telegram/SourceFiles/platform/linux/specific_linux.cpp index b483c2d05..890a7c0c4 100644 --- a/Telegram/SourceFiles/platform/linux/specific_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/specific_linux.cpp @@ -650,9 +650,6 @@ bool SkipTaskbarSupported() { } // namespace Platform -void psWriteDump() { -} - void psActivateProcess(uint64 pid) { // objc_activateProgram(); } diff --git a/Telegram/SourceFiles/platform/linux/specific_linux.h b/Telegram/SourceFiles/platform/linux/specific_linux.h index c1ce882ba..7edf24c5c 100644 --- a/Telegram/SourceFiles/platform/linux/specific_linux.h +++ b/Telegram/SourceFiles/platform/linux/specific_linux.h @@ -26,6 +26,9 @@ void InstallLauncher(bool force = false); inline void IgnoreApplicationActivationRightNow() { } +inline void WriteCrashDumpDetails() { +} + } // namespace Platform inline void psCheckLocalSocket(const QString &serverName) { @@ -35,8 +38,6 @@ inline void psCheckLocalSocket(const QString &serverName) { } } -void psWriteDump(); - void psActivateProcess(uint64 pid = 0); QString psAppDataPath(); void psAutoStart(bool start, bool silent = false); diff --git a/Telegram/SourceFiles/platform/mac/specific_mac.h b/Telegram/SourceFiles/platform/mac/specific_mac.h index 91b97a584..adc5d3cdd 100644 --- a/Telegram/SourceFiles/platform/mac/specific_mac.h +++ b/Telegram/SourceFiles/platform/mac/specific_mac.h @@ -52,8 +52,6 @@ inline void psCheckLocalSocket(const QString &serverName) { } } -void psWriteDump(); - void psActivateProcess(uint64 pid = 0); QString psAppDataPath(); void psAutoStart(bool start, bool silent = false); diff --git a/Telegram/SourceFiles/platform/mac/specific_mac.mm b/Telegram/SourceFiles/platform/mac/specific_mac.mm index d6726a80a..57456f608 100644 --- a/Telegram/SourceFiles/platform/mac/specific_mac.mm +++ b/Telegram/SourceFiles/platform/mac/specific_mac.mm @@ -37,13 +37,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include #include -void psWriteDump() { -#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS - double v = objc_appkitVersion(); - CrashReports::dump() << "OS-Version: " << v; -#endif // DESKTOP_APP_DISABLE_CRASH_REPORTS -} - void psActivateProcess(uint64 pid) { if (!pid) { const auto window = Core::App().activeWindow(); @@ -113,6 +106,13 @@ std::optional IsDarkMode() { : std::nullopt; } +void WriteCrashDumpDetails() { +#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS + double v = objc_appkitVersion(); + CrashReports::dump() << "OS-Version: " << v; +#endif // DESKTOP_APP_DISABLE_CRASH_REPORTS +} + void RegisterCustomScheme(bool force) { OSStatus result = LSSetDefaultHandlerForURLScheme(CFSTR("tg"), (CFStringRef)[[NSBundle mainBundle] bundleIdentifier]); DEBUG_LOG(("App Info: set default handler for 'tg' scheme result: %1").arg(result)); diff --git a/Telegram/SourceFiles/platform/platform_specific.h b/Telegram/SourceFiles/platform/platform_specific.h index d0bfb84dc..f7112b214 100644 --- a/Telegram/SourceFiles/platform/platform_specific.h +++ b/Telegram/SourceFiles/platform/platform_specific.h @@ -39,7 +39,8 @@ void IgnoreApplicationActivationRightNow(); bool AutostartSupported(); bool TrayIconSupported(); bool SkipTaskbarSupported(); -QImage GetImageFromClipboard(); +[[nodiscard]] QImage GetImageFromClipboard(); +void WriteCrashDumpDetails(); [[nodiscard]] std::optional IsDarkMode(); [[nodiscard]] inline bool IsDarkModeSupported() { diff --git a/Telegram/SourceFiles/platform/win/specific_win.cpp b/Telegram/SourceFiles/platform/win/specific_win.cpp index 0f323cb51..b0f9d5ac8 100644 --- a/Telegram/SourceFiles/platform/win/specific_win.cpp +++ b/Telegram/SourceFiles/platform/win/specific_win.cpp @@ -293,6 +293,31 @@ bool AutostartSupported() { return !IsWindowsStoreBuild(); } +void WriteCrashDumpDetails() { +#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS + PROCESS_MEMORY_COUNTERS data = { 0 }; + if (Dlls::GetProcessMemoryInfo + && Dlls::GetProcessMemoryInfo( + GetCurrentProcess(), + &data, + sizeof(data))) { + const auto mb = 1024 * 1024; + CrashReports::dump() + << "Memory-usage: " + << (data.PeakWorkingSetSize / mb) + << " MB (peak), " + << (data.WorkingSetSize / mb) + << " MB (current)\n"; + CrashReports::dump() + << "Pagefile-usage: " + << (data.PeakPagefileUsage / mb) + << " MB (peak), " + << (data.PagefileUsage / mb) + << " MB (current)\n"; + } +#endif // DESKTOP_APP_DISABLE_CRASH_REPORTS +} + } // namespace Platform namespace { @@ -522,31 +547,6 @@ void psSendToMenu(bool send, bool silent) { _manageAppLnk(send, silent, CSIDL_SENDTO, L"-sendpath", L"Telegram send to link.\nYou can disable send to menu item in Telegram settings."); } -void psWriteDump() { -#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS - PROCESS_MEMORY_COUNTERS data = { 0 }; - if (Dlls::GetProcessMemoryInfo - && Dlls::GetProcessMemoryInfo( - GetCurrentProcess(), - &data, - sizeof(data))) { - const auto mb = 1024 * 1024; - CrashReports::dump() - << "Memory-usage: " - << (data.PeakWorkingSetSize / mb) - << " MB (peak), " - << (data.WorkingSetSize / mb) - << " MB (current)\n"; - CrashReports::dump() - << "Pagefile-usage: " - << (data.PeakPagefileUsage / mb) - << " MB (peak), " - << (data.PagefileUsage / mb) - << " MB (current)\n"; - } -#endif // DESKTOP_APP_DISABLE_CRASH_REPORTS -} - bool psLaunchMaps(const Data::LocationPoint &point) { return QDesktopServices::openUrl(qsl("bingmaps:?lvl=16&collection=point.%1_%2_Point").arg(point.latAsString()).arg(point.lonAsString())); } diff --git a/Telegram/SourceFiles/platform/win/specific_win.h b/Telegram/SourceFiles/platform/win/specific_win.h index bd3d234e6..d35c3fcf3 100644 --- a/Telegram/SourceFiles/platform/win/specific_win.h +++ b/Telegram/SourceFiles/platform/win/specific_win.h @@ -47,8 +47,6 @@ inline void finish() { inline void psCheckLocalSocket(const QString &) { } -void psWriteDump(); - void psActivateProcess(uint64 pid = 0); QString psAppDataPath(); QString psAppDataPathOld();