-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Command does not escape arguments as expected on windows #29494
Comments
Edit: Nevermind, a look at the documentation reveals that this function takes a single string as command to be executed. |
At the very least it should strive to perform the exact, minimal inverse of CommandLineToArgvW (a very nontrivial task unfortunately, see: http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/everyone-quotes-arguments-the-wrong-way.aspx which describes the problems well enough, but the final solution given is actually still wrong!) This would be enough to fix the problems for me with msiexec and possibly cmd. However, there's no requirement that processes on windows use For reference, the string edit: Actually, no it seems it does still need escaping, it may just be that msiexec does not use CommandLineToArgvW. |
This could probably be solved by adding a |
This popped up on Stack Overflow: let comm = r#""C:\Program Files\Google\Chrome\Application\chrome.exe" https://stackoverflow.com/"#;
let mut cmd = Command::new("cmd");
cmd.arg("/c");
cmd.arg(comm); As I understand it, it is expected to execute
But instead executes
Note that the inner |
Met this issue too. Do we have any workaround now? |
The workaround is calling |
@retep998 I changed the argument in the command line to avoid the quotes. |
I'm now running into this issue while trying to fix The summary at this point seems to be, at least for Windows, with its some-what crazy command-line quoting, that there are simply some command lines which are valid and used which cannot be generated by the current IMO, there needs to be some way of using An addition to the API of Any thoughts? And what should be done to push this issue forward? cc: @rivy |
Same problem here, we can't use
|
Also ran into this, trying to open Explorer with a selected file, like this:
This does not work, due to the quotes getting escaped when they shouldn't be. Explorer.exe expects to be called like this:
which becomes
which it doesn't accept. Would a pull request adding arg_raw() be accepted at this point? This really needs a resolution, it's not acceptable to have to drop down to CreateProcess. |
The new link is at https://docs.microsoft.com/en-gb/archive/blogs/twistylittlepassagesallalike/everyone-quotes-command-line-arguments-the-wrong-way.
How exactly is it wrong? This appears to be a pretty good inverse of the function as implemented in .NET CoreFX. There are two caveats though:
(Yeah, the "better method" in this article is pretty verbose if you consider the workaround from 1. I generally just do a JS one-liner of Anyway, this blog code is what process::sys(windows)::Command does. It seems fine. There is another reason for a raw command-line thing that many people might be more familiar with: Cygwin. Cygwin and MSYS2 ship an incompatible command-line parser in their dcrt0.cc, and I don't think I need to explain how common these things are these days. If you want to interface with, say, Git for Windows correctly, you gotta escape the strings differently. |
I'd like something like
|
This should not be named as such for our CreateProcess-based invocation, since it does not really make it less safe than the default escape. We are not escaping for cmd, which actually has metacharacters for pipes and semicolons.
No. There is a DOS-inherited cmd-ism here, but it is exclusively for internal commands. See https://stackoverflow.com/questions/4094699/how-does-the-windows-command-interpreter-cmd-exe-parse-scripts. The CreateProcess documentation only mentions using spaces to tokenize when the file argument is null.
Maybe, with some big warnings about non-generality preferably. The argv[0] will almost always need quoting. Doing this does raise the question of how many kinds of helpers are supposed to be in stdlib though. |
Specifying an arbitrary command line should be completely safe. The only way you could cause unsound behavior is if the spawned process has a bug in its command line parser, which isn't Rust's problem. Just add a windows specific method to let users specify the full command line themselves, and that's all |
But it should be noted that Python solves this differently!
On Unix, this just passes the argument-array as-is. On Windows, this constructs a single command-line string with the "inverse of CommandLineToArgvW" rules. As such, just like Rust's implementation, this works in a cross-platform manner for most Windows programs, with the notable exception of But Python also has:
On Unix, this runs Having a "run command-line in shell" function nicely abstracts away this weirdness. If Rust had this (e.g. via a |
My take 2 of the raw_arg and sized arg PR is still available. A recent rebase broke some macro invocation though. |
Unescaped command-line arguments for Windows Some Windows commands, expecially `cmd.exe /c`, have unusual quoting requirements which are incompatible with default rules assumed for `.arg()`. This adds `.unquoted_arg()` to `Command` via Windows `CommandExt` trait. Fixes rust-lang#29494
It's here! https://doc.rust-lang.org/nightly/std/process/struct.Command.html#method.raw_arg Now it's a good time to bikeshed the name. Is I've tried Maybe literal? Hopefully won't be confused with string literals :/ |
Hmm. That's one thing to split off from #82930. |
Tracking issue for stabilizing the fix to this #92939 |
Summary: The `cmd.exe` does not use the "common" argv[] parsing [1] [2]. For example, the Rust code: Command::new("cmd.exe").arg("/c").arg(r#"notepad "a b.txt"#) will execute (Windows OS command line, as a single string): cmd.exe /c "notepad \"a b.txt\"" which will execute: notepad \"a b.txt\" and notepad will complain that the file cannot be found. To fix it we need to pass the unquoted command and execute either: cmd.exe /c "notepad "a b.txt"" cmd.exe /c notepad "a b.txt" which will execute: notepad "a b.txt" See also rust-lang/rust#29494. [1]: https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw [2]: https://learn.microsoft.com/en-us/cpp/c-language/parsing-c-command-line-arguments Reviewed By: zzl0 Differential Revision: D47242639 fbshipit-source-id: c75aa83430520c29002a095333546cc48695244e
Currently the windows implementation of Command will automatically attempt to escape arguments before concatenating them into a single command line string to be passed to CreateProcess. However, the escaping method used doesn't work for many windows command-line tools, including
cmd
,msiexec
and others.As an example, it is impossible to specify arguments like this:
ARG="some parameter with spaces"
because Command will try to quote the entire thing, whereas msiexec expects only the value to be quoted.
What's required is a way to pass arguments through unchanged: I suggest an
arg_raw
orarg_unescaped
method be added to Command. This function can either be a windows-specific extension, or a no-op on other platforms. The advantage of the latter is that it avoids the need tocfg
out code that relies on it at compile time.The text was updated successfully, but these errors were encountered: