diff options
author | Michael Stahl <mstahl@redhat.com> | 2014-08-17 19:58:41 +0200 |
---|---|---|
committer | Michael Stahl <mstahl@redhat.com> | 2014-08-20 16:40:09 +0200 |
commit | 37ea2c99b9374f956d2a73bf1c085f2b47d53add (patch) | |
tree | b32bd17ae2d6ea307f27cf1e5b0c33ae441583ad | |
parent | 102348fcd17ab4a862d6f15565f97d8a88cd9231 (diff) |
fdo#72695: avoid double-free race condition for SwXFrame
The problem is that Modify() may be called from ~SwFmt while another
thread is waiting on SolarMutex in the ~SwXFrame or derived class
destructor, so the ref-count is 0 and the uno::Reference in Modify()
will cause a double-free.
Since ClientModify() does some re-parenting of listeners, it is at first
glance better to call Modify() in this situation (although it is quite
possible that it actually doesn't matter), so don't avoid the call in
~SwFrmFmt by adding a SwClient* member there, but put a weak reference
to itself into SwXFrame so it can check if it's still alive...
Change-Id: I492bb8a8557af5fc725fdb7f8b21013e0886f63b
-rw-r--r-- | sw/source/core/unocore/unoframe.cxx | 23 |
1 files changed, 16 insertions, 7 deletions
diff --git a/sw/source/core/unocore/unoframe.cxx b/sw/source/core/unocore/unoframe.cxx index 225f52fd67dc..58be8ab33c5f 100644 --- a/sw/source/core/unocore/unoframe.cxx +++ b/sw/source/core/unocore/unoframe.cxx @@ -1111,6 +1111,7 @@ private: ::osl::Mutex m_Mutex; // just for OInterfaceContainerHelper public: + uno::WeakReference<uno::XInterface> m_wThis; ::cppu::OInterfaceContainerHelper m_EventListeners; Impl() : m_EventListeners(m_Mutex) { } @@ -1249,6 +1250,8 @@ SwXFrame::CreateXFrame(SwDoc & rDoc, SwFrmFmt *const pFrmFmt) { pFrmFmt->SetXObject(xFrame); } + // need a permanent Reference to initialize m_wThis + pNew->SwXFrame::m_pImpl->m_wThis = xFrame; } return xFrame; } @@ -2592,17 +2595,23 @@ throw (uno::RuntimeException, std::exception) m_pImpl->m_EventListeners.removeInterface(xListener); } -void SwXFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew) +void SwXFrame::Modify(const SfxPoolItem* pOld, const SfxPoolItem *pNew) { ClientModify(this, pOld, pNew); - if(!GetRegisteredIn()) + if (GetRegisteredIn()) { - mxStyleData.clear(); - mxStyleFamily.clear(); - m_pDoc = 0; - lang::EventObject const ev(static_cast< ::cppu::OWeakObject&>(*this)); - m_pImpl->m_EventListeners.disposeAndClear(ev); + return; // core object still alive } + mxStyleData.clear(); + mxStyleFamily.clear(); + m_pDoc = 0; + uno::Reference<uno::XInterface> const xThis(m_pImpl->m_wThis); + if (!xThis.is()) + { // fdo#72695: if UNO object is already dead, don't revive it with event + return; + } + lang::EventObject const ev(xThis); + m_pImpl->m_EventListeners.disposeAndClear(ev); } void SwXFrame::dispose(void) throw( uno::RuntimeException, std::exception ) |