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