LCOV - code coverage report
Current view: top level - src/base - libmesh_exceptions.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4475 (55045b) with base a68cc6 Lines: 0 82 0.0 %
Date: 2026-06-03 14:29:06 Functions: 0 7 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // The libMesh Finite Element Library.
       2             : // Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
       3             : 
       4             : // This library is free software; you can redistribute it and/or
       5             : // modify it under the terms of the GNU Lesser General Public
       6             : // License as published by the Free Software Foundation; either
       7             : // version 2.1 of the License, or (at your option) any later version.
       8             : 
       9             : // This library is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             : // Lesser General Public License for more details.
      13             : 
      14             : // You should have received a copy of the GNU Lesser General Public
      15             : // License along with this library; if not, write to the Free Software
      16             : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      17             : 
      18             : 
      19             : // Local includes
      20             : #include "libmesh/libmesh_exceptions.h"
      21             : 
      22             : // libMesh includes
      23             : #include "libmesh/libmesh.h"
      24             : #include "libmesh/perf_log.h"
      25             : #include "libmesh/print_trace.h"
      26             : 
      27             : // C/C++ includes
      28             : #ifdef LIBMESH_ENABLE_EXCEPTIONS
      29             : #include <exception>
      30             : #include <optional>
      31             : #endif
      32             : 
      33             : #include "signal.h"
      34             : 
      35             : // floating-point exceptions
      36             : #ifdef LIBMESH_HAVE_FENV_H
      37             : #  include <fenv.h>
      38             : #endif
      39             : #ifdef LIBMESH_HAVE_XMMINTRIN_H
      40             : #  include <xmmintrin.h>
      41             : #endif
      42             : 
      43             : // --------------------------------------------------------
      44             : // Local anonymous namespace to hold miscellaneous bits
      45             : namespace {
      46             : 
      47             : /**
      48             :  * Floating point exception handler -- courtesy of Cody Permann & MOOSE team
      49             :  */
      50             : #if LIBMESH_HAVE_DECL_SIGACTION
      51           0 : void libmesh_handleFPE(int /*signo*/, siginfo_t * info, void * /*context*/)
      52             : {
      53           0 :   libMesh::err << std::endl;
      54           0 :   libMesh::err << "Floating point exception signaled (";
      55           0 :   switch (info->si_code)
      56             :     {
      57           0 :     case FPE_INTDIV: libMesh::err << "integer divide by zero"; break;
      58           0 :     case FPE_INTOVF: libMesh::err << "integer overflow"; break;
      59           0 :     case FPE_FLTDIV: libMesh::err << "floating point divide by zero"; break;
      60           0 :     case FPE_FLTOVF: libMesh::err << "floating point overflow"; break;
      61           0 :     case FPE_FLTUND: libMesh::err << "floating point underflow"; break;
      62           0 :     case FPE_FLTRES: libMesh::err << "floating point inexact result"; break;
      63           0 :     case FPE_FLTINV: libMesh::err << "invalid floating point operation"; break;
      64           0 :     case FPE_FLTSUB: libMesh::err << "subscript out of range"; break;
      65           0 :     default:         libMesh::err << "unrecognized"; break;
      66             :     }
      67           0 :   libMesh::err << ")!" << std::endl;
      68             : 
      69           0 :   libmesh_error_msg("\nTo track this down, compile in debug mode, then in gdb do:\n" \
      70             :                     << "  break libmesh_handleFPE\n"                    \
      71             :                     << "  run ...\n"                                    \
      72             :                     << "  bt");
      73             : }
      74             : 
      75             : 
      76           0 : void libmesh_handleSEGV(int /*signo*/, siginfo_t * info, void * /*context*/)
      77             : {
      78           0 :   libMesh::err << std::endl;
      79           0 :   libMesh::err << "Segmentation fault exception signaled (";
      80           0 :   switch (info->si_code)
      81             :     {
      82           0 :     case SEGV_MAPERR: libMesh::err << "Address not mapped"; break;
      83           0 :     case SEGV_ACCERR: libMesh::err << "Invalid permissions"; break;
      84           0 :     default:         libMesh::err << "unrecognized"; break;
      85             :     }
      86           0 :   libMesh::err << ")!" << std::endl;
      87             : 
      88           0 :   libmesh_error_msg("\nTo track this down, compile in debug mode, then in gdb do:\n" \
      89             :                     << "  break libmesh_handleSEGV\n"                    \
      90             :                     << "  run ...\n"                                    \
      91             :                     << "  bt");
      92             : }
      93             : 
      94             : 
      95           0 : void libmesh_handleSIGINT(int /*signo*/, siginfo_t * /*info*/, void * /*context*/)
      96             : {
      97           0 :   libmesh_error_msg("Interrupt (Ctrl+C?) signaled!");
      98             : }
      99             : #endif
     100             : } // anonymous namespace
     101             : 
     102             : 
     103             : 
     104             : namespace libMesh
     105             : {
     106             : 
     107             : // ------------------------------------------------------------
     108             : // libMesh functions
     109             : 
     110           0 : void libmesh_terminate_handler()
     111             : {
     112           0 :   bool quiet = false;
     113             : 
     114             : #ifdef LIBMESH_ENABLE_EXCEPTIONS
     115             :   // If we have an active exception, it may have an error message that
     116             :   // we should print, or it may have a type that tells us not to print
     117             :   // anything.
     118           0 :   std::optional<std::string> exception_message;
     119           0 :   std::exception_ptr ex = std::current_exception();
     120           0 :   if (ex)
     121             :     {
     122             :       try
     123             :         {
     124           0 :           std::rethrow_exception(ex);
     125             :         }
     126             :       // Capture the exception message to be used later.
     127           0 :       catch (const std::exception & std_ex)
     128             :         {
     129           0 :           exception_message = std_ex.what();
     130           0 :         }
     131             :       // We arrived here via TerminationException (likely from
     132             :       // libmesh_terminate()), which implies that a useful
     133             :       // error message has already been emitted.
     134           0 :       catch (const TerminationException &)
     135             :         {
     136           0 :           quiet = true;
     137           0 :         }
     138             :       // We're just trying to detect exception types here, not
     139             :       // actually rethrow
     140           0 :       catch (...)
     141             :         {
     142           0 :         }
     143             :     }
     144             : #endif
     145             : 
     146           0 :   if (!quiet)
     147             :     {
     148           0 :       libMesh::err << "libMesh terminating";
     149             : #ifdef LIBMESH_ENABLE_EXCEPTIONS
     150           0 :       if (exception_message)
     151           0 :         libMesh::err << ":\n" << *exception_message;
     152             : #endif
     153           0 :       libMesh::err << std::endl;
     154             : 
     155             :       // If this got called then we're probably crashing; let's print a
     156             :       // stack trace.  The trace files that are ultimately written depend on:
     157             :       // 1.) Who throws the exception.
     158             :       // 2.) Whether the C++ runtime unwinds the stack before the
     159             :       //     terminate_handler is called (this is implementation defined).
     160             :       //
     161             :       // The various cases are summarized in the table below:
     162             :       //
     163             :       //                        | libmesh exception | other exception
     164             :       //                        -------------------------------------
     165             :       // stack unwinds          |        A          |       B
     166             :       // stack does not unwind  |        C          |       D
     167             :       //
     168             :       // Case A: There will be two stack traces in the file: one "useful"
     169             :       //         one, and one nearly empty one due to stack unwinding.
     170             :       // Case B: You will get one nearly empty stack trace (not great, Bob!)
     171             :       // Case C: You will get two nearly identical stack traces, ignore one of them.
     172             :       // Case D: You will get one useful stack trace.
     173             :       //
     174             :       // Cases A and B (where the stack unwinds when an exception leaves
     175             :       // main) appear to be non-existent in practice.  I don't have a
     176             :       // definitive list, but the stack does not unwind for GCC on either
     177             :       // Mac or Linux.  I think there's good reasons for this behavior too:
     178             :       // it's much easier to get a stack trace when the stack doesn't
     179             :       // unwind, for example.
     180           0 :       libMesh::write_traceout();
     181             : 
     182             :       // We may care about performance data pre-crash; it would be sad to
     183             :       // throw that away.
     184           0 :       LibMeshInit::perf_log().print_log();
     185             :     }
     186             : 
     187           0 :   libmesh_abort();
     188             : }
     189             : 
     190             : 
     191             : /**
     192             :  * Toggle floating point exceptions -- courtesy of Cody Permann & MOOSE team
     193             :  */
     194           0 : void enableFPE(bool on)
     195             : {
     196             : #if !defined(LIBMESH_HAVE_FEENABLEEXCEPT) && defined(LIBMESH_HAVE_XMMINTRIN_H)
     197             :   static int flags = 0;
     198             : #endif
     199             : 
     200           0 :   if (on)
     201             :     {
     202             : #ifdef LIBMESH_HAVE_FEENABLEEXCEPT
     203           0 :       feenableexcept(FE_DIVBYZERO | FE_INVALID);
     204             : #elif  LIBMESH_HAVE_XMMINTRIN_H
     205             :       flags = _MM_GET_EXCEPTION_MASK();           // store the flags
     206             :       _MM_SET_EXCEPTION_MASK(flags & ~_MM_MASK_INVALID);
     207             : #endif
     208             : 
     209             : #if LIBMESH_HAVE_DECL_SIGACTION
     210             :       struct sigaction new_action, old_action;
     211             : 
     212             :       // Set up the structure to specify the new action.
     213           0 :       new_action.sa_sigaction = libmesh_handleFPE;
     214           0 :       sigemptyset (&new_action.sa_mask);
     215           0 :       new_action.sa_flags = SA_SIGINFO;
     216             : 
     217           0 :       sigaction (SIGFPE, nullptr, &old_action);
     218           0 :       if (old_action.sa_handler != SIG_IGN)
     219           0 :         sigaction (SIGFPE, &new_action, nullptr);
     220             : #endif
     221             :     }
     222             :   else
     223             :     {
     224             : #ifdef LIBMESH_HAVE_FEDISABLEEXCEPT
     225           0 :       fedisableexcept(FE_DIVBYZERO | FE_INVALID);
     226             : #elif  LIBMESH_HAVE_XMMINTRIN_H
     227             :       _MM_SET_EXCEPTION_MASK(flags);
     228             : #endif
     229           0 :       signal(SIGFPE, SIG_DFL);
     230             :     }
     231           0 : }
     232             : 
     233             : 
     234             : // Enable handling of SIGSEGV by libMesh
     235             : // (potentially instead of PETSc)
     236           0 : void enableSEGV(bool on)
     237             : {
     238             : #if LIBMESH_HAVE_DECL_SIGACTION
     239             :   static struct sigaction old_action;
     240             :   static bool was_on = false;
     241             : 
     242           0 :   if (on)
     243             :     {
     244             :       struct sigaction new_action;
     245           0 :       was_on = true;
     246             : 
     247             :       // Set up the structure to specify the new action.
     248           0 :       new_action.sa_sigaction = libmesh_handleSEGV;
     249           0 :       sigemptyset (&new_action.sa_mask);
     250           0 :       new_action.sa_flags = SA_SIGINFO;
     251             : 
     252           0 :       sigaction (SIGSEGV, &new_action, &old_action);
     253             :     }
     254           0 :   else if (was_on)
     255             :     {
     256           0 :       was_on = false;
     257           0 :       sigaction (SIGSEGV, &old_action, nullptr);
     258             :     }
     259             : #else
     260             :   libmesh_error_msg("System call sigaction not supported.");
     261             : #endif
     262           0 : }
     263             : 
     264             : 
     265             : // Enable handling of SIGINT (Ctrl+C) by libMesh
     266           0 : void enableSIGINT(bool on)
     267             : {
     268             : #if LIBMESH_HAVE_DECL_SIGACTION
     269             :   static struct sigaction old_action;
     270             :   static bool was_on = false;
     271             : 
     272           0 :   if (on)
     273             :     {
     274             :       struct sigaction new_action;
     275           0 :       was_on = true;
     276             : 
     277             :       // Set up the structure to specify the new action.
     278           0 :       new_action.sa_sigaction = libmesh_handleSIGINT;
     279           0 :       sigemptyset (&new_action.sa_mask);
     280           0 :       new_action.sa_flags = SA_SIGINFO;
     281             : 
     282           0 :       sigaction (SIGINT, &new_action, &old_action);
     283             :     }
     284           0 :   else if (was_on)
     285             :     {
     286           0 :       was_on = false;
     287           0 :       sigaction (SIGINT, &old_action, nullptr);
     288             :     }
     289             : #else
     290             :   libmesh_error_msg("System call sigaction not supported.");
     291             : #endif
     292           0 : }
     293             : 
     294             : } // namespace libMesh

Generated by: LCOV version 1.14