Skip to content

Commit 3095fc8

Browse files
author
Daniel Kroening
committed
run(): whitespace quoting for windows
1 parent 946abb8 commit 3095fc8

File tree

1 file changed

+60
-6
lines changed

1 file changed

+60
-6
lines changed

src/util/run.cpp

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,64 @@ static int stdio_redirection(int fd, const std::string &file)
7575
}
7676
#endif
7777

78+
#ifdef _WIN32
79+
// Read
80+
// https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/
81+
std::wstring quote_windows_arg(const std::wstring &src)
82+
{
83+
if(src.find_first_of(L" \t\n\v\"") == src.npos)
84+
return src;
85+
86+
std::wstring result = L"\"";
87+
88+
for(auto it = src.begin();; ++it)
89+
{
90+
std::size_t NumberBackslashes = 0;
91+
92+
while(it != src.end() && *it == L'\\')
93+
{
94+
++it;
95+
++NumberBackslashes;
96+
}
97+
98+
if(it == src.end())
99+
{
100+
//
101+
// Escape all backslashes, but let the terminating
102+
// double quotation mark we add below be interpreted
103+
// as a metacharacter.
104+
//
105+
106+
result.append(NumberBackslashes * 2, L'\\');
107+
break;
108+
}
109+
else if(*it == L'"')
110+
{
111+
//
112+
// Escape all backslashes and the following
113+
// double quotation mark.
114+
//
115+
116+
result.append(NumberBackslashes * 2 + 1, L'\\');
117+
result.push_back(*it);
118+
}
119+
else
120+
{
121+
//
122+
// Backslashes aren't special here.
123+
//
124+
125+
result.append(NumberBackslashes, L'\\');
126+
result.push_back(*it);
127+
}
128+
}
129+
130+
result.push_back(L'"');
131+
132+
return result;
133+
}
134+
#endif
135+
78136
int run(
79137
const std::string &what,
80138
const std::vector<std::string> &argv,
@@ -112,13 +170,13 @@ int run(
112170
return run(new_argv[0], new_argv, "", "", "");
113171
}
114172

115-
// unicode version of the arguments
173+
// unicode and whitespace-quoted version of the arguments
116174
std::vector<std::wstring> wargv;
117175

118176
wargv.resize(argv.size());
119177

120178
for(std::size_t i=0; i<argv.size(); i++)
121-
wargv[i]=widen(argv[i]);
179+
wargv[i]=quote_windows_arg(widen(argv[i]));
122180

123181
std::vector<const wchar_t *> _argv(argv.size()+1);
124182

@@ -127,10 +185,6 @@ int run(
127185

128186
_argv[argv.size()]=NULL;
129187

130-
// warning: the arguments may still need escaping,
131-
// as windows will concatenate the argv strings back together,
132-
// separating them with spaces
133-
134188
std::wstring wide_what=widen(what);
135189
int status=_wspawnvp(_P_WAIT, wide_what.c_str(), _argv.data());
136190
return status;

0 commit comments

Comments
 (0)