Skip to content

Commit f1287f0

Browse files
Merge pull request livecode#6926 from runrevmark/bugfix-21787
[[ Bug 21787 ]] Fix memory leak when implicitly deleting substacks
2 parents 3dd9687 + 9557c21 commit f1287f0

File tree

3 files changed

+35
-3
lines changed

3 files changed

+35
-3
lines changed

docs/notes/bugfix-21787.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Fix memory leak which occurs when substacks are deleted implicitly

engine/src/dispatch.cpp

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -367,14 +367,32 @@ void MCDispatch::removestack(MCStack *sptr)
367367

368368
void MCDispatch::destroystack(MCStack *sptr, Boolean needremove)
369369
{
370+
/* Make sure no messages are sent when destroying the given stack as this
371+
* destruction method is only ever used for stacks which are not-yet-alive
372+
* (e.g. failed to deserialize) or in restricted contexts (e.g. licensing
373+
* dialog on startup). */
374+
Boolean oldstate = MClockmessages;
375+
MClockmessages = True;
376+
370377
if (needremove)
371378
{
372379
MCStack *t_substacks = sptr -> getsubstacks();
373-
while (t_substacks)
380+
while(t_substacks != nullptr)
374381
{
382+
/* The MCStack::dodel() method removes the stack from its mainstack
383+
* so we must explicitly delete it explicitly. Note that there is
384+
* no need to scheduledelete() in this case as destroystack() is
385+
* only called when it is known that no script is running from the
386+
* stack. */
375387
t_substacks -> dodel();
388+
delete t_substacks;
389+
390+
/* Refetch the substacks list - the substack we just processed will
391+
* have been removed from it. */
376392
t_substacks = sptr -> getsubstacks();
377393
}
394+
395+
/* Release any references to the mainstack */
378396
sptr -> dodel();
379397
}
380398
if (sptr == MCstaticdefaultstackptr)
@@ -383,9 +401,13 @@ void MCDispatch::destroystack(MCStack *sptr, Boolean needremove)
383401
MCdefaultstackptr = MCstaticdefaultstackptr;
384402
if (MCacptr && MCacptr->getmessagestack() == sptr)
385403
MCacptr->setmessagestack(NULL);
386-
Boolean oldstate = MClockmessages;
387-
MClockmessages = True;
404+
405+
/* Delete the stack explicitly. Note that there is no need to use
406+
* scheduledelete here as destroystack() is only called when it is known
407+
* that no script is running from the stack. */
388408
delete sptr;
409+
410+
/* Restore the previous message lock state. */
389411
MClockmessages = oldstate;
390412
}
391413

engine/src/stack.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1419,8 +1419,17 @@ Boolean MCStack::del(bool p_check_flag)
14191419

14201420
while (substacks)
14211421
{
1422+
/* When a substack is deleted it removes itself from its mainstack,
1423+
* however it isn't actually destroyed - it must be explicitly
1424+
* scheduled for deletion. */
1425+
MCStack *t_substack = substacks;
14221426
if (!substacks -> del(false))
14231427
return False;
1428+
1429+
/* Schedule the substack for deletion - unlike a main stack we don't
1430+
* need to check for it being in the MCtodestroy list as only mainstacks
1431+
* can ever be in that list. */
1432+
t_substack->scheduledelete();
14241433
}
14251434

14261435
return dodel();

0 commit comments

Comments
 (0)