Skip to content

Commit 5ad78ab

Browse files
committed
[CID 16369] MCCard::relayer(): Restructure code to prevent possible memory leak
Coverity detected a possible codepath by which `MCCard::relayer()` could leak a `MCObjptr` instance. This patch restructures part of the relayering code to first calculate an insertion position, then allocate the `MCObjptr`, before inserting it. It ensures that there is no possible code path that permits a new instance to be allocated without moving its ownership to the `MCCard` instance. Coverity-ID: 16369
1 parent e87980f commit 5ad78ab

File tree

1 file changed

+66
-47
lines changed

1 file changed

+66
-47
lines changed

engine/src/card.cpp

Lines changed: 66 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1742,54 +1742,73 @@ Exec_stat MCCard::relayer(MCControl *optr, uint2 newlayer)
17421742
}
17431743
else
17441744
{
1745-
MCObjptr *newptr = new (nothrow) MCObjptr;
1746-
newptr->setparent(this);
1747-
newptr->setref(optr);
1748-
optr->setparent(this);
1749-
getstack()->appendcontrol(optr);
1750-
if (foundobj == NULL)
1751-
if (newlayer <= 1)
1752-
newptr->insertto(objptrs);
1753-
else
1754-
newptr->appendto(objptrs);
1755-
else
1756-
{
1757-
Boolean g = False;
1758-
if (!MCrelayergrouped)
1759-
{
1760-
while (foundobj->getparent() != this)
1761-
{
1762-
foundobj = (MCControl *)foundobj->getparent();
1763-
g = True;
1764-
}
1765-
}
1766-
tptr = objptrs;
1767-
do
1768-
{
1769-
if (tptr->getref() == foundobj)
1770-
{
1771-
if (g)
1772-
{
1773-
uint2 tnum;
1774-
count(CT_LAYER, CT_UNDEFINED, tptr->next()->getref(), tnum, True);
1775-
if (tptr->next() == objptrs || newlayer < tnum)
1776-
{
1777-
if (tptr == objptrs)
1778-
newptr->insertto(objptrs);
1779-
else
1780-
tptr->prev()->append(newptr);
1781-
break;
1782-
}
1783-
}
1784-
tptr->append(newptr);
1785-
break;
1786-
}
1787-
tptr = tptr->next();
1788-
}
1789-
while (tptr != objptrs);
1790-
}
1745+
/* Find place in the object pointer list at which the
1746+
* relayered object should be placed. If t_before, the object
1747+
* should be placed immediately before the iterator. */
1748+
MCObjptr *t_insert_iter = objptrs;
1749+
bool t_before = false;
1750+
if (foundobj == nullptr)
1751+
{
1752+
t_before = (newlayer <= 1);
1753+
}
1754+
else
1755+
{
1756+
/* If there's a target object for relayering, and group
1757+
* relayering is banned, then we need to find the outer
1758+
* group of the target object. */
1759+
bool t_found_in_group = false;
1760+
while (!MCrelayergrouped &&
1761+
foundobj->getparent() != this)
1762+
{
1763+
foundobj = MCObjectCast<MCControl>(foundobj->getparent());
1764+
t_found_in_group = true;
1765+
}
1766+
1767+
do
1768+
{
1769+
if (foundobj == t_insert_iter->getref())
1770+
{
1771+
if (t_found_in_group)
1772+
{
1773+
uint2 t_minimum_layer = 0;
1774+
count(CT_LAYER, CT_UNDEFINED, t_insert_iter->next()->getref(),
1775+
t_minimum_layer, True);
1776+
t_before = (t_insert_iter->next() == objptrs ||
1777+
newlayer < t_minimum_layer);
1778+
}
1779+
break;
1780+
}
1781+
}
1782+
while (t_insert_iter != objptrs);
1783+
}
1784+
1785+
/* Create and insert an object pointer */
1786+
MCObjptr *newptr = new (nothrow) MCObjptr();
1787+
if (newptr == nullptr)
1788+
return ES_ERROR;
1789+
newptr->setparent(this);
1790+
newptr->setref(optr);
1791+
optr->setparent(this);
1792+
getstack()->appendcontrol(optr);
1793+
1794+
if (t_insert_iter == objptrs)
1795+
{
1796+
if (t_before)
1797+
newptr->insertto(objptrs);
1798+
else
1799+
newptr->appendto(objptrs);
1800+
}
1801+
else
1802+
{
1803+
if (t_before)
1804+
t_insert_iter->prev()->append(newptr);
1805+
else
1806+
t_insert_iter->append(newptr);
1807+
}
17911808

1792-
layer_added(optr, newptr -> prev() != objptrs -> prev() ? newptr -> prev() : nil, newptr -> next() != objptrs ? newptr -> next() : nil);
1809+
layer_added(optr,
1810+
(newptr->prev() != objptrs->prev()) ? newptr->prev() : nil,
1811+
(newptr->next() != objptrs) ? newptr->next() : nil);
17931812
}
17941813

17951814
if (oldparent == this)

0 commit comments

Comments
 (0)