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-2019, 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  * Reset fatal error handling. This should only be called in error recovery
88  * loops like PostgresMain()'s.
89  */
90 void
92 {
93  if (fatal_new_handler_depth != 0)
94  {
95  std::set_new_handler(old_new_handler);
96 #if LLVM_VERSION_MAJOR > 4
97  llvm::remove_bad_alloc_error_handler();
98 #endif
99  llvm::remove_fatal_error_handler();
100  }
102 }
103 
104 void
106 {
108 }
109 
110 static void
112 {
113  ereport(FATAL,
114  (errcode(ERRCODE_OUT_OF_MEMORY),
115  errmsg("out of memory"),
116  errdetail("while in LLVM")));
117 }
118 
119 #if LLVM_VERSION_MAJOR > 4
120 static void
121 fatal_llvm_new_handler(void *user_data,
122  const std::string& reason,
123  bool gen_crash_diag)
124 {
125  ereport(FATAL,
126  (errcode(ERRCODE_OUT_OF_MEMORY),
127  errmsg("out of memory"),
128  errdetail("While in LLVM: %s", reason.c_str())));
129 }
130 #endif
131 
132 static void
133 fatal_llvm_error_handler(void *user_data,
134  const std::string& reason,
135  bool gen_crash_diag)
136 {
137  ereport(FATAL,
138  (errcode(ERRCODE_OUT_OF_MEMORY),
139  errmsg("fatal llvm error: %s",
140  reason.c_str())));
141 }
static void fatal_system_new_handler(void)
int errcode(int sqlerrcode)
Definition: elog.c:570
#define FATAL
Definition: elog.h:52
static void fatal_llvm_error_handler(void *user_data, const std::string &reason, bool gen_crash_diag)
void llvm_assert_in_fatal_section(void)
int errdetail(const char *fmt,...)
Definition: elog.c:860
char string[11]
Definition: preproc-type.c:46
#define ereport(elevel, rest)
Definition: elog.h:141
void llvm_reset_after_error(void)
#define Assert(condition)
Definition: c.h:732
static int fatal_new_handler_depth
int errmsg(const char *fmt,...)
Definition: elog.c:784
void llvm_enter_fatal_on_oom(void)
static std::new_handler old_new_handler
void llvm_leave_fatal_on_oom(void)