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