434 lines · plain
1//===- Unix/Process.cpp - Unix Process Implementation --------- -*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file provides the generic Unix implementation of the Process class.10//11//===----------------------------------------------------------------------===//12 13#include "Unix.h"14#include "llvm/ADT/Hashing.h"15#include "llvm/ADT/StringRef.h"16#include "llvm/Config/config.h"17#include "llvm/Config/llvm-config.h" // for LLVM_ENABLE_THREADS18#include <mutex>19#include <optional>20#include <fcntl.h>21#include <sys/time.h>22#include <sys/resource.h>23#include <sys/stat.h>24#include <signal.h>25#if defined(HAVE_MALLINFO) || defined(HAVE_MALLINFO2)26#include <malloc.h>27#endif28#if defined(HAVE_MALLCTL)29#include <malloc_np.h>30#endif31#ifdef HAVE_MALLOC_MALLOC_H32#include <malloc/malloc.h>33#endif34#ifdef HAVE_GETAUXVAL35#include <sys/auxv.h>36#endif37#ifdef HAVE_SYS_IOCTL_H38#include <sys/ioctl.h>39#endif40 41//===----------------------------------------------------------------------===//42//=== WARNING: Implementation here must contain only generic UNIX code that43//=== is guaranteed to work on *all* UNIX variants.44//===----------------------------------------------------------------------===//45 46using namespace llvm;47using namespace sys;48 49static std::pair<std::chrono::microseconds, std::chrono::microseconds>50getRUsageTimes() {51#if defined(HAVE_GETRUSAGE)52 struct rusage RU;53 ::getrusage(RUSAGE_SELF, &RU);54 return {toDuration(RU.ru_utime), toDuration(RU.ru_stime)};55#else56#ifndef __MVS__ // Exclude for MVS in case -pedantic is used57#warning Cannot get usage times on this platform58#endif59 return {std::chrono::microseconds::zero(), std::chrono::microseconds::zero()};60#endif61}62 63Process::Pid Process::getProcessId() {64 static_assert(sizeof(Pid) >= sizeof(pid_t),65 "Process::Pid should be big enough to store pid_t");66 return Pid(::getpid());67}68 69// On Cygwin, getpagesize() returns 64k(AllocationGranularity) and70// offset in mmap(3) should be aligned to the AllocationGranularity.71Expected<unsigned> Process::getPageSize() {72#if defined(HAVE_GETAUXVAL)73 static const int page_size = ::getauxval(AT_PAGESZ);74#elif defined(HAVE_GETPAGESIZE)75 static const int page_size = ::getpagesize();76#elif defined(HAVE_SYSCONF)77 static long page_size = ::sysconf(_SC_PAGE_SIZE);78#else79#error Cannot get the page size on this machine80#endif81 if (page_size == -1)82 return errorCodeToError(errnoAsErrorCode());83 84 assert(page_size > 0 && "Page size cannot be 0");85 assert((page_size % 1024) == 0 && "Page size must be aligned by 1024");86 return static_cast<unsigned>(page_size);87}88 89size_t Process::GetMallocUsage() {90#if defined(HAVE_MALLINFO2)91 struct mallinfo2 mi;92 mi = ::mallinfo2();93 return mi.uordblks;94#elif defined(HAVE_MALLINFO)95 struct mallinfo mi;96 mi = ::mallinfo();97 return mi.uordblks;98#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H)99 malloc_statistics_t Stats;100 malloc_zone_statistics(malloc_default_zone(), &Stats);101 return Stats.size_in_use; // darwin102#elif defined(HAVE_MALLCTL)103 size_t alloc, sz;104 sz = sizeof(size_t);105 if (mallctl("stats.allocated", &alloc, &sz, NULL, 0) == 0)106 return alloc;107 return 0;108#elif defined(HAVE_SBRK)109 // Note this is only an approximation and more closely resembles110 // the value returned by mallinfo in the arena field.111 static char *StartOfMemory = reinterpret_cast<char *>(::sbrk(0));112 char *EndOfMemory = (char *)sbrk(0);113 if (EndOfMemory != ((char *)-1) && StartOfMemory != ((char *)-1))114 return EndOfMemory - StartOfMemory;115 return 0;116#else117#ifndef __MVS__ // Exclude for MVS in case -pedantic is used118#warning Cannot get malloc info on this platform119#endif120 return 0;121#endif122}123 124void Process::GetTimeUsage(TimePoint<> &elapsed,125 std::chrono::nanoseconds &user_time,126 std::chrono::nanoseconds &sys_time) {127 elapsed = std::chrono::system_clock::now();128 std::tie(user_time, sys_time) = getRUsageTimes();129}130 131#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)132#include <mach/mach.h>133#endif134 135// Some LLVM programs such as bugpoint produce core files as a normal part of136// their operation. To prevent the disk from filling up, this function137// does what's necessary to prevent their generation.138void Process::PreventCoreFiles() {139 struct rlimit rlim;140 getrlimit(RLIMIT_CORE, &rlim);141#ifdef __linux__142 // On Linux, if the kernel.core_pattern sysctl starts with a '|' (i.e. it143 // is being piped to a coredump handler such as systemd-coredumpd), the144 // kernel ignores RLIMIT_CORE (since we aren't creating a file in the file145 // system) except for the magic value of 1, which disables coredumps when146 // piping. 1 byte is too small for any kind of valid core dump, so it147 // also disables coredumps if kernel.core_pattern creates files directly.148 // While most piped coredump handlers do respect the crashing processes'149 // RLIMIT_CORE, this is notable not the case for Debian's systemd-coredump150 // due to a local patch that changes sysctl.d/50-coredump.conf to ignore151 // the specified limit and instead use RLIM_INFINITY.152 //153 // The alternative to using RLIMIT_CORE=1 would be to use prctl() with the154 // PR_SET_DUMPABLE flag, however that also prevents ptrace(), so makes it155 // impossible to attach a debugger.156 rlim.rlim_cur = std::min<rlim_t>(1, rlim.rlim_max);157#else158 rlim.rlim_cur = 0;159#endif160 setrlimit(RLIMIT_CORE, &rlim);161 162#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)163 // Disable crash reporting on Mac OS X 10.0-10.4164 165 // get information about the original set of exception ports for the task166 mach_msg_type_number_t Count = 0;167 exception_mask_t OriginalMasks[EXC_TYPES_COUNT];168 exception_port_t OriginalPorts[EXC_TYPES_COUNT];169 exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT];170 thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT];171 kern_return_t err = task_get_exception_ports(172 mach_task_self(), EXC_MASK_ALL, OriginalMasks, &Count, OriginalPorts,173 OriginalBehaviors, OriginalFlavors);174 if (err == KERN_SUCCESS) {175 // replace each with MACH_PORT_NULL.176 for (unsigned i = 0; i != Count; ++i)177 task_set_exception_ports(mach_task_self(), OriginalMasks[i],178 MACH_PORT_NULL, OriginalBehaviors[i],179 OriginalFlavors[i]);180 }181 182 // Disable crash reporting on Mac OS X 10.5183 signal(SIGABRT, _exit);184 signal(SIGILL, _exit);185 signal(SIGFPE, _exit);186 signal(SIGSEGV, _exit);187 signal(SIGBUS, _exit);188#endif189 190 coreFilesPrevented = true;191}192 193std::optional<std::string> Process::GetEnv(StringRef Name) {194 std::string NameStr = Name.str();195 const char *Val = ::getenv(NameStr.c_str());196 if (!Val)197 return std::nullopt;198 return std::string(Val);199}200 201namespace {202class FDCloser {203public:204 FDCloser(int &FD) : FD(FD), KeepOpen(false) {}205 void keepOpen() { KeepOpen = true; }206 ~FDCloser() {207 if (!KeepOpen && FD >= 0)208 ::close(FD);209 }210 211private:212 FDCloser(const FDCloser &) = delete;213 void operator=(const FDCloser &) = delete;214 215 int &FD;216 bool KeepOpen;217};218} // namespace219 220std::error_code Process::FixupStandardFileDescriptors() {221 int NullFD = -1;222 FDCloser FDC(NullFD);223 const int StandardFDs[] = {STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO};224 for (int StandardFD : StandardFDs) {225 struct stat st;226 errno = 0;227 if (RetryAfterSignal(-1, ::fstat, StandardFD, &st) < 0) {228 assert(errno && "expected errno to be set if fstat failed!");229 // fstat should return EBADF if the file descriptor is closed.230 if (errno != EBADF)231 return errnoAsErrorCode();232 }233 // if fstat succeeds, move on to the next FD.234 if (!errno)235 continue;236 assert(errno == EBADF && "expected errno to have EBADF at this point!");237 238 if (NullFD < 0) {239 // Call ::open in a lambda to avoid overload resolution in240 // RetryAfterSignal when open is overloaded, such as in Bionic.241 auto Open = [&]() { return ::open("/dev/null", O_RDWR); };242 if ((NullFD = RetryAfterSignal(-1, Open)) < 0)243 return errnoAsErrorCode();244 }245 246 if (NullFD == StandardFD)247 FDC.keepOpen();248 else if (dup2(NullFD, StandardFD) < 0)249 return errnoAsErrorCode();250 }251 return std::error_code();252}253 254std::error_code Process::SafelyCloseFileDescriptor(int FD) {255 // Create a signal set filled with *all* signals.256 sigset_t FullSet, SavedSet;257 if (sigfillset(&FullSet) < 0 || sigfillset(&SavedSet) < 0)258 return errnoAsErrorCode();259 260 // Atomically swap our current signal mask with a full mask.261#if LLVM_ENABLE_THREADS262 if (int EC = pthread_sigmask(SIG_SETMASK, &FullSet, &SavedSet))263 return std::error_code(EC, std::generic_category());264#else265 if (sigprocmask(SIG_SETMASK, &FullSet, &SavedSet) < 0)266 return errnoAsErrorCode();267#endif268 // Attempt to close the file descriptor.269 // We need to save the error, if one occurs, because our subsequent call to270 // pthread_sigmask might tamper with errno.271 int ErrnoFromClose = 0;272 if (::close(FD) < 0)273 ErrnoFromClose = errno;274 // Restore the signal mask back to what we saved earlier.275 int EC = 0;276#if LLVM_ENABLE_THREADS277 EC = pthread_sigmask(SIG_SETMASK, &SavedSet, nullptr);278#else279 if (sigprocmask(SIG_SETMASK, &SavedSet, nullptr) < 0)280 EC = errno;281#endif282 // The error code from close takes precedence over the one from283 // pthread_sigmask.284 if (ErrnoFromClose)285 return std::error_code(ErrnoFromClose, std::generic_category());286 return std::error_code(EC, std::generic_category());287}288 289bool Process::StandardInIsUserInput() {290 return FileDescriptorIsDisplayed(STDIN_FILENO);291}292 293bool Process::StandardOutIsDisplayed() {294 return FileDescriptorIsDisplayed(STDOUT_FILENO);295}296 297bool Process::StandardErrIsDisplayed() {298 return FileDescriptorIsDisplayed(STDERR_FILENO);299}300 301bool Process::FileDescriptorIsDisplayed(int fd) {302#if HAVE_ISATTY303 return isatty(fd);304#else305 // If we don't have isatty, just return false.306 return false;307#endif308}309 310static unsigned getColumns(int FileID) {311 // If COLUMNS is defined in the environment, wrap to that many columns.312 // This matches GCC.313 if (const char *ColumnsStr = std::getenv("COLUMNS")) {314 int Columns = std::atoi(ColumnsStr);315 if (Columns > 0)316 return Columns;317 }318 319 // Some shells do not export COLUMNS; query the column count via ioctl()320 // instead if it isn't available.321 unsigned Columns = 0;322 323#if defined(HAVE_SYS_IOCTL_H) && !defined(__sun__)324 struct winsize ws;325 if (ioctl(FileID, TIOCGWINSZ, &ws) == 0)326 Columns = ws.ws_col;327#endif328 329 return Columns;330}331 332unsigned Process::StandardOutColumns() {333 if (!StandardOutIsDisplayed())334 return 0;335 336 return getColumns(0);337}338 339unsigned Process::StandardErrColumns() {340 if (!StandardErrIsDisplayed())341 return 0;342 343 return getColumns(1);344}345 346static bool terminalHasColors() {347 // Check if the current terminal is one of terminals that are known to support348 // ANSI color escape codes.349 if (const char *TermStr = std::getenv("TERM")) {350 return StringSwitch<bool>(TermStr)351 .Case("ansi", true)352 .Case("cygwin", true)353 .Case("linux", true)354 .StartsWith("screen", true)355 .StartsWith("xterm", true)356 .StartsWith("vt100", true)357 .StartsWith("rxvt", true)358 .EndsWith("color", true)359 .Default(false);360 }361 362 return false;363}364 365bool Process::FileDescriptorHasColors(int fd) {366 // A file descriptor has colors if it is displayed and the terminal has367 // colors.368 return FileDescriptorIsDisplayed(fd) && terminalHasColors();369}370 371bool Process::StandardOutHasColors() {372 return FileDescriptorHasColors(STDOUT_FILENO);373}374 375bool Process::StandardErrHasColors() {376 return FileDescriptorHasColors(STDERR_FILENO);377}378 379void Process::UseANSIEscapeCodes(bool /*enable*/) {380 // No effect.381}382 383bool Process::ColorNeedsFlush() {384 // No, we use ANSI escape sequences.385 return false;386}387 388const char *Process::OutputColor(char code, bool bold, bool bg) {389 return colorcodes[bg ? 1 : 0][bold ? 1 : 0][code & 15];390}391 392const char *Process::OutputBold(bool bg) { return "\033[1m"; }393 394const char *Process::OutputReverse() { return "\033[7m"; }395 396const char *Process::ResetColor() { return "\033[0m"; }397 398#if !HAVE_DECL_ARC4RANDOM399static unsigned GetRandomNumberSeed() {400 // Attempt to get the initial seed from /dev/urandom, if possible.401 int urandomFD = open("/dev/urandom", O_RDONLY);402 403 if (urandomFD != -1) {404 unsigned seed;405 // Don't use a buffered read to avoid reading more data406 // from /dev/urandom than we need.407 int count = read(urandomFD, (void *)&seed, sizeof(seed));408 409 close(urandomFD);410 411 // Return the seed if the read was successful.412 if (count == sizeof(seed))413 return seed;414 }415 416 // Otherwise, swizzle the current time and the process ID to form a reasonable417 // seed.418 const auto Now = std::chrono::high_resolution_clock::now();419 return hash_combine(Now.time_since_epoch().count(), ::getpid());420}421#endif422 423unsigned llvm::sys::Process::GetRandomNumber() {424#if HAVE_DECL_ARC4RANDOM425 return arc4random();426#else427 static int x = (static_cast<void>(::srand(GetRandomNumberSeed())), 0);428 (void)x;429 return ::rand();430#endif431}432 433[[noreturn]] void Process::ExitNoCleanup(int RetCode) { _Exit(RetCode); }434