sw: fix crash when dropdown field dialog outlives its field

In COOL, EditDropDownFieldDlg runs asynchronously while the user can
keep editing the document. If anything destroys or replaces the
underlying SwFormatField (undo, edits, spell-check replacement, ...)
before the user accepts the dialog, the raw SwDropDownField* stored
in the dialog dangles and Apply() crashes in GetPar1().

Listen on the owning SwFormatField and null out the field pointers on
REMOVED/CHANGED/Dying so the existing guard in Apply() turns the click
into a safe no-op.

Change-Id: I7f52a926d3cbea259dc2b3f54618304e4c93db1d
Reviewed-on: https://gerrit.collaboraoffice.com/c/core/+/2858
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Signed-off-by: Andras Timar <andras.timar@collabora.com>
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2972
(cherry picked from commit 3d0366e6726a25ce1dbc65eda5211c8f079dcc22)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/206203
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
This commit is contained in:
Andras Timar
2026-06-08 12:41:15 +02:00
committed by Xisco Fauli
parent 0363353a99
commit 632f432d2f
2 changed files with 36 additions and 1 deletions
@@ -19,6 +19,7 @@
#include <wrtsh.hxx>
#include <fldbas.hxx>
#include <fmtfld.hxx>
#include <DropDownFieldDialog.hxx>
#include <flddropdown.hxx>
@@ -35,6 +36,7 @@ sw::DropDownFieldDialog::DropDownFieldDialog(weld::Widget *pParent, SwWrtShell &
: GenericDialogController(pParent, u"modules/swriter/ui/dropdownfielddialog.ui"_ustr, u"DropdownFieldDialog"_ustr)
, m_rSh( rS )
, m_pDropField(nullptr)
, m_pFormatField(nullptr)
, m_pPressedButton(nullptr)
, m_xListItemsLB(m_xBuilder->weld_tree_view(u"list"_ustr))
, m_xOKPB(m_xBuilder->weld_button(u"ok"_ustr))
@@ -64,6 +66,11 @@ sw::DropDownFieldDialog::DropDownFieldDialog(weld::Widget *pParent, SwWrtShell &
{
m_pDropField = static_cast<SwDropDownField*>(pField);
// Listen on the owning SwFormatField so we can detect if the field is
// removed/replaced while this (async in COOL) dialog is open.
m_pFormatField = pField->GetTyp()->FindFormatForField(pField);
if (m_pFormatField)
StartListening(*m_pFormatField);
OUString sTitle = m_xDialog->get_title() +
m_pDropField->GetPar2();
m_xDialog->set_title(sTitle);
@@ -81,6 +88,30 @@ sw::DropDownFieldDialog::DropDownFieldDialog(weld::Widget *pParent, SwWrtShell &
sw::DropDownFieldDialog::~DropDownFieldDialog()
{
EndListeningAll();
}
void sw::DropDownFieldDialog::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
{
const SfxHintId nId = rHint.GetId();
if (nId == SfxHintId::Dying)
{
EndListening(rBC);
m_pDropField = nullptr;
m_pFormatField = nullptr;
return;
}
if (nId != SfxHintId::SwFormatField)
return;
const SwFormatFieldHint& rFormatHint = static_cast<const SwFormatFieldHint&>(rHint);
const SwFormatFieldHintWhich eWhich = rFormatHint.Which();
if (eWhich == SwFormatFieldHintWhich::REMOVED
|| eWhich == SwFormatFieldHintWhich::CHANGED)
{
EndListening(rBC);
m_pDropField = nullptr;
m_pFormatField = nullptr;
}
}
void sw::DropDownFieldDialog::Apply()
+5 -1
View File
@@ -19,21 +19,24 @@
#pragma once
#include <svl/lstner.hxx>
#include <vcl/weld/Button.hxx>
#include <vcl/weld/DialogController.hxx>
#include <vcl/weld/TreeView.hxx>
class SwDropDownField;
class SwField;
class SwFormatField;
class SwWrtShell;
// Dialog to edit drop down field selection
namespace sw
{
class DropDownFieldDialog final : public weld::GenericDialogController
class DropDownFieldDialog final : public weld::GenericDialogController, public SfxListener
{
SwWrtShell &m_rSh;
SwDropDownField* m_pDropField;
SwFormatField* m_pFormatField;
weld::Button* m_pPressedButton;
std::unique_ptr<weld::TreeView> m_xListItemsLB;
@@ -53,6 +56,7 @@ public:
bool PrevButtonPressed() const;
bool NextButtonPressed() const;
void Apply();
virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override;
virtual short run() override
{
short nRet = GenericDialogController::run();