Comments (4)
Okay I kinda fell down a rabbithole with this, apologies in advance.
I think Windows should probably follow the Unix-ish variant of using the child's PATH (if set by env
, since Windows lacks a fork
-like mechanism that can modify PATH before exec), else the parent's one.
However:
- Unix has
execvp
, which searches PATH, and if PATH is not set, the behaviour is implementation defined.
On Linux (and other glibc systems) this means callingconfstr(_SC_PATH)
which returns some path which MAY (but as of glibc 2.24, does not) include the current directory (.
)
It will also try to run the file withsh
if executing it as a binary file fails. This is also defined by POSIX.
Rust doesn't use this, however it roughly approximates what Windows does. (In different order, however.) - Further complicating this, the variants of exec that don't search path (e.g.
execve
) CAN execute things in the current directory (of the child!). (The path argument works as-if passed toopen
)
I think PATH-only is a reasonable default that is relatively easy to get consistent across platforms, especially since Rust provides ways to query both the executable directory, and the working directory, so the behaviour can be implemented by the user, should they need it (Although adding them to PATH manually is maybe a little clunky.)
In a perfect world, what I would want is:
- Only search PATH (child's if applicable, else parent's), consistently on all platforms
- A method on
std::os::windows::process::CommandExt
to opt into the regular, pass-it-straight-to-CreateProcess behaviour, i.e.fn use_system_search_path(&mut self, use: bool) -> &mut Command
. Adding this toCommand
to have the same apply toexecve
on Unix doesn't seem worth it, as it restricts relative paths to only the current directory, and std wants as little platform-specificity in its APIs as possible outside of OS-specific extension traits.
Needless to say, all of this is a pretty big mess. I'm advocating for following the principle of least surprise here as much as possible. Notably, it makes "check the value of PATH" be the correct first troubleshooting step on all platforms.
from rust.
Ooph yeah, this is semi-intentional but for historic reasons. So please bare with me while I give a history lesson 🙂
The search order in CreateProcessW
(the underlying API) searches the current directory and system directories before PATH.
At some point some code was added to try to mimic Linux's search order but it was super buggy, Maybe it worked originally but broke over time due to later refactoring that went untested. This lead to (amongst other things) the behaviour you've seen.
When I came along, it was to fix a security issue. We didn't want to ever search the current directory so I rewrote the search manually. I opted to (mostly) preserve the existing behaviour except for removing the current directory because I wanted to avoid too many technically breaking changes at once. I did admittedly fix some bugs though.
The issue now is deciding which behaviour we want to use consistently. This may involve breaking someone's workflow. Our options are:
- Just search the
PATH
environment variable. No more, no less. This is my preference. - Try to mimic the Linux behaviour again. The only difference with the first bullet point is that Linux APIs search the child's
PATH
whereas Windows APIs, by default, searches the current process'PATH
. Obviously this only matters when the twoPATH
s differ. - We could try to do both (which is closest to the current behaviour). That is search the child's PATH first then fallback to the current process if not found.
Additionally there's the question of what to do about the system paths that CreateProcessW
API searches and I preserved in the rewrite. We could just remove them (again this is my preference) but I'm not sure if that would break anyone's expectations.
In any case this is ultimately an API question so tagging appropriately.
from rust.
In case the above wasn't entirely clear I'll try to explictly list the current state and future options.
Current state:
- child's PATH environment variable (but only if the child's environment is not inherited)
- application's path
- system directories
- PATH environment variable
Option 1:
- PATH only
Option 2:
- application's path
- PATH
Option 3:
- application's path
- system directories
- PATH
Option 4:
- child's PATH
Option 5:
- child's PATH
- PATH
Option 6:
- application's path
- child's PATH
- PATH
Option 7:
- application's path
- system directories
- child's PATH
- PATH
from rust.
Additionally there's the question of what to do about the system paths that CreateProcessW API searches and I preserved in the rewrite. We could just remove them (again this is my preference) but I'm not sure if that would break anyone's expectations.
By default, the system path %SystemRoot%\System32
is usually the first entry in the PATH
env variable. So, we could theoretically just search PATH
, as you have suggested. But, since the PATH
can be modified, it might be safer to also search the system path afterwards as a fallback.
Searching PATH
before the system directory seems to me like a better approach because it gives users better control over the search order (see my use case with C:\Program Files\Git\bin\bash.exe
vs C:\Windows\System32\bash.exe
). I'm not sure if this can have some security implications, though.
Regarding the options, it would be convenient (for me, as Rust developer) if the std::process::Command
behavior was consistent across platforms (unless there is some good reason for it not to be).
This seems like a situation where we will definitely break someone's workflow, no matter what approach we choose.
from rust.
Related Issues (20)
- tools depending on rustc crates can't build with `rust.download-rustc=true` and `llvm.download-ci-llvm=false` options HOT 3
- Intrinsics declared with wrong arg count ICE HOT 5
- compiletest: `run-rustfix` and `revisions` have broken interactions
- Greek question mark causes ICE HOT 2
- Lint against instantly-dangling pointers like `String::with_capacity(MAX_PATH).as_mut_ptr()` HOT 8
- `yield` without value from a `gen` block HOT 17
- Tracking Issue for stabilizing the sanitizers (e.g., AddressSanitizer, LeakSanitizer, MemorySanitizer, ThreadSanitizer) HOT 2
- Tracking issue for reviewing and moving sanitizers into a compiler crate (i.e., `rustc_sanitizers`) HOT 2
- Debuginfo tests sometimes run with the wrong Python version on MacOS HOT 8
- New error on nightly 'overflow evaluating the requirement' HOT 1
- Codegen significantly worse when using u128 rather than two u64 HOT 3
- ICE: `No HirID for DefId(...)` with feature `generic_assert` HOT 3
- Nonsensical suggested type using chumsky select! (E0284) HOT 5
- Confusing error message on using `step_by` and `take` on infinite iterator
- ICE: kcfi: `expected item, found (root_crate)` HOT 1
- ICE: kcfi: `unexpected parent of trait or impl item or item not found: ForeignMod` HOT 1
- ICE: kcfi: `cannot get associated-item of DefKey..` HOT 3
- patterns: wrong tracking issue? HOT 20
- Tracking Issue for pattern types HOT 1
- Async closure internal compiler error HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from rust.