From 520514cfe6a99f68b9e1d458fae20026f1a8f66b Mon Sep 17 00:00:00 2001 From: Michael Stahl Date: Wed, 30 Sep 2015 10:31:23 +0200 Subject: 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 --- sc/source/ui/vba/vbaeventshelper.cxx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/sc/source/ui/vba/vbaeventshelper.cxx b/sc/source/ui/vba/vbaeventshelper.cxx index a083c2252dd3..294a6c284fbd 100644 --- a/sc/source/ui/vba/vbaeventshelper.cxx +++ b/sc/source/ui/vba/vbaeventshelper.cxx @@ -170,7 +170,7 @@ private: uno::Reference< frame::XModel > mxModel; ScDocShell* mpDocShell; WindowControllerMap maControllers; /// Maps VCL top windows to their controllers. - std::set< VclPtr > maPostedWindows; /// Keeps processWindowResizeEvent windows from being deleted between postWindowResizeEvent and processWindowResizeEvent + std::multiset< VclPtr > m_PostedWindows; /// Keeps processWindowResizeEvent windows from being deleted between postWindowResizeEvent and processWindowResizeEvent VclPtr 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. @@ -472,7 +472,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 ); } } @@ -506,7 +506,14 @@ IMPL_LINK_TYPED( ScVbaEventListener, processWindowResizeEvent, void*, p, void ) } } } - 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(); } -- cgit