java-topology/defects/terraform/patch/tf-0001-dag-tarjan-onstack-map.patch

84 lines
2.7 KiB
Diff
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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
-}