-
Notifications
You must be signed in to change notification settings - Fork 13k
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
Windows: Audit, clarify, and add tests for resolve_exe()
"append .EXE extension if the extension is different" (not just missing) behavior.
#93124
Comments
resolve_exe()
.resolve_exe()
"append .EXE extension if the extension is different" (not just missing) behavior.
I for one would more than welcome any PRs helping to clean up this code! Though I think at this point it might be worth having a
You're right that this is weird but the goal of the code was to be as close to the actual behaviour of If you can make some test cases that work in Rust 1.57 but not 1.58 then that'd help to find any issues. I mean, we could simplify things here regardless but I'd personally want to be cautious about potentially breaking people's code.
use std::path::PathBuf;
fn main() {
let mut p = PathBuf::from("test.txt.exe");
p.set_extension("");
println!("{}", p.display());
} Output:
@rustbot label +O-windows |
Do you mean that the documented behavior of A particular interesting test case input would be Thanks for clarifying the |
I mean I shall look back at my test cases and see if I missed anything. |
Another thing to consider is whether
|
We now use the |
I think it would be good to add a comment at rust/library/std/src/sys/windows/process.rs Line 312 in 181e915
lpApplicationName to prevent this kind of race.
Also at rust/library/std/src/sys/windows/process.rs Lines 363 to 364 in 181e915
We should update the comments to more accurately describe the behavior:
|
Makes sense. Though note that
This is true. Though I'd ideally want to confirm the desired behaviour first so code and comment can be updated at the same time. |
Ok I've done a quick test using the pre-resolver Rust (1.57). I created a hello world type program and saved it as I then tried to run it as
The last case is an added complexity I hadn't accounted for. |
I question whether anybody would want Also, consider: |
Also, |
In general the rationale for matching the old behaviour was to avoid inadvertently breaking applications in an unrelated PR. And it is possible someone may want to run exes such as I would be happy to make such breaking changes if they're desirable but they should be done intentionally, not as a side-effect. Obviously I failed somewhat in exactly matching the edge cases of |
I see. I think there are two issues:
I think we'd need to collect more info:
...for all I think for any case where all three of these functions agree, then there's nothing to consider changing. |
Oh, also, we should consider documenting how one would spawn |
Fair enough. But why does the behaviour of |
AFAICT, this is the closest thing a Windows C programmer has to Besides the behavior of those three functions, it would also be good to know what the cmd.exe and PowerShell shells do, in these situations.
".com" files are a different kind of executable on DOS/Windows systems; roughly they are .EXEs without the PE header.
To the extent that the aforementioned APIs agree, I don't think we should do anything (by default) different. The current behavior is surprising in the case where the input path has an extension, especially when the input path has an extension that is considered "executable," like ".com," so I think it's worth validating that the surprising behavior is what is "normally" done on Windows, by other APIs and by the shells. I think the average programmer would expect the behavior to be "if a file exists at the input path exists, then spawn it. Otherwise, if it didn't have any extension, try appending .exe." Consider how one would write a program where the user is given a file picker, and based on the file the user picked, that executable is run. Very much like Windows + R. It would be strange to have the user pick "debug.com" but then run a different program "debug.com.exe" that happened to exist next to it, but which the user didn't pick. In the future it might be worthwhile to extend the |
What I'm trying to tease out here is how seriously we should take files without The trouble I'm thinking of is that there's a mismatch between common programmer behaviour (especially those with a *nix background) and Windows conventions. On the one hand it's very common for programmers to leave off the So we might end up in the opposite situation where appending |
Regarding batch files, here's what the CreateProcessW docs (https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw) say:
So, based on those docs, I wouldn't expect "foo.bat" to be treated specially. Regarding .com files, this is what the CreateProcessW documentation says:
That implies to me that specifying "foo.com" should never result in "foo.com.exe". In fact, you seem to be saying that the CreateProcessW documentation is wrong or missing important details. Perhaps we should file a pull request against https://github.com/MicrosoftDocs/sdk-api/blob/docs/sdk-api-src/content/processthreadsapi/nf-processthreadsapi-createprocessw.md to get help from Microsoft on correcting the docs or our understanding of them. |
The docs are describing the behaviour when searching But that's beside the point I was trying to make here. Current behaviour aside, I'm asking whether when someone does |
Ok, I had time to run some tests on
In summary, a I see some possibilities for the Rust standard library:
|
Here's what the docs say at https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw:
Further, as you've noted,
It would be surprising if it works differently than
The "executable list" is, AFAICT, the value of |
I does not. The only special extensions are:
|
I feel like we're getting a bit lost in the weeds there. So I'll try to sum up where I'm at as best I can: If you're saying we should behave exactly as If you're saying we only need to behave how |
I think you mean
The
It is possible that the My concern is that it may be unrealistic to "Do what CreateProcessW does, except ignore the current working directory, and append .exe when we need to but never append .exe when we shouldn't," when we consider the differences across versions of Windows, and maybe even if we don't consider the differences across versions of Windows. |
I agree. Here are my main concerns:
Here are some secondary concerns:
|
I was reading the code for
resolve_exe()
for some reason and I saw this code:(Incidentally, can't this be simplified?)
Then later:
Appending EXE_SUFFIX if the extension isn't already EXE seems wrong to me; I think instead it would make more sense to use exactly the same rules that
CreateProcessW
is documented to use, which is roughly "there is no extension," not "the extension isn't .exe".Further, let's say there is an extension that isn't EXE_SUFFIX, and we append EXE_SUFFIX and we find that the file doesn't exist. Then we remove the extension. The comment implies that this will reset the extension to what it was before, but this is only true if there was no extension at all. What if there was an extension that wasn't EXE_SUFFIX?The text was updated successfully, but these errors were encountered: