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