Skip to content
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

Unescaped command-line arguments for Windows #85832

Merged
merged 4 commits into from
Jul 9, 2021
Merged

Conversation

kornelski
Copy link
Contributor

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 #29494

@rust-highfive
Copy link
Collaborator

r? @yaahc

(rust-highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label May 30, 2021
@kornelski
Copy link
Contributor Author

There's an existing unstable feature force_quotes() that is the opposite of this feature — used to quote args that have * which aren't quoted by default in .arg().

I went for .unquoted_arg() approach, because it's more flexible. A single .unquoted_arg() can be used to build an arbitrary command-line, but also can be mixed with regular .arg(), so that users who need only some arguments with special syntax don't have to reinvent their own quoting implementation for the rest (the escaping rules for Windows are very weird, so it's better not to have to do it).

I think .force_quotes(true) could be replaced by .quoted_arg(val) to have both features with consistent interface, but I'm leaving it out of scope of this PR.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@dgrunwald
Copy link
Contributor

I haven't tried this branch; but if I read the diff correctly, unquoted_arg will still perform escaping?
Quote::Never doesn't add quotes around the argument, but it still escapes those within the argument.

You don't have any test cases where escaping would trigger (only when the argument contains ").

@dgrunwald
Copy link
Contributor

Also, isn't there a bug where Quote::Auto ends up discarding trailing backslashes from the argument if the argument doesn't contain any whitespace?

@kornelski
Copy link
Contributor Author

I've disabled inner escaping for unquoted arg.

I haven't changed escaping logic. I think it's fine — the rules of CommandLineToArgvW that it uses are just very counter-intuitive.

@dgrunwald
Copy link
Contributor

Try a test case with Arg::Quoted(OsString::from("c:\\")), (without force_quotes).
I think it'll end up passing c: without the trailing backslash to the target program. That's because backslashes is non-zero at the end, but gets ignored when the if quote is not taken.

@yaahc
Copy link
Member

yaahc commented Jun 14, 2021

Why'd you go with calling it unquoted_arg instead of raw_arg as suggested in the source issue? To me the former implies that it would still do things other than quoting, such as escaping, where as the later makes it pretty clear to me that the arg is passed directly as is.

@kornelski
Copy link
Contributor Author

That's because I've noticed that there's force_quotes, and wanted to use a similar teminology. However, you're right that this makes escaping ambiguous. I've changed back to raw_arg

@yaahc
Copy link
Member

yaahc commented Jun 21, 2021

Try a test case with Arg::Quoted(OsString::from("c:\\")), (without force_quotes).
I think it'll end up passing c: without the trailing backslash to the target program. That's because backslashes is non-zero at the end, but gets ignored when the if quote is not taken.

@kornelski have you tried the test case suggested by @dgrunwald? I'm curious to know if this is an issue.

@bors
Copy link
Contributor

bors commented Jul 4, 2021

☔ The latest upstream changes (presumably #85270) made this pull request unmergeable. Please resolve the merge conflicts.

@kornelski kornelski force-pushed the raw_arg branch 2 times, most recently from 12dd7cb to f13bc8a Compare July 4, 2021 17:41
@kornelski
Copy link
Contributor Author

@yaahc I've added tests cases for the issue raised. They're fine, because escaping rules on Windows don't double the number of backslashes, only number of backslashes before a quote (the syntax is illogical like that by design).

@ChrisDenton
Copy link
Member

ChrisDenton commented Jul 5, 2021

To recap the default rules, a backslash is treated literally unless they are directly followed by a double quote. When a double quote is encountered the rules are:

  • Any directly preceding backslashes are counted (represented here by n).
    • If n is even then replace with n/2 backslashes and toggle "quote mode".
    • If n is odd then replace with (n-1)/2 backslashes and add a literal ".

For example, the string C:\Program Files\Rust can be encoded in an argument in several ways:

"C:\Program Files\Rust"
C:\"Program Files"\Rust
C:\"Program Files\\"Rust

These rules are based on the old 80's DOS shell and can't be changed too much due to backwards compatibility. However, some applications do use their own rules, hence the need for raw_arg.

@dgrunwald
Copy link
Contributor

I misread the code; I missed that the first copy of the \ is already inserted by the loop.
So the code works fine, but thanks for adding the test.

Yeah the rules are weird. Fun fact: the interpretation of double double-quotes "" is another (undocumented) special case where the behavior changed in the 2008 update of the Microsoft C runtime. But that doesn't matter for us as we never emit those. This site has the full story: http://daviddeley.com/autohotkey/parameters/parameters.htm#WINCRULES

@yaahc
Copy link
Member

yaahc commented Jul 6, 2021

Sounds like everyone is happy with the PR in it's current state ^_^

@bors r+

@bors bors added the S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. label Jul 8, 2021
@bors
Copy link
Contributor

bors commented Jul 9, 2021

⌛ Testing commit b86d121c3af1d82425074ae8c005fa96b824aa1d with merge 61e56dc608b0077df1cdc469c0eea3e9a72275ce...

@bors
Copy link
Contributor

bors commented Jul 9, 2021

💔 Test failed - checks-actions

@bors bors added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Jul 9, 2021
@rust-log-analyzer

This comment has been minimized.

@kornelski
Copy link
Contributor Author

I think mingw uses debug output in tests? I've changed debug output to look exactly like before, and rebased.

I can't test mingw, because I don't know how to make x.py use it instead of msvc.

@yaahc
Copy link
Member

yaahc commented Jul 9, 2021

I'm not really familiar with windows at all so I can't really help with the mingw/msvc setup. For now though I can delegate bors permissions so you can restart the build as needed

@bors delegate+
@bors r+

@bors
Copy link
Contributor

bors commented Jul 9, 2021

✌️ @kornelski can now approve this pull request

@bors
Copy link
Contributor

bors commented Jul 9, 2021

📌 Commit bc67f6b has been approved by yaahc

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 9, 2021
@bors
Copy link
Contributor

bors commented Jul 9, 2021

⌛ Testing commit bc67f6b with merge 3eff244...

@bors
Copy link
Contributor

bors commented Jul 9, 2021

☀️ Test successful - checks-actions
Approved by: yaahc
Pushing 3eff244 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Jul 9, 2021
@bors bors merged commit 3eff244 into rust-lang:master Jul 9, 2021
@rustbot rustbot added this to the 1.55.0 milestone Jul 9, 2021
@kornelski kornelski deleted the raw_arg branch July 9, 2021 22:17
@Xaeroxe
Copy link
Contributor

Xaeroxe commented Jan 14, 2022

What's the path for stabilizing this feature? The unstable attribute for it doesn't point at a tracking issue.

@kornelski
Copy link
Contributor Author

@Xaeroxe There haven't been any objections to this feature, so I think you could make a tracking issue and make a PR to stabilize this feature.

@Xaeroxe
Copy link
Contributor

Xaeroxe commented Jan 15, 2022

Tracking issue: #92939

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merged-by-bors This PR was explicitly merged by bors. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Command does not escape arguments as expected on windows
10 participants