From 32403675bf9d2d0380956f9a82da71593edbb53c Mon Sep 17 00:00:00 2001 From: Michael Stahl Date: Fri, 28 Apr 2017 18:54:27 +0200 Subject: tdf#107494 sw: fix crash in SwCallMouseEvent when deleting header The problem is that SwCallMouseEvent::PTR.pFormat is not cleared when the format is destroyed; instead SwDoc::CallEvent() checks via SwFrameFormats::Contains() that the format is still alive, which uses dynamic_cast on the deleted format. (presumably regression from 0f98299f7aa44bbb55c1bfeddca7799f727d14b0) Change-Id: I0d155c162d75b5687b58329a2a862ad57a4eb72e --- sw/inc/swevent.hxx | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/sw/inc/swevent.hxx b/sw/inc/swevent.hxx index ed63b5f80b39..3eb0fb8bfa23 100644 --- a/sw/inc/swevent.hxx +++ b/sw/inc/swevent.hxx @@ -22,6 +22,8 @@ #include #include +#include +#include #define SW_EVENT_OBJECT_SELECT ( EVENT_APP_START + 0 ) #define SW_EVENT_START_INS_GLOSSARY ( EVENT_APP_START + 1 ) @@ -62,6 +64,7 @@ enum SwCallEventObjectType // Structure for the exchange between UI/CORE. struct SwCallMouseEvent + : public SwClient { SwCallEventObjectType eType; union @@ -84,14 +87,21 @@ struct SwCallMouseEvent : eType( EVENT_OBJECT_NONE ) { PTR.pFormat = nullptr; PTR.IMAP.pIMapObj = nullptr; } + SwCallMouseEvent(SwCallMouseEvent const& rOther) + : SwClient(rOther.GetRegisteredInNonConst()) + , eType(rOther.eType) + { + memcpy(&PTR, &rOther.PTR, sizeof(PTR)); + } + void Set( SwCallEventObjectType eTyp, const SwFrameFormat* pFormat ) - { eType = eTyp; PTR.pFormat = pFormat; PTR.IMAP.pIMapObj = nullptr; } + { Clear(); eType = eTyp; PTR.pFormat = pFormat; PTR.IMAP.pIMapObj = nullptr; assert(pFormat); const_cast(pFormat)->Add(this); } void Set( const SwFrameFormat* pFormat, const IMapObject* pIMapObj ) - { eType = EVENT_OBJECT_IMAGEMAP; PTR.pFormat = pFormat; PTR.IMAP.pIMapObj = pIMapObj; } + { Clear(); eType = EVENT_OBJECT_IMAGEMAP; PTR.pFormat = pFormat; PTR.IMAP.pIMapObj = pIMapObj; assert(pFormat); const_cast(pFormat)->Add(this); } void Set( const SwFormatINetFormat* pINetAttr ) - { eType = EVENT_OBJECT_INETATTR; PTR.pINetAttr = pINetAttr; PTR.IMAP.pIMapObj = nullptr; } + { Clear(); eType = EVENT_OBJECT_INETATTR; PTR.pINetAttr = pINetAttr; PTR.IMAP.pIMapObj = nullptr; } bool operator==( const SwCallMouseEvent& rEvent ) const { @@ -103,9 +113,30 @@ struct SwCallMouseEvent { return !( *this == rEvent ); } void Clear() - { eType = EVENT_OBJECT_NONE; PTR.pFormat = nullptr; PTR.IMAP.pIMapObj = nullptr; } + { + if (EVENT_OBJECT_IMAGE == eType || EVENT_OBJECT_URLITEM == eType || EVENT_OBJECT_IMAGEMAP == eType) + { + // note: pFormat is not necessarily the same as + // GetRegisteredIn() here; see ~SwFormat() + assert(PTR.pFormat); + GetRegisteredInNonConst()->Remove(this); + } + eType = EVENT_OBJECT_NONE; PTR.pFormat = nullptr; PTR.IMAP.pIMapObj = nullptr; + } bool HasEvent() const { return EVENT_OBJECT_NONE != eType; } + + virtual void Modify(SfxPoolItem const*const pOldValue, SfxPoolItem const*const pNewValue) override + { + assert(EVENT_OBJECT_IMAGE == eType || EVENT_OBJECT_URLITEM == eType || EVENT_OBJECT_IMAGEMAP == eType); + SwClient::Modify(pOldValue, pNewValue); + if (!GetRegisteredIn() || + (RES_FMT_CHG == pOldValue->Which() + && static_cast(pOldValue)->pChangedFormat == PTR.pFormat)) + { + Clear(); + } + } }; #endif -- cgit v1.2.3