From 988542ea3ea07cd7c33790036470eed90d140071 Mon Sep 17 00:00:00 2001 From: Jacob Finkelman Date: Wed, 3 May 2023 22:32:02 +0000 Subject: [PATCH] do not try an exponential number of package names --- src/cargo/sources/registry/index.rs | 85 ----------------------------- src/cargo/sources/registry/mod.rs | 12 +++- tests/testsuite/registry.rs | 5 +- 3 files changed, 12 insertions(+), 90 deletions(-) diff --git a/src/cargo/sources/registry/index.rs b/src/cargo/sources/registry/index.rs index 09b55c470cd6..d857a053ed2c 100644 --- a/src/cargo/sources/registry/index.rs +++ b/src/cargo/sources/registry/index.rs @@ -81,91 +81,6 @@ use std::path::Path; use std::str; use std::task::{ready, Poll}; -/// Crates.io treats hyphen and underscores as interchangeable, but the index and old Cargo do not. -/// Therefore, the index must store uncanonicalized version of the name so old Cargo's can find it. -/// This loop tries all possible combinations of switching hyphen and underscores to find the -/// uncanonicalized one. As all stored inputs have the correct spelling, we start with the spelling -/// as-provided. -pub struct UncanonicalizedIter<'s> { - input: &'s str, - num_hyphen_underscore: u32, - hyphen_combination_num: u16, -} - -impl<'s> UncanonicalizedIter<'s> { - pub fn new(input: &'s str) -> Self { - let num_hyphen_underscore = input.chars().filter(|&c| c == '_' || c == '-').count() as u32; - UncanonicalizedIter { - input, - num_hyphen_underscore, - hyphen_combination_num: 0, - } - } -} - -impl<'s> Iterator for UncanonicalizedIter<'s> { - type Item = String; - - fn next(&mut self) -> Option { - if self.hyphen_combination_num > 0 - && self.hyphen_combination_num.trailing_zeros() >= self.num_hyphen_underscore - { - return None; - } - - let ret = Some( - self.input - .chars() - .scan(0u16, |s, c| { - // the check against 15 here's to prevent - // shift overflow on inputs with more than 15 hyphens - if (c == '_' || c == '-') && *s <= 15 { - let switch = (self.hyphen_combination_num & (1u16 << *s)) > 0; - let out = if (c == '_') ^ switch { '_' } else { '-' }; - *s += 1; - Some(out) - } else { - Some(c) - } - }) - .collect(), - ); - self.hyphen_combination_num += 1; - ret - } -} - -#[test] -fn no_hyphen() { - assert_eq!( - UncanonicalizedIter::new("test").collect::>(), - vec!["test".to_string()] - ) -} - -#[test] -fn two_hyphen() { - assert_eq!( - UncanonicalizedIter::new("te-_st").collect::>(), - vec![ - "te-_st".to_string(), - "te__st".to_string(), - "te--st".to_string(), - "te_-st".to_string() - ] - ) -} - -#[test] -fn overflow_hyphen() { - assert_eq!( - UncanonicalizedIter::new("te-_-_-_-_-_-_-_-_-st") - .take(100) - .count(), - 100 - ) -} - /// Manager for handling the on-disk index. /// /// Note that local and remote registries store the index differently. Local diff --git a/src/cargo/sources/registry/mod.rs b/src/cargo/sources/registry/mod.rs index 8a7cce650ca3..aac63fdbedd8 100644 --- a/src/cargo/sources/registry/mod.rs +++ b/src/cargo/sources/registry/mod.rs @@ -850,9 +850,17 @@ impl<'cfg> Source for RegistrySource<'cfg> { // names to the original name. The resolver will later // reject any candidates that have the wrong name, and with this it'll // along the way produce helpful "did you mean?" suggestions. - for name_permutation in - index::UncanonicalizedIter::new(&dep.package_name()).take(1024) + // For now we only try the canonical lysing `-` to `_` and vice versa. + // More advanced fuzzy searching become in the future. + for name_permutation in [ + dep.package_name().replace('-', "_"), + dep.package_name().replace('_', "-"), + ] + .into_iter() { + if name_permutation.as_str() == dep.package_name().as_str() { + continue; + } any_pending |= self .index .query_inner( diff --git a/tests/testsuite/registry.rs b/tests/testsuite/registry.rs index 05ec9b15860d..f39644965099 100644 --- a/tests/testsuite/registry.rs +++ b/tests/testsuite/registry.rs @@ -3166,7 +3166,7 @@ fn not_found_permutations() { authors = [] [dependencies] - a-b-c = "1.0" + a-b_c = "1.0" "#, ) .file("src/lib.rs", "") @@ -3177,7 +3177,7 @@ fn not_found_permutations() { .with_stderr( "\ [UPDATING] `dummy-registry` index -error: no matching package named `a-b-c` found +error: no matching package named `a-b_c` found location searched: registry `crates-io` required by package `foo v0.0.1 ([ROOT]/foo)` ", @@ -3190,7 +3190,6 @@ required by package `foo v0.0.1 ([ROOT]/foo)` &[ "/index/a-/b-/a-b-c", "/index/a-/b_/a-b_c", - "/index/a_/b-/a_b-c", "/index/a_/b_/a_b_c" ] );