LCOV - code coverage report
Current view: top level - src/backend/jit/llvm - llvmjit_error.cpp (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 71.0 % 31 22
Test Date: 2026-03-03 13:15:30 Functions: 62.5 % 8 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-2026, 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         5819 : llvm_enter_fatal_on_oom(void)
      56              : {
      57         5819 :     if (fatal_new_handler_depth == 0)
      58              :     {
      59         5819 :         old_new_handler = std::set_new_handler(fatal_system_new_handler);
      60         5819 :         llvm::install_bad_alloc_error_handler(fatal_llvm_new_handler);
      61         5819 :         llvm::install_fatal_error_handler(fatal_llvm_error_handler);
      62              :     }
      63         5819 :     fatal_new_handler_depth++;
      64         5819 : }
      65              : 
      66              : /*
      67              :  * Leave fatal error section started with llvm_enter_fatal_on_oom().
      68              :  */
      69              : void
      70         5819 : llvm_leave_fatal_on_oom(void)
      71              : {
      72         5819 :     fatal_new_handler_depth--;
      73         5819 :     if (fatal_new_handler_depth == 0)
      74              :     {
      75         5819 :         std::set_new_handler(old_new_handler);
      76         5819 :         llvm::remove_bad_alloc_error_handler();
      77         5819 :         llvm::remove_fatal_error_handler();
      78              :     }
      79         5819 : }
      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           93 : llvm_in_fatal_on_oom(void)
      87              : {
      88           93 :     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         2038 : llvm_reset_after_error(void)
      97              : {
      98         2038 :     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         2038 :     fatal_new_handler_depth = 0;
     105         2038 : }
     106              : 
     107              : void
     108         7908 : llvm_assert_in_fatal_section(void)
     109              : {
     110              :     Assert(fatal_new_handler_depth > 0);
     111         7908 : }
     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 2.0-1