Refactor ExecScan() to allow inlining of its core logic
[pgsql.git] / src / backend / jit / llvm / llvmjit_error.cpp
blobb16444d978ef666e436384fd82e3a22144a22ff8
1 /*-------------------------------------------------------------------------
3 * llvmjit_error.cpp
4 * LLVM error related handling that requires interfacing with C++
6 * Unfortunately neither (re)setting the C++ new handler, nor the LLVM OOM
7 * handler are exposed to C. Therefore this file wraps the necessary code.
9 * Copyright (c) 2016-2025, PostgreSQL Global Development Group
11 * IDENTIFICATION
12 * src/backend/jit/llvm/llvmjit_error.cpp
14 *-------------------------------------------------------------------------
17 extern "C"
19 #include "postgres.h"
22 #include <llvm/Support/ErrorHandling.h>
24 #include "jit/llvmjit.h"
26 #include <new>
28 static int fatal_new_handler_depth = 0;
29 static std::new_handler old_new_handler = NULL;
31 static void fatal_system_new_handler(void);
32 static void fatal_llvm_new_handler(void *user_data, const char *reason, bool gen_crash_diag);
33 static void fatal_llvm_error_handler(void *user_data, const char *reason, bool gen_crash_diag);
37 * Enter a section in which C++ and LLVM errors are treated as FATAL errors.
39 * This is necessary for LLVM as LLVM's error handling for such cases
40 * (exit()ing, throwing std::bad_alloc() if compiled with exceptions, abort())
41 * isn't compatible with postgres error handling. Thus in sections where LLVM
42 * code, not LLVM generated functions!, is executing, standard new, LLVM OOM
43 * and LLVM fatal errors (some OOM errors masquerade as those) are redirected
44 * to our own error handlers.
46 * These error handlers use FATAL, because there's no reliable way from within
47 * LLVM to throw an error that's guaranteed not to corrupt LLVM's state.
49 * To avoid disturbing extensions using C++ and/or LLVM, these handlers are
50 * unset when not executing LLVM code. There is no need to call
51 * llvm_leave_fatal_on_oom() when ERRORing out, error recovery resets the
52 * handlers in that case.
54 void
55 llvm_enter_fatal_on_oom(void)
57 if (fatal_new_handler_depth == 0)
59 old_new_handler = std::set_new_handler(fatal_system_new_handler);
60 llvm::install_bad_alloc_error_handler(fatal_llvm_new_handler);
61 llvm::install_fatal_error_handler(fatal_llvm_error_handler);
63 fatal_new_handler_depth++;
67 * Leave fatal error section started with llvm_enter_fatal_on_oom().
69 void
70 llvm_leave_fatal_on_oom(void)
72 fatal_new_handler_depth--;
73 if (fatal_new_handler_depth == 0)
75 std::set_new_handler(old_new_handler);
76 llvm::remove_bad_alloc_error_handler();
77 llvm::remove_fatal_error_handler();
82 * Are we currently in a fatal-on-oom section? Useful to skip cleanup in case
83 * of errors.
85 bool
86 llvm_in_fatal_on_oom(void)
88 return fatal_new_handler_depth > 0;
92 * Reset fatal error handling. This should only be called in error recovery
93 * loops like PostgresMain()'s.
95 void
96 llvm_reset_after_error(void)
98 if (fatal_new_handler_depth != 0)
100 std::set_new_handler(old_new_handler);
101 llvm::remove_bad_alloc_error_handler();
102 llvm::remove_fatal_error_handler();
104 fatal_new_handler_depth = 0;
107 void
108 llvm_assert_in_fatal_section(void)
110 Assert(fatal_new_handler_depth > 0);
113 static void
114 fatal_system_new_handler(void)
116 ereport(FATAL,
117 (errcode(ERRCODE_OUT_OF_MEMORY),
118 errmsg("out of memory"),
119 errdetail("while in LLVM")));
122 static void
123 fatal_llvm_new_handler(void *user_data,
124 const char *reason,
125 bool gen_crash_diag)
127 ereport(FATAL,
128 (errcode(ERRCODE_OUT_OF_MEMORY),
129 errmsg("out of memory"),
130 errdetail("While in LLVM: %s", reason)));
133 static void
134 fatal_llvm_error_handler(void *user_data,
135 const char *reason,
136 bool gen_crash_diag)
138 ereport(FATAL,
139 (errcode(ERRCODE_OUT_OF_MEMORY),
140 errmsg("fatal llvm error: %s", reason)));