From e1b428609d983430994b50251970c6f4e81e2ab5 Mon Sep 17 00:00:00 2001 From: Seth Hillbrand Date: Tue, 28 Nov 2023 06:56:00 -0800 Subject: [PATCH] Rewrite followTrivialPath as iterative Remove the recursion that causes stack crash and add an additional check for if we have already seen either the current link or the last link before adding them to the line Fixes https://gitlab.com/kicad/code/kicad/-/issues/16185 --- pcbnew/router/pns_topology.cpp | 55 ++++++++++++++++++---------------- pcbnew/router/pns_topology.h | 2 +- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/pcbnew/router/pns_topology.cpp b/pcbnew/router/pns_topology.cpp index 2e0afead53..0259b52e2a 100644 --- a/pcbnew/router/pns_topology.cpp +++ b/pcbnew/router/pns_topology.cpp @@ -197,23 +197,31 @@ ITEM* TOPOLOGY::NearestUnconnectedItem( const JOINT* aStart, int* aAnchor, int a } -bool TOPOLOGY::followTrivialPath( LINE* aLine, bool aLeft, ITEM_SET& aSet, - std::set& aVisited, const JOINT** aTerminalJoint, - bool aFollowLockedSegments ) +bool TOPOLOGY::followTrivialPath( LINE* aLine2, bool aLeft, ITEM_SET& aSet, + const JOINT** aTerminalJoint, bool aFollowLockedSegments ) { - assert( aLine->IsLinked() ); + assert( aLine2->IsLinked() ); + LINE* curr_line = aLine2; + std::set visited; - VECTOR2I anchor = aLeft ? aLine->CPoint( 0 ) : aLine->CPoint( -1 ); - LINKED_ITEM* last = aLeft ? aLine->Links().front() : aLine->Links().back(); - const JOINT* jt = m_world->FindJoint( anchor, aLine ); - - assert( jt != nullptr ); - - aVisited.insert( last ); - - if( jt->IsNonFanoutVia() || jt->IsTraceWidthChange() ) + while( true ) { - ITEM* via = nullptr; + VECTOR2I anchor = aLeft ? curr_line->CPoint( 0 ) : curr_line->CPoint( -1 ); + LINKED_ITEM* last = aLeft ? curr_line->Links().front() : curr_line->Links().back(); + const JOINT* jt = m_world->FindJoint( anchor, curr_line ); + + assert( jt != nullptr ); + + if( !visited.insert( last ).second + || ( !jt->IsNonFanoutVia() && !jt->IsTraceWidthChange() ) ) + { + if( aTerminalJoint ) + *aTerminalJoint = jt; + + return false; + } + + ITEM* via = nullptr; SEGMENT* next_seg = nullptr; ITEM_SET links( jt->CLinks() ); @@ -222,7 +230,7 @@ bool TOPOLOGY::followTrivialPath( LINE* aLine, bool aLeft, ITEM_SET& aSet, { if( link->OfKind( ITEM::VIA_T ) ) via = link; - else if( aVisited.find( link ) == aVisited.end() ) + else if( visited.insert( link ).second ) next_seg = static_cast( link ); } @@ -234,8 +242,7 @@ bool TOPOLOGY::followTrivialPath( LINE* aLine, bool aLeft, ITEM_SET& aSet, return false; } - LINE l = m_world->AssembleLine( next_seg, nullptr, false, aFollowLockedSegments ); - + LINE l = m_world->AssembleLine( next_seg, nullptr, false, aFollowLockedSegments ); VECTOR2I nextAnchor = ( aLeft ? l.CLine().CPoint( -1 ) : l.CLine().CPoint( 0 ) ); if( nextAnchor != anchor ) @@ -249,6 +256,7 @@ bool TOPOLOGY::followTrivialPath( LINE* aLine, bool aLeft, ITEM_SET& aSet, aSet.Prepend( via ); aSet.Prepend( l ); + curr_line = static_cast( aSet[0] ); } else { @@ -256,15 +264,11 @@ bool TOPOLOGY::followTrivialPath( LINE* aLine, bool aLeft, ITEM_SET& aSet, aSet.Add( via ); aSet.Add( l ); + curr_line = static_cast( aSet[aSet.Size() - 1] ); } - return followTrivialPath( &l, aLeft, aSet, aVisited, aTerminalJoint, aFollowLockedSegments ); + continue; } - - if( aTerminalJoint ) - *aTerminalJoint = jt; - - return false; } @@ -273,7 +277,6 @@ const ITEM_SET TOPOLOGY::AssembleTrivialPath( ITEM* aStart, bool aFollowLockedSegments ) { ITEM_SET path; - std::set visited; LINKED_ITEM* seg = nullptr; if( aStart->Kind() == ITEM::VIA_T ) @@ -312,8 +315,8 @@ const ITEM_SET TOPOLOGY::AssembleTrivialPath( ITEM* aStart, const JOINT* jointA = nullptr; const JOINT* jointB = nullptr; - followTrivialPath( &l, false, path, visited, &jointB, aFollowLockedSegments ); - followTrivialPath( &l, true, path, visited, &jointA, aFollowLockedSegments ); + followTrivialPath( &l, false, path, &jointB, aFollowLockedSegments ); + followTrivialPath( &l, true, path, &jointA, aFollowLockedSegments ); if( aTerminalJoints ) { diff --git a/pcbnew/router/pns_topology.h b/pcbnew/router/pns_topology.h index a490737f30..225179032e 100644 --- a/pcbnew/router/pns_topology.h +++ b/pcbnew/router/pns_topology.h @@ -95,7 +95,7 @@ public: private: const int DP_PARALLELITY_THRESHOLD = 5; - bool followTrivialPath( LINE* aLine, bool aLeft, ITEM_SET& aSet, std::set& aVisited, + bool followTrivialPath( LINE* aLine, bool aLeft, ITEM_SET& aSet, const JOINT** aTerminalJoint = nullptr, bool aFollowLockedSegments = false ); NODE *m_world;