[utilities/krusader] app/UserAction: UserAction: Fix a memory leak

Toni Asensi Esteve <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit be0d1a7bcddf039f72ba839155e309896414e96a by Toni Asensi Esteve.
Committed on 16/08/2026 at 22:14.
Pushed by asensi into branch 'master'.

UserAction: Fix a memory leak

Revision: https://invent.kde.org/utilities/krusader/-/merge_requests/193

M  +18   -0    app/UserAction/kraction.cpp
M  +4    -1    app/UserAction/kraction.h
M  +3    -0    app/UserAction/kractionbase.cpp

https://invent.kde.org/utilities/krusader/-/commit/be0d1a7bcddf039f72ba839155e309896414e96a

diff --git a/app/UserAction/kraction.cpp b/app/UserAction/kraction.cpp
index 13129187f..b2fe09c54 100644
--- a/app/UserAction/kraction.cpp
+++ b/app/UserAction/kraction.cpp
@@ -55,6 +55,12 @@ KrActionProcDlg::KrActionProcDlg(const QString &caption, bool enableStderr, QWid
     , _stderr(nullptr)
     , _currentTextEdit(nullptr)
 {
+    // This dialog is intentionally used as a standalone top-level window rather
+    // than being owned through a QObject parent. Delete it as soon as the user
+    // closes it, any surviving external reference is a QPointer and will be
+    // reset automatically to nullptr
+    setAttribute(Qt::WA_DeleteOnClose);
+
     setWindowTitle(caption);
     setWindowModality(Qt::NonModal);
 
@@ -266,6 +272,10 @@ void KrActionProc::start(QStringList cmdLineList)
             cmd = KrServices::quote(KDESU_PATH) + " -t -u " + _action->user() + " -c " + KrServices::quote(cmd);
         }
         MAIN_VIEW->terminalDock()->sendInput(cmd + '\n');
+        // This KrActionProc object was created on the heap in actionProcFactoryMethod().
+        // When the command is forwarded to the embedded terminal, no external QProcess
+        // is started here, therefore no later finished signal will call processExited()
+        // to destroy this KrActionProc object. Schedule its destruction now
         deleteLater();
     } else { // will start a new process
         _proc = new KProcess(this);
@@ -280,6 +290,9 @@ void KrActionProc::start(QStringList cmdLineList)
                 QStringList termArgs = KShell::splitArgs(term, KShell::TildeExpand);
                 if (termArgs.isEmpty()) {
                     KMessageBox::error(nullptr, i18nc("Arg is a string containing the bad quoting.", "Bad quoting in terminal command:\n%1", term));
+                    // This KrActionProc object was created on the heap in actionProcFactoryMethod().
+                    // Because execution stops here and no later finished signal will call processExited()
+                    // to destroy this KrActionProc object, schedule its destruction now
                     deleteLater();
                     return;
                 }
@@ -300,6 +313,9 @@ void KrActionProc::start(QStringList cmdLineList)
             bool separateStderr = false;
             if (_action->execType() == KrAction::CollectOutputSeparateStderr)
                 separateStderr = true;
+            // Create an unparented top-level output dialog. It deletes itself when it's closed
+            // (after that, `_output` must be checked before using it). `_output` is a QPointer,
+            // so it is reset automatically to nullptr when the dialog is destroyed
             _output = new KrActionProcDlg(_action->text(), separateStderr);
             // connect the output to the dialog
             _proc->setOutputChannelMode(KProcess::SeparateChannels);
@@ -326,6 +342,8 @@ void KrActionProc::processExited(int /*exitCode*/, QProcess::ExitStatus /*exitSt
         // TODO tell the user the program exit code
         _output->slotProcessFinished();
     }
+    // This KrActionProc object was created on the heap in actionProcFactoryMethod().
+    // It is destroyed here after the external process has finished
     delete this; // banzai!!
 }
 
diff --git a/app/UserAction/kraction.h b/app/UserAction/kraction.h
index 1d10185f6..7db9063a4 100644
--- a/app/UserAction/kraction.h
+++ b/app/UserAction/kraction.h
@@ -12,6 +12,7 @@
 
 // QtCore
 #include <QByteArray>
+#include <QPointer>
 #include <QUrl>
 // QtGui
 #include <QFont>
@@ -256,7 +257,9 @@ private:
     KProcess *_proc;
     QString _stdout;
     QString _stderr;
-    KrActionProcDlg *_output;
+    // It's non-owning. It resets to nullptr when
+    // the dialog is destroyed (e.g. on close)
+    QPointer<KrActionProcDlg> _output;
 };
 
 #endif // KRACTION_H
diff --git a/app/UserAction/kractionbase.cpp b/app/UserAction/kractionbase.cpp
index 36539c4f1..6c1351528 100644
--- a/app/UserAction/kractionbase.cpp
+++ b/app/UserAction/kractionbase.cpp
@@ -69,5 +69,8 @@ void KrActionBase::handleError(const Error &err)
 
 KrActionProc *KrActionBase::actionProcFactoryMethod()
 {
+    // Create a KrActionProc object on the heap for this action. The caller
+    // must not delete the returned pointer because the KrActionProc object is
+    // responsible for destroying itself later
     return new KrActionProc(this);
 }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.