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