[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [kcmutils] src: KCMultiDialog: Fix crash when clicking OK
From:       Aurélien Gâteau <agateau () kde ! org>
Date:       2014-06-13 7:41:43
Message-ID: E1WvM7L-0002bv-Gz () scm ! kde ! org
[Download RAW message or body]

Git commit cc99fac3af737619ea220ccb7059f0d8f0623efa by Aurélien Gâteau.
Committed on 10/06/2014 at 14:40.
Pushed by gateau into branch 'master'.

KCMultiDialog: Fix crash when clicking OK

When one closes KCMultiDialog with OK, QDialog::finished() can be emitted
before the clicked() signal of the OK button. This causes the following
sequence to happen:

- KCMultiDialogPrivate::_k_dialogClosed
  * deletes the KCModule
    - KCModuleProxyPrivate::_k_moduleDestroyed
      * sets kcm to 0

- KCMultiDialog::slotOkClicked
  - KCMultiDialogPrivate::apply
    - KCModuleProxy::save
      - KCModuleProxyPrivate::realModule
        * notices kcm is 0, so recreates it
        * calls kcm->save()
          - KWinDesktopConfig::save()
            * crashes because it expects kcm->load() to have been called

To avoid this, trigger the cleanup code in closeEvent() rather than when
finished() is emitted, as we can be sure closeEvent() is always called
*after* the methods connected to the button box signals has executed.

REVIEW: 118639
BUG: 334624

M  +15   -15   src/kcmultidialog.cpp
M  +2    -1    src/kcmultidialog.h

http://commits.kde.org/kcmutils/cc99fac3af737619ea220ccb7059f0d8f0623efa

diff --git a/src/kcmultidialog.cpp b/src/kcmultidialog.cpp
index 478c25a..5be7595 100644
--- a/src/kcmultidialog.cpp
+++ b/src/kcmultidialog.cpp
@@ -199,20 +199,6 @@ void KCMultiDialogPrivate::_k_updateHeader(bool use, const QString &message)
     }
 }
 
-void KCMultiDialogPrivate::_k_dialogClosed()
-{
-    // qDebug() ;
-
-    /**
-     * If we don't delete them, the DBUS registration stays, and trying to load the KCMs
-     * in other situations will lead to "module already loaded in Foo," while to the user
-     * doesn't appear so(the dialog is hidden)
-     */
-    for (int i = 0; i < modules.count(); ++i) {
-        modules[ i ].kcm->deleteClient();
-    }
-}
-
 void KCMultiDialogPrivate::init()
 {
     Q_Q(KCMultiDialog);
@@ -238,7 +224,6 @@ void KCMultiDialogPrivate::init()
 
     q->setButtonBox(buttonBox);
 
-    q->connect(q, SIGNAL(finished(int)), SLOT(_k_dialogClosed()));
     q->connect(q, SIGNAL(currentPageChanged(KPageWidgetItem*,KPageWidgetItem*)),
                SLOT(_k_slotCurrentPageChanged(KPageWidgetItem*,KPageWidgetItem*)));
 
@@ -388,6 +373,21 @@ void KCMultiDialog::slotHelpClicked()
     }
 }
 
+void KCMultiDialog::closeEvent(QCloseEvent *event)
+{
+    Q_D(KCMultiDialog);
+    KPageDialog::closeEvent(event);
+
+    /**
+     * If we don't delete them, the DBUS registration stays, and trying to load the KCMs
+     * in other situations will lead to "module already loaded in Foo," while to the user
+     * doesn't appear so(the dialog is hidden)
+     */
+    Q_FOREACH(auto &proxy, d->modules) {
+        proxy.kcm->deleteClient();
+    }
+}
+
 KPageWidgetItem *KCMultiDialog::addModule(const QString &path, const QStringList &args)
 {
     QString complete = path;
diff --git a/src/kcmultidialog.h b/src/kcmultidialog.h
index 72e45a5..78b1625 100644
--- a/src/kcmultidialog.h
+++ b/src/kcmultidialog.h
@@ -126,6 +126,8 @@ protected:
 
     KCMultiDialogPrivate *const d_ptr;
 
+    void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE;
+
 protected Q_SLOTS:
     /**
      * This slot is called when the user presses the "Default" Button.
@@ -174,7 +176,6 @@ protected Q_SLOTS:
 private:
     Q_PRIVATE_SLOT(d_func(), void _k_slotCurrentPageChanged(KPageWidgetItem *, KPageWidgetItem *))
     Q_PRIVATE_SLOT(d_func(), void _k_clientChanged())
-    Q_PRIVATE_SLOT(d_func(), void _k_dialogClosed())
     Q_PRIVATE_SLOT(d_func(), void _k_updateHeader(bool use, const QString &message))
 };
 
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic