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