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