From bab52682bc9d4c3acef6dce3933d95d36d7f6b25 Mon Sep 17 00:00:00 2001 From: Dimitri Schoolwerth Date: Mon, 23 Jun 2014 19:58:13 +0000 Subject: [PATCH] Fix wxMenuItem::SetBitmap infinite recursion (Vista+). Calling a menu item's SetBitmap can result in a stack overflow. This occurs when setting a bitmap after the menu item has already been added to the menu and while running under Vista (and later). Under those circumstances [Do]SetBitmap will call GetHBitmapForMenu which itself calls SetBitmap again. Fix by adding a simple check for re-entry. Regression since r76202. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@76754 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- src/msw/menuitem.cpp | 14 ++++++++++++++ tests/menu/menu.cpp | 18 ++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/msw/menuitem.cpp b/src/msw/menuitem.cpp index bbaddbcf68..1704892306 100644 --- a/src/msw/menuitem.cpp +++ b/src/msw/menuitem.cpp @@ -732,6 +732,8 @@ void wxMenuItem::SetItemLabel(const wxString& txt) void wxMenuItem::DoSetBitmap(const wxBitmap& bmp, bool bChecked) { + static bool s_insideSetBitmap = false; + if ( bChecked ) { if ( m_bmpChecked.IsSameAs(bmp) ) @@ -747,6 +749,18 @@ void wxMenuItem::DoSetBitmap(const wxBitmap& bmp, bool bChecked) m_bmpUnchecked = bmp; } + if (s_insideSetBitmap) + { + // We can arrive here because of calling GetHBitmapForMenu + // further down below, which itself can call [Do]SetBitmap + // resulting in infinite recursion. After having set the + // bitmap just return instead. + return; + } + + wxON_BLOCK_EXIT_SET(s_insideSetBitmap, false); + s_insideSetBitmap = true; + #if wxUSE_OWNER_DRAWN // already marked as owner-drawn, cannot be reverted if ( IsOwnerDrawn() ) diff --git a/tests/menu/menu.cpp b/tests/menu/menu.cpp index 2f67765771..0ae436f27f 100644 --- a/tests/menu/menu.cpp +++ b/tests/menu/menu.cpp @@ -88,6 +88,7 @@ private: CPPUNIT_TEST( Labels ); CPPUNIT_TEST( RadioItems ); CPPUNIT_TEST( RemoveAdd ); + CPPUNIT_TEST( ChangeBitmap ); WXUISIM_TEST( Events ); CPPUNIT_TEST_SUITE_END(); @@ -100,6 +101,7 @@ private: void Labels(); void RadioItems(); void RemoveAdd(); + void ChangeBitmap(); void Events(); wxFrame* m_frame; @@ -405,6 +407,22 @@ void MenuTestCase::RemoveAdd() menu0->Delete(item); } +void MenuTestCase::ChangeBitmap() +{ + wxMenu *menu = new wxMenu; + + wxMenuItem *item = new wxMenuItem(menu, wxID_ANY, "Item"); + menu->Append(item); + + // On Windows Vista (and later) calling SetBitmap, *after* the menu + // item has already been added, used to result in a stack overflow: + // [Do]SetBitmap can call GetHBitmapForMenu which will call SetBitmap + // again etc... + item->SetBitmap( wxBitmap(1, 1) ); + + wxDELETE(menu); +} + void MenuTestCase::Events() { #ifdef __WXGTK__