sc/source/ui/vba/vbaeventshelper.cxx | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-)
New commits: commit 8cd187c351fe9babbbc5d23a38c5b35b0d523c47 Author: Michael Stahl <mst...@redhat.com> Date: Wed Sep 30 10:31:23 2015 +0200 sc: fix crash in ScVbaEventListener::processWindowResizeEvent() This was crashing in CppunitTest_sc_macros_test on Windows with --enable-mergelibs (release build), because the first invocation of processWindowResizeEvent() deleted the vcl::Window, and the maControllers.count(pWindow) test creates a VclPtr for it, so ends up with a double-free. TODO: is processWindowResizeEvent() supposed to be idempotent? It would be possible to detect that there is already an event posted by checking m_PostedWindows in postWindowResizeEvent(). Change-Id: I7b72f2baf21bb8223e9fe4bd929d826217b920e5 (cherry picked from commit 520514cfe6a99f68b9e1d458fae20026f1a8f66b) Reviewed-on: https://gerrit.libreoffice.org/19022 Reviewed-by: Caolán McNamara <caol...@redhat.com> Tested-by: Caolán McNamara <caol...@redhat.com> diff --git a/sc/source/ui/vba/vbaeventshelper.cxx b/sc/source/ui/vba/vbaeventshelper.cxx index e787031..d92f640 100644 --- a/sc/source/ui/vba/vbaeventshelper.cxx +++ b/sc/source/ui/vba/vbaeventshelper.cxx @@ -169,7 +169,7 @@ private: uno::Reference< frame::XModel > mxModel; ScDocShell* mpDocShell; WindowControllerMap maControllers; /// Maps VCL top windows to their controllers. - std::set< VclPtr<vcl::Window> > maPostedWindows; /// Keeps processWindowResizeEvent windows from being deleted between postWindowResizeEvent and processWindowResizeEvent + std::multiset< VclPtr<vcl::Window> > m_PostedWindows; /// Keeps processWindowResizeEvent windows from being deleted between postWindowResizeEvent and processWindowResizeEvent VclPtr<vcl::Window> mpActiveWindow; /// Currently activated window, to prevent multiple (de)activation. bool mbWindowResized; /// True = window resize system event processed. bool mbBorderChanged; /// True = borders changed system event processed. @@ -471,7 +471,7 @@ void ScVbaEventListener::postWindowResizeEvent( vcl::Window* pWindow ) { mbWindowResized = mbBorderChanged = false; acquire(); // ensure we don't get deleted before the timer fires - maPostedWindows.insert(pWindow); + m_PostedWindows.insert(pWindow); Application::PostUserEvent( LINK( this, ScVbaEventListener, processWindowResizeEvent ), pWindow ); } } @@ -504,7 +504,14 @@ IMPL_LINK( ScVbaEventListener, processWindowResizeEvent, vcl::Window*, pWindow ) } } } - maPostedWindows.erase(pWindow); + { + // note: there may be multiple processWindowResizeEvent outstanding + // for pWindow, so it may have been added to m_PostedWindows multiple + // times - so this must delete exactly one of these elements! + auto const iter(m_PostedWindows.find(pWindow)); + assert(iter != m_PostedWindows.end()); + m_PostedWindows.erase(iter); + } release(); return 0; } commit b61f03fe7f6799e909c3feaf6557f61b63fae67c Author: Caolán McNamara <caol...@redhat.com> Date: Wed Jun 3 10:57:18 2015 +0100 intermittent CppunitTest_sc_macros_test failure void OutputDevice::acquire() const: Assertion `mnRefCnt>0' failed" Window gets destroyed between postWindowResizeEvent and processWindowResizeEvent Change-Id: I3452a23ad8c3b6d863a56b73166520ef103dad1b (cherry picked from commit 5f36b1954438caef95053c2c0b7d0417e1aa5b31) Signed-off-by: Michael Stahl <mst...@redhat.com> diff --git a/sc/source/ui/vba/vbaeventshelper.cxx b/sc/source/ui/vba/vbaeventshelper.cxx index d35e885..e787031 100644 --- a/sc/source/ui/vba/vbaeventshelper.cxx +++ b/sc/source/ui/vba/vbaeventshelper.cxx @@ -169,7 +169,8 @@ private: uno::Reference< frame::XModel > mxModel; ScDocShell* mpDocShell; WindowControllerMap maControllers; /// Maps VCL top windows to their controllers. - VclPtr<vcl::Window> mpActiveWindow; /// Currently activated window, to prevent multiple (de)activation. + std::set< VclPtr<vcl::Window> > maPostedWindows; /// Keeps processWindowResizeEvent windows from being deleted between postWindowResizeEvent and processWindowResizeEvent + VclPtr<vcl::Window> mpActiveWindow; /// Currently activated window, to prevent multiple (de)activation. bool mbWindowResized; /// True = window resize system event processed. bool mbBorderChanged; /// True = borders changed system event processed. bool mbDisposed; @@ -219,7 +220,9 @@ void ScVbaEventListener::startControllerListening( const uno::Reference< frame:: try { xControllerBorder->addBorderResizeListener( this ); } catch( uno::Exception& ) {} if( vcl::Window* pWindow = VCLUnoHelper::GetWindow( xWindow ) ) + { maControllers[ pWindow ] = rxController; + } } void ScVbaEventListener::stopControllerListening( const uno::Reference< frame::XController >& rxController ) @@ -468,6 +471,7 @@ void ScVbaEventListener::postWindowResizeEvent( vcl::Window* pWindow ) { mbWindowResized = mbBorderChanged = false; acquire(); // ensure we don't get deleted before the timer fires + maPostedWindows.insert(pWindow); Application::PostUserEvent( LINK( this, ScVbaEventListener, processWindowResizeEvent ), pWindow ); } } @@ -484,7 +488,7 @@ IMPL_LINK( ScVbaEventListener, processWindowResizeEvent, vcl::Window*, pWindow ) This is handled via the disposing() function which removes the window pointer from the member maControllers. Thus, checking whether maControllers contains pWindow ensures that the window is still alive. */ - if( !mbDisposed && pWindow && (maControllers.count( pWindow ) > 0) ) + if( !mbDisposed && pWindow && !pWindow->IsDisposed() && (maControllers.count(pWindow) > 0) ) { // do not fire event unless all mouse buttons have been released vcl::Window::PointerState aPointerState = pWindow->GetPointerState(); @@ -500,6 +504,7 @@ IMPL_LINK( ScVbaEventListener, processWindowResizeEvent, vcl::Window*, pWindow ) } } } + maPostedWindows.erase(pWindow); release(); return 0; }
_______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits