mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-22 01:11:42 +00:00
Update LLVM from stable upstream (#1653)
Replace CheckedMalloc with upstream safe_malloc.
This commit is contained in:
@@ -12,7 +12,191 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/ErrorHandling.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/Error.h"
|
||||
#include "wpi/WindowsError.h"
|
||||
#include "wpi/raw_ostream.h"
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <mutex>
|
||||
#include <new>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
static fatal_error_handler_t ErrorHandler = nullptr;
|
||||
static void *ErrorHandlerUserData = nullptr;
|
||||
|
||||
static fatal_error_handler_t BadAllocErrorHandler = nullptr;
|
||||
static void *BadAllocErrorHandlerUserData = nullptr;
|
||||
|
||||
// Mutexes to synchronize installing error handlers and calling error handlers.
|
||||
// Do not use ManagedStatic, or that may allocate memory while attempting to
|
||||
// report an OOM.
|
||||
//
|
||||
// This usage of std::mutex has to be conditionalized behind ifdefs because
|
||||
// of this script:
|
||||
// compiler-rt/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh
|
||||
// That script attempts to statically link the LLVM symbolizer library with the
|
||||
// STL and hide all of its symbols with 'opt -internalize'. To reduce size, it
|
||||
// cuts out the threading portions of the hermetic copy of libc++ that it
|
||||
// builds. We can remove these ifdefs if that script goes away.
|
||||
static std::mutex ErrorHandlerMutex;
|
||||
static std::mutex BadAllocErrorHandlerMutex;
|
||||
|
||||
void wpi::install_fatal_error_handler(fatal_error_handler_t handler,
|
||||
void *user_data) {
|
||||
std::lock_guard<std::mutex> Lock(ErrorHandlerMutex);
|
||||
assert(!ErrorHandler && "Error handler already registered!\n");
|
||||
ErrorHandler = handler;
|
||||
ErrorHandlerUserData = user_data;
|
||||
}
|
||||
|
||||
void wpi::remove_fatal_error_handler() {
|
||||
std::lock_guard<std::mutex> Lock(ErrorHandlerMutex);
|
||||
ErrorHandler = nullptr;
|
||||
ErrorHandlerUserData = nullptr;
|
||||
}
|
||||
|
||||
void wpi::report_fatal_error(const char *Reason, bool GenCrashDiag) {
|
||||
report_fatal_error(Twine(Reason), GenCrashDiag);
|
||||
}
|
||||
|
||||
void wpi::report_fatal_error(const std::string &Reason, bool GenCrashDiag) {
|
||||
report_fatal_error(Twine(Reason), GenCrashDiag);
|
||||
}
|
||||
|
||||
void wpi::report_fatal_error(StringRef Reason, bool GenCrashDiag) {
|
||||
report_fatal_error(Twine(Reason), GenCrashDiag);
|
||||
}
|
||||
|
||||
void wpi::report_fatal_error(const Twine &Reason, bool GenCrashDiag) {
|
||||
wpi::fatal_error_handler_t handler = nullptr;
|
||||
void* handlerData = nullptr;
|
||||
{
|
||||
// Only acquire the mutex while reading the handler, so as not to invoke a
|
||||
// user-supplied callback under a lock.
|
||||
std::lock_guard<std::mutex> Lock(ErrorHandlerMutex);
|
||||
handler = ErrorHandler;
|
||||
handlerData = ErrorHandlerUserData;
|
||||
}
|
||||
|
||||
if (handler) {
|
||||
handler(handlerData, Reason.str(), GenCrashDiag);
|
||||
} else {
|
||||
// Blast the result out to stderr. We don't try hard to make sure this
|
||||
// succeeds (e.g. handling EINTR) and we can't use errs() here because
|
||||
// raw ostreams can call report_fatal_error.
|
||||
SmallVector<char, 64> Buffer;
|
||||
raw_svector_ostream OS(Buffer);
|
||||
OS << "LLVM ERROR: " << Reason << "\n";
|
||||
StringRef MessageStr = OS.str();
|
||||
#ifdef _WIN32
|
||||
int written = ::_write(2, MessageStr.data(), MessageStr.size());
|
||||
#else
|
||||
ssize_t written = ::write(2, MessageStr.data(), MessageStr.size());
|
||||
#endif
|
||||
(void)written; // If something went wrong, we deliberately just give up.
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void wpi::install_bad_alloc_error_handler(fatal_error_handler_t handler,
|
||||
void *user_data) {
|
||||
std::lock_guard<std::mutex> Lock(BadAllocErrorHandlerMutex);
|
||||
assert(!ErrorHandler && "Bad alloc error handler already registered!\n");
|
||||
BadAllocErrorHandler = handler;
|
||||
BadAllocErrorHandlerUserData = user_data;
|
||||
}
|
||||
|
||||
void wpi::remove_bad_alloc_error_handler() {
|
||||
std::lock_guard<std::mutex> Lock(BadAllocErrorHandlerMutex);
|
||||
BadAllocErrorHandler = nullptr;
|
||||
BadAllocErrorHandlerUserData = nullptr;
|
||||
}
|
||||
|
||||
void wpi::report_bad_alloc_error(const char *Reason, bool GenCrashDiag) {
|
||||
fatal_error_handler_t Handler = nullptr;
|
||||
void *HandlerData = nullptr;
|
||||
{
|
||||
// Only acquire the mutex while reading the handler, so as not to invoke a
|
||||
// user-supplied callback under a lock.
|
||||
std::lock_guard<std::mutex> Lock(BadAllocErrorHandlerMutex);
|
||||
Handler = BadAllocErrorHandler;
|
||||
HandlerData = BadAllocErrorHandlerUserData;
|
||||
}
|
||||
|
||||
if (Handler) {
|
||||
Handler(HandlerData, Reason, GenCrashDiag);
|
||||
wpi_unreachable("bad alloc handler should not return");
|
||||
}
|
||||
|
||||
// Don't call the normal error handler. It may allocate memory. Directly write
|
||||
// an OOM to stderr and abort.
|
||||
char OOMMessage[] = "LLVM ERROR: out of memory\n";
|
||||
#ifdef _WIN32
|
||||
int written = ::_write(2, OOMMessage, strlen(OOMMessage));
|
||||
#else
|
||||
ssize_t written = ::write(2, OOMMessage, strlen(OOMMessage));
|
||||
#endif
|
||||
(void)written;
|
||||
abort();
|
||||
}
|
||||
|
||||
// Causes crash on allocation failure. It is called prior to the handler set by
|
||||
// 'install_bad_alloc_error_handler'.
|
||||
static void out_of_memory_new_handler() {
|
||||
wpi::report_bad_alloc_error("Allocation failed");
|
||||
}
|
||||
|
||||
// Installs new handler that causes crash on allocation failure. It does not
|
||||
// need to be called explicitly, if this file is linked to application, because
|
||||
// in this case it is called during construction of 'new_handler_installer'.
|
||||
void wpi::install_out_of_memory_new_handler() {
|
||||
static bool out_of_memory_new_handler_installed = false;
|
||||
if (!out_of_memory_new_handler_installed) {
|
||||
std::set_new_handler(out_of_memory_new_handler);
|
||||
out_of_memory_new_handler_installed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Static object that causes installation of 'out_of_memory_new_handler' before
|
||||
// execution of 'main'.
|
||||
static class NewHandlerInstaller {
|
||||
public:
|
||||
NewHandlerInstaller() {
|
||||
install_out_of_memory_new_handler();
|
||||
}
|
||||
} new_handler_installer;
|
||||
|
||||
void wpi::wpi_unreachable_internal(const char *msg, const char *file,
|
||||
unsigned line) {
|
||||
// This code intentionally doesn't call the ErrorHandler callback, because
|
||||
// wpi_unreachable is intended to be used to indicate "impossible"
|
||||
// situations, and not legitimate runtime errors.
|
||||
if (msg)
|
||||
errs() << msg << "\n";
|
||||
errs() << "UNREACHABLE executed";
|
||||
if (file)
|
||||
errs() << " at " << file << ":" << line;
|
||||
errs() << "!\n";
|
||||
abort();
|
||||
#ifdef LLVM_BUILTIN_UNREACHABLE
|
||||
// Windows systems and possibly others don't declare abort() to be noreturn,
|
||||
// so use the unreachable builtin to avoid a Clang self-host warning.
|
||||
LLVM_BUILTIN_UNREACHABLE;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
|
||||
Reference in New Issue
Block a user