LCOV - code coverage report
Current view: top level - src/backend/jit/llvm - llvmjit_error.cpp (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 0.0 % 31 0
Test Date: 2026-07-03 19:57:34 Functions: 0.0 % 8 0
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 0.0 % 12 0

             Branch data     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                 :           0 : llvm_enter_fatal_on_oom(void)
      56                 :             : {
      57         [ #  # ]:           0 :     if (fatal_new_handler_depth == 0)
      58                 :             :     {
      59                 :           0 :         old_new_handler = std::set_new_handler(fatal_system_new_handler);
      60                 :           0 :         llvm::install_bad_alloc_error_handler(fatal_llvm_new_handler);
      61                 :           0 :         llvm::install_fatal_error_handler(fatal_llvm_error_handler);
      62                 :             :     }
      63                 :           0 :     fatal_new_handler_depth++;
      64                 :           0 : }
      65                 :             : 
      66                 :             : /*
      67                 :             :  * Leave fatal error section started with llvm_enter_fatal_on_oom().
      68                 :             :  */
      69                 :             : void
      70                 :           0 : llvm_leave_fatal_on_oom(void)
      71                 :             : {
      72                 :           0 :     fatal_new_handler_depth--;
      73         [ #  # ]:           0 :     if (fatal_new_handler_depth == 0)
      74                 :             :     {
      75                 :           0 :         std::set_new_handler(old_new_handler);
      76                 :           0 :         llvm::remove_bad_alloc_error_handler();
      77                 :           0 :         llvm::remove_fatal_error_handler();
      78                 :             :     }
      79                 :           0 : }
      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                 :           0 : llvm_in_fatal_on_oom(void)
      87                 :             : {
      88                 :           0 :     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                 :           0 : llvm_reset_after_error(void)
      97                 :             : {
      98         [ #  # ]:           0 :     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                 :           0 :     fatal_new_handler_depth = 0;
     105                 :           0 : }
     106                 :             : 
     107                 :             : void
     108                 :           0 : llvm_assert_in_fatal_section(void)
     109                 :             : {
     110                 :             :     Assert(fatal_new_handler_depth > 0);
     111                 :           0 : }
     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