java-topology/defects/npm/patch/npm-0002-peerpath-set.patch

56 lines
2.1 KiB
Diff

# UNDF: UNDF-2026-000000189
diff --git a/lib/can-place-dep.js b/lib/can-place-dep.js
index 1a3ccff..0708321 100644
--- a/lib/can-place-dep.js
+++ b/lib/can-place-dep.js
@@ -61,6 +61,7 @@ class CanPlaceDep {
preferDedupe,
parent = null,
peerPath = [],
+ peerPathSet = null,
explicitRequest = false,
} = options
@@ -95,6 +96,10 @@ class CanPlaceDep {
// preventing cycles when we check peer sets
this.peerPath = peerPath
+ // CWE-407 fix: shared Set for O(1) peerPath membership tests.
+ // Initialized once at the root; child CPDs receive the parent's reference.
+ // canPlacePeers() adds/removes this.dep using a backtracking DFS pattern.
+ this.peerPathSet = peerPathSet || new Set(peerPath)
// we always prefer to dedupe peers, because they are trying
// a bit harder to be singletons.
this.preferDedupe = !!preferDedupe || edge.peer
@@ -365,9 +370,12 @@ class CanPlaceDep {
// TODO: represent peerPath in ERESOLVE error somehow?
const peerPath = [...this.peerPath, this.dep]
+ // CWE-407 fix: use shared peerPathSet for O(1) cycle detection.
+ // Add this.dep now; children share the same Set reference; backtrack after.
+ this.peerPathSet.add(this.dep)
let sawConflict = false
for (const peerEdge of this.dep.edgesOut.values()) {
- if (!peerEdge.peer || !peerEdge.to || peerPath.includes(peerEdge.to)) {
+ if (!peerEdge.peer || !peerEdge.to || this.peerPathSet.has(peerEdge.to)) {
continue
}
const peer = peerEdge.to
@@ -381,6 +389,7 @@ class CanPlaceDep {
parent: this,
edge: peerEdge,
peerPath,
+ peerPathSet: this.peerPathSet,
// always place peers in preferDedupe mode
preferDedupe: true,
})
@@ -396,6 +405,9 @@ class CanPlaceDep {
sawConflict = true
}
}
+ // Backtrack: remove this.dep from the shared peerPathSet so the parent's
+ // subsequent peers are checked against the correct path state.
+ this.peerPathSet.delete(this.dep)
this._canPlacePeers = sawConflict ? CONFLICT : state
return this._canPlacePeers