iOS Simulator: Fix crash when starting app while another is running

Qt Creator would crash when starting an app in the Simulator while
another app is running, and the old app is not killed by the deployment
before run. This could happen in two cases:

1. Running an app in one simulator device and starting that or another
   app on a different simulator device
2. Running an app in the simulator and starting that or another app on
   the same device without deployment

In the first case, it actually doesn't make sense to stop the running
app, the Simulator can run multiple devices simultaneously (this might
have been different in the past).

In the second case, the new IosRunner initiated a stop of the old
RunConfig, and while that was in Stopping state, the app output window
tried to re-use the old tab and deleted the old RunConfig. This lead to
an assert in the RunConfigPrivate destructor, which only expects to be
deleted when in Initialized or Stopped state, and eventually to the
crash. The app output window should not reuse tabs that are not
"Stopped".

Fixes: QTCREATORBUG-30666
Change-Id: If46904dd487301e465e89ce7946be375ab4bdee8
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
This commit is contained in:
Eike Ziller
2024-04-11 11:16:16 +02:00
parent fa29657881
commit cf7933a980
2 changed files with 23 additions and 12 deletions

View File

@@ -60,18 +60,29 @@ using namespace Tasking;
namespace Ios::Internal { namespace Ios::Internal {
static QString identifierForRunControl(RunControl *runControl)
{
const IosDeviceTypeAspect::Data *data = runControl->aspect<IosDeviceTypeAspect>();
return data ? data->deviceType.identifier : QString();
}
static void stopRunningRunControl(RunControl *runControl) static void stopRunningRunControl(RunControl *runControl)
{ {
static QMap<Id, QPointer<RunControl>> activeRunControls; static QMap<Id, QPointer<RunControl>> activeRunControls;
// clean up deleted
Utils::erase(activeRunControls, [](const QPointer<RunControl> &rc) { return !rc; });
Target *target = runControl->target(); Target *target = runControl->target();
Id devId = DeviceKitAspect::deviceId(target->kit()); const Id devId = DeviceKitAspect::deviceId(target->kit());
const QString identifier = identifierForRunControl(runControl);
// The device can only run an application at a time, if an app is running stop it. // The device can only run an application at a time, if an app is running stop it.
if (activeRunControls.contains(devId)) { if (QPointer<RunControl> activeRunControl = activeRunControls[devId]) {
if (QPointer<RunControl> activeRunControl = activeRunControls[devId]) if (identifierForRunControl(activeRunControl) == identifier) {
activeRunControl->initiateStop(); activeRunControl->initiateStop();
activeRunControls.remove(devId); activeRunControls.remove(devId);
}
} }
if (devId.isValid()) if (devId.isValid())

View File

@@ -391,14 +391,14 @@ void AppOutputPane::createNewOutputWindow(RunControl *rc)
const CommandLine thisCommand = rc->commandLine(); const CommandLine thisCommand = rc->commandLine();
const FilePath thisWorkingDirectory = rc->workingDirectory(); const FilePath thisWorkingDirectory = rc->workingDirectory();
const Environment thisEnvironment = rc->environment(); const Environment thisEnvironment = rc->environment();
const auto tab = std::find_if(m_runControlTabs.begin(), m_runControlTabs.end(), const auto tab = std::find_if(
[&](const RunControlTab &tab) { m_runControlTabs.begin(), m_runControlTabs.end(), [&](const RunControlTab &tab) {
if (!tab.runControl || tab.runControl->isRunning() || tab.runControl->isStarting()) if (!tab.runControl || !tab.runControl->isStopped())
return false; return false;
return thisCommand == tab.runControl->commandLine() return thisCommand == tab.runControl->commandLine()
&& thisWorkingDirectory == tab.runControl->workingDirectory() && thisWorkingDirectory == tab.runControl->workingDirectory()
&& thisEnvironment == tab.runControl->environment(); && thisEnvironment == tab.runControl->environment();
}); });
if (tab != m_runControlTabs.end()) { if (tab != m_runControlTabs.end()) {
// Reuse this tab // Reuse this tab
if (tab->runControl) if (tab->runControl)