LLVM 20.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#define WIN32_NO_STATUS
241#undef WIN32_NO_STATUS
242#include <ntstatus.h>
243#include <winerror.h>
244
245// This is equivalent to NtCurrentTeb()->LastStatusValue, but the public
246// _TEB definition does not expose the LastStatusValue field directly.
247// Avoid offsetting into this structure by calling RtlGetLastNtStatus
248// from ntdll.dll.
249//
250// The return of this function will roughly match that of
251// GetLastError, but this lower level API disambiguates some cases
252// that GetLastError does not.
253//
254// For more information, see:
255// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/pebteb/teb/index.htm
256// https://github.com/llvm/llvm-project/issues/89137
257extern "C" NTSYSAPI NTSTATUS NTAPI RtlGetLastNtStatus();
258
259// This function obtains the last error code and maps it. It may call
260// RtlGetLastNtStatus, which is a lower level API that can return a
261// more specific error code than GetLastError.
262std::error_code llvm::mapLastWindowsError() {
263 unsigned EV = ::GetLastError();
264 // The mapping of NTSTATUS to Win32 error loses some information; special
265 // case the generic ERROR_ACCESS_DENIED code to check the underlying
266 // NTSTATUS and potentially return a more accurate error code.
267 if (EV == ERROR_ACCESS_DENIED) {
268 llvm::errc code = RtlGetLastNtStatus() == STATUS_DELETE_PENDING
269 ? errc::delete_pending
270 : errc::permission_denied;
271 return make_error_code(code);
272 }
273 return mapWindowsError(EV);
274}
275
276// I'd rather not double the line count of the following.
277#define MAP_ERR_TO_COND(x, y) \
278 case x: \
279 return make_error_code(errc::y)
280
281std::error_code llvm::mapWindowsError(unsigned EV) {
282 switch (EV) {
283 MAP_ERR_TO_COND(ERROR_ACCESS_DENIED, permission_denied);
284 MAP_ERR_TO_COND(ERROR_ALREADY_EXISTS, file_exists);
285 MAP_ERR_TO_COND(ERROR_BAD_NETPATH, no_such_file_or_directory);
286 MAP_ERR_TO_COND(ERROR_BAD_PATHNAME, no_such_file_or_directory);
287 MAP_ERR_TO_COND(ERROR_BAD_UNIT, no_such_device);
288 MAP_ERR_TO_COND(ERROR_BROKEN_PIPE, broken_pipe);
289 MAP_ERR_TO_COND(ERROR_BUFFER_OVERFLOW, filename_too_long);
290 MAP_ERR_TO_COND(ERROR_BUSY, device_or_resource_busy);
291 MAP_ERR_TO_COND(ERROR_BUSY_DRIVE, device_or_resource_busy);
292 MAP_ERR_TO_COND(ERROR_CANNOT_MAKE, permission_denied);
293 MAP_ERR_TO_COND(ERROR_CANTOPEN, io_error);
294 MAP_ERR_TO_COND(ERROR_CANTREAD, io_error);
295 MAP_ERR_TO_COND(ERROR_CANTWRITE, io_error);
296 MAP_ERR_TO_COND(ERROR_CURRENT_DIRECTORY, permission_denied);
297 MAP_ERR_TO_COND(ERROR_DEV_NOT_EXIST, no_such_device);
298 MAP_ERR_TO_COND(ERROR_DEVICE_IN_USE, device_or_resource_busy);
299 MAP_ERR_TO_COND(ERROR_DIR_NOT_EMPTY, directory_not_empty);
300 MAP_ERR_TO_COND(ERROR_DIRECTORY, invalid_argument);
301 MAP_ERR_TO_COND(ERROR_DISK_FULL, no_space_on_device);
302 MAP_ERR_TO_COND(ERROR_FILE_EXISTS, file_exists);
303 MAP_ERR_TO_COND(ERROR_FILE_NOT_FOUND, no_such_file_or_directory);
304 MAP_ERR_TO_COND(ERROR_HANDLE_DISK_FULL, no_space_on_device);
305 MAP_ERR_TO_COND(ERROR_INVALID_ACCESS, permission_denied);
306 MAP_ERR_TO_COND(ERROR_INVALID_DRIVE, no_such_device);
307 MAP_ERR_TO_COND(ERROR_INVALID_FUNCTION, function_not_supported);
308 MAP_ERR_TO_COND(ERROR_INVALID_HANDLE, invalid_argument);
309 MAP_ERR_TO_COND(ERROR_INVALID_NAME, invalid_argument);
310 MAP_ERR_TO_COND(ERROR_INVALID_PARAMETER, invalid_argument);
311 MAP_ERR_TO_COND(ERROR_LOCK_VIOLATION, no_lock_available);
312 MAP_ERR_TO_COND(ERROR_LOCKED, no_lock_available);
313 MAP_ERR_TO_COND(ERROR_NEGATIVE_SEEK, invalid_argument);
314 MAP_ERR_TO_COND(ERROR_NOACCESS, permission_denied);
315 MAP_ERR_TO_COND(ERROR_NOT_ENOUGH_MEMORY, not_enough_memory);
316 MAP_ERR_TO_COND(ERROR_NOT_READY, resource_unavailable_try_again);
317 MAP_ERR_TO_COND(ERROR_NOT_SUPPORTED, not_supported);
318 MAP_ERR_TO_COND(ERROR_OPEN_FAILED, io_error);
319 MAP_ERR_TO_COND(ERROR_OPEN_FILES, device_or_resource_busy);
320 MAP_ERR_TO_COND(ERROR_OUTOFMEMORY, not_enough_memory);
321 MAP_ERR_TO_COND(ERROR_PATH_NOT_FOUND, no_such_file_or_directory);
322 MAP_ERR_TO_COND(ERROR_READ_FAULT, io_error);
323 MAP_ERR_TO_COND(ERROR_REPARSE_TAG_INVALID, invalid_argument);
324 MAP_ERR_TO_COND(ERROR_RETRY, resource_unavailable_try_again);
325 MAP_ERR_TO_COND(ERROR_SEEK, io_error);
326 MAP_ERR_TO_COND(ERROR_SHARING_VIOLATION, permission_denied);
327 MAP_ERR_TO_COND(ERROR_TOO_MANY_OPEN_FILES, too_many_files_open);
328 MAP_ERR_TO_COND(ERROR_WRITE_FAULT, io_error);
329 MAP_ERR_TO_COND(ERROR_WRITE_PROTECT, permission_denied);
330 MAP_ERR_TO_COND(WSAEACCES, permission_denied);
331 MAP_ERR_TO_COND(WSAEBADF, bad_file_descriptor);
332 MAP_ERR_TO_COND(WSAEFAULT, bad_address);
333 MAP_ERR_TO_COND(WSAEINTR, interrupted);
334 MAP_ERR_TO_COND(WSAEINVAL, invalid_argument);
335 MAP_ERR_TO_COND(WSAEMFILE, too_many_files_open);
336 MAP_ERR_TO_COND(WSAENAMETOOLONG, filename_too_long);
337 default:
338 return std::error_code(EV, std::system_category());
339 }
340}
341
342#endif
#define LLVM_EXTENSION
LLVM_EXTENSION - Support compilers where we have a keyword to suppress pedantic diagnostics.
Definition: Compiler.h:344
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:691
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
std::error_code make_error_code(BitcodeError E)
std::error_code mapLastWindowsError()
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.
errc
Definition: Errc.h:35
@ 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:625
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:167
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.