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)
{
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() )

View File

@@ -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__