55 lines
2 KiB
Diff
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()
|
|
}
|
|
}
|