Skip to content

Commit fd9e35c

Browse files
author
Daniel Kroening
committed
replace _wspawnvp() by CreateProcessW()
1 parent 3095fc8 commit fd9e35c

File tree

1 file changed

+147
-43
lines changed

1 file changed

+147
-43
lines changed

src/util/run.cpp

Lines changed: 147 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Date: August 2012
1212

1313
#ifdef _WIN32
1414
#include <process.h>
15+
#include <windows.h>
1516
#else
1617

1718
#include <cstring>
@@ -37,14 +38,85 @@ int run(const std::string &what, const std::vector<std::string> &argv)
3738
return run(what, argv, "", "", "");
3839
}
3940

40-
#ifndef _WIN32
41+
#ifdef _WIN32
42+
#define STDIN_FILENO 0
43+
#define STDOUT_FILENO 1
44+
#define STDERR_FILENO 2
45+
using fdt = HANDLE;
46+
#else
47+
using fdt = int;
48+
#endif
49+
4150
/// open given file to replace either stdin, stderr, stdout
42-
static int stdio_redirection(int fd, const std::string &file)
51+
static fdt stdio_redirection(int fd, const std::string &file)
4352
{
44-
int result_fd = fd;
53+
fdt result_fd;
54+
55+
#ifdef _WIN32
56+
std::string name;
57+
58+
SECURITY_ATTRIBUTES SecurityAttributes;
59+
ZeroMemory(&SecurityAttributes, sizeof SecurityAttributes);
60+
SecurityAttributes.bInheritHandle = true;
61+
62+
switch(fd)
63+
{
64+
case STDIN_FILENO:
65+
name = "stdin";
66+
if(file.empty())
67+
result_fd = GetStdHandle(STD_INPUT_HANDLE);
68+
else
69+
result_fd = CreateFileW(
70+
widen(file).c_str(),
71+
GENERIC_READ,
72+
0,
73+
&SecurityAttributes,
74+
OPEN_EXISTING,
75+
FILE_ATTRIBUTE_READONLY,
76+
NULL);
77+
break;
78+
79+
case STDOUT_FILENO:
80+
name = "stdout";
81+
if(file.empty())
82+
result_fd = GetStdHandle(STD_OUTPUT_HANDLE);
83+
else
84+
result_fd = CreateFileW(
85+
widen(file).c_str(),
86+
GENERIC_WRITE,
87+
0,
88+
&SecurityAttributes,
89+
CREATE_ALWAYS,
90+
FILE_ATTRIBUTE_NORMAL,
91+
NULL);
92+
break;
93+
94+
case STDERR_FILENO:
95+
name = "stderr";
96+
if(file.empty())
97+
result_fd = GetStdHandle(STD_ERROR_HANDLE);
98+
else
99+
result_fd = CreateFileW(
100+
widen(file).c_str(),
101+
GENERIC_WRITE,
102+
0,
103+
&SecurityAttributes,
104+
CREATE_ALWAYS,
105+
FILE_ATTRIBUTE_NORMAL,
106+
NULL);
107+
break;
108+
109+
default:
110+
UNREACHABLE;
111+
}
112+
113+
if(result_fd == INVALID_HANDLE_VALUE)
114+
perror(("Failed to open " + name + " file " + file).c_str());
115+
116+
#else
45117

46118
if(file.empty())
47-
return result_fd;
119+
return fd;
48120

49121
int flags = 0, mode = 0;
50122
std::string name;
@@ -68,12 +140,13 @@ static int stdio_redirection(int fd, const std::string &file)
68140
}
69141

70142
result_fd = open(file.c_str(), flags, mode);
143+
71144
if(result_fd == -1)
72145
perror(("Failed to open " + name + " file " + file).c_str());
146+
#endif
73147

74148
return result_fd;
75149
}
76-
#endif
77150

