-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CARGO env var set incorrectly when Cargo invoked through ld #10113
Labels
C-bug
Category: bug
Comments
I implemented the proposed fix in #10115 for discussion. |
jonhoo
pushed a commit
to jonhoo/cargo
that referenced
this issue
Nov 23, 2021
Just to leave some breadcrumbs, I think it's likely that this will be solved by whatever solves #10119, so I'm going to close this issue in favor of that one. |
jonhoo
pushed a commit
to jonhoo/cargo
that referenced
this issue
Oct 25, 2022
Currently, Cargo will always set `$CARGO` to point to what it detects its own path to be (using `std::env::current_exe`). Unfortunately, this runs into trouble when Cargo is used as a library, or when `current_exe` is not actually the binary itself (e.g., when invoked through Valgrind or `ld.so`), since `$CARGO` will not point at something that can be used as `cargo`. This, in turn, means that users can't currently rely on `$CARGO` to do the right thing, and will sometimes have to invoke `cargo` directly from `$PATH` instead, which may not reflect the `cargo` that's currently in use. This patch makes Cargo re-use the existing value of `$CARGO` if it's already set in the environment. For Cargo subcommands, this will mean that the initial invocation of `cargo` in `cargo foo` will set `$CARGO`, and then Cargo-as-a-library inside of `cargo-foo` will inherit that (correct) value instead of overwriting it with the incorrect value `cargo-foo`. For other execution environments that do not have `cargo` in their call stack, it gives them the opportunity to set a working value for `$CARGO`. One note about the implementation of this is that the test suite now needs to override `$CARGO` explicitly so that the _user's_ `$CARGO` does not interfere with the contents of the tests. It _could_ remove `$CARGO` instead, but overriding it seemed less error-prone. Fixes rust-lang#10119. Fixes rust-lang#10113.
jonhoo
pushed a commit
to jonhoo/cargo
that referenced
this issue
Oct 25, 2022
Currently, Cargo will always set `$CARGO` to point to what it detects its own path to be (using `std::env::current_exe`). Unfortunately, this runs into trouble when Cargo is used as a library, or when `current_exe` is not actually the binary itself (e.g., when invoked through Valgrind or `ld.so`), since `$CARGO` will not point at something that can be used as `cargo`. This, in turn, means that users can't currently rely on `$CARGO` to do the right thing, and will sometimes have to invoke `cargo` directly from `$PATH` instead, which may not reflect the `cargo` that's currently in use. This patch makes Cargo re-use the existing value of `$CARGO` if it's already set in the environment. For Cargo subcommands, this will mean that the initial invocation of `cargo` in `cargo foo` will set `$CARGO`, and then Cargo-as-a-library inside of `cargo-foo` will inherit that (correct) value instead of overwriting it with the incorrect value `cargo-foo`. For other execution environments that do not have `cargo` in their call stack, it gives them the opportunity to set a working value for `$CARGO`. One note about the implementation of this is that the test suite now needs to override `$CARGO` explicitly so that the _user's_ `$CARGO` does not interfere with the contents of the tests. It _could_ remove `$CARGO` instead, but overriding it seemed less error-prone. Fixes rust-lang#10119. Fixes rust-lang#10113.
bors
added a commit
that referenced
this issue
Nov 2, 2022
Make cargo forward pre-existing CARGO if set Currently, Cargo will always set `$CARGO` to point to what it detects its own path to be (using `std::env::current_exe`). Unfortunately, this runs into trouble when Cargo is used as a library, or when `current_exe` is not actually the binary itself (e.g., when invoked through Valgrind or `ld.so`), since `$CARGO` will not point at something that can be used as `cargo`. This, in turn, means that users can't currently rely on `$CARGO` to do the right thing, and will sometimes have to invoke `cargo` directly from `$PATH` instead, which may not reflect the `cargo` that's currently in use. This patch makes Cargo re-use the existing value of `$CARGO` if it's already set in the environment. For Cargo subcommands, this will mean that the initial invocation of `cargo` in `cargo foo` will set `$CARGO`, and then Cargo-as-a-library inside of `cargo-foo` will inherit that (correct) value instead of overwriting it with the incorrect value `cargo-foo`. For other execution environments that do not have `cargo` in their call stack, it gives them the opportunity to set a working value for `$CARGO`. One note about the implementation of this is that the test suite now needs to override `$CARGO` explicitly so that the _user's_ `$CARGO` does not interfere with the contents of the tests. It _could_ remove `$CARGO` instead, but overriding it seemed less error-prone. Fixes #10119. Fixes #10113.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Problem
Earlier today I got a report from an internal developer about a build failing with an error like this:
The line in question is:
where
Digging some more using
strace
, the developer found that the culprit was thisexecve
:This led me down a bit of a rabbit hole. The error propagates an error from when
cbindgen
tries to invokecargo metadata
, which constructs the actual Command here. The name of the command is determined by theCARGO
environment variable, which Cargo sets based onConfig::cargo_exe
. Now that, in turn, is set based onstd::env::current_exe
, which gets the "full path to the current executable" (Linux impl is reading/proc/self/exe
).Which brings us to
/usr/lib64/ld-2.26.so
— the Linux dynamic linker. Internally, binaries are executed through the dynamic linker so that we can explicitly set the shared library search path to ensure that the same shared libraries used to build a given binary are used when it is executed. It has a similar effect as settingLD_LIBRARY_PATH
, but with the added benefit that it does not also set the shared library search path of any programs executed down the line. There is a lot of underlying complexity here that is probably not worth digging too much into, but the idea is that a binary should ship "with its environment", and so ifcargo
and some subcommandcargo-foo
are built separately, they should use different shared library search paths, namely the ones that map to exactly what they were built with. Executing through the dynamic linker achieves that,LD_LIBRARY_PATH
does not. (This is also done by things like go-appimage).Now, the challenge is that when you execute a binary through the dynamic linker, that's what the "current executable" is set to. Even if you execute it through
exec -a
(to setargv[0]
),/proc/self/exe
still points at the linker itself. And since Cargo preferscurrent_exe
(which is/proc/self/exe
), it ends up settingCARGO
to the linker, which means that build scripts that try to run Cargo using that path fail:cargo/src/cargo/util/config/mod.rs
Lines 383 to 414 in f066c50
You can also reproduce that with this snippet:
Steps
No response
Possible Solution(s)
It's not entirely clear how to fix this. I understand why Cargo prefers
current_exe
overargv[0]
, and that's probably the right choice generally. I wonder if perhaps the way to go about this is to have Cargo favorargv[0]
if the filename ofcurrent_exe
matchesld-*.so*
?Notes
No response
Version
The text was updated successfully, but these errors were encountered: