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