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