LCOV - code coverage report
Current view: top level - lib/Support/Unix - Program.inc (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 117 177 66.1 %
Date: 2017-09-14 15:23:50 Functions: 10 12 83.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===- llvm/Support/Unix/Program.cpp -----------------------------*- 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 implements the Unix specific portion of the Program class.
      11             : //
      12             : //===----------------------------------------------------------------------===//
      13             : 
      14             : //===----------------------------------------------------------------------===//
      15             : //=== WARNING: Implementation here must contain only generic UNIX code that
      16             : //===          is guaranteed to work on *all* UNIX variants.
      17             : //===----------------------------------------------------------------------===//
      18             : 
      19             : #include "Unix.h"
      20             : #include "llvm/ADT/StringExtras.h"
      21             : #include "llvm/Config/config.h"
      22             : #include "llvm/Support/Compiler.h"
      23             : #include "llvm/Support/Errc.h"
      24             : #include "llvm/Support/FileSystem.h"
      25             : #include "llvm/Support/Path.h"
      26             : #include "llvm/Support/raw_ostream.h"
      27             : #if HAVE_SYS_STAT_H
      28             : #include <sys/stat.h>
      29             : #endif
      30             : #if HAVE_SYS_RESOURCE_H
      31             : #include <sys/resource.h>
      32             : #endif
      33             : #if HAVE_SIGNAL_H
      34             : #include <signal.h>
      35             : #endif
      36             : #if HAVE_FCNTL_H
      37             : #include <fcntl.h>
      38             : #endif
      39             : #if HAVE_UNISTD_H
      40             : #include <unistd.h>
      41             : #endif
      42             : #ifdef HAVE_POSIX_SPAWN
      43             : #include <spawn.h>
      44             : 
      45             : #if defined(__APPLE__)
      46             : #include <TargetConditionals.h>
      47             : #endif
      48             : 
      49             : #if defined(__APPLE__) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
      50             : #define USE_NSGETENVIRON 1
      51             : #else
      52             : #define USE_NSGETENVIRON 0
      53             : #endif
      54             : 
      55             : #if !USE_NSGETENVIRON
      56             :   extern char **environ;
      57             : #else
      58             : #include <crt_externs.h> // _NSGetEnviron
      59             : #endif
      60             : #endif
      61             : 
      62             : namespace llvm {
      63             : 
      64             : using namespace sys;
      65             : 
      66     2744190 : ProcessInfo::ProcessInfo() : Pid(0), ReturnCode(0) {}
      67             : 
      68        9349 : ErrorOr<std::string> sys::findProgramByName(StringRef Name,
      69             :                                             ArrayRef<StringRef> Paths) {
      70             :   assert(!Name.empty() && "Must have a name!");
      71             :   // Use the given path verbatim if it contains any slashes; this matches
      72             :   // the behavior of sh(1) and friends.
      73        3295 :   if (Name.find('/') != StringRef::npos)
      74        9885 :     return std::string(Name);
      75             : 
      76        6054 :   SmallVector<StringRef, 16> EnvironmentPaths;
      77        6054 :   if (Paths.empty())
      78        6053 :     if (const char *PathEnv = std::getenv("PATH")) {
      79       12100 :       SplitString(PathEnv, EnvironmentPaths, ":");
      80        6050 :       Paths = EnvironmentPaths;
      81             :     }
      82             : 
      83       44589 :   for (auto Path : Paths) {
      84       35531 :     if (Path.empty())
      85           0 :       continue;
      86             : 
      87             :     // Check to see if this first directory contains the executable...
      88       68012 :     SmallString<128> FilePath(Path);
      89      142124 :     sys::path::append(FilePath, Name);
      90       71062 :     if (sys::fs::can_execute(FilePath.c_str()))
      91       12200 :       return std::string(FilePath.str()); // Found the executable!
      92             :   }
      93             :   return errc::no_such_file_or_directory;
      94             : }
      95             : 
      96           0 : static bool RedirectIO(Optional<StringRef> Path, int FD, std::string* ErrMsg) {
      97           0 :   if (!Path) // Noop
      98             :     return false;
      99           0 :   std::string File;
     100           0 :   if (Path->empty())
     101             :     // Redirect empty paths to /dev/null
     102             :     File = "/dev/null";
     103             :   else
     104           0 :     File = *Path;
     105             : 
     106             :   // Open the file
     107           0 :   int InFD = open(File.c_str(), FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666);
     108           0 :   if (InFD == -1) {
     109           0 :     MakeErrMsg(ErrMsg, "Cannot open file '" + File + "' for "
     110           0 :               + (FD == 0 ? "input" : "output"));
     111           0 :     return true;
     112             :   }
     113             : 
     114             :   // Install it as the requested FD
     115           0 :   if (dup2(InFD, FD) == -1) {
     116           0 :     MakeErrMsg(ErrMsg, "Cannot dup2");
     117           0 :     close(InFD);
     118           0 :     return true;
     119             :   }
     120           0 :   close(InFD);      // Close the original FD
     121           0 :   return false;
     122             : }
     123             : 
     124             : #ifdef HAVE_POSIX_SPAWN
     125          40 : static bool RedirectIO_PS(const std::string *Path, int FD, std::string *ErrMsg,
     126             :                           posix_spawn_file_actions_t *FileActions) {
     127          40 :   if (!Path) // Noop
     128             :     return false;
     129             :   const char *File;
     130          27 :   if (Path->empty())
     131             :     // Redirect empty paths to /dev/null
     132             :     File = "/dev/null";
     133             :   else
     134           9 :     File = Path->c_str();
     135             : 
     136          54 :   if (int Err = posix_spawn_file_actions_addopen(
     137             :           FileActions, FD, File,
     138          27 :           FD == 0 ? O_RDONLY : O_WRONLY | O_CREAT, 0666))
     139           0 :     return MakeErrMsg(ErrMsg, "Cannot dup2", Err);
     140             :   return false;
     141             : }
     142             : #endif
     143             : 
     144           1 : static void TimeOutHandler(int Sig) {
     145           1 : }
     146             : 
     147           0 : static void SetMemoryLimits(unsigned size) {
     148             : #if HAVE_SYS_RESOURCE_H && HAVE_GETRLIMIT && HAVE_SETRLIMIT
     149             :   struct rlimit r;
     150           0 :   __typeof__ (r.rlim_cur) limit = (__typeof__ (r.rlim_cur)) (size) * 1048576;
     151             : 
     152             :   // Heap size
     153           0 :   getrlimit (RLIMIT_DATA, &r);
     154           0 :   r.rlim_cur = limit;
     155           0 :   setrlimit (RLIMIT_DATA, &r);
     156             : #ifdef RLIMIT_RSS
     157             :   // Resident set size.
     158           0 :   getrlimit (RLIMIT_RSS, &r);
     159           0 :   r.rlim_cur = limit;
     160           0 :   setrlimit (RLIMIT_RSS, &r);
     161             : #endif
     162             : #endif
     163           0 : }
     164             : 
     165             : }
     166             : 
     167        5254 : static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args,
     168             :                     const char **Envp, ArrayRef<Optional<StringRef>> Redirects,
     169             :                     unsigned MemoryLimit, std::string *ErrMsg) {
     170       10508 :   if (!llvm::sys::fs::exists(Program)) {
     171           4 :     if (ErrMsg)
     172          28 :       *ErrMsg = std::string("Executable \"") + Program.str() +
     173          12 :                 std::string("\" doesn't exist!");
     174             :     return false;
     175             :   }
     176             : 
     177             :   // If this OS has posix_spawn and there is no memory limit being implied, use
     178             :   // posix_spawn.  It is more efficient than fork/exec.
     179             : #ifdef HAVE_POSIX_SPAWN
     180        5250 :   if (MemoryLimit == 0) {
     181             :     posix_spawn_file_actions_t FileActionsStore;
     182             :     posix_spawn_file_actions_t *FileActions = nullptr;
     183             : 
     184             :     // If we call posix_spawn_file_actions_addopen we have to make sure the
     185             :     // c strings we pass to it stay alive until the call to posix_spawn,
     186             :     // so we copy any StringRefs into this variable.
     187       55792 :     std::string RedirectsStorage[3];
     188             : 
     189        5072 :     if (!Redirects.empty()) {
     190             :       assert(Redirects.size() == 3);
     191          18 :       std::string *RedirectsStr[3] = {nullptr, nullptr, nullptr};
     192          72 :       for (int I = 0; I < 3; ++I) {
     193         108 :         if (Redirects[I]) {
     194         164 :           RedirectsStorage[I] = *Redirects[I];
     195          41 :           RedirectsStr[I] = &RedirectsStorage[I];
     196             :         }
     197             :       }
     198             : 
     199          18 :       FileActions = &FileActionsStore;
     200          18 :       posix_spawn_file_actions_init(FileActions);
     201             : 
     202             :       // Redirect stdin/stdout.
     203          36 :       if (RedirectIO_PS(RedirectsStr[0], 0, ErrMsg, FileActions) ||
     204          18 :           RedirectIO_PS(RedirectsStr[1], 1, ErrMsg, FileActions))
     205           0 :         return false;
     206          52 :       if (!Redirects[1] || !Redirects[2] || *Redirects[1] != *Redirects[2]) {
     207             :         // Just redirect stderr
     208           4 :         if (RedirectIO_PS(RedirectsStr[2], 2, ErrMsg, FileActions))
     209             :           return false;
     210             :       } else {
     211             :         // If stdout and stderr should go to the same place, redirect stderr
     212             :         // to the FD already open for stdout.
     213          14 :         if (int Err = posix_spawn_file_actions_adddup2(FileActions, 1, 2))
     214           0 :           return !MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout", Err);
     215             :       }
     216             :     }
     217             : 
     218        5072 :     if (!Envp)
     219             : #if !USE_NSGETENVIRON
     220        5068 :       Envp = const_cast<const char **>(environ);
     221             : #else
     222             :       // environ is missing in dylibs.
     223             :       Envp = const_cast<const char **>(*_NSGetEnviron());
     224             : #endif
     225             : 
     226             :     // Explicitly initialized to prevent what appears to be a valgrind false
     227             :     // positive.
     228        5072 :     pid_t PID = 0;
     229       15216 :     int Err = posix_spawn(&PID, Program.str().c_str(), FileActions,
     230             :                           /*attrp*/nullptr, const_cast<char **>(Args),
     231        5072 :                           const_cast<char **>(Envp));
     232             : 
     233        5072 :     if (FileActions)
     234          18 :       posix_spawn_file_actions_destroy(FileActions);
     235             : 
     236        5072 :     if (Err)
     237           0 :      return !MakeErrMsg(ErrMsg, "posix_spawn failed", Err);
     238             : 
     239        5072 :     PI.Pid = PID;
     240             : 
     241        5072 :     return true;
     242             :   }
     243             : #endif
     244             : 
     245             :   // Create a child process.
     246         178 :   int child = fork();
     247         178 :   switch (child) {
     248             :     // An error occurred:  Return to the caller.
     249             :     case -1:
     250           0 :       MakeErrMsg(ErrMsg, "Couldn't fork");
     251           0 :       return false;
     252             : 
     253             :     // Child process: Execute the program.
     254           0 :     case 0: {
     255             :       // Redirect file descriptors...
     256           0 :       if (!Redirects.empty()) {
     257             :         // Redirect stdin
     258           0 :         if (RedirectIO(Redirects[0], 0, ErrMsg)) { return false; }
     259             :         // Redirect stdout
     260           0 :         if (RedirectIO(Redirects[1], 1, ErrMsg)) { return false; }
     261           0 :         if (Redirects[1] && Redirects[2] && *Redirects[1] == *Redirects[2]) {
     262             :           // If stdout and stderr should go to the same place, redirect stderr
     263             :           // to the FD already open for stdout.
     264           0 :           if (-1 == dup2(1,2)) {
     265           0 :             MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout");
     266           0 :             return false;
     267             :           }
     268             :         } else {
     269             :           // Just redirect stderr
     270           0 :           if (RedirectIO(Redirects[2], 2, ErrMsg)) { return false; }
     271             :         }
     272             :       }
     273             : 
     274             :       // Set memory limits
     275             :       if (MemoryLimit!=0) {
     276           0 :         SetMemoryLimits(MemoryLimit);
     277             :       }
     278             : 
     279             :       // Execute!
     280           0 :       std::string PathStr = Program;
     281           0 :       if (Envp != nullptr)
     282           0 :         execve(PathStr.c_str(),
     283             :                const_cast<char **>(Args),
     284             :                const_cast<char **>(Envp));
     285             :       else
     286           0 :         execv(PathStr.c_str(),
     287             :               const_cast<char **>(Args));
     288             :       // If the execve() failed, we should exit. Follow Unix protocol and
     289             :       // return 127 if the executable was not found, and 126 otherwise.
     290             :       // Use _exit rather than exit so that atexit functions and static
     291             :       // object destructors cloned from the parent process aren't
     292             :       // redundantly run, and so that any data buffered in stdio buffers
     293             :       // cloned from the parent aren't redundantly written out.
     294           0 :       _exit(errno == ENOENT ? 127 : 126);
     295             :     }
     296             : 
     297             :     // Parent process: Break out of the switch to do our processing.
     298             :     default:
     299             :       break;
     300             :   }
     301             : 
     302         178 :   PI.Pid = child;
     303             : 
     304         178 :   return true;
     305             : }
     306             : 
     307             : namespace llvm {
     308             : 
     309     2738936 : ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
     310             :                       bool WaitUntilTerminates, std::string *ErrMsg) {
     311             :   struct sigaction Act, Old;
     312             :   assert(PI.Pid && "invalid pid to wait on, process not started?");
     313             : 
     314     2738936 :   int WaitPidOptions = 0;
     315     2738936 :   pid_t ChildPid = PI.Pid;
     316     2738936 :   if (WaitUntilTerminates) {
     317             :     SecondsToWait = 0;
     318     2733867 :   } else if (SecondsToWait) {
     319             :     // Install a timeout handler.  The handler itself does nothing, but the
     320             :     // simple fact of having a handler at all causes the wait below to return
     321             :     // with EINTR, unlike if we used SIG_IGN.
     322         180 :     memset(&Act, 0, sizeof(Act));
     323         180 :     Act.sa_handler = TimeOutHandler;
     324         180 :     sigemptyset(&Act.sa_mask);
     325         180 :     sigaction(SIGALRM, &Act, &Old);
     326         180 :     alarm(SecondsToWait);
     327             :   } else if (SecondsToWait == 0)
     328             :     WaitPidOptions = WNOHANG;
     329             : 
     330             :   // Parent process: Wait for the child process to terminate.
     331             :   int status;
     332     2738936 :   ProcessInfo WaitResult;
     333             : 
     334             :   do {
     335     2738936 :     WaitResult.Pid = waitpid(ChildPid, &status, WaitPidOptions);
     336     2738936 :   } while (WaitUntilTerminates && WaitResult.Pid == -1 && errno == EINTR);
     337             : 
     338     2738936 :   if (WaitResult.Pid != PI.Pid) {
     339     2733687 :     if (WaitResult.Pid == 0) {
     340             :       // Non-blocking wait.
     341     2733686 :       return WaitResult;
     342             :     } else {
     343           1 :       if (SecondsToWait && errno == EINTR) {
     344             :         // Kill the child.
     345           1 :         kill(PI.Pid, SIGKILL);
     346             : 
     347             :         // Turn off the alarm and restore the signal handler
     348           1 :         alarm(0);
     349           1 :         sigaction(SIGALRM, &Old, nullptr);
     350             : 
     351             :         // Wait for child to die
     352           1 :         if (wait(&status) != ChildPid)
     353           0 :           MakeErrMsg(ErrMsg, "Child timed out but wouldn't die");
     354             :         else
     355           3 :           MakeErrMsg(ErrMsg, "Child timed out", 0);
     356             : 
     357           1 :         WaitResult.ReturnCode = -2; // Timeout detected
     358           1 :         return WaitResult;
     359           0 :       } else if (errno != EINTR) {
     360           0 :         MakeErrMsg(ErrMsg, "Error waiting for child process");
     361           0 :         WaitResult.ReturnCode = -1;
     362           0 :         return WaitResult;
     363             :       }
     364             :     }
     365             :   }
     366             : 
     367             :   // We exited normally without timeout, so turn off the timer.
     368        5249 :   if (SecondsToWait && !WaitUntilTerminates) {
     369         179 :     alarm(0);
     370         179 :     sigaction(SIGALRM, &Old, nullptr);
     371             :   }
     372             : 
     373             :   // Return the proper exit status. Detect error conditions
     374             :   // so we can return -1 for them and set ErrMsg informatively.
     375        5249 :   int result = 0;
     376        5249 :   if (WIFEXITED(status)) {
     377        5161 :     result = WEXITSTATUS(status);
     378        5161 :     WaitResult.ReturnCode = result;
     379             : 
     380        5161 :     if (result == 127) {
     381           0 :       if (ErrMsg)
     382           0 :         *ErrMsg = llvm::sys::StrError(ENOENT);
     383           0 :       WaitResult.ReturnCode = -1;
     384           0 :       return WaitResult;
     385             :     }
     386        5161 :     if (result == 126) {
     387           0 :       if (ErrMsg)
     388             :         *ErrMsg = "Program could not be executed";
     389           0 :       WaitResult.ReturnCode = -1;
     390           0 :       return WaitResult;
     391             :     }
     392          88 :   } else if (WIFSIGNALED(status)) {
     393          88 :     if (ErrMsg) {
     394         176 :       *ErrMsg = strsignal(WTERMSIG(status));
     395             : #ifdef WCOREDUMP
     396          88 :       if (WCOREDUMP(status))
     397             :         *ErrMsg += " (core dumped)";
     398             : #endif
     399             :     }
     400             :     // Return a special value to indicate that the process received an unhandled
     401             :     // signal during execution as opposed to failing to execute.
     402          88 :     WaitResult.ReturnCode = -2;
     403             :   }
     404        5249 :   return WaitResult;
     405             : }
     406             : 
     407       70721 :   std::error_code sys::ChangeStdinToBinary(){
     408             :   // Do nothing, as Unix doesn't differentiate between text and binary.
     409       70721 :     return std::error_code();
     410             : }
     411             : 
     412       21394 :   std::error_code sys::ChangeStdoutToBinary(){
     413             :   // Do nothing, as Unix doesn't differentiate between text and binary.
     414       21394 :     return std::error_code();
     415             : }
     416             : 
     417             : std::error_code
     418           2 : llvm::sys::writeFileWithEncoding(StringRef FileName, StringRef Contents,
     419             :                                  WindowsEncodingMethod Encoding /*unused*/) {
     420           2 :   std::error_code EC;
     421           4 :   llvm::raw_fd_ostream OS(FileName, EC, llvm::sys::fs::OpenFlags::F_Text);
     422             : 
     423           2 :   if (EC)
     424           0 :     return EC;
     425             : 
     426           2 :   OS << Contents;
     427             : 
     428           2 :   if (OS.has_error())
     429             :     return make_error_code(errc::io_error);
     430             : 
     431           2 :   return EC;
     432             : }
     433             : 
     434        1127 : bool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program,
     435             :                                                   ArrayRef<const char *> Args) {
     436        1127 :   static long ArgMax = sysconf(_SC_ARG_MAX);
     437             : 
     438             :   // System says no practical limit.
     439        1127 :   if (ArgMax == -1)
     440             :     return true;
     441             : 
     442             :   // Conservatively account for space required by environment variables.
     443        1127 :   long HalfArgMax = ArgMax / 2;
     444             : 
     445        1127 :   size_t ArgLength = Program.size() + 1;
     446      326147 :   for (const char* Arg : Args) {
     447      323895 :     size_t length = strlen(Arg);
     448             : 
     449             :     // Ensure that we do not exceed the MAX_ARG_STRLEN constant on Linux, which
     450             :     // does not have a constant unlike what the man pages would have you
     451             :     // believe. Since this limit is pretty high, perform the check
     452             :     // unconditionally rather than trying to be aggressive and limiting it to
     453             :     // Linux only.
     454      323895 :     if (length >= (32 * 4096))
     455             :       return false;
     456             : 
     457      323894 :     ArgLength += length + 1;
     458      323894 :     if (ArgLength > size_t(HalfArgMax)) {
     459             :       return false;
     460             :     }
     461             :   }
     462             : 
     463             :   return true;
     464             : }
     465             : }

Generated by: LCOV version 1.13