LLVM 19.0.0git
ErrorHandling.cpp
Go to the documentation of this file.
1//===- lib/Support/ErrorHandling.cpp - Callbacks for errors ---------------===//
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-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines an API used to indicate fatal error conditions. Non-fatal
10// errors (most of them) should be handled through LLVMContext.
11//
12//===----------------------------------------------------------------------===//
13
17#include "llvm/ADT/Twine.h"
18#include "llvm/Config/config.h"
19#include "llvm/Support/Debug.h"
20#include "llvm/Support/Errc.h"
21#include "llvm/Support/Error.h"
27#include <cassert>
28#include <cstdlib>
29#include <mutex>
30#include <new>
31
32#if defined(HAVE_UNISTD_H)
33# include <unistd.h>
34#endif
35#if defined(_MSC_VER)
36# include <io.h>
37# include <fcntl.h>
38#endif
39
40using namespace llvm;
41
43static void *ErrorHandlerUserData = nullptr;
44
46static void *BadAllocErrorHandlerUserData = nullptr;
47
48#if LLVM_ENABLE_THREADS == 1
49// Mutexes to synchronize installing error handlers and calling error handlers.
50// Do not use ManagedStatic, or that may allocate memory while attempting to
51// report an OOM.
52//
53// This usage of std::mutex has to be conditionalized behind ifdefs because
54// of this script:
55// compiler-rt/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh
56// That script attempts to statically link the LLVM symbolizer library with the
57// STL and hide all of its symbols with 'opt -internalize'. To reduce size, it
58// cuts out the threading portions of the hermetic copy of libc++ that it
59// builds. We can remove these ifdefs if that script goes away.
60static std::mutex ErrorHandlerMutex;
61static std::mutex BadAllocErrorHandlerMutex;
62#endif
63
65 void *user_data) {
66#if LLVM_ENABLE_THREADS == 1
67 std::lock_guard<std::mutex> Lock(ErrorHandlerMutex);
68#endif
69 assert(!ErrorHandler && "Error handler already registered!\n");
70 ErrorHandler = handler;
71 ErrorHandlerUserData = user_data;
72}
73
75#if LLVM_ENABLE_THREADS == 1
76 std::lock_guard<std::mutex> Lock(ErrorHandlerMutex);
77#endif
78 ErrorHandler = nullptr;
79 ErrorHandlerUserData = nullptr;
80}
81
82void llvm::report_fatal_error(const char *Reason, bool GenCrashDiag) {
83 report_fatal_error(Twine(Reason), GenCrashDiag);
84}
85
86void llvm::report_fatal_error(StringRef Reason, bool GenCrashDiag) {
87 report_fatal_error(Twine(Reason), GenCrashDiag);
88}
89
90void llvm::report_fatal_error(const Twine &Reason, bool GenCrashDiag) {
91 llvm::fatal_error_handler_t handler = nullptr;
92 void* handlerData = nullptr;
93 {
94 // Only acquire the mutex while reading the handler, so as not to invoke a
95 // user-supplied callback under a lock.
96#if LLVM_ENABLE_THREADS == 1
97 std::lock_guard<std::mutex> Lock(ErrorHandlerMutex);
98#endif
99 handler = ErrorHandler;
100 handlerData = ErrorHandlerUserData;
101 }
102
103 if (handler) {
104 handler(handlerData, Reason.str().c_str(), GenCrashDiag);
105 } else {
106 // Blast the result out to stderr. We don't try hard to make sure this
107 // succeeds (e.g. handling EINTR) and we can't use errs() here because
108 // raw ostreams can call report_fatal_error.
110 raw_svector_ostream OS(Buffer);
111 OS << "LLVM ERROR: " << Reason << "\n";
112 StringRef MessageStr = OS.str();
113 ssize_t written = ::write(2, MessageStr.data(), MessageStr.size());
114 (void)written; // If something went wrong, we deliberately just give up.
115 }
116
117 // If we reached here, we are failing ungracefully. Run the interrupt handlers
118 // to make sure any special cleanups get done, in particular that we remove
119 // files registered with RemoveFileOnSignal.
121
122 if (GenCrashDiag)
123 abort();
124 else
125 exit(1);
126}
127
129 void *user_data) {
130#if LLVM_ENABLE_THREADS == 1
131 std::lock_guard<std::mutex> Lock(BadAllocErrorHandlerMutex);
132#endif
134 "Bad alloc error handler already registered!\n");
135 BadAllocErrorHandler = handler;
137}
138
140#if LLVM_ENABLE_THREADS == 1
141 std::lock_guard<std::mutex> Lock(BadAllocErrorHandlerMutex);
142#endif
143 BadAllocErrorHandler = nullptr;
145}
146
147void llvm::report_bad_alloc_error(const char *Reason, bool GenCrashDiag) {
148 fatal_error_handler_t Handler = nullptr;
149 void *HandlerData = nullptr;
150 {
151 // Only acquire the mutex while reading the handler, so as not to invoke a
152 // user-supplied callback under a lock.
153#if LLVM_ENABLE_THREADS == 1
154 std::lock_guard<std::mutex> Lock(BadAllocErrorHandlerMutex);
155#endif
156 Handler = BadAllocErrorHandler;
157 HandlerData = BadAllocErrorHandlerUserData;
158 }
159
160 if (Handler) {
161 Handler(HandlerData, Reason, GenCrashDiag);
162 llvm_unreachable("bad alloc handler should not return");
163 }
164
165#ifdef LLVM_ENABLE_EXCEPTIONS
166 // If exceptions are enabled, make OOM in malloc look like OOM in new.
167 throw std::bad_alloc();
168#else
169 // Don't call the normal error handler. It may allocate memory. Directly write
170 // an OOM to stderr and abort.
171 const char *OOMMessage = "LLVM ERROR: out of memory\n";
172 const char *Newline = "\n";
173 (void)!::write(2, OOMMessage, strlen(OOMMessage));
174 (void)!::write(2, Reason, strlen(Reason));
175 (void)!::write(2, Newline, strlen(Newline));
176 abort();
177#endif
178}
179
180#ifdef LLVM_ENABLE_EXCEPTIONS
181// Do not set custom new handler if exceptions are enabled. In this case OOM
182// errors are handled by throwing 'std::bad_alloc'.
184}
185#else
186// Causes crash on allocation failure. It is called prior to the handler set by
187// 'install_bad_alloc_error_handler'.
189 llvm::report_bad_alloc_error("Allocation failed");
190}
191
192// Installs new handler that causes crash on allocation failure. It is called by
193// InitLLVM.
195 std::new_handler old = std::set_new_handler(out_of_memory_new_handler);
196 (void)old;
197 assert((old == nullptr || old == out_of_memory_new_handler) &&
198 "new-handler already installed");
199}
200#endif
201
202void llvm::llvm_unreachable_internal(const char *msg, const char *file,
203 unsigned line) {
204 // This code intentionally doesn't call the ErrorHandler callback, because
205 // llvm_unreachable is intended to be used to indicate "impossible"
206 // situations, and not legitimate runtime errors.
207 if (msg)
208 dbgs() << msg << "\n";
209 dbgs() << "UNREACHABLE executed";
210 if (file)
211 dbgs() << " at " << file << ":" << line;
212 dbgs() << "!\n";
213 abort();
214#ifdef LLVM_BUILTIN_UNREACHABLE
215 // Windows systems and possibly others don't declare abort() to be noreturn,
216 // so use the unreachable builtin to avoid a Clang self-host warning.
217 LLVM_BUILTIN_UNREACHABLE;
218#endif
219}
220
221static void bindingsErrorHandler(void *user_data, const char *reason,
222 bool gen_crash_diag) {
223 LLVMFatalErrorHandler handler =
224 LLVM_EXTENSION reinterpret_cast<LLVMFatalErrorHandler>(user_data);
225 handler(reason);
226}
227
230 LLVM_EXTENSION reinterpret_cast<void *>(Handler));
231}
232
235}
236
237#ifdef _WIN32
238
239#include <winerror.h>
240
241// I'd rather not double the line count of the following.
242#define MAP_ERR_TO_COND(x, y) \
243 case x: \
244 return make_error_code(errc::y)
245
246std::error_code llvm::mapWindowsError(unsigned EV) {
247 switch (EV) {
248 MAP_ERR_TO_COND(ERROR_ACCESS_DENIED, permission_denied);
249 MAP_ERR_TO_COND(ERROR_ALREADY_EXISTS, file_exists);
250 MAP_ERR_TO_COND(ERROR_BAD_NETPATH, no_such_file_or_directory);
251 MAP_ERR_TO_COND(ERROR_BAD_PATHNAME, no_such_file_or_directory);
252 MAP_ERR_TO_COND(ERROR_BAD_UNIT, no_such_device);
253 MAP_ERR_TO_COND(ERROR_BROKEN_PIPE, broken_pipe);
254 MAP_ERR_TO_COND(ERROR_BUFFER_OVERFLOW, filename_too_long);
255 MAP_ERR_TO_COND(ERROR_BUSY, device_or_resource_busy);
256 MAP_ERR_TO_COND(ERROR_BUSY_DRIVE, device_or_resource_busy);
257 MAP_ERR_TO_COND(ERROR_CANNOT_MAKE, permission_denied);
258 MAP_ERR_TO_COND(ERROR_CANTOPEN, io_error);
259 MAP_ERR_TO_COND(ERROR_CANTREAD, io_error);
260 MAP_ERR_TO_COND(ERROR_CANTWRITE, io_error);
261 MAP_ERR_TO_COND(ERROR_CURRENT_DIRECTORY, permission_denied);
262 MAP_ERR_TO_COND(ERROR_DEV_NOT_EXIST, no_such_device);
263 MAP_ERR_TO_COND(ERROR_DEVICE_IN_USE, device_or_resource_busy);
264 MAP_ERR_TO_COND(ERROR_DIR_NOT_EMPTY, directory_not_empty);
265 MAP_ERR_TO_COND(ERROR_DIRECTORY, invalid_argument);
266 MAP_ERR_TO_COND(ERROR_DISK_FULL, no_space_on_device);
267 MAP_ERR_TO_COND(ERROR_FILE_EXISTS, file_exists);
268 MAP_ERR_TO_COND(ERROR_FILE_NOT_FOUND, no_such_file_or_directory);
269 MAP_ERR_TO_COND(ERROR_HANDLE_DISK_FULL, no_space_on_device);
270 MAP_ERR_TO_COND(ERROR_INVALID_ACCESS, permission_denied);
271 MAP_ERR_TO_COND(ERROR_INVALID_DRIVE, no_such_device);
272 MAP_ERR_TO_COND(ERROR_INVALID_FUNCTION, function_not_supported);
273 MAP_ERR_TO_COND(ERROR_INVALID_HANDLE, invalid_argument);
274 MAP_ERR_TO_COND(ERROR_INVALID_NAME, invalid_argument);
275 MAP_ERR_TO_COND(ERROR_INVALID_PARAMETER, invalid_argument);
276 MAP_ERR_TO_COND(ERROR_LOCK_VIOLATION, no_lock_available);
277 MAP_ERR_TO_COND(ERROR_LOCKED, no_lock_available);
278 MAP_ERR_TO_COND(ERROR_NEGATIVE_SEEK, invalid_argument);
279 MAP_ERR_TO_COND(ERROR_NOACCESS, permission_denied);
280 MAP_ERR_TO_COND(ERROR_NOT_ENOUGH_MEMORY, not_enough_memory);
281 MAP_ERR_TO_COND(ERROR_NOT_READY, resource_unavailable_try_again);
282 MAP_ERR_TO_COND(ERROR_NOT_SUPPORTED, not_supported);
283 MAP_ERR_TO_COND(ERROR_OPEN_FAILED, io_error);
284 MAP_ERR_TO_COND(ERROR_OPEN_FILES, device_or_resource_busy);
285 MAP_ERR_TO_COND(ERROR_OUTOFMEMORY, not_enough_memory);
286 MAP_ERR_TO_COND(ERROR_PATH_NOT_FOUND, no_such_file_or_directory);
287 MAP_ERR_TO_COND(ERROR_READ_FAULT, io_error);
288 MAP_ERR_TO_COND(ERROR_REPARSE_TAG_INVALID, invalid_argument);
289 MAP_ERR_TO_COND(ERROR_RETRY, resource_unavailable_try_again);
290 MAP_ERR_TO_COND(ERROR_SEEK, io_error);
291 MAP_ERR_TO_COND(ERROR_SHARING_VIOLATION, permission_denied);
292 MAP_ERR_TO_COND(ERROR_TOO_MANY_OPEN_FILES, too_many_files_open);
293 MAP_ERR_TO_COND(ERROR_WRITE_FAULT, io_error);
294 MAP_ERR_TO_COND(ERROR_WRITE_PROTECT, permission_denied);
295 MAP_ERR_TO_COND(WSAEACCES, permission_denied);
296 MAP_ERR_TO_COND(WSAEBADF, bad_file_descriptor);
297 MAP_ERR_TO_COND(WSAEFAULT, bad_address);
298 MAP_ERR_TO_COND(WSAEINTR, interrupted);
299 MAP_ERR_TO_COND(WSAEINVAL, invalid_argument);
300 MAP_ERR_TO_COND(WSAEMFILE, too_many_files_open);
301 MAP_ERR_TO_COND(WSAENAMETOOLONG, filename_too_long);
302 default:
303 return std::error_code(EV, std::system_category());
304 }
305}
306
307#endif
#define LLVM_EXTENSION
LLVM_EXTENSION - Support compilers where we have a keyword to suppress pedantic diagnostics.
Definition: Compiler.h:340
static fatal_error_handler_t ErrorHandler
static void out_of_memory_new_handler()
static void bindingsErrorHandler(void *user_data, const char *reason, bool gen_crash_diag)
static fatal_error_handler_t BadAllocErrorHandler
static void * BadAllocErrorHandlerUserData
static void * ErrorHandlerUserData
Provides a library for accessing information about this process and other processes on the operating ...
dot regions Print regions of function to dot file(with no function bodies)"
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
raw_pwrite_stream & OS
This file defines the SmallVector class.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
constexpr size_t size() const
size - Get the string size.
Definition: StringRef.h:137
constexpr const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
Definition: StringRef.h:131
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
std::string str() const
Return the twine contents as a std::string.
Definition: Twine.cpp:17
A raw_ostream that writes to an SmallVector or SmallString.
Definition: raw_ostream.h:690
void LLVMResetFatalErrorHandler()
Reset the fatal error handler.
void(* LLVMFatalErrorHandler)(const char *Reason)
Definition: ErrorHandling.h:27
void LLVMInstallFatalErrorHandler(LLVMFatalErrorHandler Handler)
Install a fatal error handler.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
void RunInterruptHandlers()
This function runs all the registered interrupt handlers, including the removal of files registered b...
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
void(* fatal_error_handler_t)(void *user_data, const char *reason, bool gen_crash_diag)
An error handler callback.
Definition: ErrorHandling.h:24
void install_fatal_error_handler(fatal_error_handler_t handler, void *user_data=nullptr)
install_fatal_error_handler - Installs a new error handler to be used whenever a serious (non-recover...
void install_bad_alloc_error_handler(fatal_error_handler_t handler, void *user_data=nullptr)
Installs a new bad alloc error handler that should be used whenever a bad alloc error,...
void remove_bad_alloc_error_handler()
Restores default bad alloc error handling behavior.
@ no_space_on_device
@ no_such_file_or_directory
@ directory_not_empty
@ bad_file_descriptor
@ function_not_supported
@ device_or_resource_busy
@ resource_unavailable_try_again
@ too_many_files_open
Error write(MCStreamer &Out, ArrayRef< std::string > Inputs, OnCuIndexOverflow OverflowOptValue)
Definition: DWP.cpp:601
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:156
void install_out_of_memory_new_handler()
void llvm_unreachable_internal(const char *msg=nullptr, const char *file=nullptr, unsigned line=0)
This function calls abort(), and prints the optional message to stderr.
void remove_fatal_error_handler()
Restores default error handling behaviour.
std::error_code mapWindowsError(unsigned EV)
void report_bad_alloc_error(const char *Reason, bool GenCrashDiag=true)
Reports a bad alloc error, calling any user defined bad alloc error handler.