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
This commit is contained in:
Dimitri Schoolwerth
2014-06-23 19:58:13 +00:00
parent af77028fcf
commit bab52682bc
2 changed files with 32 additions and 0 deletions

View File

@@ -732,6 +732,8 @@ void wxMenuItem::SetItemLabel(const wxString& txt)
void wxMenuItem::DoSetBitmap(const wxBitmap& bmp, bool bChecked) void wxMenuItem::DoSetBitmap(const wxBitmap& bmp, bool bChecked)
{ {
static bool s_insideSetBitmap = false;
if ( bChecked ) if ( bChecked )
{ {
if ( m_bmpChecked.IsSameAs(bmp) ) if ( m_bmpChecked.IsSameAs(bmp) )
@@ -747,6 +749,18 @@ void wxMenuItem::DoSetBitmap(const wxBitmap& bmp, bool bChecked)
m_bmpUnchecked = bmp; 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 #if wxUSE_OWNER_DRAWN
// already marked as owner-drawn, cannot be reverted // already marked as owner-drawn, cannot be reverted
if ( IsOwnerDrawn() ) if ( IsOwnerDrawn() )

View File

@@ -88,6 +88,7 @@ private:
CPPUNIT_TEST( Labels ); CPPUNIT_TEST( Labels );
CPPUNIT_TEST( RadioItems ); CPPUNIT_TEST( RadioItems );
CPPUNIT_TEST( RemoveAdd ); CPPUNIT_TEST( RemoveAdd );
CPPUNIT_TEST( ChangeBitmap );
WXUISIM_TEST( Events ); WXUISIM_TEST( Events );
CPPUNIT_TEST_SUITE_END(); CPPUNIT_TEST_SUITE_END();
@@ -100,6 +101,7 @@ private:
void Labels(); void Labels();
void RadioItems(); void RadioItems();
void RemoveAdd(); void RemoveAdd();
void ChangeBitmap();
void Events(); void Events();
wxFrame* m_frame; wxFrame* m_frame;
@@ -405,6 +407,22 @@ void MenuTestCase::RemoveAdd()
menu0->Delete(item); 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() void MenuTestCase::Events()
{ {
#ifdef __WXGTK__ #ifdef __WXGTK__