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
17extern "C"
18{
19#include "postgres.h"
20}
21
22#include <llvm/Support/ErrorHandling.h>
23
24#include "jit/llvmjit.h"
25
26
27static int fatal_new_handler_depth = 0;
28static std::new_handler old_new_handler = NULL;
29
30static void fatal_system_new_handler(void);
31#if LLVM_VERSION_MAJOR > 4
32static void fatal_llvm_new_handler(void *user_data, const std::string& reason, bool gen_crash_diag);
33#endif
34static 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 */
55void
56llvm_enter_fatal_on_oom(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 }
66 fatal_new_handler_depth++;
67}
68
69/*
70 * Leave fatal error section started with llvm_enter_fatal_on_oom().
71 */
72void
73llvm_leave_fatal_on_oom(void)
74{
75 fatal_new_handler_depth--;
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 */
90void
91llvm_reset_after_error(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 }
101 fatal_new_handler_depth = 0;
102}
103
104void
105llvm_assert_in_fatal_section(void)
106{
107 Assert(fatal_new_handler_depth > 0);
108}
109
110static void
111fatal_system_new_handler(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
120static void
121fatal_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
132static void
133fatal_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}
142