PostgreSQL Source Code  git master
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-2021, PostgreSQL Global Development Group
10  *
11  * IDENTIFICATION
12  * src/backend/jit/llvm/llvmjit_error.cpp
13  *
14  *-------------------------------------------------------------------------
15  */
16 
17 extern "C"
18 {
19 #include "postgres.h"
20 }
21 
22 #include <llvm/Support/ErrorHandling.h>
23 
24 #include "jit/llvmjit.h"
25 
26 
27 static int fatal_new_handler_depth = 0;
28 static std::new_handler old_new_handler = NULL;
29 
30 static void fatal_system_new_handler(void);
31 #if LLVM_VERSION_MAJOR > 4
32 static void fatal_llvm_new_handler(void *user_data, const std::string& reason, bool gen_crash_diag);
33 #endif
34 static void fatal_llvm_error_handler(void *user_data, const std::string& reason, bool gen_crash_diag);
35 
36 
37 /*
38  * Enter a section in which C++ and LLVM errors are treated as FATAL errors.
39  *
40  * This is necessary for LLVM as LLVM's error handling for such cases
41  * (exit()ing, throwing std::bad_alloc() if compiled with exceptions, abort())
42  * isn't compatible with postgres error handling. Thus in sections where LLVM
43  * code, not LLVM generated functions!, is executing, standard new, LLVM OOM
44  * and LLVM fatal errors (some OOM errors masquerade as those) are redirected
45  * to our own error handlers.
46  *
47  * These error handlers use FATAL, because there's no reliable way from within
48  * LLVM to throw an error that's guaranteed not to corrupt LLVM's state.
49  *
50  * To avoid disturbing extensions using C++ and/or LLVM, these handlers are
51  * unset when not executing LLVM code. There is no need to call
52  * llvm_leave_fatal_on_oom() when ERRORing out, error recovery resets the
53  * handlers in that case.
54  */
55 void
57 {
58  if (fatal_new_handler_depth == 0)
59  {
60  old_new_handler = std::set_new_handler(fatal_system_new_handler);
61 #if LLVM_VERSION_MAJOR > 4
62  llvm::install_bad_alloc_error_handler(fatal_llvm_new_handler);
63 #endif
64  llvm::install_fatal_error_handler(fatal_llvm_error_handler);
65  }
67 }
68 
69 /*
70  * Leave fatal error section started with llvm_enter_fatal_on_oom().
71  */
72 void
74 {
76  if (fatal_new_handler_depth == 0)
77  {
78  std::set_new_handler(old_new_handler);
79 #if LLVM_VERSION_MAJOR > 4
80  llvm::remove_bad_alloc_error_handler();
81 #endif
82  llvm::remove_fatal_error_handler();
83  }
84 }
85 
86 /*
87  * Are we currently in an fatal-on-oom section? Useful to skip cleanup in case
88  * of errors.
89  */
90 bool
92 {
93  return fatal_new_handler_depth > 0;
94 }
95 
96 /*
97  * Reset fatal error handling. This should only be called in error recovery
98  * loops like PostgresMain()'s.
99  */
100 void
102 {
103  if (fatal_new_handler_depth != 0)
104  {
105  std::set_new_handler(old_new_handler);
106 #if LLVM_VERSION_MAJOR > 4
107  llvm::remove_bad_alloc_error_handler();
108 #endif
109  llvm::remove_fatal_error_handler();
110  }
112 }
113 
114 void
116 {
118 }
119 
120 static void
122 {
123  ereport(FATAL,
124  (errcode(ERRCODE_OUT_OF_MEMORY),
125  errmsg("out of memory"),
126  errdetail("while in LLVM")));
127 }
128 
129 #if LLVM_VERSION_MAJOR > 4
130 static void
131 fatal_llvm_new_handler(void *user_data,
132  const std::string& reason,
133  bool gen_crash_diag)
134 {
135  ereport(FATAL,
136  (errcode(ERRCODE_OUT_OF_MEMORY),
137  errmsg("out of memory"),
138  errdetail("While in LLVM: %s", reason.c_str())));
139 }
140 #endif
141 
142 static void
143 fatal_llvm_error_handler(void *user_data,
144  const std::string& reason,
145  bool gen_crash_diag)
146 {
147  ereport(FATAL,
148  (errcode(ERRCODE_OUT_OF_MEMORY),
149  errmsg("fatal llvm error: %s",
150  reason.c_str())));
151 }
int errdetail(const char *fmt,...)
Definition: elog.c:1042
int errcode(int sqlerrcode)
Definition: elog.c:698
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define FATAL
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:143
Assert(fmt[strlen(fmt) - 1] !='\n')
void llvm_enter_fatal_on_oom(void)
static std::new_handler old_new_handler
bool llvm_in_fatal_on_oom(void)
static void fatal_llvm_error_handler(void *user_data, const std::string &reason, bool gen_crash_diag)
static void fatal_system_new_handler(void)
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)
char string[11]
Definition: preproc-type.c:46