Skip to content

Commit 67b804e

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

File tree

1 file changed

+145
-44
lines changed

1 file changed

+145
-44
lines changed

src/util/run.cpp

Lines changed: 145 additions & 44 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,82 @@ 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;
4578

46-
if(file.empty())
47-
return result_fd;
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
48117

49118
int flags = 0, mode = 0;
50119
std::string name;
@@ -68,12 +137,13 @@ static int stdio_redirection(int fd, const std::string &file)
68137
}
69138

70139
result_fd = open(file.c_str(), flags, mode);
140+
71141
if(result_fd == -1)
72142
perror(("Failed to open " + name + " file " + file).c_str());
143+
#endif
73144

74145
return result_fd;
75146
}
76-
#endif
77147

78148
#ifdef _WIN32
79149
// Read
@@ -140,56 +210,87 @@ int run(
140210
const std::string &std_output,
141211
const std::string &std_error)
142212
{
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())
213+
#ifdef _WIN32
214+
// unicode commandline, quoted
215+
std::wstring cmdline;
216+
217+
// we replace argv[0] by what
218+
cmdline = quote_windows_arg(widen(what));
219+
220+
for(std::size_t i = 1; i < argv.size(); i++)
146221
{
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");
222+
cmdline += L" ";
223+
cmdline += quote_windows_arg(widen(argv[i]));
224+
}
150225

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

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

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

169-
// this is recursive
170-
return run(new_argv[0], new_argv, "", "", "");
171-
}
234+
siStartInfo.hStdInput = stdio_redirection(STDIN_FILENO, std_input);
235+
siStartInfo.hStdOutput = stdio_redirection(STDOUT_FILENO, std_output);
236+
siStartInfo.hStdError = stdio_redirection(STDERR_FILENO, std_error);
237+
238+
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
239+
240+
// CreateProcessW wants to modify the command line
241+
std::vector<wchar_t> mutable_cmdline(cmdline.begin(), cmdline.end());
242+
mutable_cmdline.push_back(0); // zero termination
243+
wchar_t *cmdline_ptr = mutable_cmdline.data();
172244

173-
// unicode and whitespace-quoted version of the arguments
174-
std::vector<std::wstring> wargv;
245+
BOOL bSuccess = CreateProcessW(
246+
NULL, // application name
247+
cmdline_ptr, // command line
248+
NULL, // process security attributes
249+
NULL, // primary thread security attributes
250+
true, // handles are inherited
251+
0, // creation flags
252+
NULL, // use parent's environment
253+
NULL, // use parent's current directory
254+
&siStartInfo, // STARTUPINFO
255+
&piProcInfo); // PROCESS_INFORMATION
256+
257+
if(!bSuccess)
258+
{
259+
if(!std_input.empty())
260+
CloseHandle(siStartInfo.hStdInput);
261+
if(!std_output.empty())
262+
CloseHandle(siStartInfo.hStdOutput);
263+
if(!std_error.empty())
264+
CloseHandle(siStartInfo.hStdError);
265+
return -1;
266+
}
175267

176-
wargv.resize(argv.size());
268+
// wait for child to finish
269+
WaitForSingleObject(piProcInfo.hProcess, INFINITE);
177270

178-
for(std::size_t i=0; i<argv.size(); i++)
179-
wargv[i]=quote_windows_arg(widen(argv[i]));
271+
if(!std_input.empty())
272+
CloseHandle(siStartInfo.hStdInput);
273+
if(!std_output.empty())
274+
CloseHandle(siStartInfo.hStdOutput);
275+
if(!std_error.empty())
276+
CloseHandle(siStartInfo.hStdError);
180277

181-
std::vector<const wchar_t *> _argv(argv.size()+1);
278+
DWORD exit_code;
182279

183-
for(std::size_t i=0; i<wargv.size(); i++)
184-
_argv[i]=wargv[i].c_str();
280+
// get exit code
281+
if(!GetExitCodeProcess(piProcInfo.hProcess, &exit_code))
282+
{
283+
CloseHandle(piProcInfo.hProcess);
284+
CloseHandle(piProcInfo.hThread);
285+
return -1;
286+
}
185287

186-
_argv[argv.size()]=NULL;
288+
CloseHandle(piProcInfo.hProcess);
289+
CloseHandle(piProcInfo.hThread);
187290

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

192-
#else
293+
#else
193294
int stdin_fd = stdio_redirection(STDIN_FILENO, std_input);
194295
int stdout_fd = stdio_redirection(STDOUT_FILENO, std_output);
195296
int stderr_fd = stdio_redirection(STDERR_FILENO, std_error);
@@ -280,5 +381,5 @@ int run(
280381

281382
return 1;
282383
}
283-
#endif
384+
#endif
284385
}

0 commit comments

Comments
 (0)