21 #include "llvm/Config/config.h" 31 #if HAVE_SYS_RESOURCE_H 32 #include <sys/resource.h> 43 #ifdef HAVE_POSIX_SPAWN 46 #if defined(__APPLE__) 47 #include <TargetConditionals.h> 50 #if defined(__APPLE__) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) 51 #define USE_NSGETENVIRON 1 53 #define USE_NSGETENVIRON 0 57 extern char **environ;
59 #include <crt_externs.h> 70 ArrayRef<StringRef> Paths) {
71 assert(!Name.empty() &&
"Must have a name!");
75 return std::string(Name);
77 SmallVector<StringRef, 16> EnvironmentPaths;
79 if (
const char *PathEnv = std::getenv(
"PATH")) {
81 Paths = EnvironmentPaths;
84 for (
auto Path : Paths) {
89 SmallString<128> FilePath(Path);
92 return std::string(FilePath.str());
97 static bool RedirectIO(Optional<StringRef> Path,
int FD, std::string* ErrMsg) {
108 int InFD = open(File.c_str(), FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666);
110 MakeErrMsg(ErrMsg,
"Cannot open file '" + File +
"' for " 111 + (FD == 0 ?
"input" :
"output"));
116 if (dup2(InFD, FD) == -1) {
125 #ifdef HAVE_POSIX_SPAWN 126 static bool RedirectIO_PS(
const std::string *Path,
int FD, std::string *ErrMsg,
127 posix_spawn_file_actions_t *FileActions) {
135 File = Path->c_str();
137 if (
int Err = posix_spawn_file_actions_addopen(
138 FileActions, FD, File,
139 FD == 0 ? O_RDONLY : O_WRONLY | O_CREAT, 0666))
140 return MakeErrMsg(ErrMsg,
"Cannot dup2", Err);
145 static void TimeOutHandler(
int Sig) {
148 static void SetMemoryLimits(
unsigned size) {
149 #if HAVE_SYS_RESOURCE_H && HAVE_GETRLIMIT && HAVE_SETRLIMIT 151 __typeof__ (r.rlim_cur) limit = (__typeof__ (r.rlim_cur)) (size) * 1048576;
154 getrlimit (RLIMIT_DATA, &r);
156 setrlimit (RLIMIT_DATA, &r);
159 getrlimit (RLIMIT_RSS, &r);
161 setrlimit (RLIMIT_RSS, &r);
168 static std::vector<const char *>
169 toNullTerminatedCStringArray(ArrayRef<StringRef> Strings, StringSaver &Saver) {
170 std::vector<const char *>
Result;
171 for (StringRef S : Strings)
172 Result.push_back(Saver.save(S).data());
173 Result.push_back(
nullptr);
177 static bool Execute(ProcessInfo &PI, StringRef Program,
178 ArrayRef<StringRef>
Args,
Optional<ArrayRef<StringRef>> Env,
179 ArrayRef<Optional<StringRef>> Redirects,
180 unsigned MemoryLimit, std::string *ErrMsg) {
183 *ErrMsg = std::string(
"Executable \"") + Program.str() +
184 std::string(
"\" doesn't exist!");
189 StringSaver Saver(Allocator);
190 std::vector<const char *> ArgVector, EnvVector;
191 const char **Argv =
nullptr;
192 const char **Envp =
nullptr;
193 ArgVector = toNullTerminatedCStringArray(Args, Saver);
194 Argv = ArgVector.data();
196 EnvVector = toNullTerminatedCStringArray(*Env, Saver);
197 Envp = EnvVector.data();
202 #ifdef HAVE_POSIX_SPAWN 203 if (MemoryLimit == 0) {
204 posix_spawn_file_actions_t FileActionsStore;
205 posix_spawn_file_actions_t *FileActions =
nullptr;
210 std::string RedirectsStorage[3];
212 if (!Redirects.empty()) {
213 assert(Redirects.size() == 3);
214 std::string *RedirectsStr[3] = {
nullptr,
nullptr,
nullptr};
215 for (
int I = 0;
I < 3; ++
I) {
217 RedirectsStorage[
I] = *Redirects[
I];
218 RedirectsStr[
I] = &RedirectsStorage[
I];
222 FileActions = &FileActionsStore;
223 posix_spawn_file_actions_init(FileActions);
226 if (RedirectIO_PS(RedirectsStr[0], 0, ErrMsg, FileActions) ||
227 RedirectIO_PS(RedirectsStr[1], 1, ErrMsg, FileActions))
229 if (!Redirects[1] || !Redirects[2] || *Redirects[1] != *Redirects[2]) {
231 if (RedirectIO_PS(RedirectsStr[2], 2, ErrMsg, FileActions))
236 if (
int Err = posix_spawn_file_actions_adddup2(FileActions, 1, 2))
237 return !
MakeErrMsg(ErrMsg,
"Can't redirect stderr to stdout", Err);
242 #if !USE_NSGETENVIRON 243 Envp =
const_cast<const char **
>(environ);
246 Envp =
const_cast<const char **
>(*_NSGetEnviron());
252 int Err = posix_spawn(&PID, Program.str().c_str(), FileActions,
253 nullptr,
const_cast<char **
>(Argv),
254 const_cast<char **>(Envp));
257 posix_spawn_file_actions_destroy(FileActions);
260 return !
MakeErrMsg(ErrMsg,
"posix_spawn failed", Err);
280 if (!Redirects.empty()) {
282 if (RedirectIO(Redirects[0], 0, ErrMsg)) {
return false; }
284 if (RedirectIO(Redirects[1], 1, ErrMsg)) {
return false; }
285 if (Redirects[1] && Redirects[2] && *Redirects[1] == *Redirects[2]) {
288 if (-1 == dup2(1,2)) {
289 MakeErrMsg(ErrMsg,
"Can't redirect stderr to stdout");
294 if (RedirectIO(Redirects[2], 2, ErrMsg)) {
return false; }
299 if (MemoryLimit!=0) {
300 SetMemoryLimits(MemoryLimit);
304 std::string PathStr = Program;
306 execve(PathStr.c_str(),
const_cast<char **
>(Argv),
307 const_cast<char **>(Envp));
309 execv(PathStr.c_str(),
const_cast<char **
>(Argv));
316 _exit(errno == ENOENT ? 127 : 126);
332 ProcessInfo
sys::Wait(
const ProcessInfo &PI,
unsigned SecondsToWait,
333 bool WaitUntilTerminates, std::string *ErrMsg) {
334 struct sigaction Act, Old;
335 assert(PI.Pid &&
"invalid pid to wait on, process not started?");
337 int WaitPidOptions = 0;
338 pid_t ChildPid = PI.Pid;
339 if (WaitUntilTerminates) {
341 }
else if (SecondsToWait) {
345 memset(&Act, 0,
sizeof(Act));
346 Act.sa_handler = TimeOutHandler;
347 sigemptyset(&Act.sa_mask);
348 sigaction(SIGALRM, &Act, &Old);
349 alarm(SecondsToWait);
350 }
else if (SecondsToWait == 0)
351 WaitPidOptions = WNOHANG;
355 ProcessInfo WaitResult;
358 WaitResult.Pid = waitpid(ChildPid, &status, WaitPidOptions);
359 }
while (WaitUntilTerminates && WaitResult.Pid == -1 && errno == EINTR);
361 if (WaitResult.Pid != PI.Pid) {
362 if (WaitResult.Pid == 0) {
366 if (SecondsToWait && errno == EINTR) {
368 kill(PI.Pid, SIGKILL);
372 sigaction(SIGALRM, &Old,
nullptr);
375 if (wait(&status) != ChildPid)
376 MakeErrMsg(ErrMsg,
"Child timed out but wouldn't die");
380 WaitResult.ReturnCode = -2;
382 }
else if (errno != EINTR) {
383 MakeErrMsg(ErrMsg,
"Error waiting for child process");
384 WaitResult.ReturnCode = -1;
391 if (SecondsToWait && !WaitUntilTerminates) {
393 sigaction(SIGALRM, &Old,
nullptr);
399 if (WIFEXITED(status)) {
400 result = WEXITSTATUS(status);
401 WaitResult.ReturnCode = result;
406 WaitResult.ReturnCode = -1;
411 *ErrMsg =
"Program could not be executed";
412 WaitResult.ReturnCode = -1;
415 }
else if (WIFSIGNALED(status)) {
417 *ErrMsg = strsignal(WTERMSIG(status));
419 if (WCOREDUMP(status))
420 *ErrMsg +=
" (core dumped)";
425 WaitResult.ReturnCode = -2;
432 return std::error_code();
437 return std::error_code();
458 ArrayRef<StringRef> Args) {
459 static long ArgMax = sysconf(_SC_ARG_MAX);
462 static long ArgMin = _POSIX_ARG_MAX;
465 long EffectiveArgMax = 128 * 1024;
467 if (EffectiveArgMax > ArgMax)
468 EffectiveArgMax = ArgMax;
469 else if (EffectiveArgMax < ArgMin)
470 EffectiveArgMax = ArgMin;
477 long HalfArgMax = EffectiveArgMax / 2;
479 size_t ArgLength = Program.size() + 1;
480 for (StringRef
Arg : Args) {
486 if (
Arg.size() >= (32 * 4096))
489 ArgLength +=
Arg.size() + 1;
490 if (ArgLength >
size_t(HalfArgMax)) {
bool can_execute(const Twine &Path)
Can we execute this file?
This class represents lattice values for constants.
std::error_code ChangeStdoutToBinary()
ErrorOr< std::string > findProgramByName(StringRef Name, ArrayRef< StringRef > Paths={})
Find the first executable file Name in Paths.
void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
amdgpu Simplify well known AMD library false Value Value const Twine & Name
std::string StrError()
Returns a string representation of the errno value, using whatever thread-safe variant of strerror() ...
std::error_code make_error_code(BitcodeError E)
void SplitString(StringRef Source, SmallVectorImpl< StringRef > &OutFragments, StringRef Delimiters=" \\\)
SplitString - Split up the specified string according to the specified delimiters, appending the result fragments to the output list.
BumpPtrAllocatorImpl BumpPtrAllocator
The standard BumpPtrAllocator which just uses the default template parameters.
std::error_code status(const Twine &path, file_status &result, bool follow=true)
Get file status as if by POSIX stat().
bool commandLineFitsWithinSystemLimits(StringRef Program, ArrayRef< StringRef > Args)
Return true if the given arguments fit within system-specific argument length limits.
auto size(R &&Range, typename std::enable_if< std::is_same< typename std::iterator_traits< decltype(Range.begin())>::iterator_category, std::random_access_iterator_tag >::value, void >::type *=nullptr) -> decltype(std::distance(Range.begin(), Range.end()))
Get the size of a range.
std::error_code writeFileWithEncoding(StringRef FileName, StringRef Contents, WindowsEncodingMethod Encoding=WEM_UTF8)
Saves the UTF8-encoded contents string into the file FileName using a specific encoding.
bool MakeErrMsg(std::string *ErrMsg, const std::string &prefix)
WindowsEncodingMethod
File encoding options when writing contents that a non-UTF8 tool will read (on Windows systems)...
std::error_code ChangeStdinToBinary()
amdgpu Simplify well known AMD library false Value Value * Arg
A raw_ostream that writes to a file descriptor.
static bool Execute(ProcessInfo &PI, StringRef Program, ArrayRef< StringRef > Args, Optional< ArrayRef< StringRef >> Env, ArrayRef< Optional< StringRef >> Redirects, unsigned MemoryLimit, std::string *ErrMsg)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
ProcessInfo Wait(const ProcessInfo &PI, unsigned SecondsToWait, bool WaitUntilTerminates, std::string *ErrMsg=nullptr)
This function waits for the process specified by PI to finish.
bool exists(const basic_file_status &status)
Does file exist?
constexpr char Args[]
Key for Kernel::Metadata::mArgs.