From 1c7adf5addf82bc35784621d4f5b1217220ccfa2 Mon Sep 17 00:00:00 2001 From: Nick Bolton Date: Mon, 10 Feb 2025 17:59:43 +0000 Subject: [PATCH] refactor: Allocate daemon app and it's thread on stack to reduce memory leak risk --- src/apps/deskflow-daemon/deskflow-daemon.cpp | 44 ++++++++++---------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/apps/deskflow-daemon/deskflow-daemon.cpp b/src/apps/deskflow-daemon/deskflow-daemon.cpp index a840cb053..204467d4c 100644 --- a/src/apps/deskflow-daemon/deskflow-daemon.cpp +++ b/src/apps/deskflow-daemon/deskflow-daemon.cpp @@ -44,10 +44,8 @@ int main(int argc, char **argv) LOG((CLOG_PRINT "%s daemon (v%s)", kAppName, kVersion)); - QCoreApplication app(argc, argv); - - const auto pDaemon = &DaemonApp::instance(); - const auto initResult = pDaemon->init(&events, argc, argv); + auto &daemon = DaemonApp::instance(); + const auto initResult = daemon.init(&events, argc, argv); switch (initResult) { using enum DaemonApp::InitResult; @@ -55,41 +53,45 @@ int main(int argc, char **argv) case StartDaemon: { QCoreApplication app(argc, argv); - // Thread must be heap-allocated for deferred deletion on thread exit. - // Avoid setting Qt ownership to prevent premature deletion (thread may run longer than Qt loop). - auto *pDaemonThread = new QThread(); // NOSONAR - Qt memory - pDaemon->moveToThread(pDaemonThread); + QThread daemonThread; + daemon.moveToThread(&daemonThread); - QObject::connect(pDaemonThread, &QThread::started, pDaemon, &DaemonApp::run); - QObject::connect(pDaemonThread, &QThread::finished, pDaemon, &QObject::deleteLater); - QObject::connect(pDaemonThread, &QThread::finished, pDaemonThread, &QThread::deleteLater); - QObject::connect(pDaemonThread, &QThread::finished, QCoreApplication::instance(), &QCoreApplication::quit); + QObject::connect(&daemonThread, &QThread::started, [&daemon, &daemonThread]() { + daemon.run(); + daemonThread.quit(); + }); + QObject::connect(&daemonThread, &QThread::finished, &app, &QCoreApplication::quit); - // The daemon app is on it's own thread which doesn't have a Qt event loop, so we need to use direct connection. - auto *ipcServer = new ipc::DaemonIpcServer(&app, QString::fromStdString(pDaemon->logFilename())); // NOSONAR + ipc::DaemonIpcServer ipcServer(&app, QString::fromStdString(daemon.logFilename())); + + // Use direct connection as the daemon app is on it's own thread, and so is on a different event loop. QObject::connect( - ipcServer, &ipc::DaemonIpcServer::logLevelChanged, pDaemon, &DaemonApp::saveLogLevel, // + &ipcServer, &ipc::DaemonIpcServer::logLevelChanged, &daemon, &DaemonApp::saveLogLevel, // Qt::DirectConnection ); QObject::connect( - ipcServer, &ipc::DaemonIpcServer::elevateModeChanged, pDaemon, &DaemonApp::setElevate, // + &ipcServer, &ipc::DaemonIpcServer::elevateModeChanged, &daemon, &DaemonApp::setElevate, // Qt::DirectConnection ); QObject::connect( - ipcServer, &ipc::DaemonIpcServer::commandChanged, pDaemon, &DaemonApp::setCommand, // + &ipcServer, &ipc::DaemonIpcServer::commandChanged, &daemon, &DaemonApp::setCommand, // Qt::DirectConnection ); QObject::connect( - ipcServer, &ipc::DaemonIpcServer::startProcessRequested, pDaemon, &DaemonApp::applyWatchdogCommand, // + &ipcServer, &ipc::DaemonIpcServer::startProcessRequested, &daemon, &DaemonApp::applyWatchdogCommand, // Qt::DirectConnection ); QObject::connect( - ipcServer, &ipc::DaemonIpcServer::stopProcessRequested, pDaemon, &DaemonApp::clearWatchdogCommand, // + &ipcServer, &ipc::DaemonIpcServer::stopProcessRequested, &daemon, &DaemonApp::clearWatchdogCommand, // Qt::DirectConnection ); - pDaemonThread->start(); - return QCoreApplication::exec(); + daemonThread.start(); + const auto exitCode = QCoreApplication::exec(); + daemonThread.wait(); + + LOG_DEBUG("daemon exited, code: %d", exitCode); + return exitCode; } case FatalError: