1//===- Win32/Program.cpp - Win32 Program Implementation ------- -*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file provides the Win32 specific implementation of the Program class. 11// 12//===----------------------------------------------------------------------===// 13 14#include "WindowsSupport.h" 15#include "llvm/Support/FileSystem.h" 16#include <cstdio> 17#include <fcntl.h> 18#include <io.h> 19#include <malloc.h> 20 21//===----------------------------------------------------------------------===// 22//=== WARNING: Implementation here must contain only Win32 specific code 23//=== and must not be UNIX code 24//===----------------------------------------------------------------------===// 25 26namespace llvm { 27using namespace sys; 28 29ProcessInfo::ProcessInfo() : ProcessHandle(0), Pid(0), ReturnCode(0) {} 30 31// This function just uses the PATH environment variable to find the program. 32std::string sys::FindProgramByName(const std::string &progName) { 33 // Check some degenerate cases 34 if (progName.length() == 0) // no program 35 return ""; 36 std::string temp = progName; 37 // Return paths with slashes verbatim. 38 if (progName.find('\\') != std::string::npos || 39 progName.find('/') != std::string::npos) 40 return temp; 41 42 // At this point, the file name is valid and does not contain slashes. 43 // Let Windows search for it. 44 SmallVector<wchar_t, MAX_PATH> progNameUnicode; 45 if (windows::UTF8ToUTF16(progName, progNameUnicode)) 46 return ""; 47 48 SmallVector<wchar_t, MAX_PATH> buffer; 49 DWORD len = MAX_PATH; 50 do { 51 buffer.reserve(len); 52 len = ::SearchPathW(NULL, progNameUnicode.data(), L".exe", 53 buffer.capacity(), buffer.data(), NULL); 54 55 // See if it wasn't found. 56 if (len == 0) 57 return ""; 58 59 // Buffer was too small; grow and retry. 60 } while (len > buffer.capacity()); 61 62 buffer.set_size(len); 63 SmallVector<char, MAX_PATH> result; 64 if (windows::UTF16ToUTF8(buffer.begin(), buffer.size(), result)) 65 return ""; 66 67 return std::string(result.data(), result.size()); 68} 69 70static HANDLE RedirectIO(const StringRef *path, int fd, std::string* ErrMsg) { 71 HANDLE h; 72 if (path == 0) { 73 if (!DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd), 74 GetCurrentProcess(), &h, 75 0, TRUE, DUPLICATE_SAME_ACCESS)) 76 return INVALID_HANDLE_VALUE; 77 return h; 78 } 79 80 std::string fname; 81 if (path->empty()) 82 fname = "NUL"; 83 else 84 fname = *path; 85 86 SECURITY_ATTRIBUTES sa; 87 sa.nLength = sizeof(sa); 88 sa.lpSecurityDescriptor = 0; 89 sa.bInheritHandle = TRUE; 90 91 SmallVector<wchar_t, 128> fnameUnicode; 92 if (windows::UTF8ToUTF16(fname, fnameUnicode)) 93 return INVALID_HANDLE_VALUE; 94 95 h = CreateFileW(fnameUnicode.data(), fd ? GENERIC_WRITE : GENERIC_READ, 96 FILE_SHARE_READ, &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS, 97 FILE_ATTRIBUTE_NORMAL, NULL); 98 if (h == INVALID_HANDLE_VALUE) { 99 MakeErrMsg(ErrMsg, std::string(fname) + ": Can't open file for " + 100 (fd ? "input: " : "output: ")); 101 } 102 103 return h; 104} 105 106/// ArgNeedsQuotes - Check whether argument needs to be quoted when calling 107/// CreateProcess. 108static bool ArgNeedsQuotes(const char *Str) { 109 return Str[0] == '\0' || strpbrk(Str, "\t \"&\'()*<>\\`^|") != 0; 110} 111 112/// CountPrecedingBackslashes - Returns the number of backslashes preceding Cur 113/// in the C string Start. 114static unsigned int CountPrecedingBackslashes(const char *Start, 115 const char *Cur) { 116 unsigned int Count = 0; 117 --Cur; 118 while (Cur >= Start && *Cur == '\\') { 119 ++Count; 120 --Cur; 121 } 122 return Count; 123} 124 125/// EscapePrecedingEscapes - Append a backslash to Dst for every backslash 126/// preceding Cur in the Start string. Assumes Dst has enough space. 127static char *EscapePrecedingEscapes(char *Dst, const char *Start, 128 const char *Cur) { 129 unsigned PrecedingEscapes = CountPrecedingBackslashes(Start, Cur); 130 while (PrecedingEscapes > 0) { 131 *Dst++ = '\\'; 132 --PrecedingEscapes; 133 } 134 return Dst; 135} 136 137/// ArgLenWithQuotes - Check whether argument needs to be quoted when calling 138/// CreateProcess and returns length of quoted arg with escaped quotes 139static unsigned int ArgLenWithQuotes(const char *Str) { 140 const char *Start = Str; 141 bool Quoted = ArgNeedsQuotes(Str); 142 unsigned int len = Quoted ? 2 : 0; 143 144 while (*Str != '\0') { 145 if (*Str == '\"') { 146 // We need to add a backslash, but ensure that it isn't escaped. 147 unsigned PrecedingEscapes = CountPrecedingBackslashes(Start, Str); 148 len += PrecedingEscapes + 1; 149 } 150 // Note that we *don't* need to escape runs of backslashes that don't 151 // precede a double quote! See MSDN: 152 // http://msdn.microsoft.com/en-us/library/17w5ykft%28v=vs.85%29.aspx 153 154 ++len; 155 ++Str; 156 } 157 158 if (Quoted) { 159 // Make sure the closing quote doesn't get escaped by a trailing backslash. 160 unsigned PrecedingEscapes = CountPrecedingBackslashes(Start, Str); 161 len += PrecedingEscapes + 1; 162 } 163 164 return len; 165} 166 167} 168 169static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, 170 const char **envp, const StringRef **redirects, 171 unsigned memoryLimit, std::string *ErrMsg) { 172 if (!sys::fs::can_execute(Program)) { 173 if (ErrMsg) 174 *ErrMsg = "program not executable"; 175 return false; 176 } 177 178 // Windows wants a command line, not an array of args, to pass to the new 179 // process. We have to concatenate them all, while quoting the args that 180 // have embedded spaces (or are empty). 181 182 // First, determine the length of the command line. 183 unsigned len = 0; 184 for (unsigned i = 0; args[i]; i++) { 185 len += ArgLenWithQuotes(args[i]) + 1; 186 } 187 188 // Now build the command line. 189 std::unique_ptr<char[]> command(new char[len+1]); 190 char *p = command.get(); 191 192 for (unsigned i = 0; args[i]; i++) { 193 const char *arg = args[i]; 194 const char *start = arg; 195 196 bool needsQuoting = ArgNeedsQuotes(arg); 197 if (needsQuoting) 198 *p++ = '"'; 199 200 while (*arg != '\0') { 201 if (*arg == '\"') { 202 // Escape all preceding escapes (if any), and then escape the quote. 203 p = EscapePrecedingEscapes(p, start, arg); 204 *p++ = '\\'; 205 } 206 207 *p++ = *arg++; 208 } 209 210 if (needsQuoting) { 211 // Make sure our quote doesn't get escaped by a trailing backslash. 212 p = EscapePrecedingEscapes(p, start, arg); 213 *p++ = '"'; 214 } 215 *p++ = ' '; 216 } 217 218 *p = 0; 219 220 // The pointer to the environment block for the new process. 221 std::vector<wchar_t> EnvBlock; 222 223 if (envp) { 224 // An environment block consists of a null-terminated block of 225 // null-terminated strings. Convert the array of environment variables to 226 // an environment block by concatenating them. 227 for (unsigned i = 0; envp[i]; ++i) { 228 SmallVector<wchar_t, MAX_PATH> EnvString; 229 if (std::error_code ec = windows::UTF8ToUTF16(envp[i], EnvString)) { 230 SetLastError(ec.value()); 231 MakeErrMsg(ErrMsg, "Unable to convert environment variable to UTF-16"); 232 return false; 233 } 234 235 EnvBlock.insert(EnvBlock.end(), EnvString.begin(), EnvString.end()); 236 EnvBlock.push_back(0); 237 } 238 EnvBlock.push_back(0); 239 } 240 241 // Create a child process. 242 STARTUPINFOW si; 243 memset(&si, 0, sizeof(si)); 244 si.cb = sizeof(si); 245 si.hStdInput = INVALID_HANDLE_VALUE; 246 si.hStdOutput = INVALID_HANDLE_VALUE; 247 si.hStdError = INVALID_HANDLE_VALUE; 248 249 if (redirects) { 250 si.dwFlags = STARTF_USESTDHANDLES; 251 252 si.hStdInput = RedirectIO(redirects[0], 0, ErrMsg); 253 if (si.hStdInput == INVALID_HANDLE_VALUE) { 254 MakeErrMsg(ErrMsg, "can't redirect stdin"); 255 return false; 256 } 257 si.hStdOutput = RedirectIO(redirects[1], 1, ErrMsg); 258 if (si.hStdOutput == INVALID_HANDLE_VALUE) { 259 CloseHandle(si.hStdInput); 260 MakeErrMsg(ErrMsg, "can't redirect stdout"); 261 return false; 262 } 263 if (redirects[1] && redirects[2] && *(redirects[1]) == *(redirects[2])) { 264 // If stdout and stderr should go to the same place, redirect stderr 265 // to the handle already open for stdout. 266 if (!DuplicateHandle(GetCurrentProcess(), si.hStdOutput, 267 GetCurrentProcess(), &si.hStdError, 268 0, TRUE, DUPLICATE_SAME_ACCESS)) { 269 CloseHandle(si.hStdInput); 270 CloseHandle(si.hStdOutput); 271 MakeErrMsg(ErrMsg, "can't dup stderr to stdout"); 272 return false; 273 } 274 } else { 275 // Just redirect stderr 276 si.hStdError = RedirectIO(redirects[2], 2, ErrMsg); 277 if (si.hStdError == INVALID_HANDLE_VALUE) { 278 CloseHandle(si.hStdInput); 279 CloseHandle(si.hStdOutput); 280 MakeErrMsg(ErrMsg, "can't redirect stderr"); 281 return false; 282 } 283 } 284 } 285 286 PROCESS_INFORMATION pi; 287 memset(&pi, 0, sizeof(pi)); 288 289 fflush(stdout); 290 fflush(stderr); 291 292 SmallVector<wchar_t, MAX_PATH> ProgramUtf16; 293 if (std::error_code ec = windows::UTF8ToUTF16(Program, ProgramUtf16)) { 294 SetLastError(ec.value()); 295 MakeErrMsg(ErrMsg, 296 std::string("Unable to convert application name to UTF-16")); 297 return false; 298 } 299 300 SmallVector<wchar_t, MAX_PATH> CommandUtf16; 301 if (std::error_code ec = windows::UTF8ToUTF16(command.get(), CommandUtf16)) { 302 SetLastError(ec.value()); 303 MakeErrMsg(ErrMsg, 304 std::string("Unable to convert command-line to UTF-16")); 305 return false; 306 } 307 308 BOOL rc = CreateProcessW(ProgramUtf16.data(), CommandUtf16.data(), 0, 0, 309 TRUE, CREATE_UNICODE_ENVIRONMENT, 310 EnvBlock.empty() ? 0 : EnvBlock.data(), 0, &si, 311 &pi); 312 DWORD err = GetLastError(); 313 314 // Regardless of whether the process got created or not, we are done with 315 // the handles we created for it to inherit. 316 CloseHandle(si.hStdInput); 317 CloseHandle(si.hStdOutput); 318 CloseHandle(si.hStdError); 319 320 // Now return an error if the process didn't get created. 321 if (!rc) { 322 SetLastError(err); 323 MakeErrMsg(ErrMsg, std::string("Couldn't execute program '") + 324 Program.str() + "'"); 325 return false; 326 } 327 328 PI.Pid = pi.dwProcessId; 329 PI.ProcessHandle = pi.hProcess; 330 331 // Make sure these get closed no matter what. 332 ScopedCommonHandle hThread(pi.hThread); 333 334 // Assign the process to a job if a memory limit is defined. 335 ScopedJobHandle hJob; 336 if (memoryLimit != 0) { 337 hJob = CreateJobObjectW(0, 0); 338 bool success = false; 339 if (hJob) { 340 JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli; 341 memset(&jeli, 0, sizeof(jeli)); 342 jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY; 343 jeli.ProcessMemoryLimit = uintptr_t(memoryLimit) * 1048576; 344 if (SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, 345 &jeli, sizeof(jeli))) { 346 if (AssignProcessToJobObject(hJob, pi.hProcess)) 347 success = true; 348 } 349 } 350 if (!success) { 351 SetLastError(GetLastError()); 352 MakeErrMsg(ErrMsg, std::string("Unable to set memory limit")); 353 TerminateProcess(pi.hProcess, 1); 354 WaitForSingleObject(pi.hProcess, INFINITE); 355 return false; 356 } 357 } 358 359 return true; 360} 361 362namespace llvm { 363ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, 364 bool WaitUntilChildTerminates, std::string *ErrMsg) { 365 assert(PI.Pid && "invalid pid to wait on, process not started?"); 366 assert(PI.ProcessHandle && 367 "invalid process handle to wait on, process not started?"); 368 DWORD milliSecondsToWait = 0; 369 if (WaitUntilChildTerminates) 370 milliSecondsToWait = INFINITE; 371 else if (SecondsToWait > 0) 372 milliSecondsToWait = SecondsToWait * 1000; 373 374 ProcessInfo WaitResult = PI; 375 DWORD WaitStatus = WaitForSingleObject(PI.ProcessHandle, milliSecondsToWait); 376 if (WaitStatus == WAIT_TIMEOUT) { 377 if (SecondsToWait) { 378 if (!TerminateProcess(PI.ProcessHandle, 1)) { 379 if (ErrMsg) 380 MakeErrMsg(ErrMsg, "Failed to terminate timed-out program."); 381 382 // -2 indicates a crash or timeout as opposed to failure to execute. 383 WaitResult.ReturnCode = -2; 384 CloseHandle(PI.ProcessHandle); 385 return WaitResult; 386 } 387 WaitForSingleObject(PI.ProcessHandle, INFINITE); 388 CloseHandle(PI.ProcessHandle); 389 } else { 390 // Non-blocking wait. 391 return ProcessInfo(); 392 } 393 } 394 395 // Get its exit status. 396 DWORD status; 397 BOOL rc = GetExitCodeProcess(PI.ProcessHandle, &status); 398 DWORD err = GetLastError(); 399 CloseHandle(PI.ProcessHandle); 400 401 if (!rc) { 402 SetLastError(err); 403 if (ErrMsg) 404 MakeErrMsg(ErrMsg, "Failed getting status for program."); 405 406 // -2 indicates a crash or timeout as opposed to failure to execute. 407 WaitResult.ReturnCode = -2; 408 return WaitResult; 409 } 410 411 if (!status) 412 return WaitResult; 413 414 // Pass 10(Warning) and 11(Error) to the callee as negative value. 415 if ((status & 0xBFFF0000U) == 0x80000000U) 416 WaitResult.ReturnCode = static_cast<int>(status); 417 else if (status & 0xFF) 418 WaitResult.ReturnCode = status & 0x7FFFFFFF; 419 else 420 WaitResult.ReturnCode = 1; 421 422 return WaitResult; 423} 424 425 std::error_code sys::ChangeStdinToBinary(){ 426 int result = _setmode( _fileno(stdin), _O_BINARY ); 427 if (result == -1) 428 return std::error_code(errno, std::generic_category()); 429 return std::error_code(); 430} 431 432 std::error_code sys::ChangeStdoutToBinary(){ 433 int result = _setmode( _fileno(stdout), _O_BINARY ); 434 if (result == -1) 435 return std::error_code(errno, std::generic_category()); 436 return std::error_code(); 437} 438 439bool llvm::sys::argumentsFitWithinSystemLimits(ArrayRef<const char*> Args) { 440 // The documented max length of the command line passed to CreateProcess. 441 static const size_t MaxCommandStringLength = 32768; 442 size_t ArgLength = 0; 443 for (ArrayRef<const char*>::iterator I = Args.begin(), E = Args.end(); 444 I != E; ++I) { 445 // Account for the trailing space for every arg but the last one and the 446 // trailing NULL of the last argument. 447 ArgLength += ArgLenWithQuotes(*I) + 1; 448 if (ArgLength > MaxCommandStringLength) { 449 return false; 450 } 451 } 452 return true; 453} 454} 455