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
win/spawn: run executables with no file extension #4241
win/spawn: run executables with no file extension #4241
Conversation
1244a01
to
35cdb72
Compare
I think I figured it out. The build and test for mingw were happening in two different steps, and Edit: it passed :) |
35cdb72
to
c2753aa
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, checking this behavior on a Windows system in cmd
, it is actually not permitted for a program to run without an extension. Even something explicitly given as a literal absolute path will fail to run from cmd if the file does not have an extension. It doesn't matter what the extension is, but cmd will fail to run it if it does not have one. This is not a security feature of any sort, since it doesn't have this mis-feature when there is a .
; it is just a weird unnecessary edge case of the OS. Powershell is even worse, since it appears to use ShellExecute, which (despite the name) does not actually execute it but rather takes the default action in the registry for that file type (as if double-clicking on it). Sigh, I hate Windows. :/
I think we can break from cmd's inane behavior here. But might be good to get at least one other reviewer to confirm, and perhaps we should run nodejs's testsuite to make sure it isn't somehow explicitly relying on this.
10e0442
to
e17cacc
Compare
2ae6e42
to
62d0333
Compare
62d0333
to
c4cb050
Compare
c4cb050
to
6c88530
Compare
@bnoordhuis are you okay with this? I am surprised that libuv cannot run a program specified literally, unless the filename includes a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should maybe be a UV_PROCESS_NAME_TBD flag because:
a) it's contrary to how CreateProcess() works and therefore contrary to how users may reasonably expect it to work, and
b) it's potentially a backwards-incompatible change in behavior
@@ -367,12 +369,14 @@ static WCHAR* search_path(const WCHAR *file, | |||
name_has_ext = (dot != NULL && dot[1] != L'\0'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: move this into the else
block below. That's now the the only place that uses it.
memcpy(new_exepath, exepath, exepath_size - (sizeof(".exe") - sizeof(char))); | ||
strcpy(new_exepath + exepath_size - (sizeof(".exe") / sizeof(char) - 1), "_no_ext"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sizeof(char) is always 1 and use snprintf() instead of strcpy():
memcpy(new_exepath, exepath, exepath_size - (sizeof(".exe") - sizeof(char))); | |
strcpy(new_exepath + exepath_size - (sizeof(".exe") / sizeof(char) - 1), "_no_ext"); | |
snprintf(new_exepath, sizeof(new_exepath), "%.*s_no_ext", | |
(int) (exepath_size - sizeof(".exe") + 1), | |
exepath); |
Also in the next test.
Do you mean
It does change behavior if the user has both |
No, CreateProcess().
I'll have to get my crystal ball to answer that. :-) You can decide if you want to merge this as-is or behind a flag. |
Oh, I see what you mean--if you skip the first argument then CreateProcess can do a search. But in that cause, the current behavior is contradictory to the behavior of CreateProcess still, since libuv always adds From the docs: "If the file name... contains a path, .exe is not appended" |
@vtjnash as Kyle mentioned in #4241 (comment) I'm taking over this work. I've revised the commit to address above feedback and pushed a branch with the same name to my own fork. You can fetch it from there and (with maintainer access) force-push it to Kyle's fork to update this PR, or just close this and I'll open a new PR. Which do you prefer? |
Probably easier if you make a new PR, so that you have full control of it and don't need access rights to Kyle's repo to make any tweaks to it. I just took a quick look and it sounded good to me. I am just wondering if we should make the new behavior the default (more closely matching unix/CreateProcess), but give users the option of explicitly asking libuv to exactly match the undocumented cmd behavior for backwards compatibility, as mentioned by Ben. Or just assume that since the fix on the user's side would be pretty easily forwards compatible (e.g. explicitly specify the I guess the case this change could break someone's workflow (trying to guess from my opaque crystal ball), is if someone relies on having the unix script and windows exe in the same folder, and having libuv pick the right one based just on the file extension, like so:
However, this feels distinctly non-portable already, from the assumption that the user has |
This was prompted by https://gitlab.kitware.com/cmake/cmake/-/issues/25450#note_1451473.