LCOV - code coverage report
Current view: top level - src/backend/jit/llvm - llvmjit_error.cpp (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 22 31 71.0 %
Date: 2024-10-07 02:11:23 Functions: 5 8 62.5 %
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             : static 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             :  */
      54             : void
      55       15140 : llvm_enter_fatal_on_oom(void)
      56             : {
      57       15140 :     if (fatal_new_handler_depth == 0)
      58             :     {
      59       15140 :         old_new_handler = std::set_new_handler(fatal_system_new_handler);
      60       15140 :         llvm::install_bad_alloc_error_handler(fatal_llvm_new_handler);
      61       15140 :         llvm::install_fatal_error_handler(fatal_llvm_error_handler);
      62             :     }
      63       15140 :     fatal_new_handler_depth++;
      64       15140 : }
      65             : 
      66             : /*
      67             :  * Leave fatal error section started with llvm_enter_fatal_on_oom().
      68             :  */
      69             : void
      70       15140 : llvm_leave_fatal_on_oom(void)
      71             : {
      72       15140 :     fatal_new_handler_depth--;
      73       15140 :     if (fatal_new_handler_depth == 0)
      74             :     {
      75       15140 :         std::set_new_handler(old_new_handler);
      76       15140 :         llvm::remove_bad_alloc_error_handler();
      77       15140 :         llvm::remove_fatal_error_handler();
      78             :     }
      79       15140 : }
      80             : 
      81             : /*
      82             :  * Are we currently in a fatal-on-oom section? Useful to skip cleanup in case
      83             :  * of errors.
      84             :  */
      85             : bool
      86         470 : llvm_in_fatal_on_oom(void)
      87             : {
      88         470 :     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             :  */
      95             : void
      96        2854 : llvm_reset_after_error(void)
      97             : {
      98        2854 :     if (fatal_new_handler_depth != 0)
      99             :     {
     100           0 :         std::set_new_handler(old_new_handler);
     101           0 :         llvm::remove_bad_alloc_error_handler();
     102           0 :         llvm::remove_fatal_error_handler();
     103             :     }
     104        2854 :     fatal_new_handler_depth = 0;
     105        2854 : }
     106             : 
     107             : void
     108       20570 : llvm_assert_in_fatal_section(void)
     109             : {
     110             :     Assert(fatal_new_handler_depth > 0);
     111       20570 : }
     112             : 
     113             : static void
     114           0 : fatal_system_new_handler(void)
     115             : {
     116           0 :     ereport(FATAL,
     117             :             (errcode(ERRCODE_OUT_OF_MEMORY),
     118             :              errmsg("out of memory"),
     119             :              errdetail("while in LLVM")));
     120             : }
     121             : 
     122             : static void
     123           0 : fatal_llvm_new_handler(void *user_data,
     124             :                        const char *reason,
     125             :                        bool gen_crash_diag)
     126             : {
     127           0 :     ereport(FATAL,
     128             :             (errcode(ERRCODE_OUT_OF_MEMORY),
     129             :              errmsg("out of memory"),
     130             :              errdetail("While in LLVM: %s", reason)));
     131             : }
     132             : 
     133             : static void
     134           0 : fatal_llvm_error_handler(void *user_data,
     135             :                          const char *reason,
     136             :                          bool gen_crash_diag)
     137             : {
     138           0 :     ereport(FATAL,
     139             :             (errcode(ERRCODE_OUT_OF_MEMORY),
     140             :              errmsg("fatal llvm error: %s", reason)));
     141             : }

Generated by: LCOV version 1.14