84 lines
2.7 KiB
Diff
84 lines
2.7 KiB
Diff
# UNDF: UNDF-2026-000000307
|
||
From: agent-blackops <blackops@unturf.com>
|
||
Date: Thu, 26 Mar 2026 00:00:00 +0000
|
||
Subject: [PATCH] dag/tarjan: replace inStack linear scan with onStack map
|
||
|
||
CWE-407: Algorithmic complexity via O(V) linear stack scan per call to
|
||
inStack() inside stronglyConnected(). inStack() iterated s.Stack []Vertex
|
||
looking for needle — O(stack-depth) per call. stronglyConnected() calls
|
||
inStack once per outgoing edge, yielding O(V×E) total comparisons for a
|
||
dense graph.
|
||
|
||
Add onStack map[Vertex]bool to sccAcct. Set onStack[v] = true on push,
|
||
delete(onStack, v) on pop. Replace inStack(s.Stack, w) with s.onStack[w]
|
||
for O(1) amortised map lookup per call.
|
||
|
||
The standalone inStack() helper function is removed; the check is now
|
||
expressed directly as s.onStack[target] in the one call site.
|
||
|
||
Defect-Id: TF-001
|
||
Severity: HIGH
|
||
CWE: CWE-407 (Inefficient Algorithmic Complexity)
|
||
---
|
||
internal/dag/tarjan.go | 22 ++++++++--------------
|
||
1 file changed, 9 insertions(+), 13 deletions(-)
|
||
|
||
diff --git a/internal/dag/tarjan.go b/internal/dag/tarjan.go
|
||
index xxxxxxx..yyyyyyy 100644
|
||
--- a/internal/dag/tarjan.go
|
||
+++ b/internal/dag/tarjan.go
|
||
@@ -10,6 +10,7 @@ func StronglyConnected(g *Graph) [][]Vertex {
|
||
acct := sccAcct{
|
||
NextIndex: 1,
|
||
VertexIndex: make(map[Vertex]int, len(vs)),
|
||
+ onStack: make(map[Vertex]bool, len(vs)), // CWE-407 fix: O(1) stack membership
|
||
}
|
||
for _, v := range vs {
|
||
// Recurse on any non-visited nodes
|
||
@@ -30,7 +31,7 @@ func stronglyConnected(acct *sccAcct, g *Graph, v Vertex) int {
|
||
if targetIdx == 0 {
|
||
minIdx = min(minIdx, stronglyConnected(acct, g, target))
|
||
- } else if acct.inStack(target) {
|
||
+ } else if acct.onStack[target] { // CWE-407 fix: O(1) map lookup replaces O(V) scan
|
||
// Check if the vertex is in the stack
|
||
minIdx = min(minIdx, targetIdx)
|
||
}
|
||
@@ -56,6 +57,7 @@ type sccAcct struct {
|
||
NextIndex int
|
||
VertexIndex map[Vertex]int
|
||
Stack []Vertex
|
||
+ onStack map[Vertex]bool // CWE-407 fix: shadow set for O(1) inStack queries
|
||
SCC [][]Vertex
|
||
}
|
||
|
||
@@ -64,7 +66,8 @@ func (s *sccAcct) visit(v Vertex) int {
|
||
idx := s.NextIndex
|
||
s.VertexIndex[v] = idx
|
||
s.NextIndex++
|
||
- s.push(v)
|
||
+ s.push(v) // push also sets onStack[v] = true
|
||
return idx
|
||
}
|
||
|
||
@@ -72,6 +75,7 @@ func (s *sccAcct) push(n Vertex) {
|
||
s.Stack = append(s.Stack, n)
|
||
+ s.onStack[n] = true // CWE-407 fix: O(1) insert
|
||
}
|
||
|
||
// pop removes a vertex from the stack
|
||
@@ -82,20 +86,12 @@ func (s *sccAcct) pop() Vertex {
|
||
vertex := s.Stack[n-1]
|
||
s.Stack = s.Stack[:n-1]
|
||
+ delete(s.onStack, vertex) // CWE-407 fix: O(1) remove
|
||
return vertex
|
||
}
|
||
-
|
||
-// inStack checks if a vertex is in the stack
|
||
-func (s *sccAcct) inStack(needle Vertex) bool {
|
||
- for _, n := range s.Stack {
|
||
- if n == needle {
|
||
- return true
|
||
- }
|
||
- }
|
||
- return false
|
||
-}
|