LLVM 22.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/Config/llvm-config.h" // for LLVM_ENABLE_THREADS
20#include "llvm/Support/Debug.h"
21#include "llvm/Support/Errc.h"
22#include "llvm/Support/Errno.h"
23#include "llvm/Support/Error.h"
29#include <cassert>
30#include <cstdlib>
31#include <mutex>
32#include <new>
33
34#if defined(HAVE_UNISTD_H)
35# include <unistd.h>
36#endif
37#if defined(_WIN32)
38# include <io.h>
39# include <fcntl.h>
40#endif
41
42using namespace llvm;
43
45static void *ErrorHandlerUserData = nullptr;
46
48static void *BadAllocErrorHandlerUserData = nullptr;
49
50#if LLVM_ENABLE_THREADS == 1
51// Mutexes to synchronize installing error handlers and calling error handlers.
52// Do not use ManagedStatic, or that may allocate memory while attempting to
53// report an OOM.
54//
55// This usage of std::mutex has to be conditionalized behind ifdefs because
56// of this script:
57// compiler-rt/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh
58// That script attempts to statically link the LLVM symbolizer library with the
59// STL and hide all of its symbols with 'opt -internalize'. To reduce size, it
60// cuts out the threading portions of the hermetic copy of libc++ that it
61// builds. We can remove these ifdefs if that script goes away.
62static std::mutex ErrorHandlerMutex;
63static std::mutex BadAllocErrorHandlerMutex;
64#endif
65
66static bool write_retry(int fd, const char *buf, size_t count) {
67 while (count > 0) {
68 ssize_t written = sys::RetryAfterSignal(-1, ::write, fd, buf, count);
69 if (written <= 0)
70 return false;
71 buf += written;
72 count -= written;
73 }
74 return true;
75}
76
78 void *user_data) {
79#if LLVM_ENABLE_THREADS == 1
80 std::lock_guard<std::mutex> Lock(ErrorHandlerMutex);
81#endif
82 assert(!ErrorHandler && "Error handler already registered!\n");
83 ErrorHandler = handler;
84 ErrorHandlerUserData = user_data;
85}
86
88#if LLVM_ENABLE_THREADS == 1
89 std::lock_guard<std::mutex> Lock(ErrorHandlerMutex);
90#endif
91 ErrorHandler = nullptr;
92 ErrorHandlerUserData = nullptr;
93}
94
95void llvm::report_fatal_error(const char *Reason, bool GenCrashDiag) {
96 report_fatal_error(Twine(Reason), GenCrashDiag);
97}
98
99void llvm::report_fatal_error(StringRef Reason, bool GenCrashDiag) {
100 report_fatal_error(Twine(Reason), GenCrashDiag);
101}
102
103void llvm::report_fatal_error(const Twine &Reason, bool GenCrashDiag) {
104 llvm::fatal_error_handler_t handler = nullptr;
105 void* handlerData = nullptr;
106 {
107 // Only acquire the mutex while reading the handler, so as not to invoke a
108 // user-supplied callback under a lock.
109#if LLVM_ENABLE_THREADS == 1
110 std::lock_guard<std::mutex> Lock(ErrorHandlerMutex);
111#endif
112 handler = ErrorHandler;
113 handlerData = ErrorHandlerUserData;
114 }
115
116 if (handler) {
117 handler(handlerData, Reason.str().c_str(), GenCrashDiag);
118 } else {
119 // Blast the result out to stderr. We don't try hard to make sure this
120 // succeeds (e.g. handling EINTR) and we can't use errs() here because
121 // raw ostreams can call report_fatal_error.
123 raw_svector_ostream OS(Buffer);
124 OS << "LLVM ERROR: " << Reason << "\n";
125 StringRef MessageStr = OS.str();
126 write_retry(2, MessageStr.data(), MessageStr.size());
127 }
128
129 // If we reached here, we are failing ungracefully. Run the interrupt handlers
130 // to make sure any special cleanups get done, in particular that we remove
131 // files registered with RemoveFileOnSignal.
133
134 if (GenCrashDiag)
135 abort();
136 else
137 exit(1);
138}
139
140void llvm::reportFatalInternalError(const char *reason) {
141 report_fatal_error(reason, /*GenCrashDiag=*/true);
142}
144 report_fatal_error(reason, /*GenCrashDiag=*/true);
145}
147 report_fatal_error(reason, /*GenCrashDiag=*/true);
148}
149void llvm::reportFatalUsageError(const char *reason) {
150 report_fatal_error(reason, /*GenCrashDiag=*/false);
151}
153 report_fatal_error(reason, /*GenCrashDiag=*/false);
154}
156 report_fatal_error(reason, /*GenCrashDiag=*/false);
157}
158
160 void *user_data) {
161#if LLVM_ENABLE_THREADS == 1
162 std::lock_guard<std::mutex> Lock(BadAllocErrorHandlerMutex);
163#endif
165 "Bad alloc error handler already registered!\n");
166 BadAllocErrorHandler = handler;
168}
169
171#if LLVM_ENABLE_THREADS == 1
172 std::lock_guard<std::mutex> Lock(BadAllocErrorHandlerMutex);
173#endif
174 BadAllocErrorHandler = nullptr;
176}
177
178void llvm::report_bad_alloc_error(const char *Reason, bool GenCrashDiag) {
179 fatal_error_handler_t Handler = nullptr;
180 void *HandlerData = nullptr;
181 {
182 // Only acquire the mutex while reading the handler, so as not to invoke a
183 // user-supplied callback under a lock.
184#if LLVM_ENABLE_THREADS == 1
185 std::lock_guard<std::mutex> Lock(BadAllocErrorHandlerMutex);
186#endif
187 Handler = BadAllocErrorHandler;
188 HandlerData = BadAllocErrorHandlerUserData;
189 }
190
191 if (Handler) {
192 Handler(HandlerData, Reason, GenCrashDiag);
193 llvm_unreachable("bad alloc handler should not return");
194 }
195
196#ifdef LLVM_ENABLE_EXCEPTIONS
197 // If exceptions are enabled, make OOM in malloc look like OOM in new.
198 throw std::bad_alloc();
199#else
200 // Don't call the normal error handler. It may allocate memory. Directly write
201 // an OOM to stderr and abort.
202 const char *OOMMessage = "LLVM ERROR: out of memory\n";
203 const char *Newline = "\n";
204 write_retry(2, OOMMessage, strlen(OOMMessage));
205 write_retry(2, Reason, strlen(Reason));
206 write_retry(2, Newline, strlen(Newline));
207 abort();
208#endif
209}
210
211#ifdef LLVM_ENABLE_EXCEPTIONS
212// Do not set custom new handler if exceptions are enabled. In this case OOM
213// errors are handled by throwing 'std::bad_alloc'.
215}
216#else
217// Causes crash on allocation failure. It is called prior to the handler set by
218// 'install_bad_alloc_error_handler'.
220 llvm::report_bad_alloc_error("Allocation failed");
221}
222
223// Installs new handler that causes crash on allocation failure. It is called by
224// InitLLVM.
226 std::new_handler old = std::set_new_handler(out_of_memory_new_handler);
227 (void)old;
228 assert((old == nullptr || old == out_of_memory_new_handler) &&
229 "new-handler already installed");
230}
231#endif
232
233void llvm::llvm_unreachable_internal(const char *msg, const char *file,
234 unsigned line) {
235 // This code intentionally doesn't call the ErrorHandler callback, because
236 // llvm_unreachable is intended to be used to indicate "impossible"
237 // situations, and not legitimate runtime errors.
238 if (msg)
239 dbgs() << msg << "\n";
240 dbgs() << "UNREACHABLE executed";
241 if (file)
242 dbgs() << " at " << file << ":" << line;
243 dbgs() << "!\n";
244 abort();
245#ifdef LLVM_BUILTIN_UNREACHABLE
246 // Windows systems and possibly others don't declare abort() to be noreturn,
247 // so use the unreachable builtin to avoid a Clang self-host warning.
248 LLVM_BUILTIN_UNREACHABLE;
249#endif
250}
251
252static void bindingsErrorHandler(void *user_data, const char *reason,
253 bool gen_crash_diag) {
254 LLVMFatalErrorHandler handler =
255 LLVM_EXTENSION reinterpret_cast<LLVMFatalErrorHandler>(user_data);
256 handler(reason);
257}
258
263
267
268#ifdef _WIN32
269
270#define WIN32_NO_STATUS
272#undef WIN32_NO_STATUS
273#include <ntstatus.h>
274#include <winerror.h>
275
276// This is equivalent to NtCurrentTeb()->LastStatusValue, but the public
277// _TEB definition does not expose the LastStatusValue field directly.
278// Avoid offsetting into this structure by calling RtlGetLastNtStatus
279// from ntdll.dll.
280//
281// The return of this function will roughly match that of
282// GetLastError, but this lower level API disambiguates some cases
283// that GetLastError does not.
284//
285// For more information, see:
286// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/pebteb/teb/index.htm
287// https://github.com/llvm/llvm-project/issues/89137
288extern "C" NTSYSAPI NTSTATUS NTAPI RtlGetLastNtStatus();
289
290// This function obtains the last error code and maps it. It may call
291// RtlGetLastNtStatus, which is a lower level API that can return a
292// more specific error code than GetLastError.
293std::error_code llvm::mapLastWindowsError() {
294 unsigned EV = ::GetLastError();
295 // The mapping of NTSTATUS to Win32 error loses some information; special
296 // case the generic ERROR_ACCESS_DENIED code to check the underlying
297 // NTSTATUS and potentially return a more accurate error code.
298 if (EV == ERROR_ACCESS_DENIED) {
299 llvm::errc code = RtlGetLastNtStatus() == STATUS_DELETE_PENDING
302 return make_error_code(code);
303 }
304 return mapWindowsError(EV);
305}
306
307// I'd rather not double the line count of the following.
308#define MAP_ERR_TO_COND(x, y) \
309 case x: \
310 return make_error_code(errc::y)
311
312std::error_code llvm::mapWindowsError(unsigned EV) {
313 switch (EV) {
314 MAP_ERR_TO_COND(ERROR_ACCESS_DENIED, permission_denied);
315 MAP_ERR_TO_COND(ERROR_ALREADY_EXISTS, file_exists);
316 MAP_ERR_TO_COND(ERROR_BAD_NETPATH, no_such_file_or_directory);
317 MAP_ERR_TO_COND(ERROR_BAD_PATHNAME, no_such_file_or_directory);
318 MAP_ERR_TO_COND(ERROR_BAD_UNIT, no_such_device);
319 MAP_ERR_TO_COND(ERROR_BROKEN_PIPE, broken_pipe);
320 MAP_ERR_TO_COND(ERROR_BUFFER_OVERFLOW, filename_too_long);
321 MAP_ERR_TO_COND(ERROR_BUSY, device_or_resource_busy);
322 MAP_ERR_TO_COND(ERROR_BUSY_DRIVE, device_or_resource_busy);
323 MAP_ERR_TO_COND(ERROR_CANNOT_MAKE, permission_denied);
324 MAP_ERR_TO_COND(ERROR_CANTOPEN, io_error);
325 MAP_ERR_TO_COND(ERROR_CANTREAD, io_error);
326 MAP_ERR_TO_COND(ERROR_CANTWRITE, io_error);
327 MAP_ERR_TO_COND(ERROR_CURRENT_DIRECTORY, permission_denied);
328 MAP_ERR_TO_COND(ERROR_DEV_NOT_EXIST, no_such_device);
329 MAP_ERR_TO_COND(ERROR_DEVICE_IN_USE, device_or_resource_busy);
330 MAP_ERR_TO_COND(ERROR_DIR_NOT_EMPTY, directory_not_empty);
331 MAP_ERR_TO_COND(ERROR_DIRECTORY, invalid_argument);
332 MAP_ERR_TO_COND(ERROR_DISK_FULL, no_space_on_device);
333 MAP_ERR_TO_COND(ERROR_FILE_EXISTS, file_exists);
334 MAP_ERR_TO_COND(ERROR_FILE_NOT_FOUND, no_such_file_or_directory);
335 MAP_ERR_TO_COND(ERROR_HANDLE_DISK_FULL, no_space_on_device);
336 MAP_ERR_TO_COND(ERROR_INVALID_ACCESS, permission_denied);
337 MAP_ERR_TO_COND(ERROR_INVALID_DRIVE, no_such_device);
338 MAP_ERR_TO_COND(ERROR_INVALID_FUNCTION, function_not_supported);
339 MAP_ERR_TO_COND(ERROR_INVALID_HANDLE, invalid_argument);
340 MAP_ERR_TO_COND(ERROR_INVALID_NAME, invalid_argument);
341 MAP_ERR_TO_COND(ERROR_INVALID_PARAMETER, invalid_argument);
342 MAP_ERR_TO_COND(ERROR_LOCK_VIOLATION, no_lock_available);
343 MAP_ERR_TO_COND(ERROR_LOCKED, no_lock_available);
344 MAP_ERR_TO_COND(ERROR_NEGATIVE_SEEK, invalid_argument);
345 MAP_ERR_TO_COND(ERROR_NOACCESS, permission_denied);
346 MAP_ERR_TO_COND(ERROR_NOT_ENOUGH_MEMORY, not_enough_memory);
347 MAP_ERR_TO_COND(ERROR_NOT_READY, resource_unavailable_try_again);
348 MAP_ERR_TO_COND(ERROR_NOT_SUPPORTED, not_supported);
349 MAP_ERR_TO_COND(ERROR_OPEN_FAILED, io_error);
350 MAP_ERR_TO_COND(ERROR_OPEN_FILES, device_or_resource_busy);
351 MAP_ERR_TO_COND(ERROR_OUTOFMEMORY, not_enough_memory);
352 MAP_ERR_TO_COND(ERROR_PATH_NOT_FOUND, no_such_file_or_directory);
353 MAP_ERR_TO_COND(ERROR_READ_FAULT, io_error);
354 MAP_ERR_TO_COND(ERROR_REPARSE_TAG_INVALID, invalid_argument);
355 MAP_ERR_TO_COND(ERROR_RETRY, resource_unavailable_try_again);
356 MAP_ERR_TO_COND(ERROR_SEEK, io_error);
357 MAP_ERR_TO_COND(ERROR_SHARING_VIOLATION, permission_denied);
358 MAP_ERR_TO_COND(ERROR_TOO_MANY_OPEN_FILES, too_many_files_open);
359 MAP_ERR_TO_COND(ERROR_WRITE_FAULT, io_error);
360 MAP_ERR_TO_COND(ERROR_WRITE_PROTECT, permission_denied);
361 MAP_ERR_TO_COND(WSAEACCES, permission_denied);
362 MAP_ERR_TO_COND(WSAEBADF, bad_file_descriptor);
363 MAP_ERR_TO_COND(WSAEFAULT, bad_address);
364 MAP_ERR_TO_COND(WSAEINTR, interrupted);
365 MAP_ERR_TO_COND(WSAEINVAL, invalid_argument);
366 MAP_ERR_TO_COND(WSAEMFILE, too_many_files_open);
367 MAP_ERR_TO_COND(WSAENAMETOOLONG, filename_too_long);
368 default:
369 return std::error_code(EV, std::system_category());
370 }
371}
372
373#endif
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define LLVM_EXTENSION
LLVM_EXTENSION - Support compilers where we have a keyword to suppress pedantic diagnostics.
Definition Compiler.h:449
static fatal_error_handler_t ErrorHandler
static void out_of_memory_new_handler()
static bool write_retry(int fd, const char *buf, size_t count)
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)"
This file defines the SmallVector class.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
constexpr size_t size() const
size - Get the string size.
Definition StringRef.h:154
constexpr const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
Definition StringRef.h:148
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
LLVM_ABI 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.
StringRef str() const
Return a StringRef for the vector contents.
void LLVMResetFatalErrorHandler()
Reset the fatal error handler.
void(* LLVMFatalErrorHandler)(const char *Reason)
void LLVMInstallFatalErrorHandler(LLVMFatalErrorHandler Handler)
Install a fatal error handler.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
decltype(auto) RetryAfterSignal(const FailT &Fail, const Fun &F, const Args &... As)
Definition Errno.h:33
LLVM_ABI 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.
LLVM_ABI std::error_code mapLastWindowsError()
std::error_code make_error_code(BitcodeError E)
void(* fatal_error_handler_t)(void *user_data, const char *reason, bool gen_crash_diag)
An error handler callback.
LLVM_ABI 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...
LLVM_ABI 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,...
LLVM_ABI void remove_bad_alloc_error_handler()
Restores default bad alloc error handling behavior.
LLVM_ABI void reportFatalInternalError(Error Err)
Report a fatal error that indicates a bug in LLVM.
Definition Error.cpp:177
errc
Definition Errc.h:35
@ no_space_on_device
Definition Errc.h:62
@ no_such_file_or_directory
Definition Errc.h:65
@ broken_pipe
Definition Errc.h:40
@ file_exists
Definition Errc.h:48
@ no_lock_available
Definition Errc.h:61
@ directory_not_empty
Definition Errc.h:46
@ filename_too_long
Definition Errc.h:50
@ bad_file_descriptor
Definition Errc.h:39
@ function_not_supported
Definition Errc.h:51
@ not_supported
Definition Errc.h:69
@ bad_address
Definition Errc.h:38
@ not_enough_memory
Definition Errc.h:68
@ device_or_resource_busy
Definition Errc.h:45
@ io_error
Definition Errc.h:58
@ delete_pending
Definition Errc.h:44
@ resource_unavailable_try_again
Definition Errc.h:74
@ invalid_argument
Definition Errc.h:56
@ permission_denied
Definition Errc.h:71
@ too_many_files_open
Definition Errc.h:78
@ no_such_device
Definition Errc.h:64
@ interrupted
Definition Errc.h:55
LLVM_ABI Error write(MCStreamer &Out, ArrayRef< std::string > Inputs, OnCuIndexOverflow OverflowOptValue)
Definition DWP.cpp:622
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:167
LLVM_ABI void install_out_of_memory_new_handler()
LLVM_ABI 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.
auto count(R &&Range, const E &Element)
Wrapper function around std::count to count the number of times an element Element occurs in the give...
Definition STLExtras.h:1956
LLVM_ABI void remove_fatal_error_handler()
Restores default error handling behaviour.
LLVM_ABI std::error_code mapWindowsError(unsigned EV)
LLVM_ABI void report_bad_alloc_error(const char *Reason, bool GenCrashDiag=true)
Reports a bad alloc error, calling any user defined bad alloc error handler.
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
Definition Error.cpp:180