Skip to content

Commit 2c1a476

Browse files
committed
Guard process signal handlers against double-emit/use-after-move crash
1 parent 071b1d3 commit 2c1a476

4 files changed

Lines changed: 45 additions & 12 deletions

File tree

‎src/cloud/doc/RELEASE_NOTES.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
- Added max body size configuration to http server
66

7+
### Bug Fixes
8+
9+
- Guard process signal handlers against double-emit/use-after-move crash
10+
711
### Submodules
812

913
- range-ai-lib @ v1.0.0

‎src/cloud/src/process_manager.cpp‎

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -282,42 +282,71 @@ QJsonObject ProcessManager::toJson() const
282282

283283
void ProcessManager::onProcessErrorOccurred(QUuid id, QProcess::ProcessError error)
284284
{
285-
this->statistics.recordCounter(this->runningProcesses.value(id)->getProcessInfo().getName() + "Errored",1);
285+
// Qt may emit both errorOccurred and finished for the same process, so the
286+
// entry can already have been moved out of runningProcesses by a sibling slot.
287+
QSharedPointer<Process> process = this->runningProcesses.value(id);
288+
if (process.isNull())
289+
{
290+
RLogger::warning("[%s] Error occured for unknown or already finished process id = \"%s\".\n",
291+
this->settings.getName().toUtf8().constData(),
292+
id.toString(QUuid::WithoutBraces).toUtf8().constData());
293+
return;
294+
}
295+
296+
this->statistics.recordCounter(process->getProcessInfo().getName() + "Errored",1);
286297
RLogger::error("[%s] Error occured id = \"%s\" with error \"%s\".\n",
287298
this->settings.getName().toUtf8().constData(),
288299
id.toString(QUuid::WithoutBraces).toUtf8().constData(),
289300
Process::processErrorToString(error).toUtf8().constData());
290301

291-
this->runningProcesses.value(id);
292-
this->finishedProcesses.insert(id,this->runningProcesses.value(id));
302+
this->finishedProcesses.insert(id,process);
293303
this->runningProcesses.remove(id);
294304

295-
emit this->processCompleted(id,this->finishedProcesses.value(id)->getProcessResult());
305+
emit this->processCompleted(id,process->getProcessResult());
296306
}
297307

298308
void ProcessManager::onProcessFinished(QUuid id, int exitCode, QProcess::ExitStatus exitStatus)
299309
{
300-
this->statistics.recordCounter(this->runningProcesses.value(id)->getProcessInfo().getName() + (exitStatus == QProcess::NormalExit ? "Finished" : "Crashed"),1);
310+
// Qt may emit both errorOccurred and finished for the same process, so the
311+
// entry can already have been moved out of runningProcesses by a sibling slot.
312+
QSharedPointer<Process> process = this->runningProcesses.value(id);
313+
if (process.isNull())
314+
{
315+
RLogger::warning("[%s] Finished signal for unknown or already finished process id = \"%s\".\n",
316+
this->settings.getName().toUtf8().constData(),
317+
id.toString(QUuid::WithoutBraces).toUtf8().constData());
318+
return;
319+
}
320+
321+
this->statistics.recordCounter(process->getProcessInfo().getName() + (exitStatus == QProcess::NormalExit ? "Finished" : "Crashed"),1);
301322
RLogger::info("[%s] Finished id = \"%s\" with exit code \"%d\" and exit status \"%s\".\n",
302323
this->settings.getName().toUtf8().constData(),
303324
id.toString(QUuid::WithoutBraces).toUtf8().constData(),
304325
exitCode,
305326
exitStatus == QProcess::NormalExit ? "Normal exit" : "Crash exit");
306327

307-
this->runningProcesses.value(id);
308-
this->finishedProcesses.insert(id,this->runningProcesses.value(id));
328+
this->finishedProcesses.insert(id,process);
309329
this->runningProcesses.remove(id);
310330

311-
emit this->processCompleted(id,this->finishedProcesses.value(id)->getProcessResult());
331+
emit this->processCompleted(id,process->getProcessResult());
312332
}
313333

314334
void ProcessManager::onProcessStarted(QUuid id)
315335
{
316-
this->statistics.recordCounter(this->runningProcesses.value(id)->getProcessInfo().getName() + "Started",1);
336+
QSharedPointer<Process> process = this->runningProcesses.value(id);
337+
if (process.isNull())
338+
{
339+
RLogger::warning("[%s] Started signal for unknown process id = \"%s\".\n",
340+
this->settings.getName().toUtf8().constData(),
341+
id.toString(QUuid::WithoutBraces).toUtf8().constData());
342+
return;
343+
}
344+
345+
this->statistics.recordCounter(process->getProcessInfo().getName() + "Started",1);
317346
RLogger::info("[%s] Started id = \"%s\" command = \"%s\".\n",
318347
this->settings.getName().toUtf8().constData(),
319348
id.toString(QUuid::WithoutBraces).toUtf8().constData(),
320-
this->runningProcesses.value(id)->getProcessInfo().buildCommand().toUtf8().constData());
349+
process->getProcessInfo().buildCommand().toUtf8().constData());
321350
}
322351

323352
void ProcessManager::onProcessStateChanged(QUuid id, QProcess::ProcessState newState)

0 commit comments

Comments
 (0)