LLVM 17.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
133 assert(!ErrorHandler && "Bad alloc error handler already registered!\n");
134 BadAllocErrorHandler = handler;
136}
137
139#if LLVM_ENABLE_THREADS == 1
140 std::lock_guard<std::mutex> Lock(BadAllocErrorHandlerMutex);
141#endif
142 BadAllocErrorHandler = nullptr;
144}
145
146void llvm::report_bad_alloc_error(const char *Reason, bool GenCrashDiag) {
147 fatal_error_handler_t Handler = nullptr;
148 void *HandlerData = nullptr;
149 {
150 // Only acquire the mutex while reading the handler, so as not to invoke a
151 // user-supplied callback under a lock.
152#if LLVM_ENABLE_THREADS == 1
153 std::lock_guard<std::mutex> Lock(BadAllocErrorHandlerMutex);
154#endif
155 Handler = BadAllocErrorHandler;
156 HandlerData = BadAllocErrorHandlerUserData;
157 }
158
159 if (Handler) {
160 Handler(HandlerData, Reason, GenCrashDiag);
161 llvm_unreachable("bad alloc handler should not return");
162 }
163
164#ifdef LLVM_ENABLE_EXCEPTIONS
165 // If exceptions are enabled, make OOM in malloc look like OOM in new.
166 throw std::bad_alloc();
167#else
168 // Don't call the normal error handler. It may allocate memory. Directly write
169 // an OOM to stderr and abort.
170 const char *OOMMessage = "LLVM ERROR: out of memory\n";
171 const char *Newline = "\n";
172 (void)!::write(2, OOMMessage, strlen(OOMMessage));
173 (void)!::write(2, Reason, strlen(Reason));
174 (void)!::write(2, Newline, strlen(Newline));
175 abort();
176#endif
177}
178
179#ifdef LLVM_ENABLE_EXCEPTIONS
180// Do not set custom new handler if exceptions are enabled. In this case OOM
181// errors are handled by throwing 'std::bad_alloc'.
183}
184#else
185// Causes crash on allocation failure. It is called prior to the handler set by
186// 'install_bad_alloc_error_handler'.
188 llvm::report_bad_alloc_error("Allocation failed");
189}
190
191// Installs new handler that causes crash on allocation failure. It is called by
192// InitLLVM.
194 std::new_handler old = std::set_new_handler(out_of_memory_new_handler);
195 (void)old;
196 assert((old == nullptr || old == out_of_memory_new_handler) &&
197 "new-handler already installed");
198}
199#endif
200
201void llvm::llvm_unreachable_internal(const char *msg, const char *file,
202 unsigned line) {
203 // This code intentionally doesn't call the ErrorHandler callback, because
204 // llvm_unreachable is intended to be used to indicate "impossible"
205 // situations, and not legitimate runtime errors.
206 if (msg)
207 dbgs() << msg << "\n";
208 dbgs() << "UNREACHABLE executed";
209 if (file)
210 dbgs() << " at " << file << ":" << line;
211 dbgs() << "!\n";
212 abort();
213#ifdef LLVM_BUILTIN_UNREACHABLE
214 // Windows systems and possibly others don't declare abort() to be noreturn,
215 // so use the unreachable builtin to avoid a Clang self-host warning.
216 LLVM_BUILTIN_UNREACHABLE;
217#endif
218}
219
220static void bindingsErrorHandler(void *user_data, const char *reason,
221 bool gen_crash_diag) {
222 LLVMFatalErrorHandler handler =
223 LLVM_EXTENSION reinterpret_cast<LLVMFatalErrorHandler>(user_data);
224 handler(reason);
225}
226
229 LLVM_EXTENSION reinterpret_cast<void *>(Handler));
230}
231
234}
235
236#ifdef _WIN32
237
238#include <winerror.h>
239
240// I'd rather not double the line count of the following.
241#define MAP_ERR_TO_COND(x, y) \
242 case x: \
243 return make_error_code(errc::y)
244
245std::error_code llvm::mapWindowsError(unsigned EV) {
246 switch (EV) {
247 MAP_ERR_TO_COND(ERROR_ACCESS_DENIED, permission_denied);
248 MAP_ERR_TO_COND(ERROR_ALREADY_EXISTS, file_exists);
249 MAP_ERR_TO_COND(ERROR_BAD_NETPATH, no_such_file_or_directory);
250 MAP_ERR_TO_COND(ERROR_BAD_PATHNAME, no_such_file_or_directory);
251 MAP_ERR_TO_COND(ERROR_BAD_UNIT, no_such_device);
252 MAP_ERR_TO_COND(ERROR_BROKEN_PIPE, broken_pipe);
253 MAP_ERR_TO_COND(ERROR_BUFFER_OVERFLOW, filename_too_long);
254 MAP_ERR_TO_COND(ERROR_BUSY, device_or_resource_busy);
255 MAP_ERR_TO_COND(ERROR_BUSY_DRIVE, device_or_resource_busy);
256 MAP_ERR_TO_COND(ERROR_CANNOT_MAKE, permission_denied);
257 MAP_ERR_TO_COND(ERROR_CANTOPEN, io_error);
258 MAP_ERR_TO_COND(ERROR_CANTREAD, io_error);
259 MAP_ERR_TO_COND(ERROR_CANTWRITE, io_error);
260 MAP_ERR_TO_COND(ERROR_CURRENT_DIRECTORY, permission_denied);
261 MAP_ERR_TO_COND(ERROR_DEV_NOT_EXIST, no_such_device);
262 MAP_ERR_TO_COND(ERROR_DEVICE_IN_USE, device_or_resource_busy);
263 MAP_ERR_TO_COND(ERROR_DIR_NOT_EMPTY, directory_not_empty);
264 MAP_ERR_TO_COND(ERROR_DIRECTORY, invalid_argument);
265 MAP_ERR_TO_COND(ERROR_DISK_FULL, no_space_on_device);
266 MAP_ERR_TO_COND(ERROR_FILE_EXISTS, file_exists);
267 MAP_ERR_TO_COND(ERROR_FILE_NOT_FOUND, no_such_file_or_directory);
268 MAP_ERR_TO_COND(ERROR_HANDLE_DISK_FULL, no_space_on_device);
269 MAP_ERR_TO_COND(ERROR_INVALID_ACCESS, permission_denied);
270 MAP_ERR_TO_COND(ERROR_INVALID_DRIVE, no_such_device);
271 MAP_ERR_TO_COND(ERROR_INVALID_FUNCTION, function_not_supported);
272 MAP_ERR_TO_COND(ERROR_INVALID_HANDLE, invalid_argument);
273 MAP_ERR_TO_COND(ERROR_INVALID_NAME, invalid_argument);
274 MAP_ERR_TO_COND(ERROR_INVALID_PARAMETER, invalid_argument);
275 MAP_ERR_TO_COND(ERROR_LOCK_VIOLATION, no_lock_available);
276 MAP_ERR_TO_COND(ERROR_LOCKED, no_lock_available);
277 MAP_ERR_TO_COND(ERROR_NEGATIVE_SEEK, invalid_argument);
278 MAP_ERR_TO_COND(ERROR_NOACCESS, permission_denied);
279 MAP_ERR_TO_COND(ERROR_NOT_ENOUGH_MEMORY, not_enough_memory);
280 MAP_ERR_TO_COND(ERROR_NOT_READY, resource_unavailable_try_again);
281 MAP_ERR_TO_COND(ERROR_NOT_SUPPORTED, not_supported);
282 MAP_ERR_TO_COND(ERROR_OPEN_FAILED, io_error);
283 MAP_ERR_TO_COND(ERROR_OPEN_FILES, device_or_resource_busy);
284 MAP_ERR_TO_COND(ERROR_OUTOFMEMORY, not_enough_memory);
285 MAP_ERR_TO_COND(ERROR_PATH_NOT_FOUND, no_such_file_or_directory);
286 MAP_ERR_TO_COND(ERROR_READ_FAULT, io_error);
287 MAP_ERR_TO_COND(ERROR_REPARSE_TAG_INVALID, invalid_argument);
288 MAP_ERR_TO_COND(ERROR_RETRY, resource_unavailable_try_again);
289 MAP_ERR_TO_COND(ERROR_SEEK, io_error);
290 MAP_ERR_TO_COND(ERROR_SHARING_VIOLATION, permission_denied);
291 MAP_ERR_TO_COND(ERROR_TOO_MANY_OPEN_FILES, too_many_files_open);
292 MAP_ERR_TO_COND(ERROR_WRITE_FAULT, io_error);
293 MAP_ERR_TO_COND(ERROR_WRITE_PROTECT, permission_denied);
294 MAP_ERR_TO_COND(WSAEACCES, permission_denied);
295 MAP_ERR_TO_COND(WSAEBADF, bad_file_descriptor);
296 MAP_ERR_TO_COND(WSAEFAULT, bad_address);
297 MAP_ERR_TO_COND(WSAEINTR, interrupted);
298 MAP_ERR_TO_COND(WSAEINVAL, invalid_argument);
299 MAP_ERR_TO_COND(WSAEMFILE, too_many_files_open);
300 MAP_ERR_TO_COND(WSAENAMETOOLONG, filename_too_long);
301 default:
302 return std::error_code(EV, std::system_category());
303 }
304}
305
306#endif
#define LLVM_EXTENSION
LLVM_EXTENSION - Support compilers where we have a keyword to suppress pedantic diagnostics.
Definition: Compiler.h:303
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:1200
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
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:672
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,...
Error write(MCStreamer &Out, ArrayRef< std::string > Inputs, bool ContinueOnCuIndexOverflow)
Definition: DWP.cpp:585
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
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:145
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.