MFEM  v4.6.0
Finite element discretization library
error.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010-2023, Lawrence Livermore National Security, LLC. Produced
2 // at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3 // LICENSE and NOTICE for details. LLNL-CODE-806117.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability visit https://mfem.org.
7 //
8 // MFEM is free software; you can redistribute it and/or modify it under the
9 // terms of the BSD-3 license. We welcome feedback and contributions, see file
10 // CONTRIBUTING.md for details.
11 
12 #include "error.hpp"
13 #include "globals.hpp"
14 #include "array.hpp"
15 #include <cstdlib>
16 #include <iostream>
17 
18 #ifdef MFEM_USE_LIBUNWIND
19 #define UNW_LOCAL_ONLY
20 #define UNW_NAME_LEN 512
21 #include <libunwind.h>
22 #include <cxxabi.h>
23 #if defined(__APPLE__) || defined(__linux__)
24 #ifndef _GNU_SOURCE
25 #define _GNU_SOURCE
26 #endif
27 #include <dlfcn.h>
28 #endif
29 #endif // MFEM_USE_LIBUNWIND
30 
31 #ifdef MFEM_USE_MPI
32 #include <mpi.h>
33 #endif
34 
35 namespace mfem
36 {
37 
38 #ifdef MFEM_USE_EXCEPTIONS
39 const char* ErrorException::what() const throw()
40 {
41  return msg.c_str();
42 }
43 
44 static ErrorAction mfem_error_action = MFEM_ERROR_THROW;
45 #else
46 static ErrorAction mfem_error_action = MFEM_ERROR_ABORT;
47 #endif
48 
50 {
51  // Check if 'action' is valid.
52  switch (action)
53  {
54  case MFEM_ERROR_ABORT: break;
55  case MFEM_ERROR_THROW:
56 #ifdef MFEM_USE_EXCEPTIONS
57  break;
58 #else
59  mfem_error("set_error_action: MFEM_ERROR_THROW requires the build "
60  "option MFEM_USE_EXCEPTIONS=YES");
61  return;
62 #endif
63  default:
64  mfem::err << "\n\nset_error_action: invalid action: " << action
65  << '\n';
66  mfem_error();
67  return;
68  }
69  mfem_error_action = action;
70 }
71 
73 {
74  return mfem_error_action;
75 }
76 
77 namespace internal
78 {
79 // defined in globals.cpp
80 extern bool mfem_out_initialized, mfem_err_initialized;
81 }
82 
83 void mfem_backtrace(int mode, int depth)
84 {
85 #ifdef MFEM_USE_LIBUNWIND
86  char name[UNW_NAME_LEN];
87  unw_cursor_t cursor;
88  unw_context_t uc;
89  unw_word_t ip, offp;
90  std::ostream &merr = internal::mfem_err_initialized ? mfem::err : std::cerr;
91 
92  int err_flag = unw_getcontext(&uc);
93  err_flag = err_flag ? err_flag : unw_init_local(&cursor, &uc);
94 
96  while (unw_step(&cursor) > 0 && addrs.Size() != depth)
97  {
98  err_flag = err_flag ? err_flag :
99  unw_get_proc_name(&cursor, name, UNW_NAME_LEN, &offp);
100  err_flag = err_flag ? err_flag : unw_get_reg(&cursor, UNW_REG_IP, &ip);
101  if (err_flag) { break; }
102  char *name_p = name;
103  int demangle_status;
104 
105  // __cxa_demangle is not standard, but works with GCC, Intel, PGI, Clang
106  char *name_demangle =
107  abi::__cxa_demangle(name, NULL, NULL, &demangle_status);
108  if (demangle_status == 0) // use mangled name if something goes wrong
109  {
110  name_p = name_demangle;
111  }
112 
113  merr << addrs.Size() << ") [0x" << std::hex << ip - 1 << std::dec
114  << "]: " << name_p << std::endl;
115  addrs.Append(ip - 1);
116 
117  if (demangle_status == 0)
118  {
119  free(name_demangle);
120  }
121  }
122 #if defined(__APPLE__) || defined(__linux__)
123  if (addrs.Size() > 0 && (mode & 1))
124  {
125  merr << "\nLookup backtrace source lines:";
126  const char *fname = NULL;
127  for (int i = 0; i < addrs.Size(); i++)
128  {
129  Dl_info info;
130  err_flag = !dladdr((void*)addrs[i], &info);
131  if (err_flag)
132  {
133  fname = "<exe>";
134  }
135  else if (fname != info.dli_fname)
136  {
137  fname = info.dli_fname;
138  merr << '\n';
139 #ifdef __linux__
140  merr << "addr2line -C -e " << fname;
141 #else
142  merr << "atos -o " << fname << " -l "
143  << (err_flag ? 0 : info.dli_fbase);
144 #endif
145  }
146  merr << " 0x" << std::hex << addrs[i] << std::dec;
147  }
148  merr << '\n';
149  }
150 #endif
151 #endif // MFEM_USE_LIBUNWIND
152 }
153 
154 void mfem_error(const char *msg)
155 {
156  std::ostream &merr = internal::mfem_err_initialized ? mfem::err : std::cerr;
157  if (msg)
158  {
159  // NOTE: By default, each call of the "operator <<" method of the
160  // mfem::err object results in flushing the I/O stream, which can be a
161  // very bad thing if all your processors try to do it at the same time.
162  merr << "\n\n" << msg << "\n";
163  }
164 
165 #ifdef MFEM_USE_LIBUNWIND
166  merr << "Backtrace:" << std::endl;
167  mfem_backtrace(1, -1);
168  merr << std::endl;
169 #endif
170 
171 #ifdef MFEM_USE_EXCEPTIONS
172  if (mfem_error_action == MFEM_ERROR_THROW)
173  {
174  throw ErrorException(msg);
175  }
176 #endif
177 
178 #ifdef MFEM_USE_MPI
179  int init_flag, fin_flag;
180  MPI_Initialized(&init_flag);
181  MPI_Finalized(&fin_flag);
182  if (init_flag && !fin_flag) { MPI_Abort(GetGlobalMPI_Comm(), 1); }
183 #endif
184  std::abort(); // force crash by calling abort
185 }
186 
187 void mfem_warning(const char *msg)
188 {
189  std::ostream &mout = internal::mfem_out_initialized ? mfem::out : std::cout;
190  if (msg)
191  {
192  mout << "\n\n" << msg << std::endl;
193  }
194 }
195 
196 }
virtual const char * what() const
Definition: error.cpp:39
OutStream err(std::cerr)
Global stream used by the library for standard error output. Initially it uses the same std::streambu...
Definition: globals.hpp:71
ErrorAction get_error_action()
Get the action MFEM takes when an error is encountered.
Definition: error.cpp:72
Exception class thrown when MFEM encounters an error and the current ErrorAction is set to MFEM_ERROR...
Definition: error.hpp:44
int Append(const T &el)
Append element &#39;el&#39; to array, resize if necessary.
Definition: array.hpp:759
void mfem_error(const char *msg)
Function called when an error is encountered. Used by the macros MFEM_ABORT, MFEM_ASSERT, MFEM_VERIFY.
Definition: error.cpp:154
void set_error_action(ErrorAction action)
Set the action MFEM takes when an error is encountered.
Definition: error.cpp:49
ErrorAction
Action to take when MFEM encounters an error.
Definition: error.hpp:26
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Definition: globals.hpp:66
Host memory; using new[] and delete[].
void mfem_warning(const char *msg)
Function called by the macro MFEM_WARNING.
Definition: error.cpp:187
void mfem_backtrace(int mode, int depth)
Definition: error.cpp:83
int Size() const
Return the logical size of the array.
Definition: array.hpp:141
MPI_Comm GetGlobalMPI_Comm()
Get MFEM&#39;s "global" MPI communicator.
Definition: globals.cpp:62