LLVM API Documentation

Windows/Program.inc
Go to the documentation of this file.
00001 //===- Win32/Program.cpp - Win32 Program Implementation ------- -*- C++ -*-===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This file provides the Win32 specific implementation of the Program class.
00011 //
00012 //===----------------------------------------------------------------------===//
00013 
00014 #include "WindowsSupport.h"
00015 #include "llvm/Support/ConvertUTF.h"
00016 #include "llvm/Support/FileSystem.h"
00017 #include "llvm/Support/raw_ostream.h"
00018 #include <cstdio>
00019 #include <fcntl.h>
00020 #include <io.h>
00021 #include <malloc.h>
00022 
00023 //===----------------------------------------------------------------------===//
00024 //=== WARNING: Implementation here must contain only Win32 specific code
00025 //===          and must not be UNIX code
00026 //===----------------------------------------------------------------------===//
00027 
00028 namespace llvm {
00029 using namespace sys;
00030 
00031 ProcessInfo::ProcessInfo() : ProcessHandle(0), Pid(0), ReturnCode(0) {}
00032 
00033 // This function just uses the PATH environment variable to find the program.
00034 std::string sys::FindProgramByName(const std::string &progName) {
00035   // Check some degenerate cases
00036   if (progName.length() == 0) // no program
00037     return "";
00038   std::string temp = progName;
00039   // Return paths with slashes verbatim.
00040   if (progName.find('\\') != std::string::npos ||
00041       progName.find('/') != std::string::npos)
00042     return temp;
00043 
00044   // At this point, the file name is valid and does not contain slashes.
00045   // Let Windows search for it.
00046   SmallVector<wchar_t, MAX_PATH> progNameUnicode;
00047   if (windows::UTF8ToUTF16(progName, progNameUnicode))
00048     return "";
00049 
00050   SmallVector<wchar_t, MAX_PATH> buffer;
00051   DWORD len = MAX_PATH;
00052   do {
00053     buffer.reserve(len);
00054     len = ::SearchPathW(NULL, progNameUnicode.data(), L".exe",
00055                         buffer.capacity(), buffer.data(), NULL);
00056 
00057     // See if it wasn't found.
00058     if (len == 0)
00059       return "";
00060 
00061     // Buffer was too small; grow and retry.
00062   } while (len > buffer.capacity());
00063 
00064   buffer.set_size(len);
00065   SmallVector<char, MAX_PATH> result;
00066   if (windows::UTF16ToUTF8(buffer.begin(), buffer.size(), result))
00067     return "";
00068 
00069   return std::string(result.data(), result.size());
00070 }
00071 
00072 static HANDLE RedirectIO(const StringRef *path, int fd, std::string* ErrMsg) {
00073   HANDLE h;
00074   if (path == 0) {
00075     if (!DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd),
00076                          GetCurrentProcess(), &h,
00077                          0, TRUE, DUPLICATE_SAME_ACCESS))
00078       return INVALID_HANDLE_VALUE;
00079     return h;
00080   }
00081 
00082   std::string fname;
00083   if (path->empty())
00084     fname = "NUL";
00085   else
00086     fname = *path;
00087 
00088   SECURITY_ATTRIBUTES sa;
00089   sa.nLength = sizeof(sa);
00090   sa.lpSecurityDescriptor = 0;
00091   sa.bInheritHandle = TRUE;
00092 
00093   SmallVector<wchar_t, 128> fnameUnicode;
00094   if (windows::UTF8ToUTF16(fname, fnameUnicode))
00095     return INVALID_HANDLE_VALUE;
00096 
00097   h = CreateFileW(fnameUnicode.data(), fd ? GENERIC_WRITE : GENERIC_READ,
00098                   FILE_SHARE_READ, &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS,
00099                   FILE_ATTRIBUTE_NORMAL, NULL);
00100   if (h == INVALID_HANDLE_VALUE) {
00101     MakeErrMsg(ErrMsg, std::string(fname) + ": Can't open file for " +
00102         (fd ? "input: " : "output: "));
00103   }
00104 
00105   return h;
00106 }
00107 
00108 /// ArgNeedsQuotes - Check whether argument needs to be quoted when calling
00109 /// CreateProcess.
00110 static bool ArgNeedsQuotes(const char *Str) {
00111   return Str[0] == '\0' || strpbrk(Str, "\t \"&\'()*<>\\`^|") != 0;
00112 }
00113 
00114 /// CountPrecedingBackslashes - Returns the number of backslashes preceding Cur
00115 /// in the C string Start.
00116 static unsigned int CountPrecedingBackslashes(const char *Start,
00117                                               const char *Cur) {
00118   unsigned int Count = 0;
00119   --Cur;
00120   while (Cur >= Start && *Cur == '\\') {
00121     ++Count;
00122     --Cur;
00123   }
00124   return Count;
00125 }
00126 
00127 /// EscapePrecedingEscapes - Append a backslash to Dst for every backslash
00128 /// preceding Cur in the Start string.  Assumes Dst has enough space.
00129 static char *EscapePrecedingEscapes(char *Dst, const char *Start,
00130                                     const char *Cur) {
00131   unsigned PrecedingEscapes = CountPrecedingBackslashes(Start, Cur);
00132   while (PrecedingEscapes > 0) {
00133     *Dst++ = '\\';
00134     --PrecedingEscapes;
00135   }
00136   return Dst;
00137 }
00138 
00139 /// ArgLenWithQuotes - Check whether argument needs to be quoted when calling
00140 /// CreateProcess and returns length of quoted arg with escaped quotes
00141 static unsigned int ArgLenWithQuotes(const char *Str) {
00142   const char *Start = Str;
00143   bool Quoted = ArgNeedsQuotes(Str);
00144   unsigned int len = Quoted ? 2 : 0;
00145 
00146   while (*Str != '\0') {
00147     if (*Str == '\"') {
00148       // We need to add a backslash, but ensure that it isn't escaped.
00149       unsigned PrecedingEscapes = CountPrecedingBackslashes(Start, Str);
00150       len += PrecedingEscapes + 1;
00151     }
00152     // Note that we *don't* need to escape runs of backslashes that don't
00153     // precede a double quote!  See MSDN:
00154     // http://msdn.microsoft.com/en-us/library/17w5ykft%28v=vs.85%29.aspx
00155 
00156     ++len;
00157     ++Str;
00158   }
00159 
00160   if (Quoted) {
00161     // Make sure the closing quote doesn't get escaped by a trailing backslash.
00162     unsigned PrecedingEscapes = CountPrecedingBackslashes(Start, Str);
00163     len += PrecedingEscapes + 1;
00164   }
00165 
00166   return len;
00167 }
00168 
00169 }
00170 
00171 static std::unique_ptr<char[]> flattenArgs(const char **args) {
00172   // First, determine the length of the command line.
00173   unsigned len = 0;
00174   for (unsigned i = 0; args[i]; i++) {
00175     len += ArgLenWithQuotes(args[i]) + 1;
00176   }
00177 
00178   // Now build the command line.
00179   std::unique_ptr<char[]> command(new char[len+1]);
00180   char *p = command.get();
00181 
00182   for (unsigned i = 0; args[i]; i++) {
00183     const char *arg = args[i];
00184     const char *start = arg;
00185 
00186     bool needsQuoting = ArgNeedsQuotes(arg);
00187     if (needsQuoting)
00188       *p++ = '"';
00189 
00190     while (*arg != '\0') {
00191       if (*arg == '\"') {
00192         // Escape all preceding escapes (if any), and then escape the quote.
00193         p = EscapePrecedingEscapes(p, start, arg);
00194         *p++ = '\\';
00195       }
00196 
00197       *p++ = *arg++;
00198     }
00199 
00200     if (needsQuoting) {
00201       // Make sure our quote doesn't get escaped by a trailing backslash.
00202       p = EscapePrecedingEscapes(p, start, arg);
00203       *p++ = '"';
00204     }
00205     *p++ = ' ';
00206   }
00207 
00208   *p = 0;
00209   return command;
00210 }
00211 
00212 static bool Execute(ProcessInfo &PI, StringRef Program, const char **args,
00213                     const char **envp, const StringRef **redirects,
00214                     unsigned memoryLimit, std::string *ErrMsg) {
00215   if (!sys::fs::can_execute(Program)) {
00216     if (ErrMsg)
00217       *ErrMsg = "program not executable";
00218     return false;
00219   }
00220 
00221   // Windows wants a command line, not an array of args, to pass to the new
00222   // process.  We have to concatenate them all, while quoting the args that
00223   // have embedded spaces (or are empty).
00224   std::unique_ptr<char[]> command = flattenArgs(args);
00225 
00226   // The pointer to the environment block for the new process.
00227   std::vector<wchar_t> EnvBlock;
00228 
00229   if (envp) {
00230     // An environment block consists of a null-terminated block of
00231     // null-terminated strings. Convert the array of environment variables to
00232     // an environment block by concatenating them.
00233     for (unsigned i = 0; envp[i]; ++i) {
00234       SmallVector<wchar_t, MAX_PATH> EnvString;
00235       if (std::error_code ec = windows::UTF8ToUTF16(envp[i], EnvString)) {
00236         SetLastError(ec.value());
00237         MakeErrMsg(ErrMsg, "Unable to convert environment variable to UTF-16");
00238         return false;
00239       }
00240 
00241       EnvBlock.insert(EnvBlock.end(), EnvString.begin(), EnvString.end());
00242       EnvBlock.push_back(0);
00243     }
00244     EnvBlock.push_back(0);
00245   }
00246 
00247   // Create a child process.
00248   STARTUPINFOW si;
00249   memset(&si, 0, sizeof(si));
00250   si.cb = sizeof(si);
00251   si.hStdInput = INVALID_HANDLE_VALUE;
00252   si.hStdOutput = INVALID_HANDLE_VALUE;
00253   si.hStdError = INVALID_HANDLE_VALUE;
00254 
00255   if (redirects) {
00256     si.dwFlags = STARTF_USESTDHANDLES;
00257 
00258     si.hStdInput = RedirectIO(redirects[0], 0, ErrMsg);
00259     if (si.hStdInput == INVALID_HANDLE_VALUE) {
00260       MakeErrMsg(ErrMsg, "can't redirect stdin");
00261       return false;
00262     }
00263     si.hStdOutput = RedirectIO(redirects[1], 1, ErrMsg);
00264     if (si.hStdOutput == INVALID_HANDLE_VALUE) {
00265       CloseHandle(si.hStdInput);
00266       MakeErrMsg(ErrMsg, "can't redirect stdout");
00267       return false;
00268     }
00269     if (redirects[1] && redirects[2] && *(redirects[1]) == *(redirects[2])) {
00270       // If stdout and stderr should go to the same place, redirect stderr
00271       // to the handle already open for stdout.
00272       if (!DuplicateHandle(GetCurrentProcess(), si.hStdOutput,
00273                            GetCurrentProcess(), &si.hStdError,
00274                            0, TRUE, DUPLICATE_SAME_ACCESS)) {
00275         CloseHandle(si.hStdInput);
00276         CloseHandle(si.hStdOutput);
00277         MakeErrMsg(ErrMsg, "can't dup stderr to stdout");
00278         return false;
00279       }
00280     } else {
00281       // Just redirect stderr
00282       si.hStdError = RedirectIO(redirects[2], 2, ErrMsg);
00283       if (si.hStdError == INVALID_HANDLE_VALUE) {
00284         CloseHandle(si.hStdInput);
00285         CloseHandle(si.hStdOutput);
00286         MakeErrMsg(ErrMsg, "can't redirect stderr");
00287         return false;
00288       }
00289     }
00290   }
00291 
00292   PROCESS_INFORMATION pi;
00293   memset(&pi, 0, sizeof(pi));
00294 
00295   fflush(stdout);
00296   fflush(stderr);
00297 
00298   SmallVector<wchar_t, MAX_PATH> ProgramUtf16;
00299   if (std::error_code ec = windows::UTF8ToUTF16(Program, ProgramUtf16)) {
00300     SetLastError(ec.value());
00301     MakeErrMsg(ErrMsg,
00302                std::string("Unable to convert application name to UTF-16"));
00303     return false;
00304   }
00305 
00306   SmallVector<wchar_t, MAX_PATH> CommandUtf16;
00307   if (std::error_code ec = windows::UTF8ToUTF16(command.get(), CommandUtf16)) {
00308     SetLastError(ec.value());
00309     MakeErrMsg(ErrMsg,
00310                std::string("Unable to convert command-line to UTF-16"));
00311     return false;
00312   }
00313 
00314   BOOL rc = CreateProcessW(ProgramUtf16.data(), CommandUtf16.data(), 0, 0,
00315                            TRUE, CREATE_UNICODE_ENVIRONMENT,
00316                            EnvBlock.empty() ? 0 : EnvBlock.data(), 0, &si,
00317                            &pi);
00318   DWORD err = GetLastError();
00319 
00320   // Regardless of whether the process got created or not, we are done with
00321   // the handles we created for it to inherit.
00322   CloseHandle(si.hStdInput);
00323   CloseHandle(si.hStdOutput);
00324   CloseHandle(si.hStdError);
00325 
00326   // Now return an error if the process didn't get created.
00327   if (!rc) {
00328     SetLastError(err);
00329     MakeErrMsg(ErrMsg, std::string("Couldn't execute program '") +
00330                Program.str() + "'");
00331     return false;
00332   }
00333 
00334   PI.Pid = pi.dwProcessId;
00335   PI.ProcessHandle = pi.hProcess;
00336 
00337   // Make sure these get closed no matter what.
00338   ScopedCommonHandle hThread(pi.hThread);
00339 
00340   // Assign the process to a job if a memory limit is defined.
00341   ScopedJobHandle hJob;
00342   if (memoryLimit != 0) {
00343     hJob = CreateJobObjectW(0, 0);
00344     bool success = false;
00345     if (hJob) {
00346       JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli;
00347       memset(&jeli, 0, sizeof(jeli));
00348       jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY;
00349       jeli.ProcessMemoryLimit = uintptr_t(memoryLimit) * 1048576;
00350       if (SetInformationJobObject(hJob, JobObjectExtendedLimitInformation,
00351                                   &jeli, sizeof(jeli))) {
00352         if (AssignProcessToJobObject(hJob, pi.hProcess))
00353           success = true;
00354       }
00355     }
00356     if (!success) {
00357       SetLastError(GetLastError());
00358       MakeErrMsg(ErrMsg, std::string("Unable to set memory limit"));
00359       TerminateProcess(pi.hProcess, 1);
00360       WaitForSingleObject(pi.hProcess, INFINITE);
00361       return false;
00362     }
00363   }
00364 
00365   return true;
00366 }
00367 
00368 namespace llvm {
00369 ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
00370                       bool WaitUntilChildTerminates, std::string *ErrMsg) {
00371   assert(PI.Pid && "invalid pid to wait on, process not started?");
00372   assert(PI.ProcessHandle &&
00373          "invalid process handle to wait on, process not started?");
00374   DWORD milliSecondsToWait = 0;
00375   if (WaitUntilChildTerminates)
00376     milliSecondsToWait = INFINITE;
00377   else if (SecondsToWait > 0)
00378     milliSecondsToWait = SecondsToWait * 1000;
00379 
00380   ProcessInfo WaitResult = PI;
00381   DWORD WaitStatus = WaitForSingleObject(PI.ProcessHandle, milliSecondsToWait);
00382   if (WaitStatus == WAIT_TIMEOUT) {
00383     if (SecondsToWait) {
00384       if (!TerminateProcess(PI.ProcessHandle, 1)) {
00385         if (ErrMsg)
00386           MakeErrMsg(ErrMsg, "Failed to terminate timed-out program.");
00387 
00388         // -2 indicates a crash or timeout as opposed to failure to execute.
00389         WaitResult.ReturnCode = -2;
00390         CloseHandle(PI.ProcessHandle);
00391         return WaitResult;
00392       }
00393       WaitForSingleObject(PI.ProcessHandle, INFINITE);
00394       CloseHandle(PI.ProcessHandle);
00395     } else {
00396       // Non-blocking wait.
00397       return ProcessInfo();
00398     }
00399   }
00400 
00401   // Get its exit status.
00402   DWORD status;
00403   BOOL rc = GetExitCodeProcess(PI.ProcessHandle, &status);
00404   DWORD err = GetLastError();
00405   CloseHandle(PI.ProcessHandle);
00406 
00407   if (!rc) {
00408     SetLastError(err);
00409     if (ErrMsg)
00410       MakeErrMsg(ErrMsg, "Failed getting status for program.");
00411 
00412     // -2 indicates a crash or timeout as opposed to failure to execute.
00413     WaitResult.ReturnCode = -2;
00414     return WaitResult;
00415   }
00416 
00417   if (!status)
00418     return WaitResult;
00419 
00420   // Pass 10(Warning) and 11(Error) to the callee as negative value.
00421   if ((status & 0xBFFF0000U) == 0x80000000U)
00422     WaitResult.ReturnCode = static_cast<int>(status);
00423   else if (status & 0xFF)
00424     WaitResult.ReturnCode = status & 0x7FFFFFFF;
00425   else
00426     WaitResult.ReturnCode = 1;
00427 
00428   return WaitResult;
00429 }
00430 
00431   std::error_code sys::ChangeStdinToBinary(){
00432   int result = _setmode( _fileno(stdin), _O_BINARY );
00433   if (result == -1)
00434     return std::error_code(errno, std::generic_category());
00435   return std::error_code();
00436 }
00437 
00438   std::error_code sys::ChangeStdoutToBinary(){
00439   int result = _setmode( _fileno(stdout), _O_BINARY );
00440   if (result == -1)
00441     return std::error_code(errno, std::generic_category());
00442   return std::error_code();
00443 }
00444 
00445 std::error_code
00446 llvm::sys::writeFileWithEncoding(StringRef FileName, StringRef Contents,
00447                                  WindowsEncodingMethod Encoding) {
00448   std::error_code EC;
00449   llvm::raw_fd_ostream OS(FileName, EC, llvm::sys::fs::OpenFlags::F_Text);
00450   if (EC)
00451     return EC;
00452 
00453   if (Encoding == WEM_UTF8) {
00454     OS << Contents;
00455   } else if (Encoding == WEM_CurrentCodePage) {
00456     SmallVector<wchar_t, 1> ArgsUTF16;
00457     SmallVector<char, 1> ArgsCurCP;
00458 
00459     if ((EC = windows::UTF8ToUTF16(Contents, ArgsUTF16)))
00460       return EC;
00461 
00462     if ((EC = windows::UTF16ToCurCP(
00463              ArgsUTF16.data(), ArgsUTF16.size(), ArgsCurCP)))
00464       return EC;
00465 
00466     OS.write(ArgsCurCP.data(), ArgsCurCP.size());
00467   } else if (Encoding == WEM_UTF16) {
00468     SmallVector<wchar_t, 1> ArgsUTF16;
00469 
00470     if ((EC = windows::UTF8ToUTF16(Contents, ArgsUTF16)))
00471       return EC;
00472 
00473     // Endianness guessing
00474     char BOM[2];
00475     uint16_t src = UNI_UTF16_BYTE_ORDER_MARK_NATIVE;
00476     memcpy(BOM, &src, 2);
00477     OS.write(BOM, 2);
00478     OS.write((char *)ArgsUTF16.data(), ArgsUTF16.size() << 1);
00479   } else {
00480     llvm_unreachable("Unknown encoding");
00481   }
00482 
00483   if (OS.has_error())
00484     return std::make_error_code(std::errc::io_error);
00485 
00486   return EC;
00487 }
00488 
00489 bool llvm::sys::argumentsFitWithinSystemLimits(ArrayRef<const char*> Args) {
00490   // The documented max length of the command line passed to CreateProcess.
00491   static const size_t MaxCommandStringLength = 32768;
00492   size_t ArgLength = 0;
00493   for (ArrayRef<const char*>::iterator I = Args.begin(), E = Args.end();
00494        I != E; ++I) {
00495     // Account for the trailing space for every arg but the last one and the
00496     // trailing NULL of the last argument.
00497     ArgLength += ArgLenWithQuotes(*I) + 1;
00498     if (ArgLength > MaxCommandStringLength) {
00499       return false;
00500     }
00501   }
00502   return true;
00503 }
00504 }