diff options
author | Simon Tatham <simon.tatham@arm.com> | 2022-05-03 10:33:11 +0100 |
---|---|---|
committer | Simon Tatham <simon.tatham@arm.com> | 2022-05-03 11:57:50 +0100 |
commit | 32814df442690d4673759296d850804773a7ea5b (patch) | |
tree | 9eda48776326782c9bd2daf68faac03289704213 /llvm/unittests/Support/CommandLineTest.cpp | |
parent | 1be024ee450f2d3cb07086f6141d50f291c1910b (diff) | |
download | llvm-32814df442690d4673759296d850804773a7ea5b.zip llvm-32814df442690d4673759296d850804773a7ea5b.tar.gz llvm-32814df442690d4673759296d850804773a7ea5b.tar.bz2 |
[Windows] Fix handling of \" in program name on cmd line.
Bugzilla #47579: if you invoke clang on Windows via a pathname in
which a quoted section closes just after a backslash, e.g.
"C:\Program Files\Whatever\"clang.exe
then cmd.exe and CreateProcess will correctly find the binary, because
when they parse the program name at the start of the command line,
they don't regard the \ before the " as having any kind of escaping
effect. This is different from the behaviour of the Windows standard C
library when it parses the rest of the command line, which would
consider that \" not to close the quoted string.
But this confuses windows::GetCommandLineArguments, because the
Windows API function GetCommandLineW() will return a command line
containing that \" sequence, and cl::TokenizeWindowsCommandLine will
tokenize the whole string according to the C library's rules. So it
will misidentify where the program name stops and the arguments start.
To fix this, I've introduced a new variant function
cl::TokenizeWindowsCommandLineFull(), intended to be applied to the
string returned from GetCommandLineW(). It parses the first word of
the command line according to CreateProcess's rules, considering \ to
never be an escaping character; thereafter, it switches over to the C
library rules for the rest of the command line.
Reviewed By: hans
Differential Revision: https://reviews.llvm.org/D122914
Diffstat (limited to 'llvm/unittests/Support/CommandLineTest.cpp')
-rw-r--r-- | llvm/unittests/Support/CommandLineTest.cpp | 18 |
1 files changed, 18 insertions, 0 deletions
diff --git a/llvm/unittests/Support/CommandLineTest.cpp b/llvm/unittests/Support/CommandLineTest.cpp index 7f751e5..ec9901a 100644 --- a/llvm/unittests/Support/CommandLineTest.cpp +++ b/llvm/unittests/Support/CommandLineTest.cpp @@ -257,6 +257,24 @@ TEST(CommandLineTest, TokenizeWindowsCommandLineQuotedLastArgument) { testCommandLineTokenizer(cl::TokenizeWindowsCommandLine, Input3, Output3); } +TEST(CommandLineTest, TokenizeWindowsCommandLineExeName) { + const char Input1[] = + R"("C:\Program Files\Whatever\"clang.exe z.c -DY=\"x\")"; + const char *const Output1[] = {"C:\\Program Files\\Whatever\\clang.exe", + "z.c", "-DY=\"x\""}; + testCommandLineTokenizer(cl::TokenizeWindowsCommandLineFull, Input1, Output1); + + const char Input2[] = "\"a\\\"b c\\\"d\n\"e\\\"f g\\\"h\n"; + const char *const Output2[] = {"a\\b", "c\"d", nullptr, + "e\\f", "g\"h", nullptr}; + testCommandLineTokenizer(cl::TokenizeWindowsCommandLineFull, Input2, Output2, + /*MarkEOLs=*/true); + + const char Input3[] = R"(\\server\share\subdir\clang.exe)"; + const char *const Output3[] = {"\\\\server\\share\\subdir\\clang.exe"}; + testCommandLineTokenizer(cl::TokenizeWindowsCommandLineFull, Input3, Output3); +} + TEST(CommandLineTest, TokenizeAndMarkEOLs) { // Clang uses EOL marking in response files to support options that consume // the rest of the arguments on the current line, but do not consume arguments |