FastJet  3.4.0-beta.1
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 #else
56 bool Error::_print_errors = true;
57 bool Error::_print_backtrace = false;
58 ostream * Error::_default_ostr = & cerr;
59 #endif // FASTJET_HAVE_LIMITED_THREAD_SAFETY
60 
61 #if (!defined(FASTJET_HAVE_EXECINFO_H)) || defined(__FJCORE__)
62  LimitedWarning Error::_execinfo_undefined;
63 #endif
64 
65 //----------------------------------------------------------------------
66 #ifndef __FJCORE__
67 
68 // demangling only is included, i.e. --enable-demangling is specified
69 // at configure time, execinfo.h is present and the GNU C++ ABI is
70 // supported
71 #if defined(FASTJET_HAVE_EXECINFO_H) && defined(FASTJET_HAVE_DEMANGLING_SUPPORT)
72 // demangle a given backtrace symbol
73 //
74 // Notes:
75 // - at the moment, only the symbol is parsed.
76 // - one can get the offset by using
77 // "%*[^(]%*[^_]%127[^+)]%64[+x0123456789abcdef]", symbol, offset
78 // and checking if sscanf returns 0, 1 or 2
79 // (offset includes the leading +)
80 // - Similarly one could exctract the address and try to convert it
81 // into a filename+line number like addr2line does but this seems
82 // to require exteral dependencies. If we want to go down that
83 // route, one could look into the inplementation o faddr2line(.c)
84 // and/or dladdr.
85 string Error::_demangle(const char* symbol) {
86  size_t size;
87  int status;
88  char temp[128];
89  char* demangled;
90  // first, try to demangle a c++ name
91  // decryption:
92  // %*[^(] matches any number of characters different from "("
93  // the * tells not to store in input var
94  // %*[^_] matches any number of characters different from "_"
95  // the * tells not to store in input var
96  // %127[^)+] matches at most 127 characters different from "+"
97  // match is stored
98  if (1 == sscanf(symbol, "%*[^(]%*[^_]%127[^)+]", temp)) {
99  //cout << symbol << " -> " << temp << endl;
100  if (NULL != (demangled = abi::__cxa_demangle(temp, NULL, &size, &status))) {
101  string result(demangled);
102  free(demangled);
103  return result;
104  }
105  }
106  //if that didn't work, try to get a regular c symbol
107  if (1 == sscanf(symbol, "%127s", temp)) {
108  return temp;
109  }
110 
111  //if all else fails, just return the symbol
112  return symbol;
113 }
114 #endif // FASTJET_HAVE_DEMANGLING_SUPPORT && FASTJET_HAVE_EXECINFO_H
115 #endif // __FJCORE__
116 
117 
118 //----------------------------------------------------------------------
119 Error::Error(const std::string & message_in) {
120  _message = message_in;
121 
122  // Thread-safety note:
123  // get the ostream once and for all (avoids that another thread
124  // comes and changes that somewhere in the processing after the
125  // test
126  ostream* ostr = _default_ostr;
127  if (_print_errors && ostr){
128  ostringstream oss;
129  oss << "fastjet::Error: "<< message_in << endl;
130 
131 #ifndef __FJCORE__
132  // only print the stack if execinfo is available and stack enabled
133 #ifdef FASTJET_HAVE_EXECINFO_H
134  if (_print_backtrace){
135  void * array[10];
136  char ** messages;
137 
138  int size = backtrace(array, 10);
139  messages = backtrace_symbols(array, size);
140 
141  oss << "stack:" << endl;
142  for (int i = 1; i < size && messages != NULL; ++i){
143 #ifdef FASTJET_HAVE_DEMANGLING_SUPPORT
144  oss << " #" << i << ": " << _demangle(messages[i])
145  << " [" << messages[i] << "]" << endl;
146 #else
147  oss << " #" << i << ": " << messages[i] << endl;
148 #endif
149  }
150  free(messages);
151  }
152 #endif // FASTJET_HAVE_EXECINFO_H
153 #endif // __FJCORE__
154 
155  *ostr << oss.str();
156  // get something written to file even
157  // if the program aborts
158  ostr->flush();
159 
160  // // output error message either to cerr or to the user-set stream
161  // if (_default_ostr) { *_default_ostr << oss.str();
162  // // get something written to file even
163  // // if the program aborts
164  // _default_ostr->flush(); }
165  // else { std::cerr << oss.str(); }
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