MFEM v4.7.0
Finite element discretization library
Loading...
Searching...
No Matches
error.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2024, 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
35namespace mfem
36{
37
38#ifdef MFEM_USE_EXCEPTIONS
39const char* ErrorException::what() const throw()
40{
41 return msg.c_str();
42}
43
44static ErrorAction mfem_error_action = MFEM_ERROR_THROW;
45#else
46static 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;
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
77namespace internal
78{
79// defined in globals.cpp
80extern bool mfem_out_initialized, mfem_err_initialized;
81}
82
83void 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
154void 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
187void 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}
int Size() const
Return the logical size of the array.
Definition: array.hpp:144
int Append(const T &el)
Append element 'el' to array, resize if necessary.
Definition: array.hpp:769
Exception class thrown when MFEM encounters an error and the current ErrorAction is set to MFEM_ERROR...
Definition: error.hpp:45
virtual const char * what() const
Definition: error.cpp:39
void mfem_error(const char *msg)
Definition: error.cpp:154
void mfem_warning(const char *msg)
Definition: error.cpp:187
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
void mfem_backtrace(int mode, int depth)
Definition: error.cpp:83
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:27
@ MFEM_ERROR_ABORT
Definition: error.hpp:28
@ MFEM_ERROR_THROW
Definition: error.hpp:31
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
@ HOST
Host memory; using new[] and delete[].
MPI_Comm GetGlobalMPI_Comm()
Get MFEM's "global" MPI communicator.
Definition: globals.cpp:62