diff options
Diffstat (limited to 'contrib/llvm/lib/Support/Unix')
-rw-r--r-- | contrib/llvm/lib/Support/Unix/Memory.inc | 4 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Unix/Path.inc | 137 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Unix/Process.inc | 4 | ||||
-rw-r--r-- | contrib/llvm/lib/Support/Unix/Signals.inc | 148 |
4 files changed, 236 insertions, 57 deletions
diff --git a/contrib/llvm/lib/Support/Unix/Memory.inc b/contrib/llvm/lib/Support/Unix/Memory.inc index d703191..f3463e5 100644 --- a/contrib/llvm/lib/Support/Unix/Memory.inc +++ b/contrib/llvm/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/contrib/llvm/lib/Support/Unix/Path.inc b/contrib/llvm/lib/Support/Unix/Path.inc index d85c37a..84aafcb 100644 --- a/contrib/llvm/lib/Support/Unix/Path.inc +++ b/contrib/llvm/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/contrib/llvm/lib/Support/Unix/Process.inc b/contrib/llvm/lib/Support/Unix/Process.inc index 27083ee..d81836b 100644 --- a/contrib/llvm/lib/Support/Unix/Process.inc +++ b/contrib/llvm/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/contrib/llvm/lib/Support/Unix/Signals.inc b/contrib/llvm/lib/Support/Unix/Signals.inc index 061cdb3..55fd76d 100644 --- a/contrib/llvm/lib/Support/Unix/Signals.inc +++ b/contrib/llvm/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,20 +355,64 @@ 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__ +#if HAVE_DLFCN_H && __GNUG__ && !defined(__CYGWIN__) int width = 0; for (int i = 0; i < depth; ++i) { Dl_info dlinfo; @@ -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 |