FastJet 3.4.1
Error.cc
1//FJSTARTHEADER
2// $Id$
3//
4// Copyright (c) 2005-2023, 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
47FASTJET_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
48
49using namespace std;
50
51#ifdef FASTJET_HAVE_LIMITED_THREAD_SAFETY
52atomic<bool> Error::_print_errors{true};
53atomic<bool> Error::_print_backtrace{false};
54atomic<ostream *> Error::_default_ostr{& cerr};
55atomic<mutex *> Error::_stream_mutex{nullptr};
56#else
57bool Error::_print_errors = true;
58bool Error::_print_backtrace = false;
59ostream * 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.
86string 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//----------------------------------------------------------------------
120Error::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//----------------------------------------------------------------------
171void 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
180FASTJET_END_NAMESPACE
181