LCOV - differential code coverage report
Current view: top level - src/backend/jit/llvm - llvmjit_error.cpp (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 81.2 % 32 26 6 26
Current Date: 2023-04-08 15:15:32 Functions: 62.5 % 8 5 3 5
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

Generated by: LCOV version v1.16-55-g56c0a2a