java-topology/defects/cargo/patch/cargo-0002-edges-add-edge-indexset.patch

55 lines
2 KiB
Diff

# UNDF: UNDF-2026-000000022
diff --git a/src/cargo/ops/tree/graph.rs b/src/cargo/ops/tree/graph.rs
--- a/src/cargo/ops/tree/graph.rs
+++ b/src/cargo/ops/tree/graph.rs
@@ -1,5 +1,6 @@
+use indexmap::IndexSet;
+
// ... (lines omitted for brevity) ...
-/// Set of outgoing edges for a single node.
-///
-/// Edges are separated by the edge kind (`DepKind` or `Feature`). This is
-/// primarily done so that the output can easily display separate sections
-/// like `[build-dependencies]`.
-///
-/// The value is a `Vec` because each edge kind can have multiple outgoing
-/// edges. For example, package "foo" can have multiple normal dependencies.
+/// Set of outgoing edges for a single node.
+///
+/// Edges are separated by the edge kind (`DepKind` or `Feature`). This is
+/// primarily done so that the output can easily display separate sections
+/// like `[build-dependencies]`.
+///
+/// CWE-407 fix: changed from `Vec<Edge>` to `IndexSet<Edge>` so that
+/// `add_edge` is O(1) amortised instead of O(k) per insertion. In
+/// `--graph-features` mode a heavily-featured node (e.g. tokio, serde) can
+/// accumulate 100+ edges; the old Vec scan made the total cost O(E²/K).
#[derive(Clone, Debug)]
-struct Edges(HashMap<EdgeKind, Vec<Edge>>);
+struct Edges(HashMap<EdgeKind, IndexSet<Edge>>);
impl Edges {
fn new() -> Edges {
Edges(HashMap::new())
}
/// Adds an edge pointing to the given node.
fn add_edge(&mut self, edge: Edge) {
- let indexes = self.0.entry(edge.kind()).or_default();
- if !indexes.contains(&edge) {
- indexes.push(edge)
- }
+ // CWE-407 fix: IndexSet::insert is O(1) amortised and ignores duplicates.
+ self.0.entry(edge.kind()).or_default().insert(edge);
}
fn all(&self) -> impl Iterator<Item = &Edge> + '_ {
self.0.values().flatten()
}
fn of_kind(&self, kind: &EdgeKind) -> &[Edge] {
- self.0.get(kind).map(Vec::as_slice).unwrap_or_default()
+ self.0.get(kind).map(IndexSet::as_slice).unwrap_or_default()
}
}