Skip to content

Commit 0a4b945

Browse files
committed
[[ Bug 21928 ]] Fix memory leak when using menu buttons
This patch fixes a memory leak when using menu buttons caused by failing to delete the internal stack created to enable them to function. The leak came about when object deletion was being abstracted, and the code was being refactored to use object handles. The button's menu pointer was changed to an object handle and the explicit deletion which was there previously removed. As object handles are weak references, this meant that they were never being deleted. The leak has been fixed by ensuring that the dodel() method can be run on menus-as-stacks (which required an extra check in the MCStack::removereferences method) and then additionally adding an explicit delete operator call on the button's menu-as-stack in MCButton::freemenu().
1 parent bbadbd7 commit 0a4b945

File tree

3 files changed

+24
-4
lines changed

3 files changed

+24
-4
lines changed

docs/notes/bugfix-21928.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Fix memory leak when using menu buttons

engine/src/button.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2860,11 +2860,23 @@ void MCButton::freemenu(Boolean force)
28602860
else
28612861
{
28622862
if (!MCStringIsEmpty(menustring) || force)
2863-
{
2864-
closemenu(False, True);
2865-
MCdispatcher->removepanel(menu);
2863+
{
2864+
closemenu(False, True);
2865+
2866+
/* In this case the button owns the menu so after removing
2867+
* any references to it that might exist in the environment
2868+
* it must be explicitly deleted. */
2869+
MCStack *t_menu_ptr = menu.Get();
2870+
MCdispatcher->removepanel(t_menu_ptr);
28662871
MCstacks->deleteaccelerator(this, NULL);
2867-
menu->removeneed(this);
2872+
t_menu_ptr->removeneed(this);
2873+
t_menu_ptr->dodel();
2874+
2875+
/* It is safe to explicitly delete the menu stack here (rather
2876+
* than 'scheduledelete()') as menu stacks and their contents
2877+
* can never be on C stack as they don't contain script. */
2878+
delete t_menu_ptr;
2879+
28682880
menu = nil;
28692881
}
28702882
}

engine/src/stack.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1476,6 +1476,13 @@ void MCStack::removereferences()
14761476
{
14771477
MCdispatcher->remove_transient_stack(this);
14781478
}
1479+
else if (!parent.IsValid() || parent->gettype() == CT_BUTTON)
1480+
{
1481+
/* If the parent is a button or non-existant then this is a
1482+
* menu-as-stack - registered with MCdispatcher as a panel. This code
1483+
* path is hit when performing dodel() on a menu-as-stack before it
1484+
* is explicitly deleted in MCButton::freemenu. */
1485+
}
14791486
else if (parent->gettype() == CT_STACK)
14801487
{
14811488
remove(parent.GetAs<MCStack>()->substacks);

0 commit comments

Comments
 (0)