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