Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
964590f84ca87426195f5aa3e1eb92c8999b8355
[simgrid.git] / src / xbt / exception.cpp
1 /* Copyright (c) 2005-2018. The SimGrid Team. All rights reserved.          */
2
3 /* This program is free software; you can redistribute it and/or modify it
4  * under the terms of the license (GNU LGPL) which comes with this package. */
5
6 #include <cstdlib>
7
8 #include <atomic>
9 #include <exception>
10 #include <string>
11 #include <typeinfo>
12 #include <vector>
13 #include <memory>
14 #include <mutex>
15
16 #include "simgrid/Exception.hpp"
17 #include <xbt/backtrace.hpp>
18 #include <xbt/config.hpp>
19 #include <xbt/log.h>
20 #include <xbt/log.hpp>
21
22 XBT_LOG_EXTERNAL_CATEGORY(xbt);
23 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_exception, xbt, "Exceptions");
24
25 // DO NOT define ~xbt_ex() in exception.hpp.
26 // Defining it here ensures that xbt_ex is defined only in libsimgrid, but not in libsimgrid-java.
27 // Doing otherwise naturally breaks things (at least on freebsd with clang).
28
29 xbt_ex::~xbt_ex() = default;
30
31 void _xbt_throw(char* message, xbt_errcat_t errcat, int value, const char* file, int line, const char* func)
32 {
33   xbt_ex e(simgrid::xbt::ThrowPoint(file, line, func), message);
34   xbt_free(message);
35   e.category = errcat;
36   e.value    = value;
37   throw e;
38 }
39
40 /** @brief shows an exception content and the associated stack if available */
41 void xbt_ex_display(xbt_ex_t* e)
42 {
43   simgrid::xbt::log_exception(xbt_log_priority_critical, "UNCAUGHT EXCEPTION", *e);
44 }
45
46 /** @brief returns a short name for the given exception category */
47 const char* xbt_ex_catname(xbt_errcat_t cat)
48 {
49   switch (cat) {
50     case unknown_error:
51       return "unknown error";
52     case arg_error:
53       return "invalid argument";
54     case bound_error:
55       return "out of bounds";
56     case mismatch_error:
57       return "mismatch";
58     case not_found_error:
59       return "not found";
60     case system_error:
61       return "system error";
62     case network_error:
63       return "network error";
64     case timeout_error:
65       return "timeout";
66     case cancel_error:
67       return "action canceled";
68     case thread_error:
69       return "thread error";
70     case host_error:
71       return "host failed";
72     case tracing_error:
73       return "tracing error";
74     case io_error:
75       return "io error";
76     case vm_error:
77       return "vm error";
78     default:
79       return "INVALID ERROR";
80   }
81   return "INVALID ERROR";
82 }
83
84 namespace simgrid {
85 namespace xbt {
86
87 ContextedException::~ContextedException() = default;
88
89 void log_exception(e_xbt_log_priority_t prio, const char* context, std::exception const& exception)
90 {
91   try {
92     auto name = simgrid::xbt::demangle(typeid(exception).name());
93
94     auto* with_context = dynamic_cast<const simgrid::xbt::ContextedException*>(&exception);
95     if (with_context != nullptr)
96       XBT_LOG(prio, "%s %s by %s/%d: %s", context, name.get(), with_context->process_name().c_str(),
97               with_context->pid(), exception.what());
98     else
99       XBT_LOG(prio, "%s %s: %s", context, name.get(), exception.what());
100
101     // Do we have a backtrace?
102     if (with_context != nullptr && not simgrid::config::get_value<bool>("exception/cutpath")) {
103       auto backtrace =
104           simgrid::xbt::resolve_backtrace(with_context->backtrace().data(), with_context->backtrace().size());
105       for (std::string const& s : backtrace)
106         XBT_LOG(prio, "  -> %s", s.c_str());
107     }
108
109     // Do we have a nested exception?
110     auto* with_nested = dynamic_cast<const std::nested_exception*>(&exception);
111     if (with_nested == nullptr ||  with_nested->nested_ptr() == nullptr)
112       return;
113     try {
114       with_nested->rethrow_nested();
115     }
116     catch (std::exception& nested_exception) {
117       log_exception(prio, "Caused by", nested_exception);
118     }
119     // We could catch nested_exception or WithContextException but we don't bother:
120     catch (...) {
121       XBT_LOG(prio, "Caused by an unknown exception");
122     }
123   }
124   catch (...) {
125     // Don't log exceptions we got when trying to log exception
126   }
127 }
128
129 static void showBacktrace(std::vector<xbt_backtrace_location_t>& bt)
130 {
131   if (simgrid::config::get_value<bool>("exception/cutpath")) {
132     XBT_LOG(xbt_log_priority_critical, "Display of current backtrace disabled by --cfg=exception/cutpath.");
133     return;
134   }
135   std::vector<std::string> res = resolve_backtrace(&bt[0], bt.size());
136   XBT_LOG(xbt_log_priority_critical, "Current backtrace:");
137   for (std::string const& s : res)
138     XBT_LOG(xbt_log_priority_critical, "  -> %s", s.c_str());
139 }
140
141 static std::terminate_handler previous_terminate_handler = nullptr;
142
143 static void handler()
144 {
145   // Avoid doing crazy things if we get an uncaught exception inside
146   // an uncaught exception
147   static std::atomic_flag lock = ATOMIC_FLAG_INIT;
148   if (lock.test_and_set()) {
149     XBT_ERROR("Handling an exception raised an exception. Bailing out.");
150     std::abort();
151   }
152
153   // Get the current backtrace and exception
154   auto e = std::current_exception();
155   auto bt = backtrace();
156   try {
157     std::rethrow_exception(e);
158   }
159
160   // We manage C++ exception ourselves
161   catch (std::exception& e) {
162     log_exception(xbt_log_priority_critical, "Uncaught exception", e);
163     showBacktrace(bt);
164     std::abort();
165   }
166
167   // We don't know how to manage other exceptions
168   catch (...) {
169     // If there was another handler let's delegate to it
170     if (previous_terminate_handler)
171       previous_terminate_handler();
172     else {
173       XBT_ERROR("Unknown uncaught exception");
174       showBacktrace(bt);
175       std::abort();
176     }
177   }
178
179 }
180
181 void install_exception_handler()
182 {
183   static std::once_flag handler_flag;
184   std::call_once(handler_flag, [] {
185     previous_terminate_handler = std::set_terminate(handler);
186   });
187 }
188 // deprecated
189 void logException(e_xbt_log_priority_t priority, const char* context, std::exception const& exception)
190 {
191   log_exception(priority, context, exception);
192 }
193 void installExceptionHandler()
194 {
195   install_exception_handler();
196 }
197
198 } // namespace xbt
199 }