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