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