LCOV - code coverage report
Current view: top level - src/backend/jit/llvm - llvmjit_error.cpp (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 22 37 59.5 %
Date: 2024-05-19 09:11:23 Functions: 5 10 50.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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-2024, 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             : #include <new>
      27             : 
      28             : static int fatal_new_handler_depth = 0;
      29             : static std::new_handler old_new_handler = NULL;
      30             : 
      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             : #if LLVM_VERSION_MAJOR < 14
      34             : static void fatal_llvm_new_handler(void *user_data, const std::string& reason, bool gen_crash_diag);
      35             : #endif
      36             : static void fatal_llvm_error_handler(void *user_data, const char *reason, bool gen_crash_diag);
      37             : #if LLVM_VERSION_MAJOR < 14
      38             : static void fatal_llvm_error_handler(void *user_data, const std::string& reason, bool gen_crash_diag);
      39             : #endif
      40             : 
      41             : 
      42             : /*
      43             :  * Enter a section in which C++ and LLVM errors are treated as FATAL errors.
      44             :  *
      45             :  * This is necessary for LLVM as LLVM's error handling for such cases
      46             :  * (exit()ing, throwing std::bad_alloc() if compiled with exceptions, abort())
      47             :  * isn't compatible with postgres error handling.  Thus in sections where LLVM
      48             :  * code, not LLVM generated functions!, is executing, standard new, LLVM OOM
      49             :  * and LLVM fatal errors (some OOM errors masquerade as those) are redirected
      50             :  * to our own error handlers.
      51             :  *
      52             :  * These error handlers use FATAL, because there's no reliable way from within
      53             :  * LLVM to throw an error that's guaranteed not to corrupt LLVM's state.
      54             :  *
      55             :  * To avoid disturbing extensions using C++ and/or LLVM, these handlers are
      56             :  * unset when not executing LLVM code. There is no need to call
      57             :  * llvm_leave_fatal_on_oom() when ERRORing out, error recovery resets the
      58             :  * handlers in that case.
      59             :  */
      60             : void
      61       18676 : llvm_enter_fatal_on_oom(void)
      62             : {
      63       18676 :     if (fatal_new_handler_depth == 0)
      64             :     {
      65       18676 :         old_new_handler = std::set_new_handler(fatal_system_new_handler);
      66       18676 :         llvm::install_bad_alloc_error_handler(fatal_llvm_new_handler);
      67       18676 :         llvm::install_fatal_error_handler(fatal_llvm_error_handler);
      68             :     }
      69       18676 :     fatal_new_handler_depth++;
      70       18676 : }
      71             : 
      72             : /*
      73             :  * Leave fatal error section started with llvm_enter_fatal_on_oom().
      74             :  */
      75             : void
      76       18676 : llvm_leave_fatal_on_oom(void)
      77             : {
      78       18676 :     fatal_new_handler_depth--;
      79       18676 :     if (fatal_new_handler_depth == 0)
      80             :     {
      81       18676 :         std::set_new_handler(old_new_handler);
      82       18676 :         llvm::remove_bad_alloc_error_handler();
      83       18676 :         llvm::remove_fatal_error_handler();
      84             :     }
      85       18676 : }
      86             : 
      87             : /*
      88             :  * Are we currently in a fatal-on-oom section? Useful to skip cleanup in case
      89             :  * of errors.
      90             :  */
      91             : bool
      92         794 : llvm_in_fatal_on_oom(void)
      93             : {
      94         794 :     return fatal_new_handler_depth > 0;
      95             : }
      96             : 
      97             : /*
      98             :  * Reset fatal error handling. This should only be called in error recovery
      99             :  * loops like PostgresMain()'s.
     100             :  */
     101             : void
     102        3370 : llvm_reset_after_error(void)
     103             : {
     104        3370 :     if (fatal_new_handler_depth != 0)
     105             :     {
     106           0 :         std::set_new_handler(old_new_handler);
     107           0 :         llvm::remove_bad_alloc_error_handler();
     108           0 :         llvm::remove_fatal_error_handler();
     109             :     }
     110        3370 :     fatal_new_handler_depth = 0;
     111        3370 : }
     112             : 
     113             : void
     114       25168 : llvm_assert_in_fatal_section(void)
     115             : {
     116             :     Assert(fatal_new_handler_depth > 0);
     117       25168 : }
     118             : 
     119             : static void
     120           0 : fatal_system_new_handler(void)
     121             : {
     122           0 :     ereport(FATAL,
     123             :             (errcode(ERRCODE_OUT_OF_MEMORY),
     124             :              errmsg("out of memory"),
     125             :              errdetail("while in LLVM")));
     126             : }
     127             : 
     128             : static void
     129           0 : fatal_llvm_new_handler(void *user_data,
     130             :                        const char *reason,
     131             :                        bool gen_crash_diag)
     132             : {
     133           0 :     ereport(FATAL,
     134             :             (errcode(ERRCODE_OUT_OF_MEMORY),
     135             :              errmsg("out of memory"),
     136             :              errdetail("While in LLVM: %s", reason)));
     137             : }
     138             : #if LLVM_VERSION_MAJOR < 14
     139             : static void
     140           0 : fatal_llvm_new_handler(void *user_data,
     141             :                        const std::string& reason,
     142             :                        bool gen_crash_diag)
     143             : {
     144           0 :     fatal_llvm_new_handler(user_data, reason.c_str(), gen_crash_diag);
     145           0 : }
     146             : #endif
     147             : 
     148             : static void
     149           0 : fatal_llvm_error_handler(void *user_data,
     150             :                          const char *reason,
     151             :                          bool gen_crash_diag)
     152             : {
     153           0 :     ereport(FATAL,
     154             :             (errcode(ERRCODE_OUT_OF_MEMORY),
     155             :              errmsg("fatal llvm error: %s", reason)));
     156             : }
     157             : 
     158             : #if LLVM_VERSION_MAJOR < 14
     159             : static void
     160           0 : fatal_llvm_error_handler(void *user_data,
     161             :                          const std::string& reason,
     162             :                          bool gen_crash_diag)
     163             : {
     164           0 :     fatal_llvm_error_handler(user_data, reason.c_str(), gen_crash_diag);
     165           0 : }
     166             : #endif

Generated by: LCOV version 1.14