Skip to content
This repository was archived by the owner on Aug 31, 2021. It is now read-only.

Commit ab5faf0

Browse files
committed
[[ Bug 19032 ]] Uncache object IDs when removing from object tree
This patch recursively removes objects from the parent stack ID cache before unlinking them from the parent during deletion. This ensures that an object is always removed from the correct id cache.
1 parent 3d7c724 commit ab5faf0

File tree

7 files changed

+44
-33
lines changed

7 files changed

+44
-33
lines changed

docs/notes/bugfix-19032.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Prevent crash when creating and deleting two data grids

engine/src/card.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,6 +1158,7 @@ Boolean MCCard::del(bool p_check_flag)
11581158
}
11591159
else
11601160
{
1161+
optr->getref()->uncacheid();
11611162
getstack()->removecontrol(optr->getref());
11621163
}
11631164
MCCdata *dptr = optr->getref()->getdata(obj_id, False);
@@ -1168,6 +1169,8 @@ Boolean MCCard::del(bool p_check_flag)
11681169
while (optr != objptrs);
11691170
}
11701171

1172+
uncacheid();
1173+
11711174
// MCObject now does things on del(), so we must make sure we finish by
11721175
// calling its implementation.
11731176
return MCObject::del(p_check_flag);

engine/src/control.cpp

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -501,25 +501,25 @@ Boolean MCControl::del(bool p_check_flag)
501501
getcard()->count(CT_LAYER, CT_UNDEFINED, this, num, True);
502502
switch (parent->gettype())
503503
{
504-
case CT_CARD:
505-
{
506-
MCCard *cptr = parent.GetAs<MCCard>();
507-
if (!cptr->removecontrol(this, False, True))
504+
case CT_STACK:
505+
uncacheid();
506+
parent.GetAs<MCStack>()->removecontrol(this);
507+
break;
508+
509+
case CT_CARD:
510+
if (!parent.GetAs<MCCard>()->removecontrol(this, False, True))
508511
return False;
512+
uncacheid();
509513
getstack()->removecontrol(this);
510514
break;
511-
}
512-
case CT_GROUP:
513-
{
514-
MCGroup *gptr = parent.GetAs<MCGroup>();
515-
gptr->removecontrol(this, True);
515+
516+
case CT_GROUP:
517+
parent.GetAs<MCGroup>()->removecontrol(this, True);
518+
uncacheid();
516519
break;
517-
}
518-
default:
519-
{ //stack
520-
MCStack *sptr = parent.GetAs<MCStack>();
521-
sptr->removecontrol(this);
522-
}
520+
521+
default:
522+
MCUnreachable();
523523
}
524524

525525
// IM-2012-05-16 [[ BZ 10212 ]] deleting the dragtarget control in response

engine/src/group.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,6 +1031,22 @@ void MCGroup::applyrect(const MCRectangle &nrect)
10311031
}
10321032
}
10331033

1034+
void MCGroup::uncacheid()
1035+
{
1036+
if (controls != NULL)
1037+
{
1038+
MCControl *t_control;
1039+
t_control = controls;
1040+
do
1041+
{ t_control -> uncacheid();
1042+
t_control = t_control -> next();
1043+
}
1044+
while(t_control != controls);
1045+
}
1046+
1047+
MCObject::uncacheid();
1048+
}
1049+
10341050
bool MCGroup::isdeletable(bool p_check_flag)
10351051
{
10361052
if (!parent || scriptdepth != 0 ||

engine/src/group.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ class MCGroup : public MCControl, public MCMixinObjectHandle<MCGroup>
9292
virtual Boolean doubleup(uint2 which);
9393
virtual void applyrect(const MCRectangle &nrect);
9494

95-
95+
virtual void uncacheid(void);
9696
virtual Boolean del(bool p_check_flag);
9797
virtual void recompute();
9898

engine/src/object.cpp

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -317,11 +317,6 @@ MCObject::~MCObject()
317317
MCMemoryDeleteArray(patterns);
318318
deletepropsets();
319319
MCValueRelease(tooltip);
320-
321-
// MW-2012-11-20: [[ IdCache ]] Make sure we delete the object from the cache - not
322-
// all deletions vector through 'scheduledelete'.
323-
if (m_in_id_cache)
324-
getstack() -> uncacheobjectbyid(this);
325320

326321
// If this object is a parent-script make sure we flush it from the table.
327322
if (m_is_parent_script)
@@ -859,6 +854,12 @@ void MCObject::deselect()
859854
state &= ~CS_SELECTED;
860855
}
861856

857+
void MCObject::uncacheid()
858+
{
859+
if (m_in_id_cache)
860+
getstack()->uncacheobjectbyid(this);
861+
}
862+
862863
bool MCObject::isdeletable(bool p_check_flag)
863864
{
864865
if (!parent || scriptdepth != 0 || MCdispatcher -> getmenu() == this || MCmenuobjectptr == this)
@@ -880,18 +881,6 @@ Boolean MCObject::del(bool p_check_flag)
880881
MCParentScript::FlushObject(this);
881882
m_is_parent_script = false;
882883
}
883-
884-
// SN-2015-06-04: [[ Bug 14642 ]] These two blocks have been moved from
885-
// MCObject::scheduledelete, since a deleted object is no longer something
886-
// we want to listen to. In case we undo the deletion, it will be added
887-
// back to the list of listened objects; in case we revert the stack to its
888-
// saved state, we will now be left with a list of listened-to objects with
889-
// no dangling pointers.
890-
891-
// MW-2012-10-10: [[ IdCache ]] Remove the object from the stack's id cache
892-
// (if it is in it!).
893-
if (m_in_id_cache)
894-
getstack() -> uncacheobjectbyid(this);
895884

896885
// This object is in the process of being deleted; invalidate any weak refs
897886
// and prevent any new ones from being created.

engine/src/object.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,8 @@ class MCObject :
672672
virtual void undo(Ustruct *us);
673673
virtual void freeundo(Ustruct *us);
674674

675+
virtual void uncacheid(void);
676+
675677
// [[ C++11 ]] MSVC doesn't support typename here while other compilers require it
676678
#ifdef _MSC_VER
677679
virtual MCObjectProxy<MCStack>::Handle getstack();

0 commit comments

Comments
 (0)