EmbarkStudios / krates

📦 Creates graphs of crates from cargo metadata 🦀
Apache License 2.0
58 stars 18 forks source link

Bug: resolving features fails when the same package is included multiple times with different versions #69

Closed louisdewar closed 10 months ago

louisdewar commented 10 months ago

Describe the bug

When a project depends on multiple versions of the same crate where the different versions support different features (see minimal reproduction) I get:

$ RUST_BACKTRACE=1 cargo deny check advisories
2024-01-20 14:27:55 [WARN] unable to find a config path, falling back to default config
thread '<unnamed>' panicked at /home/runner/.cargo/registry/src/index.crates.io-6f17d22bba15001f/krates-0.16.1/src/builder.rs:715:25:
internal error: entered unreachable code: unable to locate sensitive-headers for crate tower-http 0.4.4 (registry+https://github.com/rust-lang/crates.io-index) features(["default"])
stack backtrace:
   0: rust_begin_unwind
             at /rustc/82e1608dfa6e0b5569232559e3d385fea5a93112/library/std/src/panicking.rs:645:5
   1: core::panicking::panic_fmt
             at /rustc/82e1608dfa6e0b5569232559e3d385fea5a93112/library/core/src/panicking.rs:72:14
   2: krates::builder::Builder::build_with_metadata
   3: cargo_deny::common::KrateContext::gather_krates
   4: <rayon_core::job::HeapJob<BODY> as rayon_core::job::Job>::execute
   5: rayon_core::registry::WorkerThread::wait_until_cold
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

I've tested 3 versions, and it appears it was introduced in 0.14.4:

To reproduce

Create a new cargo project cargo new example, then populate the Cargo.toml with:

[package]
name = "example"
version = "0.1.0"
edition = "2021"

[dependencies]
tower_http_4 = { package = "tower-http", version = "0.4.4", features = [] }
tower-http = { package = "tower-http", version = "0.5.0", features = ["sensitive-headers"] }

While trying to get a minimal reproducible example I noticed that renaming the 0.5.0 version of the package away from "tower-http" meant that the bug didn't appear, for example the following Cargo.toml works fine:

[package]
name = "example"
version = "0.1.0"
edition = "2021"

[dependencies]
tower_http_4 = { package = "tower-http", version = "0.4.4", features = [] }
tower-http-blah = { package = "tower-http", version = "0.5.0", features = ["sensitive-headers"] }

cargo-deny version

0.14.4,0.14.5

What OS were you running cargo-deny on?

Linux

Additional context

No response

Jake-Shadle commented 10 months ago

Thank you for the repro, will look into this later.

louisdewar commented 10 months ago

Thanks for the rapid turnaround! The fix has fixed the issue present in the minimal reproduction but when I got back to my original project it still doesn't work. I've made a new similar minimal reproduction but now the issue is only triggered when there are an odd number of crates:

[package]
name = "example"
version = "0.1.0"
edition = "2021"

[dependencies]

tower_http_4 = { package = "tower-http", version = "0.4.4" }
tower-http = { version = "0.5.0", features = ["sensitive-headers"] }
# NOTE: the choice of crate here doesn't appear to matter, only that the total number of crates is odd
tower = "0.4.13"

With this config I get:

$ cargo deny --version
cargo-deny 0.14.6
$ RUST_BACKTRACE=1 cargo deny check advisories
2024-01-22 07:49:26 [WARN] unable to find a config path, falling back to default config
thread '<unnamed>' panicked at /home/runner/.cargo/registry/src/index.crates.io-6f17d22bba15001f/krates-0.16.2/src/builder.rs:716:25:
internal error: entered unreachable code: unable to locate sensitive-headers for crate tower-http 0.4.4 (registry+https://github.com/rust-lang/crates.io-index) features(["default"])
stack backtrace:
   0: rust_begin_unwind
             at /rustc/82e1608dfa6e0b5569232559e3d385fea5a93112/library/std/src/panicking.rs:645:5
   1: core::panicking::panic_fmt
             at /rustc/82e1608dfa6e0b5569232559e3d385fea5a93112/library/core/src/panicking.rs:72:14
   2: krates::builder::Builder::build_with_metadata
   3: cargo_deny::common::KrateContext::gather_krates
   4: <rayon_core::job::HeapJob<BODY> as rayon_core::job::Job>::execute
   5: rayon_core::registry::WorkerThread::wait_until_cold
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

As soon as I have an even number of dependencies it works (I've tested this with random crates up to N=11):

$ cargo deny check advisories
2024-01-22 07:01:45 [WARN] unable to find a config path, falling back to default config
advisories ok

I eventually discovered the issue in krates and I'm about to make a PR to fix it.