78151
#ifdef _WIN32
79152
// Read
@@ -140,56 +213,87 @@ int run(
140213
const std::string &std_output,
141214
const std::string &std_error)
142215
{
143-
#ifdef _WIN32
144-
// we use the cmd.exe shell to do stdin/stdout/stderr redirection on Windows
145-
if(!std_input.empty() || !std_output.empty() || !std_error.empty())
216+
#ifdef _WIN32
217+
// unicode commandline, quoted
218+
std::wstring cmdline;
219+
220+
// we replace argv[0] by what
221+
cmdline = quote_windows_arg(widen(what));
222+
223+
for(std::size_t i = 1; i < argv.size(); i++)
146224
{
147-
std::vector<std::string> new_argv = argv;
148-
new_argv.insert(new_argv.begin(), "cmd.exe");
149-
new_argv.insert(new_argv.begin() + 1, "/c");
225+
cmdline += L" ";
226+
cmdline += quote_windows_arg(widen(argv[i]));
227+
}
150228

151-
if(!std_input.empty())
152-
{
153-
new_argv.push_back("<");
154-
new_argv.push_back(std_input);
155-
}
229+
PROCESS_INFORMATION piProcInfo;
230+
STARTUPINFOW siStartInfo;
156231

157-
if(!std_output.empty())
158-
{
159-
new_argv.push_back(">");
160-
new_argv.push_back(std_output);
161-
}
232+
ZeroMemory(&piProcInfo, sizeof piProcInfo);
233+
ZeroMemory(&siStartInfo, sizeof siStartInfo);
162234

163-
if(!std_error.empty())
164-
{
165-
new_argv.push_back("2>");
166-
new_argv.push_back(std_error);
167-
}
235+
siStartInfo.cb = sizeof siStartInfo;
168236

169-
// this is recursive
170-
return run(new_argv[0], new_argv, "", "", "");
171-
}
237+
siStartInfo.hStdInput = stdio_redirection(STDIN_FILENO, std_input);
238+
siStartInfo.hStdOutput = stdio_redirection(STDOUT_FILENO, std_output);
239+
siStartInfo.hStdError = stdio_redirection(STDERR_FILENO, std_error);
172240

173-
// unicode and whitespace-quoted version of the arguments
174-
std::vector<std::wstring> wargv;
241+
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
175242

176-
wargv.resize(argv.size());
243+
// CreateProcessW wants to modify the command line
244+
std::vector<wchar_t> mutable_cmdline(cmdline.begin(), cmdline.end());
245+
mutable_cmdline.push_back(0); // zero termination
246+
wchar_t *cmdline_ptr = mutable_cmdline.data();
177247

178-
for(std::size_t i=0; i<argv.size(); i++)
179-
wargv[i]=quote_windows_arg(widen(argv[i]));
248+
BOOL bSuccess = CreateProcessW(
249+
NULL, // application name
250+
cmdline_ptr, // command line
251+
NULL, // process security attributes
252+
NULL, // primary thread security attributes
253+
true, // handles are inherited
254+
0, // creation flags
255+
NULL, // use parent's environment
256+
NULL, // use parent's current directory
257+
&siStartInfo, // STARTUPINFO
258+
&piProcInfo); // PROCESS_INFORMATION
180259

181-
std::vector<const wchar_t *> _argv(argv.size()+1);
260+
if(!bSuccess)
261+
{
262+
if(!std_input.empty())
263+
CloseHandle(siStartInfo.hStdInput);
264+
if(!std_output.empty())
265+
CloseHandle(siStartInfo.hStdOutput);
266+
if(!std_error.empty())
267+
CloseHandle(siStartInfo.hStdError);
268+
return -1;
269+
}
182270

183-
for(std::size_t i=0; i<wargv.size(); i++)
184-
_argv[i]=wargv[i].c_str();
271+
// wait for child to finish
272+
WaitForSingleObject(piProcInfo.hProcess, INFINITE);
185273

186-
_argv[argv.size()]=NULL;
274+
if(!std_input.empty())
275+
CloseHandle(siStartInfo.hStdInput);
276+
if(!std_output.empty())
277+
CloseHandle(siStartInfo.hStdOutput);
278+
if(!std_error.empty())
279+
CloseHandle(siStartInfo.hStdError);
187280

188-
std::wstring wide_what=widen(what);
189-
int status=_wspawnvp(_P_WAIT, wide_what.c_str(), _argv.data());
190-
return status;
281+
DWORD exit_code;
191282

192-
#else
283+
// get exit code
284+
if(!GetExitCodeProcess(piProcInfo.hProcess, &exit_code))
285+
{
286+
CloseHandle(piProcInfo.hProcess);
287+
CloseHandle(piProcInfo.hThread);
288+
return -1;
289+
}
290+
291+
CloseHandle(piProcInfo.hProcess);
292+
CloseHandle(piProcInfo.hThread);
293+
294+
return exit_code;
295+
296+
#else
193297
int stdin_fd = stdio_redirection(STDIN_FILENO, std_input);
194298
int stdout_fd = stdio_redirection(STDOUT_FILENO, std_output);
195299
int stderr_fd = stdio_redirection(STDERR_FILENO, std_error);
@@ -280,5 +384,5 @@ int run(
280384

281385
return 1;
282386
}
283-
#endif
387+
#endif
284388
}

0 commit comments

Comments
 (0)