fix(config): [env] relative paths definition #16957
fix(config): [env] relative paths definition #16957weihanglo merged 2 commits intorust-lang:masterfrom
[env] relative paths definition #16957Conversation
|
r? @epage rustbot has assigned @epage. Use Why was this reviewer chosen?The reviewer was selected based on:
|
|
Evaluates to But now consider: write_config_at(
"foo/.cargo/config.toml",
"
include = ['../../inc.toml']
",
);
write_config_at(
"inc.toml",
"
[env]
MY_ENV = { value = 'outer', relative = true }
",
);which will evaluate to |
This comment has been minimized.
This comment has been minimized.
| Definition::Environment(_) | Definition::Cli(None) | Definition::BuiltIn => gctx.cwd(), | ||
| } | ||
| .join(&self.path); | ||
| let abs_path = paths::normalize_path(&abs_path); |
There was a problem hiding this comment.
@thomasw04 commented in #16957 (comment):
Evaluates to
foo/.cargo/../../outer, thusouter.But now consider:
write_config_at( "foo/.cargo/config.toml", " include = ['../../inc.toml'] ", ); write_config_at( "inc.toml", " [env] MY_ENV = { value = 'outer', relative = true } ", );which will evaluate to
foo/.cargo/../outer, thusfoo/outer.
Nice catch! That is actually another bug. Fixed in 255bff3
|
What behavior of relative paths do you assume/implement with this fix? Wouldn't it make sense to specify that in the docs as well, or is there already a specification I missed? |
https://doc.rust-lang.org/nightly/cargo/reference/config.html#config-relative-paths file goes to parent.parent, otherwise current working directory |
|
Aha, okay, thanks. So I assume this is then also applicable for included config files and also distinguishes where the path came from (or took precedence):
|
This comment has been minimized.
This comment has been minimized.
### What does this PR try to resolve? Extracted from <rust-lang#16957>. Without normalizing included config paths, `Definition::root()` will do `parent().parent()` on non-normalized paths containing `..` segments. And that will remove `..` and result in wrong path resolution. ### How to test and review this PR? Two tested are added to showcase the buggy behavior, especially `env_relative_path_included_from_upper_level` which was a wrong path resolution.
`EnvConfigValue` was wrapped in `Value<T>`, which captured the table-level `Definition` for path resolution. 1. In merge_helper, we merge all keys in a table but not the definition of the table itself: <https://github.com/rust-lang/cargo/blob/60960cbe4148295890ccd0f2890c2fb5dd9a0914/src/cargo/util/context/config_value.rs?plain=1#L177-L199> It is probably hard to defined the source definition of a merged struct though, perhaps people shouldn't access it to do anything meaningful. 2. When deserializing a `[env]` struct with `Value<T>`, `Value<T>` delegate to `ValueDeserializer` to deserialize the value, which only takes the struct definition into account. And that turns out to be the stale table definition: <https://github.com/rust-lang/cargo/blob/60960cbe4148295890ccd0f2890c2fb5dd9a0914/src/cargo/util/context/de.rs?plain=1#L119-L137> 3. Unlike file config discovery, `include` is loaded before the including config, hence its definition is stale and is used. This caused in rust-lang#16954 that `[env]` struct got a stale old config source definition. This fix doesn't touch the core problem that A merged `Value<T>` table holds a stale source definition. Holding either new or old doesn't seem correct to me, as it is a merged one. This is really a footgun.
|
This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
Update cargo submodule 13 commits in 4f9b52075316e9ced380c8fa492858048d5758b6..a343accce8526b128adc517d33348573d22920a3 2026-05-01 22:36:41 +0000 to 2026-05-08 22:41:35 +0000 - docs(guide): Fix a typo (rust-lang/cargo#16980) - chore(deps): update msrv (3 versions) to v1.93 (rust-lang/cargo#16979) - refactor(diag): Move lints to diagnostics (rust-lang/cargo#16978) - refactor(lints): Pull out `unknown_lints` lint logic and `missing_lints_features` diagnostic logic (rust-lang/cargo#16976) - refactor(lints): Move things out of `lints/mod.rs` (rust-lang/cargo#16975) - test: cover search API redirects (rust-lang/cargo#16971) - refactor(lints): Instrument lints for logging (rust-lang/cargo#16972) - docs: `.cargo-checksum.json` is not a security mechanism (rust-lang/cargo#16966) - fix(vendor): add `$comment` to `.cargo-checksum.json` (rust-lang/cargo#16967) - test: Fixed arg order in rustdoc json test (rust-lang/cargo#16968) - fix(config): `[env]` relative paths definition (rust-lang/cargo#16957) - fix(config): normalize included config paths (rust-lang/cargo#16964) - Fix heading level of `build.warnings` documentation. (rust-lang/cargo#16961) r? ghost
What does this PR try to resolve?
EnvConfigValuewas wrapped inValue<T>,which captured the table-level
Definitionfor path resolution.In
merge_helper,we merge all keys in a table but not the definition of the table itself:
cargo/src/cargo/util/context/config_value.rs
Lines 177 to 199 in 60960cb
It is probably hard to defined the source definition of a merged struct though, perhaps people shouldn't access it to do anything meaningful.
When deserializing a
[env]struct withValue<T>,Value<T>delegate toValueDeserializerto deserialize the value,which only takes the struct definition into account.
And that turns out to be the stale table definition:
cargo/src/cargo/util/context/de.rs
Lines 119 to 137 in 60960cb
Unlike file config discovery,
includeis loaded before the including config,hence its definition is stale and is used.
This caused in #16954 that
[env]struct got a stale old config source definition.How to test and review this PR?
New regression tests should have covered cases in #16954, and also captured the non-canonicalized case which is a separate issue.
This fix doesn't touch the core problem that a merged
Value<T>table holds a stale source definition. Holding either new or old doesn't seem correct to me, as it is a merged one. This is really a footgun.Fixes #16954