Program.inc revision 845a932af74ecbd2a20af5751dd61fa8cf2246f5
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 130/// ArgLenWithQuotes - Check whether argument needs to be quoted when calling 131/// CreateProcess and returns length of quoted arg with escaped quotes 132static unsigned int ArgLenWithQuotes(const char *Str) { 133 unsigned int len = ArgNeedsQuotes(Str) ? 2 : 0; 134 135 while (*Str != '\0') { 136 if (*Str == '\"') 137 ++len; 138 139 ++len; 140 ++Str; 141 } 142 143 return len; 144} 145 146 147bool 148Program::Execute(const Path& path, 149 const char** args, 150 const char** envp, 151 const Path** redirects, 152 unsigned memoryLimit, 153 std::string* ErrMsg) { 154 if (Data_) { 155 Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_); 156 CloseHandle(wpi->hProcess); 157 delete wpi; 158 Data_ = 0; 159 } 160 161 if (!path.canExecute()) { 162 if (ErrMsg) 163 *ErrMsg = "program not executable"; 164 return false; 165 } 166 167 // Windows wants a command line, not an array of args, to pass to the new 168 // process. We have to concatenate them all, while quoting the args that 169 // have embedded spaces (or are empty). 170 171 // First, determine the length of the command line. 172 unsigned len = 0; 173 for (unsigned i = 0; args[i]; i++) { 174 len += ArgLenWithQuotes(args[i]) + 1; 175 } 176 177 // Now build the command line. 178 char *command = reinterpret_cast<char *>(_alloca(len+1)); 179 char *p = command; 180 181 for (unsigned i = 0; args[i]; i++) { 182 const char *arg = args[i]; 183 184 bool needsQuoting = ArgNeedsQuotes(arg); 185 if (needsQuoting) 186 *p++ = '"'; 187 188 while (*arg != '\0') { 189 if (*arg == '\"') 190 *p++ = '\\'; 191 192 *p++ = *arg++; 193 } 194 195 if (needsQuoting) 196 *p++ = '"'; 197 *p++ = ' '; 198 } 199 200 *p = 0; 201 202 // The pointer to the environment block for the new process. 203 char *envblock = 0; 204 205 if (envp) { 206 // An environment block consists of a null-terminated block of 207 // null-terminated strings. Convert the array of environment variables to 208 // an environment block by concatenating them. 209 210 // First, determine the length of the environment block. 211 len = 0; 212 for (unsigned i = 0; envp[i]; i++) 213 len += strlen(envp[i]) + 1; 214 215 // Now build the environment block. 216 envblock = reinterpret_cast<char *>(_alloca(len+1)); 217 p = envblock; 218 219 for (unsigned i = 0; envp[i]; i++) { 220 const char *ev = envp[i]; 221 size_t len = strlen(ev) + 1; 222 memcpy(p, ev, len); 223 p += len; 224 } 225 226 *p = 0; 227 } 228 229 // Create a child process. 230 STARTUPINFO si; 231 memset(&si, 0, sizeof(si)); 232 si.cb = sizeof(si); 233 si.hStdInput = INVALID_HANDLE_VALUE; 234 si.hStdOutput = INVALID_HANDLE_VALUE; 235 si.hStdError = INVALID_HANDLE_VALUE; 236 237 if (redirects) { 238 si.dwFlags = STARTF_USESTDHANDLES; 239 240 si.hStdInput = RedirectIO(redirects[0], 0, ErrMsg); 241 if (si.hStdInput == INVALID_HANDLE_VALUE) { 242 MakeErrMsg(ErrMsg, "can't redirect stdin"); 243 return false; 244 } 245 si.hStdOutput = RedirectIO(redirects[1], 1, ErrMsg); 246 if (si.hStdOutput == INVALID_HANDLE_VALUE) { 247 CloseHandle(si.hStdInput); 248 MakeErrMsg(ErrMsg, "can't redirect stdout"); 249 return false; 250 } 251 if (redirects[1] && redirects[2] && *(redirects[1]) == *(redirects[2])) { 252 // If stdout and stderr should go to the same place, redirect stderr 253 // to the handle already open for stdout. 254 DuplicateHandle(GetCurrentProcess(), si.hStdOutput, 255 GetCurrentProcess(), &si.hStdError, 256 0, TRUE, DUPLICATE_SAME_ACCESS); 257 } else { 258 // Just redirect stderr 259 si.hStdError = RedirectIO(redirects[2], 2, ErrMsg); 260 if (si.hStdError == INVALID_HANDLE_VALUE) { 261 CloseHandle(si.hStdInput); 262 CloseHandle(si.hStdOutput); 263 MakeErrMsg(ErrMsg, "can't redirect stderr"); 264 return false; 265 } 266 } 267 } 268 269 PROCESS_INFORMATION pi; 270 memset(&pi, 0, sizeof(pi)); 271 272 fflush(stdout); 273 fflush(stderr); 274 BOOL rc = CreateProcess(path.c_str(), command, NULL, NULL, TRUE, 0, 275 envblock, NULL, &si, &pi); 276 DWORD err = GetLastError(); 277 278 // Regardless of whether the process got created or not, we are done with 279 // the handles we created for it to inherit. 280 CloseHandle(si.hStdInput); 281 CloseHandle(si.hStdOutput); 282 CloseHandle(si.hStdError); 283 284 // Now return an error if the process didn't get created. 285 if (!rc) { 286 SetLastError(err); 287 MakeErrMsg(ErrMsg, std::string("Couldn't execute program '") + 288 path.str() + "'"); 289 return false; 290 } 291 Win32ProcessInfo* wpi = new Win32ProcessInfo; 292 wpi->hProcess = pi.hProcess; 293 wpi->dwProcessId = pi.dwProcessId; 294 Data_ = wpi; 295 296 // Make sure these get closed no matter what. 297 ScopedCommonHandle hThread(pi.hThread); 298 299 // Assign the process to a job if a memory limit is defined. 300 ScopedJobHandle hJob; 301 if (memoryLimit != 0) { 302 hJob = CreateJobObject(0, 0); 303 bool success = false; 304 if (hJob) { 305 JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli; 306 memset(&jeli, 0, sizeof(jeli)); 307 jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY; 308 jeli.ProcessMemoryLimit = uintptr_t(memoryLimit) * 1048576; 309 if (SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, 310 &jeli, sizeof(jeli))) { 311 if (AssignProcessToJobObject(hJob, pi.hProcess)) 312 success = true; 313 } 314 } 315 if (!success) { 316 SetLastError(GetLastError()); 317 MakeErrMsg(ErrMsg, std::string("Unable to set memory limit")); 318 TerminateProcess(pi.hProcess, 1); 319 WaitForSingleObject(pi.hProcess, INFINITE); 320 return false; 321 } 322 } 323 324 return true; 325} 326 327int 328Program::Wait(const Path &path, 329 unsigned secondsToWait, 330 std::string* ErrMsg) { 331 if (Data_ == 0) { 332 MakeErrMsg(ErrMsg, "Process not started!"); 333 return -1; 334 } 335 336 Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_); 337 HANDLE hProcess = wpi->hProcess; 338 339 // Wait for the process to terminate. 340 DWORD millisecondsToWait = INFINITE; 341 if (secondsToWait > 0) 342 millisecondsToWait = secondsToWait * 1000; 343 344 if (WaitForSingleObject(hProcess, millisecondsToWait) == WAIT_TIMEOUT) { 345 if (!TerminateProcess(hProcess, 1)) { 346 MakeErrMsg(ErrMsg, "Failed to terminate timed-out program."); 347 // -2 indicates a crash or timeout as opposed to failure to execute. 348 return -2; 349 } 350 WaitForSingleObject(hProcess, INFINITE); 351 } 352 353 // Get its exit status. 354 DWORD status; 355 BOOL rc = GetExitCodeProcess(hProcess, &status); 356 DWORD err = GetLastError(); 357 358 if (!rc) { 359 SetLastError(err); 360 MakeErrMsg(ErrMsg, "Failed getting status for program."); 361 // -2 indicates a crash or timeout as opposed to failure to execute. 362 return -2; 363 } 364 365 if (!status) 366 return 0; 367 368 // Pass 10(Warning) and 11(Error) to the callee as negative value. 369 if ((status & 0xBFFF0000U) == 0x80000000U) 370 return (int)status; 371 372 if (status & 0xFF) 373 return status & 0x7FFFFFFF; 374 375 return 1; 376} 377 378error_code Program::ChangeStdinToBinary(){ 379 int result = _setmode( _fileno(stdin), _O_BINARY ); 380 if (result == -1) 381 return error_code(errno, generic_category()); 382 return make_error_code(errc::success); 383} 384 385error_code Program::ChangeStdoutToBinary(){ 386 int result = _setmode( _fileno(stdout), _O_BINARY ); 387 if (result == -1) 388 return error_code(errno, generic_category()); 389 return make_error_code(errc::success); 390} 391 392error_code Program::ChangeStderrToBinary(){ 393 int result = _setmode( _fileno(stderr), _O_BINARY ); 394 if (result == -1) 395 return error_code(errno, generic_category()); 396 return make_error_code(errc::success); 397} 398 399bool llvm::sys::argumentsFitWithinSystemLimits(ArrayRef<const char*> Args) { 400 // The documented max length of the command line passed to CreateProcess. 401 static const size_t MaxCommandStringLength = 32768; 402 size_t ArgLength = 0; 403 for (ArrayRef<const char*>::iterator I = Args.begin(), E = Args.end(); 404 I != E; ++I) { 405 // Account for the trailing space for every arg but the last one and the 406 // trailing NULL of the last argument. 407 ArgLength += ArgLenWithQuotes(*I) + 1; 408 if (ArgLength > MaxCommandStringLength) { 409 return false; 410 } 411 } 412 return true; 413} 414 415} 416