vcl/source/window/dialog.cxx |   45 +++++++++++++++++++------------------------
 1 file changed, 20 insertions(+), 25 deletions(-)

New commits:
commit d2280c07bfc0887d8784aff04ac5ea20981b17b8
Author:     Noel Grandin <noel.gran...@collabora.co.uk>
AuthorDate: Fri Jan 31 10:45:31 2025 +0200
Commit:     Noel Grandin <noel.gran...@collabora.co.uk>
CommitDate: Fri Jan 31 12:07:35 2025 +0100

    make Dialog destruction a little safer
    
    rather keep the Impl object around for the lifetime of the Dialog
    object.
    
    where I saw a backtrace that looked like
    
    vcl/source/window/dialog.cxx:1098: short Dialog::Execute(): Assertion
    `mpDialogImpl' failed.
     Dialog::Execute()
     SalInstanceDialog::run()
     ScSpellingEngine::ShowFinishDialog()
     ScConversionEngineBase::FindNextConversionCell()
     ScSpellingEngine::SpellNextDocument()
     ScSpellDialogChildWindow::GetNextWrongSentence(bool)
    
    Change-Id: I5858f3cd126185bc4f59932dfa53f6a6a3a66aa6
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/180980
    Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk>
    Tested-by: Jenkins

diff --git a/vcl/source/window/dialog.cxx b/vcl/source/window/dialog.cxx
index ecf2302bfe4d..d407626388d6 100644
--- a/vcl/source/window/dialog.cxx
+++ b/vcl/source/window/dialog.cxx
@@ -373,6 +373,11 @@ struct DialogImpl
 #endif
 
     ~DialogImpl()
+    {
+        disposeAndClear();
+    }
+
+    void disposeAndClear()
     {
         for (VclPtr<PushButton> & pOwnedButton : maOwnedButtons)
             pOwnedButton.disposeAndClear();
@@ -619,7 +624,7 @@ void Dialog::dispose()
 {
     bool bTunnelingEnabled = mpDialogImpl->m_bLOKTunneling;
 
-    mpDialogImpl.reset();
+    mpDialogImpl->disposeAndClear();
     RemoveFromDlgList();
     mpActionArea.clear();
     mpContentArea.clear();
@@ -1095,20 +1100,11 @@ short Dialog::Execute()
         OSL_FAIL( "Dialog::Execute() - Dialog destroyed in Execute()" );
     }
 
-    assert(mpDialogImpl);
 
-    if (mpDialogImpl)
-    {
-        tools::Long nRet = mpDialogImpl->mnResult;
-        mpDialogImpl->mnResult = -1;
+    tools::Long nRet = mpDialogImpl->mnResult;
+    mpDialogImpl->mnResult = -1;
 
-        return static_cast<short>(nRet);
-    }
-    else
-    {
-        SAL_WARN( "vcl", "Dialog::Execute() : missing mpDialogImpl " );
-        return 0;
-    }
+    return static_cast<short>(nRet);
 }
 
 // virtual
@@ -1143,6 +1139,9 @@ void Dialog::EndDialog( tools::Long nResult )
     if (!mbInExecute || isDisposed())
         return;
 
+    // do not let this object be destroyed from underneath us
+    VclPtr<vcl::Window> xWindow = this;
+
     const bool bModal = GetType() != WindowType::MODELESSDIALOG;
 
     Hide();
@@ -1186,8 +1185,7 @@ void Dialog::EndDialog( tools::Long nResult )
     if ( mpDialogImpl->mbStartedModal )
         ImplEndExecuteModal();
 
-    // coverity[check_after_deref] - ImplEndExecuteModal might trigger 
destruction of mpDialogImpl
-    if ( mpDialogImpl && mpDialogImpl->maEndCtx.isSet() )
+    if ( mpDialogImpl->maEndCtx.isSet() )
     {
         // We have a special case with async-dialogs that re-execute 
themselves.
         // In order to prevent overwriting state we need here, we need to 
extract
@@ -1214,26 +1212,23 @@ void Dialog::EndDialog( tools::Long nResult )
 
         // Destroy ourselves, if we have a context with VclPtr owner, and
         // we have not been re-executed.
-        if (!mpDialogImpl || !mpDialogImpl->maEndCtx.isSet())
+        if (!mpDialogImpl->maEndCtx.isSet())
             xOwner.disposeAndClear();
         xOwnerDialogController.reset();
         xOwnerSelf.reset();
     }
     else
     {
-        if ( mpDialogImpl && mpDialogImpl->mbStartedModal )
+        if ( mpDialogImpl->mbStartedModal )
         {
             mpDialogImpl->mbStartedModal = false;
             mpDialogImpl->mnResult = -1;
         }
         mbInExecute = false;
-        if ( mpDialogImpl)
-        {
-            // Destroy ourselves (if we have a context with VclPtr owner)
-            std::shared_ptr<weld::DialogController> xOwnerDialogController = 
std::move(mpDialogImpl->maEndCtx.mxOwnerDialogController);
-            std::shared_ptr<weld::Dialog> xOwnerSelf = 
std::move(mpDialogImpl->maEndCtx.mxOwnerSelf);
-            mpDialogImpl->maEndCtx.mxOwner.disposeAndClear();
-        }
+        // Destroy ourselves (if we have a context with VclPtr owner)
+        std::shared_ptr<weld::DialogController> xOwnerDialogController = 
std::move(mpDialogImpl->maEndCtx.mxOwnerDialogController);
+        std::shared_ptr<weld::Dialog> xOwnerSelf = 
std::move(mpDialogImpl->maEndCtx.mxOwnerSelf);
+        mpDialogImpl->maEndCtx.mxOwner.disposeAndClear();
     }
 }
 
@@ -1666,7 +1661,7 @@ void Dialog::Activate()
 
 void Dialog::Command(const CommandEvent& rCEvt)
 {
-    if (mpDialogImpl && mpDialogImpl->m_aPopupMenuHdl.Call(rCEvt))
+    if (mpDialogImpl->m_aPopupMenuHdl.Call(rCEvt))
         return;
     SystemWindow::Command(rCEvt);
 }

Reply via email to