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