Skip to content

Commit 7da3733

Browse files
committed
Fix win32 command-line quoting on rust_run_program.
1 parent 7c1d1d6 commit 7da3733

File tree

1 file changed

+62
-4
lines changed

1 file changed

+62
-4
lines changed

src/rt/rust_run_program.cpp

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,64 @@
55
#include <process.h>
66
#include <io.h>
77

8+
bool backslash_run_ends_in_quote(char const *c) {
9+
while (*c == '\\') ++c;
10+
return *c == '"';
11+
}
12+
13+
void append_first_char(char *&buf, char const *c) {
14+
switch (*c) {
15+
16+
case '"':
17+
// Escape quotes.
18+
*buf++ = '\\';
19+
*buf++ = '"';
20+
break;
21+
22+
23+
case '\\':
24+
if (backslash_run_ends_in_quote(c)) {
25+
// Double all backslashes that are in runs before quotes.
26+
*buf++ = '\\';
27+
*buf++ = '\\';
28+
} else {
29+
// Pass other backslashes through unescaped.
30+
*buf++ = '\\';
31+
}
32+
break;
33+
34+
default:
35+
*buf++ = *c;
36+
}
37+
}
38+
39+
bool contains_whitespace(char const *arg) {
40+
while (*arg) {
41+
switch (*arg++) {
42+
case ' ':
43+
case '\t':
44+
return true;
45+
}
46+
}
47+
return false;
48+
}
49+
50+
void append_arg(char *& buf, char const *arg, bool last) {
51+
bool quote = contains_whitespace(arg);
52+
if (quote)
53+
*buf++ = '"';
54+
while (*arg)
55+
append_first_char(buf, arg++);
56+
if (quote)
57+
*buf++ = '"';
58+
59+
if (! last) {
60+
*buf++ = ' ';
61+
} else {
62+
*buf++ = '\0';
63+
}
64+
}
65+
866
extern "C" CDECL int
967
rust_run_program(const char* argv[], int in_fd, int out_fd, int err_fd) {
1068
STARTUPINFO si;
@@ -29,14 +87,14 @@ rust_run_program(const char* argv[], int in_fd, int out_fd, int err_fd) {
2987
size_t cmd_len = 0;
3088
for (const char** arg = argv; *arg; arg++) {
3189
cmd_len += strlen(*arg);
32-
cmd_len++; // Space or \0
90+
cmd_len += 3; // Two quotes plus trailing space or \0
3391
}
92+
cmd_len *= 2; // Potentially backslash-escape everything.
93+
3494
char* cmd = (char*)malloc(cmd_len);
3595
char* pos = cmd;
3696
for (const char** arg = argv; *arg; arg++) {
37-
strcpy(pos, *arg);
38-
pos += strlen(*arg);
39-
if (*(arg+1)) *(pos++) = ' ';
97+
append_arg(pos, *arg, *(arg+1) == NULL);
4098
}
4199

42100
PROCESS_INFORMATION pi;

0 commit comments

Comments
 (0)