forked from OSchip/llvm-project
Use std::mutex to avoid memory allocation after OOM
ManagedStatic<sys::Mutex> would lazilly allocate a sys::Mutex to lock when reporting an OOM, which is a bad idea. The three STL implementations that I know of use pthread_mutex_lock and EnterCriticalSection to implement std::mutex. I'm pretty sure that neither of those allocate heap memory. It seems that we unconditionally use std::mutex without testing LLVM_ENABLE_THREADS elsewhere in the codebase, so this should be portable. llvm-svn: 307827
This commit is contained in:
parent
52b2dbb673
commit
5ae1bfe813
|
@ -20,15 +20,13 @@
|
|||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/Errc.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/Mutex.h"
|
||||
#include "llvm/Support/MutexGuard.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include "llvm/Support/Threading.h"
|
||||
#include "llvm/Support/WindowsError.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <mutex>
|
||||
#include <new>
|
||||
|
||||
#if defined(HAVE_UNISTD_H)
|
||||
|
@ -43,22 +41,26 @@ using namespace llvm;
|
|||
|
||||
static fatal_error_handler_t ErrorHandler = nullptr;
|
||||
static void *ErrorHandlerUserData = nullptr;
|
||||
static ManagedStatic<sys::Mutex> ErrorHandlerMutex;
|
||||
|
||||
static fatal_error_handler_t BadAllocErrorHandler = nullptr;
|
||||
static void *BadAllocErrorHandlerUserData = nullptr;
|
||||
static ManagedStatic<sys::Mutex> BadAllocErrorHandlerMutex;
|
||||
|
||||
// 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.
|
||||
static std::mutex ErrorHandlerMutex;
|
||||
static std::mutex BadAllocErrorHandlerMutex;
|
||||
|
||||
void llvm::install_fatal_error_handler(fatal_error_handler_t handler,
|
||||
void *user_data) {
|
||||
llvm::MutexGuard Lock(*ErrorHandlerMutex);
|
||||
std::lock_guard<std::mutex> Lock(ErrorHandlerMutex);
|
||||
assert(!ErrorHandler && "Error handler already registered!\n");
|
||||
ErrorHandler = handler;
|
||||
ErrorHandlerUserData = user_data;
|
||||
}
|
||||
|
||||
void llvm::remove_fatal_error_handler() {
|
||||
llvm::MutexGuard Lock(*ErrorHandlerMutex);
|
||||
std::lock_guard<std::mutex> Lock(ErrorHandlerMutex);
|
||||
ErrorHandler = nullptr;
|
||||
ErrorHandlerUserData = nullptr;
|
||||
}
|
||||
|
@ -81,7 +83,7 @@ void llvm::report_fatal_error(const Twine &Reason, bool GenCrashDiag) {
|
|||
{
|
||||
// Only acquire the mutex while reading the handler, so as not to invoke a
|
||||
// user-supplied callback under a lock.
|
||||
llvm::MutexGuard Lock(*ErrorHandlerMutex);
|
||||
std::lock_guard<std::mutex> Lock(ErrorHandlerMutex);
|
||||
handler = ErrorHandler;
|
||||
handlerData = ErrorHandlerUserData;
|
||||
}
|
||||
|
@ -110,14 +112,14 @@ void llvm::report_fatal_error(const Twine &Reason, bool GenCrashDiag) {
|
|||
|
||||
void llvm::install_bad_alloc_error_handler(fatal_error_handler_t handler,
|
||||
void *user_data) {
|
||||
MutexGuard Lock(*BadAllocErrorHandlerMutex);
|
||||
std::lock_guard<std::mutex> Lock(BadAllocErrorHandlerMutex);
|
||||
assert(!ErrorHandler && "Bad alloc error handler already registered!\n");
|
||||
BadAllocErrorHandler = handler;
|
||||
BadAllocErrorHandlerUserData = user_data;
|
||||
}
|
||||
|
||||
void llvm::remove_bad_alloc_error_handler() {
|
||||
MutexGuard Lock(*BadAllocErrorHandlerMutex);
|
||||
std::lock_guard<std::mutex> Lock(BadAllocErrorHandlerMutex);
|
||||
BadAllocErrorHandler = nullptr;
|
||||
BadAllocErrorHandlerUserData = nullptr;
|
||||
}
|
||||
|
@ -128,7 +130,7 @@ void llvm::report_bad_alloc_error(const char *Reason, bool GenCrashDiag) {
|
|||
{
|
||||
// Only acquire the mutex while reading the handler, so as not to invoke a
|
||||
// user-supplied callback under a lock.
|
||||
MutexGuard Lock(*BadAllocErrorHandlerMutex);
|
||||
std::lock_guard<std::mutex> Lock(BadAllocErrorHandlerMutex);
|
||||
Handler = BadAllocErrorHandler;
|
||||
HandlerData = BadAllocErrorHandlerUserData;
|
||||
}
|
||||
|
@ -142,8 +144,11 @@ void llvm::report_bad_alloc_error(const char *Reason, bool GenCrashDiag) {
|
|||
// If exceptions are enabled, make OOM in malloc look like OOM in new.
|
||||
throw std::bad_alloc();
|
||||
#else
|
||||
// Otherwise, fall back to the normal fatal error handler.
|
||||
report_fatal_error("out of memory: " + Twine(Reason));
|
||||
// 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";
|
||||
(void)::write(2, OOMMessage, strlen(OOMMessage));
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue