java-topology/defects/kicad/patch/kicad-0001-fromto-visited-unordered-set.patch

105 lines
3.3 KiB
Diff

# UNDF: UNDF-2026-000000133
--- a/pcbnew/connectivity/from_to_cache.cpp
+++ b/pcbnew/connectivity/from_to_cache.cpp
@@ -19,6 +19,7 @@
#include <cstdio>
#include <memory>
+#include <unordered_set>
#include <reporter.h>
#include <board.h>
@@ -55,33 +56,55 @@ void FROM_TO_CACHE::buildEndpointList( )
enum PATH_STATUS {
PS_OK = 0,
PS_MULTIPLE_PATHS = -1,
PS_NO_PATH = -2
};
-static bool isVertexVisited( CN_ITEM* v, const std::vector<CN_ITEM*>& path )
+// CWE-407 fix: accept an unordered_set for O(1) membership instead of O(|path|) linear scan.
+static bool isVertexVisited( CN_ITEM* v, const std::unordered_set<CN_ITEM*>& visited )
{
- for( CN_ITEM* u : path )
- {
- if ( u == v )
- return true;
- }
-
- return false;
+ return visited.count( v ) != 0;
}
static PATH_STATUS uniquePathBetweenNodes( CN_ITEM* u, CN_ITEM* v, std::vector<CN_ITEM*>& outPath )
{
- using Path = std::vector<CN_ITEM*>;
+ // CWE-407 fix: Path now carries a companion unordered_set so that isVertexVisited()
+ // across both the current path and every queued path is O(1) instead of O(V).
+ // Previous complexity: O(V^2 * B) per BFS call.
+ // Fixed complexity: O(V * B) per BFS call.
+ struct Path
+ {
+ std::vector<CN_ITEM*> nodes; // ordered traversal
+ std::unordered_set<CN_ITEM*> visited; // O(1) membership
+
+ CN_ITEM* back() const { return nodes.back(); }
+
+ void push_back( CN_ITEM* item )
+ {
+ nodes.push_back( item );
+ visited.insert( item );
+ }
+
+ // Copy constructor — must duplicate both containers.
+ Path( const Path& ) = default;
+ Path() = default;
+ };
+
std::deque<Path> Q;
Path pInit;
bool pathFound = false;
- pInit.push_back( u );
+ pInit.push_back( u ); // inserts into both nodes and visited
Q.push_back( std::move( pInit ) );
while( Q.size() )
{
Path path = Q.front();
Q.pop_front();
- CN_ITEM* last = path.back();
+ CN_ITEM* last = path.back(); // uses Path::back()
if( last == v )
{
- outPath = path;
+ outPath = path.nodes;
if( pathFound )
return PS_MULTIPLE_PATHS;
@@ -92,13 +115,15 @@ static PATH_STATUS uniquePathBetweenNodes( CN_ITEM* u, CN_ITEM* v, std::vector<C
for( CN_ITEM* ci : last->ConnectedItems() )
{
- bool vertexVisited = isVertexVisited( ci, path );
+ // CWE-407 fix: O(1) lookup in the current path's visited set.
+ bool vertexVisited = isVertexVisited( ci, path.visited );
for( std::vector<CN_ITEM*>& p : Q )
{
- if( isVertexVisited( ci, p ) )
+ // CWE-407 fix: O(1) lookup in each queued path's visited set.
+ if( isVertexVisited( ci, p.visited ) )
{
vertexVisited = true;
break;
}
}
if( !vertexVisited )
{
Path newpath( path );
- newpath.push_back( ci );
+ newpath.push_back( ci ); // inserts into both nodes and visited
Q.push_back( std::move( newpath ) );
}
}