LCOV - code coverage report
Current view: top level - src/backend/jit/llvm - llvmjit_error.cpp (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 23 29 79.3 %
Date: 2019-11-16 00:06:57 Functions: 4 7 57.1 %
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-2019, 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             : 
      27             : static int fatal_new_handler_depth = 0;
      28             : static std::new_handler old_new_handler = NULL;
      29             : 
      30             : static void fatal_system_new_handler(void);
      31             : #if LLVM_VERSION_MAJOR > 4
      32             : static void fatal_llvm_new_handler(void *user_data, const std::string& reason, bool gen_crash_diag);
      33             : #endif
      34             : static void fatal_llvm_error_handler(void *user_data, const std::string& reason, bool gen_crash_diag);
      35             : 
      36             : 
      37             : /*
      38             :  * Enter a section in which C++ and LLVM errors are treated as FATAL errors.
      39             :  *
      40             :  * This is necessary for LLVM as LLVM's error handling for such cases
      41             :  * (exit()ing, throwing std::bad_alloc() if compiled with exceptions, abort())
      42             :  * isn't compatible with postgres error handling.  Thus in sections where LLVM
      43             :  * code, not LLVM generated functions!, is executing, standard new, LLVM OOM
      44             :  * and LLVM fatal errors (some OOM errors masquerade as those) are redirected
      45             :  * to our own error handlers.
      46             :  *
      47             :  * These error handlers use FATAL, because there's no reliable way from within
      48             :  * LLVM to throw an error that's guaranteed not to corrupt LLVM's state.
      49             :  *
      50             :  * To avoid disturbing extensions using C++ and/or LLVM, these handlers are
      51             :  * unset when not executing LLVM code. There is no need to call
      52             :  * llvm_leave_fatal_on_oom() when ERRORing out, error recovery resets the
      53             :  * handlers in that case.
      54             :  */
      55             : void
      56        8014 : llvm_enter_fatal_on_oom(void)
      57             : {
      58        8014 :     if (fatal_new_handler_depth == 0)
      59             :     {
      60        4886 :         old_new_handler = std::set_new_handler(fatal_system_new_handler);
      61             : #if LLVM_VERSION_MAJOR > 4
      62        4886 :         llvm::install_bad_alloc_error_handler(fatal_llvm_new_handler);
      63             : #endif
      64        4886 :         llvm::install_fatal_error_handler(fatal_llvm_error_handler);
      65             :     }
      66        8014 :     fatal_new_handler_depth++;
      67        8014 : }
      68             : 
      69             : /*
      70             :  * Leave fatal error section started with llvm_enter_fatal_on_oom().
      71             :  */
      72             : void
      73        7158 : llvm_leave_fatal_on_oom(void)
      74             : {
      75        7158 :     fatal_new_handler_depth--;
      76        7158 :     if (fatal_new_handler_depth == 0)
      77             :     {
      78        4344 :         std::set_new_handler(old_new_handler);
      79             : #if LLVM_VERSION_MAJOR > 4
      80        4344 :         llvm::remove_bad_alloc_error_handler();
      81             : #endif
      82        4344 :         llvm::remove_fatal_error_handler();
      83             :     }
      84        7158 : }
      85             : 
      86             : /*
      87             :  * Reset fatal error handling. This should only be called in error recovery
      88             :  * loops like PostgresMain()'s.
      89             :  */
      90             : void
      91         822 : llvm_reset_after_error(void)
      92             : {
      93         822 :     if (fatal_new_handler_depth != 0)
      94             :     {
      95         126 :         std::set_new_handler(old_new_handler);
      96             : #if LLVM_VERSION_MAJOR > 4
      97         126 :         llvm::remove_bad_alloc_error_handler();
      98             : #endif
      99         126 :         llvm::remove_fatal_error_handler();
     100             :     }
     101         822 :     fatal_new_handler_depth = 0;
     102         822 : }
     103             : 
     104             : void
     105       10750 : llvm_assert_in_fatal_section(void)
     106             : {
     107             :     Assert(fatal_new_handler_depth > 0);
     108       10750 : }
     109             : 
     110             : static void
     111           0 : fatal_system_new_handler(void)
     112             : {
     113           0 :     ereport(FATAL,
     114             :             (errcode(ERRCODE_OUT_OF_MEMORY),
     115             :              errmsg("out of memory"),
     116             :              errdetail("while in LLVM")));
     117             : }
     118             : 
     119             : #if LLVM_VERSION_MAJOR > 4
     120             : static void
     121           0 : fatal_llvm_new_handler(void *user_data,
     122             :                        const std::string& reason,
     123             :                        bool gen_crash_diag)
     124             : {
     125           0 :     ereport(FATAL,
     126             :             (errcode(ERRCODE_OUT_OF_MEMORY),
     127             :              errmsg("out of memory"),
     128             :              errdetail("While in LLVM: %s", reason.c_str())));
     129             : }
     130             : #endif
     131             : 
     132             : static void
     133           0 : fatal_llvm_error_handler(void *user_data,
     134             :                          const std::string& reason,
     135             :                          bool gen_crash_diag)
     136             : {
     137           0 :     ereport(FATAL,
     138             :             (errcode(ERRCODE_OUT_OF_MEMORY),
     139             :              errmsg("fatal llvm error: %s",
     140             :                     reason.c_str())));
     141             : }

Generated by: LCOV version 1.13