router: fix use-after-free crash in single trace shove routing when m_endItem's owning NODE is erased by the springback algorithm.

Fixes: https://gitlab.com/kicad/code/kicad/-/issues/9994
This commit is contained in:
Tomasz Wlostowski 2021-12-15 01:32:05 +01:00
parent 1ca90f31bf
commit 2ae3a83b54
4 changed files with 24 additions and 0 deletions

View File

@ -762,6 +762,12 @@ bool LINE_PLACER::rhShoveOnly( const VECTOR2I& aP, LINE& aNewHead )
return false;
}
if( m_endItem )
{
// Make sure the springback algorithm won't erase the NODE that owns m_endItem.
m_shove->SetSpringbackDoNotTouchNode( m_endItem->Owner() );
}
SHOVE::SHOVE_STATUS status = m_shove->ShoveLines( l );
m_currentNode = m_shove->CurrentNode();
@ -1105,6 +1111,7 @@ bool LINE_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem )
m_placingVia = false;
m_chainedPlacement = false;
m_fixedTail.Clear();
m_endItem = nullptr;
setInitialDirection( Settings().InitialDirection() );
@ -1208,6 +1215,8 @@ bool LINE_PLACER::Move( const VECTOR2I& aP, ITEM* aEndItem )
m_lastNode = nullptr;
}
m_endItem = aEndItem;
bool reachesEnd = route( p );
current = Trace();

View File

@ -353,6 +353,7 @@ private:
LINE m_currentTrace;
ITEM* m_startItem;
ITEM* m_endItem;
bool m_idle;
bool m_chainedPlacement;

View File

@ -170,6 +170,7 @@ SHOVE::SHOVE( NODE* aWorld, ROUTER* aRouter ) :
m_iter = 0;
m_multiLineMode = false;
m_restrictSpringbackTagId = 0;
m_springbackDoNotTouchNode = nullptr;
}
@ -788,6 +789,11 @@ NODE* SHOVE::reduceSpringback( const ITEM_SET& aHeadSet, VIA_HANDLE& aDraggedVia
{
SPRINGBACK_TAG& spTag = m_nodeStack.back();
// Prevent the springback algo from erasing NODEs that might contain items used by the ROUTER_TOOL/LINE_PLACER.
// I noticed this can happen for the endItem provided to LINE_PLACER::Move() and cause a nasty crash.
if( spTag.m_node == m_springbackDoNotTouchNode )
break;
OPT<OBSTACLE> obs = spTag.m_node->CheckColliding( aHeadSet );
if( !obs && !spTag.m_locked )
@ -1881,5 +1887,11 @@ void SHOVE::DisablePostShoveOptimizations( int aMask )
m_optFlagDisableMask = aMask;
}
void SHOVE::SetSpringbackDoNotTouchNode( NODE *aNode )
{
m_springbackDoNotTouchNode = aNode;
}
}

View File

@ -90,6 +90,7 @@ public:
bool RewindSpringbackTo( NODE* aNode );
bool RewindToLastLockedNode();
void DisablePostShoveOptimizations( int aMask );
void SetSpringbackDoNotTouchNode( NODE *aNode );
private:
typedef std::vector<SHAPE_LINE_CHAIN> HULL_SET;
@ -171,6 +172,7 @@ private:
NODE* m_root;
NODE* m_currentNode;
NODE* m_springbackDoNotTouchNode;
int m_restrictSpringbackTagId;
OPT_LINE m_newHead;