From b02b0f104a1251064885b23a937cdd627c372924 Mon Sep 17 00:00:00 2001 From: Robert Griebl Date: Tue, 7 Feb 2023 17:49:57 +0100 Subject: Fix race condition when un-installing running apps It is very unlikely, but there is a race condition between the installer thread and the main thread regarding the life time of the Application object that is currently being uninstalled. We have a clear backtrace from a production system pointing to this error, but we cannot reproduce this problem in an unit test. Change-Id: I290582f270455c64e8653813c5e9d47c294f60e1 Reviewed-by: Dominik Holland (cherry picked from commit 3d36fe9fbdd18f635de8c3f01b3067d37e3014d7) Reviewed-by: Qt Cherry-pick Bot --- src/manager-lib/applicationmanager.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/manager-lib/applicationmanager.cpp b/src/manager-lib/applicationmanager.cpp index 2b345f57..cd75d81b 100644 --- a/src/manager-lib/applicationmanager.cpp +++ b/src/manager-lib/applicationmanager.cpp @@ -604,7 +604,7 @@ bool ApplicationManager::startApplicationInternal(const QString &appId, const QS if (d->shuttingDown) throw Exception("Cannot start applications during shutdown"); - Application *app = fromId(appId); + QPointer app = fromId(appId); if (!app) throw Exception("Cannot start application: id '%1' is not known").arg(appId); if (app->isBlocked()) @@ -795,10 +795,14 @@ bool ApplicationManager::startApplicationInternal(const QString &appId, const QS return false; } - connect(runtime, &AbstractRuntime::stateChanged, this, [this, app](Am::RunState newRuntimeState) { - app->setRunState(newRuntimeState); - emit applicationRunStateChanged(app->id(), newRuntimeState); - emitDataChanged(app, QVector { IsRunning, IsStartingUp, IsShuttingDown }); + // if an app is stopped because of a removal and the container is slow to stop, we might + // end up with a dead app pointer in this callback at some point + connect(runtime, &AbstractRuntime::stateChanged, this, [this, app, appId](Am::RunState newRuntimeState) { + if (app) + app->setRunState(newRuntimeState); + emit applicationRunStateChanged(appId, newRuntimeState); + if (app) + emitDataChanged(app, QVector { IsRunning, IsStartingUp, IsShuttingDown }); }); if (!documentUrl.isNull()) @@ -826,8 +830,11 @@ bool ApplicationManager::startApplicationInternal(const QString &appId, const QS // object plus the per-app state. Relying on 2 lambdas is the easier choice for now. auto doStartInContainer = [this, app, attachRuntime, runtime]() -> bool { - bool successfullyStarted = attachRuntime ? runtime->attachApplicationToQuickLauncher(app) - : runtime->start(); + bool successfullyStarted = false; + if (app) { + successfullyStarted = attachRuntime ? runtime->attachApplicationToQuickLauncher(app) + : runtime->start(); + } if (successfullyStarted) emitActivated(app); else -- cgit v1.2.1