diff options
author | Aron Budea <aron.budea@collabora.com> | 2017-04-03 02:21:28 +0200 |
---|---|---|
committer | Aron Budea <aron.budea@collabora.com> | 2017-04-05 18:06:52 +0000 |
commit | 9fcb6cb86893b991ceb6395fbabba63c962f59db (patch) | |
tree | ebca63dc2945b5908609a91ede938a88a43c263f | |
parent | 137ad218db262fb3531215adbc88b7093b4999c7 (diff) |
tdf#104686: do not crash if Menu has been somehow disposed
The rare crashes in MenuFloatingWindow::ImplGetStartY() and
MenuFloatingWindow::ImplScroll(bool) likely happen because
of a disposed Menu.
Let's guard against invalid accesses.
Change-Id: Ie31240abbc48c06edd40d0a95f319725cdb3db16
Reviewed-on: https://gerrit.libreoffice.org/36026
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Michael Meeks <michael.meeks@collabora.com>
Reviewed-on: https://gerrit.libreoffice.org/36151
Reviewed-by: Aron Budea <aron.budea@collabora.com>
-rw-r--r-- | include/vcl/menu.hxx | 4 | ||||
-rw-r--r-- | vcl/source/window/menu.cxx | 4 | ||||
-rw-r--r-- | vcl/source/window/menufloatingwindow.cxx | 74 | ||||
-rw-r--r-- | vcl/source/window/menuitemlist.cxx | 7 | ||||
-rw-r--r-- | vcl/source/window/menuitemlist.hxx | 1 |
5 files changed, 58 insertions, 32 deletions
diff --git a/include/vcl/menu.hxx b/include/vcl/menu.hxx index 3c132cc32e07..1c2e82a69683 100644 --- a/include/vcl/menu.hxx +++ b/include/vcl/menu.hxx @@ -133,7 +133,7 @@ class VCL_DLLPUBLIC Menu : public Resource, public VclReferenceBase friend struct ImplMenuDelData; private: ImplMenuDelData* mpFirstDel; - MenuItemList* pItemList; // Liste mit den MenuItems + std::unique_ptr<MenuItemList> pItemList; // list with MenuItems MenuLogo* pLogo; VclPtr<Menu> pStartedFrom; VclPtr<vcl::Window> pWindow; @@ -359,7 +359,7 @@ public: // Fuer Menu-'Funktionen' MenuItemList* GetItemList() const { - return pItemList; + return pItemList.get(); } // returns the system's menu handle if native menus are supported diff --git a/vcl/source/window/menu.cxx b/vcl/source/window/menu.cxx index b327f3d10e7e..012131f33962 100644 --- a/vcl/source/window/menu.cxx +++ b/vcl/source/window/menu.cxx @@ -175,9 +175,11 @@ void Menu::dispose() bKilled = true; - delete pItemList; + pItemList->Clear(); delete pLogo; + pLogo = nullptr; delete mpLayoutData; + mpLayoutData = nullptr; // Native-support: destroy SalMenu ImplSetSalMenu( nullptr ); diff --git a/vcl/source/window/menufloatingwindow.cxx b/vcl/source/window/menufloatingwindow.cxx index 366aeed1ad1d..6bf2fde56e3e 100644 --- a/vcl/source/window/menufloatingwindow.cxx +++ b/vcl/source/window/menufloatingwindow.cxx @@ -152,6 +152,12 @@ long MenuFloatingWindow::ImplGetStartY() const long nY = 0; if( pMenu ) { + // avoid crash if somehow menu got disposed, and MenuItemList is empty (workaround for tdf#104686) + if ( nFirstEntry > 0 && !pMenu->GetItemList()->GetDataFromPos(nFirstEntry - 1) ) + { + return 0; + } + for ( sal_uInt16 n = 0; n < nFirstEntry; n++ ) nY += pMenu->GetItemList()->GetDataFromPos( n )->aSz.Height(); nY -= pMenu->GetTitleHeight(); @@ -606,45 +612,55 @@ void MenuFloatingWindow::ImplScroll( bool bUp ) nFirstEntry = pMenu->ImplGetPrevVisible( nFirstEntry ); SAL_WARN_IF( nFirstEntry == ITEMPOS_INVALID, "vcl", "Scroll?!" ); - long nScrollEntryHeight = pMenu->GetItemList()->GetDataFromPos( nFirstEntry )->aSz.Height(); - - if ( !bScrollDown ) + // avoid crash if somehow menu got disposed, and MenuItemList is empty (workaround for tdf#104686) + const auto pItemData = pMenu->GetItemList()->GetDataFromPos( nFirstEntry ); + if ( pItemData ) { - bScrollDown = true; - Invalidate(); - } + long nScrollEntryHeight = pItemData->aSz.Height(); - if ( pMenu->ImplGetPrevVisible( nFirstEntry ) == ITEMPOS_INVALID ) - { - bScrollUp = false; - Invalidate(); - } + if ( !bScrollDown ) + { + bScrollDown = true; + Invalidate(); + } + + if ( pMenu->ImplGetPrevVisible( nFirstEntry ) == ITEMPOS_INVALID ) + { + bScrollUp = false; + Invalidate(); + } - Scroll( 0, nScrollEntryHeight, ImplCalcClipRegion( false ).GetBoundRect(), ScrollFlags::Clip ); + Scroll( 0, nScrollEntryHeight, ImplCalcClipRegion( false ).GetBoundRect(), ScrollFlags::Clip ); + } } else if ( bScrollDown && !bUp ) { - long nScrollEntryHeight = pMenu->GetItemList()->GetDataFromPos( nFirstEntry )->aSz.Height(); + // avoid crash if somehow menu got disposed, and MenuItemList is empty (workaround for tdf#104686) + const auto pItemData = pMenu->GetItemList()->GetDataFromPos( nFirstEntry ); + if ( pItemData ) + { + long nScrollEntryHeight = pItemData->aSz.Height(); - nFirstEntry = pMenu->ImplGetNextVisible( nFirstEntry ); - SAL_WARN_IF( nFirstEntry == ITEMPOS_INVALID, "vcl", "Scroll?!" ); + nFirstEntry = pMenu->ImplGetNextVisible( nFirstEntry ); + SAL_WARN_IF( nFirstEntry == ITEMPOS_INVALID, "vcl", "Scroll?!" ); - if ( !bScrollUp ) - { - bScrollUp = true; - Invalidate(); - } + if ( !bScrollUp ) + { + bScrollUp = true; + Invalidate(); + } - long nHeight = GetOutputSizePixel().Height(); - sal_uInt16 nLastVisible; - static_cast<PopupMenu*>(pMenu.get())->ImplCalcVisEntries( nHeight, nFirstEntry, &nLastVisible ); - if ( pMenu->ImplGetNextVisible( nLastVisible ) == ITEMPOS_INVALID ) - { - bScrollDown = false; - Invalidate(); - } + long nHeight = GetOutputSizePixel().Height(); + sal_uInt16 nLastVisible; + static_cast<PopupMenu*>(pMenu.get())->ImplCalcVisEntries( nHeight, nFirstEntry, &nLastVisible ); + if ( pMenu->ImplGetNextVisible( nLastVisible ) == ITEMPOS_INVALID ) + { + bScrollDown = false; + Invalidate(); + } - Scroll( 0, -nScrollEntryHeight, ImplCalcClipRegion( false ).GetBoundRect(), ScrollFlags::Clip ); + Scroll( 0, -nScrollEntryHeight, ImplCalcClipRegion( false ).GetBoundRect(), ScrollFlags::Clip ); + } } Invalidate(); diff --git a/vcl/source/window/menuitemlist.cxx b/vcl/source/window/menuitemlist.cxx index 44757a4778ba..30bd874d9763 100644 --- a/vcl/source/window/menuitemlist.cxx +++ b/vcl/source/window/menuitemlist.cxx @@ -135,6 +135,13 @@ void MenuItemList::Remove( size_t nPos ) } } +void MenuItemList::Clear() +{ + for (MenuItemData* i : maItemList) + delete i; + maItemList.resize(0); +} + MenuItemData* MenuItemList::GetData( sal_uInt16 nSVId, size_t& rPos ) const { for( size_t i = 0, n = maItemList.size(); i < n; ++i ) diff --git a/vcl/source/window/menuitemlist.hxx b/vcl/source/window/menuitemlist.hxx index 89befc106e28..556a5a049597 100644 --- a/vcl/source/window/menuitemlist.hxx +++ b/vcl/source/window/menuitemlist.hxx @@ -116,6 +116,7 @@ public: ); void InsertSeparator(const OString &rIdent, size_t nPos); void Remove( size_t nPos ); + void Clear(); MenuItemData* GetData( sal_uInt16 nSVId, size_t& rPos ) const; MenuItemData* GetData( sal_uInt16 nSVId ) const |