FastJet  3.4.0
Error.cc
1 //FJSTARTHEADER
2 // $Id$
3 //
4 // Copyright (c) 2005-2021, Matteo Cacciari, Gavin P. Salam and Gregory Soyez
5 //
6 //----------------------------------------------------------------------
7 // This file is part of FastJet.
8 //
9 // FastJet is free software; you can redistribute it and/or modify
10 // it under the terms of the GNU General Public License as published by
11 // the Free Software Foundation; either version 2 of the License, or
12 // (at your option) any later version.
13 //
14 // The algorithms that underlie FastJet have required considerable
15 // development. They are described in the original FastJet paper,
16 // hep-ph/0512210 and in the manual, arXiv:1111.6097. If you use
17 // FastJet as part of work towards a scientific publication, please
18 // quote the version you use and include a citation to the manual and
19 // optionally also to hep-ph/0512210.
20 //
21 // FastJet is distributed in the hope that it will be useful,
22 // but WITHOUT ANY WARRANTY; without even the implied warranty of
23 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 // GNU General Public License for more details.
25 //
26 // You should have received a copy of the GNU General Public License
27 // along with FastJet. If not, see <http://www.gnu.org/licenses/>.
28 //----------------------------------------------------------------------
29 //FJENDHEADER
30 
31 #include "fastjet/Error.hh"
32 #include "fastjet/config.h"
33 #include <sstream>
34 
35 #ifndef __FJCORE__
36 // printing the stack would need execinfo
37 #ifdef FASTJET_HAVE_EXECINFO_H
38 #include <execinfo.h>
39 #include <cstdlib>
40 #ifdef FASTJET_HAVE_DEMANGLING_SUPPORT
41 #include <cstdio>
42 #include <cxxabi.h>
43 #endif // FASTJET_HAVE_DEMANGLING_SUPPORT
44 #endif // FASTJET_HAVE_EXECINFO_H
45 #endif // __FJCORE__
46 
47 FASTJET_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
48 
49 using namespace std;
50 
51 #ifdef FASTJET_HAVE_LIMITED_THREAD_SAFETY
52 atomic<bool> Error::_print_errors{true};
53 atomic<bool> Error::_print_backtrace{false};
54 atomic<ostream *> Error::_default_ostr{& cerr};
55 atomic<mutex *> Error::_stream_mutex{nullptr};
56 #else
57 bool Error::_print_errors = true;
58 bool Error::_print_backtrace = false;
59 ostream * Error::_default_ostr = & cerr;
60 #endif // FASTJET_HAVE_LIMITED_THREAD_SAFETY
61 
62 #if (!defined(FASTJET_HAVE_EXECINFO_H)) || defined(__FJCORE__)
63  LimitedWarning Error::_execinfo_undefined;
64 #endif
65 
66 //----------------------------------------------------------------------
67 #ifndef __FJCORE__
68 
69 // demangling only is included, i.e. --enable-demangling is specified
70 // at configure time, execinfo.h is present and the GNU C++ ABI is
71 // supported
72 #if defined(FASTJET_HAVE_EXECINFO_H) && defined(FASTJET_HAVE_DEMANGLING_SUPPORT)
73 // demangle a given backtrace symbol
74 //
75 // Notes:
76 // - at the moment, only the symbol is parsed.
77 // - one can get the offset by using
78 // "%*[^(]%*[^_]%127[^+)]%64[+x0123456789abcdef]", symbol, offset
79 // and checking if sscanf returns 0, 1 or 2
80 // (offset includes the leading +)
81 // - Similarly one could exctract the address and try to convert it
82 // into a filename+line number like addr2line does but this seems
83 // to require exteral dependencies. If we want to go down that
84 // route, one could look into the inplementation o faddr2line(.c)
85 // and/or dladdr.
86 string Error::_demangle(const char* symbol) {
87  size_t size;
88  int status;
89  char temp[128];
90  char* demangled;
91  // first, try to demangle a c++ name
92  // decryption:
93  // %*[^(] matches any number of characters different from "("
94  // the * tells not to store in input var
95  // %*[^_] matches any number of characters different from "_"
96  // the * tells not to store in input var
97  // %127[^)+] matches at most 127 characters different from "+"
98  // match is stored
99  if (1 == sscanf(symbol, "%*[^(]%*[^_]%127[^)+]", temp)) {
100  //cout << symbol << " -> " << temp << endl;
101  if (NULL != (demangled = abi::__cxa_demangle(temp, NULL, &size, &status))) {
102  string result(demangled);
103  free(demangled);
104  return result;
105  }
106  }
107  //if that didn't work, try to get a regular c symbol
108  if (1 == sscanf(symbol, "%127s", temp)) {
109  return temp;
110  }
111 
112  //if all else fails, just return the symbol
113  return symbol;
114 }
115 #endif // FASTJET_HAVE_DEMANGLING_SUPPORT && FASTJET_HAVE_EXECINFO_H
116 #endif // __FJCORE__
117 
118 
119 //----------------------------------------------------------------------
120 Error::Error(const std::string & message_in) {
121  _message = message_in;
122 
123  // Thread-safety note:
124  // get the ostream once and for all (avoids that another thread
125  // comes and changes that somewhere in the processing after the
126  // test
127  ostream* ostr = _default_ostr;
128  if (_print_errors && ostr){
129  ostringstream oss;
130  oss << "fastjet::Error: "<< message_in << endl;
131 
132 #ifndef __FJCORE__
133  // only print the stack if execinfo is available and stack enabled
134 #ifdef FASTJET_HAVE_EXECINFO_H
135  if (_print_backtrace){
136  void * array[10];
137  char ** messages;
138 
139  int size = backtrace(array, 10);
140  messages = backtrace_symbols(array, size);
141 
142  oss << "stack:" << endl;
143  for (int i = 1; i < size && messages != NULL; ++i){
144 #ifdef FASTJET_HAVE_DEMANGLING_SUPPORT
145  oss << " #" << i << ": " << _demangle(messages[i])
146  << " [" << messages[i] << "]" << endl;
147 #else
148  oss << " #" << i << ": " << messages[i] << endl;
149 #endif
150  }
151  free(messages);
152  }
153 #endif // FASTJET_HAVE_EXECINFO_H
154 #endif // __FJCORE__
155 
156 #ifdef FASTJET_HAVE_LIMITED_THREAD_SAFETY
157  if (_stream_mutex){
158  std::lock_guard<std::mutex> guard(*_stream_mutex);
159  *ostr << oss.str();
160  ostr->flush(); // get something written to file even if the program aborts
161  } else
162 #endif // FASTJET_HAVE_LIMITED_THREAD_SAFETY
163  {
164  *ostr << oss.str();
165  ostr->flush(); // get something written to file even if the program aborts
166  }
167  }
168 }
169 
170 //----------------------------------------------------------------------
171 void Error::set_print_backtrace(bool enabled) {
172 #if (!defined(FASTJET_HAVE_EXECINFO_H)) || defined(__FJCORE__)
173  if (enabled) {
174  _execinfo_undefined.warn("Error::set_print_backtrace(true) will not work with this build of FastJet");
175  }
176 #endif
177  _print_backtrace = enabled;
178 }
179 
180 FASTJET_END_NAMESPACE
181