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