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