PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
llvmjit_error.cpp
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * llvmjit_error.cpp
4 * LLVM error related handling that requires interfacing with C++
5 *
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.
8 *
9 * Copyright (c) 2016-2025, PostgreSQL Global Development Group
10 *
11 * IDENTIFICATION
12 * src/backend/jit/llvm/llvmjit_error.cpp
13 *
14 *-------------------------------------------------------------------------
15 */
16
17extern "C"
18{
19#include "postgres.h"
20}
21
22#include <llvm/Support/ErrorHandling.h>
23
24#include "jit/llvmjit.h"
25
26#include <new>
27
29static std::new_handler old_new_handler = NULL;
30
31static void fatal_system_new_handler(void);
32static void fatal_llvm_new_handler(void *user_data, const char *reason, bool gen_crash_diag);
33static void fatal_llvm_error_handler(void *user_data, const char *reason, bool gen_crash_diag);
34
35
36/*
37 * Enter a section in which C++ and LLVM errors are treated as FATAL errors.
38 *
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.
45 *
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.
48 *
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.
53 */
54void
56{
58 {
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);
62 }
64}
65
66/*
67 * Leave fatal error section started with llvm_enter_fatal_on_oom().
68 */
69void
71{
74 {
75 std::set_new_handler(old_new_handler);
76 llvm::remove_bad_alloc_error_handler();
77 llvm::remove_fatal_error_handler();
78 }
79}
80
81/*
82 * Are we currently in a fatal-on-oom section? Useful to skip cleanup in case
83 * of errors.
84 */
85bool
87{
88 return fatal_new_handler_depth > 0;
89}
90
91/*
92 * Reset fatal error handling. This should only be called in error recovery
93 * loops like PostgresMain()'s.
94 */
95void
97{
99 {
100 std::set_new_handler(old_new_handler);
101 llvm::remove_bad_alloc_error_handler();
102 llvm::remove_fatal_error_handler();
103 }
105}
106
107void
109{
111}
112
113static void
115{
117 (errcode(ERRCODE_OUT_OF_MEMORY),
118 errmsg("out of memory"),
119 errdetail("while in LLVM")));
120}
121
122static void
124 const char *reason,
125 bool gen_crash_diag)
126{
128 (errcode(ERRCODE_OUT_OF_MEMORY),
129 errmsg("out of memory"),
130 errdetail("While in LLVM: %s", reason)));
131}
132
133static void
135 const char *reason,
136 bool gen_crash_diag)
137{
139 (errcode(ERRCODE_OUT_OF_MEMORY),
140 errmsg("fatal llvm error: %s", reason)));
141}
int errdetail(const char *fmt,...)
Definition: elog.c:1204
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define FATAL
Definition: elog.h:41
#define ereport(elevel,...)
Definition: elog.h:149
Assert(PointerIsAligned(start, uint64))
void llvm_enter_fatal_on_oom(void)
static std::new_handler old_new_handler
bool llvm_in_fatal_on_oom(void)
static void fatal_system_new_handler(void)
static void fatal_llvm_new_handler(void *user_data, const char *reason, bool gen_crash_diag)
static int fatal_new_handler_depth
void llvm_assert_in_fatal_section(void)
void llvm_reset_after_error(void)
void llvm_leave_fatal_on_oom(void)
static void fatal_llvm_error_handler(void *user_data, const char *reason, bool gen_crash_diag)