Commit 210c9d88 authored by Harald Sitter's avatar Harald Sitter 🏳🌈
Browse files

disable bug report when there are signs of an update

Summary:
this actually improves UX more than anything. when there was an update it
is fairly impossible to install debug symbols, so drkonqi may get stuck in
a loop between saying this crash is garbage and suggesting the user install
some more symbols. what's more is that the crash can be the result
of incompatibilities in runtime-loaded plugins (a notorious example are
KIO slaves, which get forked from klauncher which I think can lead
to problems when loading the newer libQt5Core.so etc.).

all in all crashes coming from a half-update runtime are hard to trace
and also at risk of being worthless. so, instead disable the report and
the install symbols features and inform the user about what
went wrong in both cases.

this is pretty much exclusively working for linux where the kernel will
actually add " (deleted)" hints to all symlinks in procfs and have a
map_files directory where all mmap'd regions are symlinked to their
respective paths... also with that suffix as needed.

the way it works is super easy: iter all map_files, get all deleted paths,
make sure none of the .so or the executable itself are marked deleted.
if anything is marked deleted, the report feature gets disabled

Test Plan: update dolphin -> attach drkonqi -> drkonqi whines about dolphin being updated

Reviewers: #plasma, apol

Reviewed By: apol

Subscribers: apol, plasma-devel

Tags: #plasma

Differential Revision: https://phabricator.kde.org/D25002
parent 5599273f
......@@ -76,6 +76,12 @@ BacktraceWidget::BacktraceWidget(BacktraceGenerator *generator, QWidget *parent,
"install the missing debug symbols packages.")));
ui.m_installDebugButton->setVisible(false);
connect(ui.m_installDebugButton, &QPushButton::clicked, this, &BacktraceWidget::installDebugPackages);
if (DrKonqi::crashedApplication()->hasDeletedFiles()) {
ui.m_installDebugButton->setEnabled(false);
ui.m_installDebugButton->setToolTip(i18nc("@info:tooltip",
"Symbol installation is unavailable because the application "
"was updated or uninstalled after it had been started."));
}
KGuiItem::assign(ui.m_copyButton, KGuiItem2(QString(), QIcon::fromTheme(QStringLiteral("edit-copy")),
i18nc("@info:tooltip", "Use this button to copy the "
......
......@@ -146,6 +146,11 @@ const QDateTime& CrashedApplication::datetime() const
return m_datetime;
}
bool CrashedApplication::hasDeletedFiles() const
{
return m_hasDeletedFiles;
}
void CrashedApplication::restart()
{
if (m_restarted) {
......
......@@ -66,6 +66,9 @@ public:
const QDateTime& datetime() const;
/** @returns whether mmap'd files have been deleted, e.g. updated since start of app */
bool hasDeletedFiles() const;
public Q_SLOTS:
void restart();
......@@ -86,6 +89,7 @@ protected:
bool m_restarted;
int m_thread;
QDateTime m_datetime;
bool m_hasDeletedFiles;
};
QString getSuggestedKCrashFilename(const CrashedApplication* app);
......
......@@ -23,6 +23,7 @@
#include <QTimer>
#include <QDir>
#include <QRegularExpression>
#include <KConfig>
#include <KConfigGroup>
......@@ -125,16 +126,52 @@ CrashedApplication *KCrashBackend::constructCrashedApplication()
a->m_thread = DrKonqi::thread();
//try to determine the executable that crashed
if ( QFileInfo(QStringLiteral("/proc/%1/exe").arg(a->m_pid)).exists() ) {
const QString procPath(QStringLiteral("/proc/%1").arg(a->m_pid));
const QString exeProcPath(procPath + QStringLiteral("/exe"));
if (QFileInfo(exeProcPath).exists()) {
//on linux, the fastest and most reliable way is to get the path from /proc
qCDebug(DRKONQI_LOG) << "Using /proc to determine executable path";
a->m_executable.setFile(QFile::symLinkTarget(QStringLiteral("/proc/%1/exe").arg(a->m_pid)));
const QString exePath = QFile::symLinkTarget(exeProcPath);
a->m_executable.setFile(exePath);
if (DrKonqi::isKdeinit() ||
a->m_executable.fileName().startsWith(QLatin1String("python")) ) {
a->m_fakeBaseName = DrKonqi::appName();
}
QDir mapFilesDir(procPath + QStringLiteral("/map_files"));
mapFilesDir.setFilter(mapFilesDir.filter() | QDir::System); // proc is system!
// "/bin/foo (deleted)" is how the kernel tells us that a file has been deleted since
// it was mmap'd.
QRegularExpression expression(QStringLiteral("(?<path>.+) \\(deleted\\)$"));
// For the map_files we filter only .so files to ensure that
// we don't trip over cache files or the like, as a result we
// manually need to check if the main exe was deleted and add
// it.
// NB: includes .so* and .py* since we also implicitly support snakes to
// a degree
QRegularExpression soExpression(QStringLiteral("(?<path>.+\\.(so|py)([^/]*)) \\(deleted\\)$"));
bool hasDeletedFiles = false;
const auto exeMatch = expression.match(exePath);
if (exeMatch.isValid() && exeMatch.hasMatch()) {
hasDeletedFiles = true;
}
const auto list = mapFilesDir.entryInfoList();
for (auto it = list.constBegin(); !hasDeletedFiles && it != list.constEnd(); ++it) {
const auto match = soExpression.match(it->symLinkTarget());
if (!match.isValid() || !match.hasMatch()) {
continue;
}
hasDeletedFiles = true;
}
a->m_hasDeletedFiles = hasDeletedFiles;
qCDebug(DRKONQI_LOG) << "exe" << exePath << "has deleted files:" << hasDeletedFiles;
} else {
if ( DrKonqi::isKdeinit() ) {
a->m_executable = QFileInfo(QStandardPaths::findExecutable(QStringLiteral("kdeinit5")));
......
......@@ -128,6 +128,14 @@ void DrKonqiDialog::buildIntroWidget()
"(including the backtrace from the "
"<interface>Developer Information</interface> "
"tab.)</para>", crashedApp->bugReportAddress());
} else if (crashedApp->hasDeletedFiles()) {
reportMessage = xi18nc("@info", "<para>The reporting assistant is disabled because "
"the crashed application appears to have been updated or "
"uninstalled since it had been started. This prevents accurate "
"crash reporting and can also be the cause of this crash.</para>"
"<para>After updating it is always a good idea to log out and back "
"in to make sure the update is fully applied and will not cause "
"any side effects.</para>");
} else {
reportMessage = xi18nc("@info", "<para>You can help us improve KDE Software by reporting "
"this error.<nl /><link url='%1'>Learn "
......@@ -209,7 +217,7 @@ void DrKonqiDialog::buildDialogButtons()
reportButton->setEnabled(!crashedApp->bugReportAddress().isEmpty() &&
crashedApp->fakeExecutableBaseName() != QLatin1String("drkonqi") &&
!DrKonqi::isSafer());
!DrKonqi::isSafer() && !crashedApp->hasDeletedFiles());
connect(reportButton, &QPushButton::clicked, this, &DrKonqiDialog::startBugReportAssistant);
//Restart application button
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment