about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Howell <michael@notriddle.com>2022-04-29 08:49:14 -0700
committerMichael Howell <michael@notriddle.com>2022-04-29 09:06:50 -0700
commit8743ce85231d1b889323286aa3c88e0cfbc1a76b (patch)
tree9f97bc830d176c3c27006073ac6485021ed3ca8e
parent346065f621c861179a4f51d701c9c7c7a907346b (diff)
downloadrust-8743ce85231d1b889323286aa3c88e0cfbc1a76b.tar.gz
rust-8743ce85231d1b889323286aa3c88e0cfbc1a76b.zip
rustdoc: prevent B -> C -> B -> C loops from stack overflowing
-rw-r--r--src/librustdoc/passes/collect_trait_impls.rs15
1 files changed, 12 insertions, 3 deletions
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index 7b6b1ba0d96..9644e3d15fd 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -100,6 +100,7 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate
         cx: &DocContext<'_>,
         map: &FxHashMap<DefId, &Type>,
         cleaner: &mut BadImplStripper<'_>,
+        targets: &mut FxHashSet<DefId>,
         type_did: DefId,
     ) {
         if let Some(target) = map.get(&type_did) {
@@ -108,12 +109,12 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate
                 cleaner.prims.insert(target_prim);
             } else if let Some(target_did) = target.def_id(&cx.cache) {
                 // `impl Deref<Target = S> for S`
-                if target_did == type_did {
+                if !targets.insert(target_did) {
                     // Avoid infinite cycles
                     return;
                 }
                 cleaner.items.insert(target_did.into());
-                add_deref_target(cx, map, cleaner, target_did);
+                add_deref_target(cx, map, cleaner, targets, target_did);
             }
         }
     }
@@ -143,7 +144,15 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate
                         // `Deref` target type and the impl for type positions, this map of types is keyed by
                         // `DefId` and for convenience uses a special cleaner that accepts `DefId`s directly.
                         if cleaner.keep_impl_with_def_id(for_did.into()) {
-                            add_deref_target(cx, &type_did_to_deref_target, &mut cleaner, for_did);
+                            let mut targets = FxHashSet::default();
+                            targets.insert(for_did);
+                            add_deref_target(
+                                cx,
+                                &type_did_to_deref_target,
+                                &mut cleaner,
+                                &mut targets,
+                                for_did,
+                            );
                         }
                     }
                 }