Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 38 additions & 26 deletions subprocess.h
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,7 @@ int subprocess_create_ex(const char *const commandLine[], int options,
int wide_len;
int i, j;
int need_quoting;
subprocess_size_t bs_run;
unsigned long flags = 0;
unsigned long last_error = 0;
int result = subprocess_error_unknown;
Expand Down Expand Up @@ -906,25 +907,29 @@ int subprocess_create_ex(const char *const commandLine[], int options,
len++;

// Quote the argument if it has a space in it
if (strpbrk(commandLine[i], "\t\v ") != SUBPROCESS_NULL ||
commandLine[i][0] == SUBPROCESS_NULL)
need_quoting = strpbrk(commandLine[i], "\t\v ") != SUBPROCESS_NULL ||
commandLine[i][0] == SUBPROCESS_NULL;
if (need_quoting)
len += 2;

bs_run = 0;
for (j = 0; '\0' != commandLine[i][j]; j++) {
switch (commandLine[i][j]) {
default:
break;
case '\\':
if (commandLine[i][j + 1] == '"') {
len++;
}
len++;

break;
case '"':
len++;
break;
if ('\\' == commandLine[i][j]) {
bs_run++;
} else {
if ('"' == commandLine[i][j]) {
// Duplicate the preceding run and escape the quote.
len += bs_run + 1;
}
bs_run = 0;
}
len++;
}

if (need_quoting) {
// Duplicate trailing slashes before the generated closing quote.
len += bs_run;
}
}

Expand All @@ -949,22 +954,29 @@ int subprocess_create_ex(const char *const commandLine[], int options,
commandLineCombined[len++] = '"';
}

for (j = 0; '\0' != commandLine[i][j]; j++) {
switch (commandLine[i][j]) {
default:
break;
case '\\':
if (commandLine[i][j + 1] == '"') {
commandLineCombined[len++] = '\\';
}
for (j = 0; '\0' != commandLine[i][j];) {
bs_run = 0;
while ('\\' == commandLine[i][j]) {
bs_run++;
j++;
}

if ('"' == commandLine[i][j]) {
// 2n + 1 slashes preserve n slashes and escape the quote.
bs_run = (bs_run * 2) + 1;
} else if ('\0' == commandLine[i][j] && need_quoting) {
// 2n slashes preserve n slashes before the closing quote.
bs_run *= 2;
}

break;
case '"':
while (bs_run > 0) {
commandLineCombined[len++] = '\\';
break;
bs_run--;
}

commandLineCombined[len++] = commandLine[i][j];
if ('\0' != commandLine[i][j]) {
commandLineCombined[len++] = commandLine[i][j++];
}
}
if (need_quoting) {
commandLineCombined[len++] = '"';
Expand Down
10 changes: 9 additions & 1 deletion test/process_return_special_argv.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,16 @@
#include <string.h>
int main(int argc, const char *const argv[]) {
unsigned int res = 0;
if (argc != 9) {
return 0;
}
res |= ((strcmp(argv[1], "foo\nbar") == 0) << 0);
res |= ((strcmp(argv[2], "\"baz\"") == 0) << 1);
res |= ((strcmp(argv[3], "faz\\\"faz") == 0) << 2);
res |= ((strcmp(argv[4], "a b\\") == 0) << 3);
res |= ((strcmp(argv[5], "foo\\\\\"bar") == 0) << 4);
res |= ((strcmp(argv[6], "a b\\\\") == 0) << 5);
res |= ((strcmp(argv[7], "a \\\\\"b") == 0) << 6);
res |= ((strcmp(argv[8], "after") == 0) << 7);
return (int)res;
}
}
12 changes: 10 additions & 2 deletions test/test_shared.h
Original file line number Diff line number Diff line change
Expand Up @@ -411,14 +411,22 @@ SUBPROCESS_TEST(create, subprocess_stderr_argv) {

SUBPROCESS_TEST(create, subprocess_return_special_argv) {
const char *const commandLine[] = {"./process_return_special_argv",
"foo\nbar", "\"baz\"", "faz\\\"faz", 0};
"foo\nbar",
"\"baz\"",
"faz\\\"faz",
"a b\\",
"foo\\\\\"bar",
"a b\\\\",
"a \\\\\"b",
"after",
0};
struct subprocess_s process;
int ret = -1;

ASSERT_EQ(0, subprocess_create(commandLine, 0, &process));
ASSERT_EQ(0, subprocess_join(&process, &ret));

ASSERT_EQ(7, ret); // 0b111
ASSERT_EQ(255, ret); // 0b11111111

ASSERT_EQ(0, subprocess_destroy(&process));
}
Expand Down