diff options
Diffstat (limited to 'lib/Support/Unix')
| -rw-r--r-- | lib/Support/Unix/Memory.inc | 4 | ||||
| -rw-r--r-- | lib/Support/Unix/Path.inc | 137 | ||||
| -rw-r--r-- | lib/Support/Unix/Process.inc | 4 | ||||
| -rw-r--r-- | lib/Support/Unix/Signals.inc | 146 | 
4 files changed, 235 insertions, 56 deletions
diff --git a/lib/Support/Unix/Memory.inc b/lib/Support/Unix/Memory.inc index d70319168b84d..f3463e5817359 100644 --- a/lib/Support/Unix/Memory.inc +++ b/lib/Support/Unix/Memory.inc @@ -73,7 +73,7 @@ int getPosixProtectionFlags(unsigned Flags) {    return PROT_NONE;  } -} // namespace +} // anonymous namespace  namespace llvm {  namespace sys { @@ -265,7 +265,7 @@ bool Memory::setWritable (MemoryBlock &M, std::string *ErrMsg) {  }  bool Memory::setExecutable (MemoryBlock &M, std::string *ErrMsg) { -  if (M.Address == 0 || M.Size == 0) return false; +  if (M.Address == nullptr || M.Size == 0) return false;    Memory::InvalidateInstructionCache(M.Address, M.Size);  #if defined(__APPLE__) && (defined(__arm__) || defined(__arm64__))    kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)M.Address, diff --git a/lib/Support/Unix/Path.inc b/lib/Support/Unix/Path.inc index d85c37ab3bfaf..84aafcb70d73a 100644 --- a/lib/Support/Unix/Path.inc +++ b/lib/Support/Unix/Path.inc @@ -25,6 +25,9 @@  #if HAVE_FCNTL_H  #include <fcntl.h>  #endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif  #ifdef HAVE_SYS_MMAN_H  #include <sys/mman.h>  #endif @@ -47,6 +50,7 @@  #ifdef __APPLE__  #include <mach-o/dyld.h> +#include <sys/attr.h>  #endif  // Both stdio.h and cstdio are included via different pathes and @@ -60,6 +64,25 @@  # define PATH_MAX 4096  #endif +#include <sys/types.h> +#if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__ANDROID__) +#include <sys/statvfs.h> +#define STATVFS statvfs +#define STATVFS_F_FRSIZE(vfs) vfs.f_frsize +#else +#ifdef __OpenBSD__ +#include <sys/param.h> +#include <sys/mount.h> +#elif defined(__ANDROID__) +#include <sys/vfs.h> +#else +#include <sys/mount.h> +#endif +#define STATVFS statfs +#define STATVFS_F_FRSIZE(vfs) static_cast<uint64_t>(vfs.f_bsize) +#endif + +  using namespace llvm;  namespace llvm { @@ -70,7 +93,7 @@ namespace fs {      defined(__linux__) || defined(__CYGWIN__) || defined(__DragonFly__)  static int  test_dir(char ret[PATH_MAX], const char *dir, const char *bin) -{   +{    struct stat sb;    char fullpath[PATH_MAX]; @@ -174,6 +197,12 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) {    return "";  } +TimeValue file_status::getLastAccessedTime() const { +  TimeValue Ret; +  Ret.fromEpochTime(fs_st_atime); +  return Ret; +} +  TimeValue file_status::getLastModificationTime() const {    TimeValue Ret;    Ret.fromEpochTime(fs_st_mtime); @@ -184,6 +213,18 @@ UniqueID file_status::getUniqueID() const {    return UniqueID(fs_st_dev, fs_st_ino);  } +ErrorOr<space_info> disk_space(const Twine &Path) { +  struct STATVFS Vfs; +  if (::STATVFS(Path.str().c_str(), &Vfs)) +    return std::error_code(errno, std::generic_category()); +  auto FrSize = STATVFS_F_FRSIZE(Vfs); +  space_info SpaceInfo; +  SpaceInfo.capacity = static_cast<uint64_t>(Vfs.f_blocks) * FrSize; +  SpaceInfo.free = static_cast<uint64_t>(Vfs.f_bfree) * FrSize; +  SpaceInfo.available = static_cast<uint64_t>(Vfs.f_bavail) * FrSize; +  return SpaceInfo; +} +  std::error_code current_path(SmallVectorImpl<char> &result) {    result.clear(); @@ -373,8 +414,9 @@ static std::error_code fillStatus(int StatRet, const struct stat &Status,    perms Perms = static_cast<perms>(Status.st_mode);    Result = -      file_status(Type, Perms, Status.st_dev, Status.st_ino, Status.st_mtime, -                  Status.st_uid, Status.st_gid, Status.st_size); +      file_status(Type, Perms, Status.st_dev, Status.st_ino, Status.st_atime, +                  Status.st_mtime, Status.st_uid, Status.st_gid, +                  Status.st_size);    return std::error_code();  } @@ -506,13 +548,47 @@ std::error_code detail::directory_iterator_increment(detail::DirIterState &it) {    return std::error_code();  } -std::error_code openFileForRead(const Twine &Name, int &ResultFD) { +#if !defined(F_GETPATH) +static bool hasProcSelfFD() { +  // If we have a /proc filesystem mounted, we can quickly establish the +  // real name of the file with readlink +  static const bool Result = (::access("/proc/self/fd", R_OK) == 0); +  return Result; +} +#endif + +std::error_code openFileForRead(const Twine &Name, int &ResultFD, +                                SmallVectorImpl<char> *RealPath) {    SmallString<128> Storage;    StringRef P = Name.toNullTerminatedStringRef(Storage);    while ((ResultFD = open(P.begin(), O_RDONLY)) < 0) {      if (errno != EINTR)        return std::error_code(errno, std::generic_category());    } +  // Attempt to get the real name of the file, if the user asked +  if(!RealPath) +    return std::error_code(); +  RealPath->clear(); +#if defined(F_GETPATH) +  // When F_GETPATH is availble, it is the quickest way to get +  // the real path name. +  char Buffer[MAXPATHLEN]; +  if (::fcntl(ResultFD, F_GETPATH, Buffer) != -1) +    RealPath->append(Buffer, Buffer + strlen(Buffer)); +#else +  char Buffer[PATH_MAX]; +  if (hasProcSelfFD()) { +    char ProcPath[64]; +    snprintf(ProcPath, sizeof(ProcPath), "/proc/self/fd/%d", ResultFD); +    ssize_t CharCount = ::readlink(ProcPath, Buffer, sizeof(Buffer)); +    if (CharCount > 0) +      RealPath->append(Buffer, Buffer + CharCount); +  } else { +    // Use ::realpath to get the real path name +    if (::realpath(P.begin(), Buffer) != nullptr) +      RealPath->append(Buffer, Buffer + strlen(Buffer)); +  } +#endif    return std::error_code();  } @@ -546,6 +622,53 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD,    return std::error_code();  } +std::error_code getPathFromOpenFD(int FD, SmallVectorImpl<char> &ResultPath) { +  if (FD < 0) +    return make_error_code(errc::bad_file_descriptor); + +#if defined(F_GETPATH) +  // When F_GETPATH is availble, it is the quickest way to get +  // the path from a file descriptor. +  ResultPath.reserve(MAXPATHLEN); +  if (::fcntl(FD, F_GETPATH, ResultPath.begin()) == -1) +    return std::error_code(errno, std::generic_category()); + +  ResultPath.set_size(strlen(ResultPath.begin())); +#else +  // If we have a /proc filesystem mounted, we can quickly establish the +  // real name of the file with readlink. Otherwise, we don't know how to +  // get the filename from a file descriptor. Give up. +  if (!fs::hasProcSelfFD()) +    return make_error_code(errc::function_not_supported); + +  ResultPath.reserve(PATH_MAX); +  char ProcPath[64]; +  snprintf(ProcPath, sizeof(ProcPath), "/proc/self/fd/%d", FD); +  ssize_t CharCount = ::readlink(ProcPath, ResultPath.begin(), ResultPath.capacity()); +  if (CharCount < 0) +      return std::error_code(errno, std::generic_category()); + +  // Was the filename truncated? +  if (static_cast<size_t>(CharCount) == ResultPath.capacity()) { +    // Use lstat to get the size of the filename +    struct stat sb; +    if (::lstat(ProcPath, &sb) < 0) +      return std::error_code(errno, std::generic_category()); + +    ResultPath.reserve(sb.st_size + 1); +    CharCount = ::readlink(ProcPath, ResultPath.begin(), ResultPath.capacity()); +    if (CharCount < 0) +      return std::error_code(errno, std::generic_category()); + +    // Test for race condition: did the link size change? +    if (CharCount > sb.st_size) +      return std::error_code(ENAMETOOLONG, std::generic_category()); +  } +  ResultPath.set_size(static_cast<size_t>(CharCount)); +#endif +  return std::error_code(); +} +  } // end namespace fs  namespace path { @@ -586,12 +709,12 @@ static bool getDarwinConfDir(bool TempDir, SmallVectorImpl<char> &Result) {  }  static bool getUserCacheDir(SmallVectorImpl<char> &Result) { -  // First try using XDS_CACHE_HOME env variable, +  // First try using XDG_CACHE_HOME env variable,    // as specified in XDG Base Directory Specification at    // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html -  if (const char *XdsCacheDir = std::getenv("XDS_CACHE_HOME")) { +  if (const char *XdgCacheDir = std::getenv("XDG_CACHE_HOME")) {      Result.clear(); -    Result.append(XdsCacheDir, XdsCacheDir + strlen(XdsCacheDir)); +    Result.append(XdgCacheDir, XdgCacheDir + strlen(XdgCacheDir));      return true;    } diff --git a/lib/Support/Unix/Process.inc b/lib/Support/Unix/Process.inc index 27083eeb072d3..d81836b92daef 100644 --- a/lib/Support/Unix/Process.inc +++ b/lib/Support/Unix/Process.inc @@ -169,6 +169,8 @@ void Process::PreventCoreFiles() {    signal(SIGSEGV, _exit);    signal(SIGBUS,  _exit);  #endif + +  coreFilesPrevented = true;  }  Optional<std::string> Process::GetEnv(StringRef Name) { @@ -456,7 +458,7 @@ unsigned llvm::sys::Process::GetRandomNumber() {  #if defined(HAVE_DECL_ARC4RANDOM) && HAVE_DECL_ARC4RANDOM    return arc4random();  #else -  static int x = (::srand(GetRandomNumberSeed()), 0); +  static int x = (static_cast<void>(::srand(GetRandomNumberSeed())), 0);    (void)x;    return ::rand();  #endif diff --git a/lib/Support/Unix/Signals.inc b/lib/Support/Unix/Signals.inc index 061cdb3da216e..117d4e8bcb523 100644 --- a/lib/Support/Unix/Signals.inc +++ b/lib/Support/Unix/Signals.inc @@ -45,6 +45,17 @@  #if HAVE_LINK_H  #include <link.h>  #endif +#if HAVE_UNWIND_BACKTRACE +// FIXME: We should be able to use <unwind.h> for any target that has an +// _Unwind_Backtrace function, but on FreeBSD the configure test passes +// despite the function not existing, and on Android, <unwind.h> conflicts +// with <link.h>. +#ifdef __GLIBC__ +#include <unwind.h> +#else +#undef HAVE_UNWIND_BACKTRACE +#endif +#endif  using namespace llvm; @@ -57,6 +68,8 @@ static void (*InterruptFunction)() = nullptr;  static ManagedStatic<std::vector<std::string>> FilesToRemove; +static StringRef Argv0; +  // IntSigs - Signals that represent requested termination. There's no bug  // or failure, or if there is, it's not our direct responsibility. For whatever  // reason, our continued execution is no longer desirable. @@ -96,7 +109,7 @@ static void RegisterHandler(int Signal) {    struct sigaction NewHandler;    NewHandler.sa_handler = SignalHandler; -  NewHandler.sa_flags = SA_NODEFER|SA_RESETHAND; +  NewHandler.sa_flags = SA_NODEFER | SA_RESETHAND | SA_ONSTACK;    sigemptyset(&NewHandler.sa_mask);    // Install the new handler, save the old one in RegisteredSignalInfo. @@ -106,6 +119,35 @@ static void RegisterHandler(int Signal) {    ++NumRegisteredSignals;  } +#if defined(HAVE_SIGALTSTACK) +// Hold onto the old alternate signal stack so that it's not reported as a leak. +// We don't make any attempt to remove our alt signal stack if we remove our +// signal handlers; that can't be done reliably if someone else is also trying +// to do the same thing. +static stack_t OldAltStack; + +static void CreateSigAltStack() { +  const size_t AltStackSize = MINSIGSTKSZ + 8192; + +  // If we're executing on the alternate stack, or we already have an alternate +  // signal stack that we're happy with, there's nothing for us to do. Don't +  // reduce the size, some other part of the process might need a larger stack +  // than we do. +  if (sigaltstack(nullptr, &OldAltStack) != 0 || +      OldAltStack.ss_flags & SS_ONSTACK || +      (OldAltStack.ss_sp && OldAltStack.ss_size >= AltStackSize)) +    return; + +  stack_t AltStack = {}; +  AltStack.ss_sp = reinterpret_cast<char *>(malloc(AltStackSize)); +  AltStack.ss_size = AltStackSize; +  if (sigaltstack(&AltStack, &OldAltStack) != 0) +    free(AltStack.ss_sp); +} +#else +static void CreateSigAltStack() {} +#endif +  static void RegisterHandlers() {    // We need to dereference the signals mutex during handler registration so    // that we force its construction. This is to prevent the first use being @@ -116,6 +158,10 @@ static void RegisterHandlers() {    // If the handlers are already registered, we're done.    if (NumRegisteredSignals != 0) return; +  // Create an alternate stack for signal handling. This is necessary for us to +  // be able to reliably handle signals due to stack overflow. +  CreateSigAltStack(); +    for (auto S : IntSigs) RegisterHandler(S);    for (auto S : KillSigs) RegisterHandler(S);  } @@ -309,18 +355,62 @@ static bool findModulesAndOffsets(void **StackTrace, int Depth,  }  #endif // defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES) && ... +#if defined(ENABLE_BACKTRACES) && defined(HAVE_UNWIND_BACKTRACE) +static int unwindBacktrace(void **StackTrace, int MaxEntries) { +  if (MaxEntries < 0) +    return 0; + +  // Skip the first frame ('unwindBacktrace' itself). +  int Entries = -1; + +  auto HandleFrame = [&](_Unwind_Context *Context) -> _Unwind_Reason_Code { +    // Apparently we need to detect reaching the end of the stack ourselves. +    void *IP = (void *)_Unwind_GetIP(Context); +    if (!IP) +      return _URC_END_OF_STACK; + +    assert(Entries < MaxEntries && "recursively called after END_OF_STACK?"); +    if (Entries >= 0) +      StackTrace[Entries] = IP; + +    if (++Entries == MaxEntries) +      return _URC_END_OF_STACK; +    return _URC_NO_REASON; +  }; + +  _Unwind_Backtrace( +      [](_Unwind_Context *Context, void *Handler) { +        return (*static_cast<decltype(HandleFrame) *>(Handler))(Context); +      }, +      static_cast<void *>(&HandleFrame)); +  return std::max(Entries, 0); +} +#endif +  // PrintStackTrace - In the case of a program crash or fault, print out a stack  // trace so that the user has an indication of why and where we died.  //  // On glibc systems we have the 'backtrace' function, which works nicely, but  // doesn't demangle symbols.  void llvm::sys::PrintStackTrace(raw_ostream &OS) { -#if defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES) -  static void* StackTrace[256]; +#if defined(ENABLE_BACKTRACES) +  static void *StackTrace[256]; +  int depth = 0; +#if defined(HAVE_BACKTRACE)    // Use backtrace() to output a backtrace on Linux systems with glibc. -  int depth = backtrace(StackTrace, +  if (!depth) +    depth = backtrace(StackTrace, static_cast<int>(array_lengthof(StackTrace))); +#endif +#if defined(HAVE_UNWIND_BACKTRACE) +  // Try _Unwind_Backtrace() if backtrace() failed. +  if (!depth) +    depth = unwindBacktrace(StackTrace,                          static_cast<int>(array_lengthof(StackTrace))); -  if (printSymbolizedStackTrace(StackTrace, depth, OS)) +#endif +  if (!depth) +    return; + +  if (printSymbolizedStackTrace(Argv0, StackTrace, depth, OS))      return;  #if HAVE_DLFCN_H && __GNUG__    int width = 0; @@ -369,7 +459,7 @@ void llvm::sys::PrintStackTrace(raw_ostream &OS) {      }      OS << '\n';    } -#else +#elif defined(HAVE_BACKTRACE)    backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO);  #endif  #endif @@ -383,7 +473,10 @@ void llvm::sys::DisableSystemDialogsOnCrash() {}  /// PrintStackTraceOnErrorSignal - When an error signal (such as SIGABRT or  /// SIGSEGV) is delivered to the process, print a stack trace and then exit. -void llvm::sys::PrintStackTraceOnErrorSignal(bool DisableCrashReporting) { +void llvm::sys::PrintStackTraceOnErrorSignal(StringRef Argv0, +                                             bool DisableCrashReporting) { +  ::Argv0 = Argv0; +    AddSignalHandler(PrintStackTraceSignalHandler, nullptr);  #if defined(__APPLE__) && defined(ENABLE_CRASH_OVERRIDES) @@ -402,42 +495,3 @@ void llvm::sys::PrintStackTraceOnErrorSignal(bool DisableCrashReporting) {    }  #endif  } - - -/***/ - -// On Darwin, raise sends a signal to the main thread instead of the current -// thread. This has the unfortunate effect that assert() and abort() will end up -// bypassing our crash recovery attempts. We work around this for anything in -// the same linkage unit by just defining our own versions of the assert handler -// and abort. - -#if defined(__APPLE__) && defined(ENABLE_CRASH_OVERRIDES) - -#include <signal.h> -#include <pthread.h> - -int raise(int sig) { -  return pthread_kill(pthread_self(), sig); -} - -void __assert_rtn(const char *func, -                  const char *file, -                  int line, -                  const char *expr) { -  if (func) -    fprintf(stderr, "Assertion failed: (%s), function %s, file %s, line %d.\n", -            expr, func, file, line); -  else -    fprintf(stderr, "Assertion failed: (%s), file %s, line %d.\n", -            expr, file, line); -  abort(); -} - -void abort() { -  raise(SIGABRT); -  usleep(1000); -  __builtin_trap(); -} - -#endif  | 
