Closed xgdgsc closed 3 years ago
You must select a single symbol resolver implementation. Take a look at the top of backward.hpp
for a better understanding.
Hi there, we are running into this error as well. Here is how we use backward:
#define BACKWARD_HAS_DW 1
#include "backward.hpp"
class SignalHandlerUtils
{
public:
SignalHandlerUtils() = default;
private:
// we only need one member variable that does everything,
// that is signal handling registration + stackwalking + symbolication
// the backtrace is printed by backward library on stderr
backward::SignalHandling sh;
};
// our main just does this
int main()
{
SignalHandlerUtils signalHandler{};
....
}
@bombela, is this incorrect usage ?
We use it on Linux with a static binary + elfutils library git://sourceware.org/git/elfutils.git
Could it be the object being in main is destroyed somehow before being used? Maybe it should be a global? I am just throwing ideas here.
On Tue, 23 Feb 2021, 19:19 Benjamin Sergeant, notifications@github.com wrote:
We use it on Linux with a static binary + elfutils library git:// sourceware.org/git/elfutils.git
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/bombela/backward-cpp/issues/194#issuecomment-784720664, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABUZDDWWJ3M73PUEORDUCLTARV2JANCNFSM4TATGYJQ .
Everything is possible but that sounds unlikely. Our main is server code so we essentially never exit main.
In the past I wrote crash-handling code too, and I remember avoiding fwrite and using straight write with a file descriptor instead. fwrite is not ’signal safe’ according to the internet. I’m contemplating making a PR that would add an interface with ‘write’ for the code that prints the backtrace.
On Feb 23, 2021, at 7:39 PM, François-Xavier Bourlet notifications@github.com wrote:
Could it be the object being in main is destroyed somehow before being used? Maybe it should be a global? I am just throwing ideas here.
On Tue, 23 Feb 2021, 19:19 Benjamin Sergeant, notifications@github.com wrote:
We use it on Linux with a static binary + elfutils library git:// sourceware.org/git/elfutils.git
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/bombela/backward-cpp/issues/194#issuecomment-784720664, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABUZDDWWJ3M73PUEORDUCLTARV2JANCNFSM4TATGYJQ .
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/bombela/backward-cpp/issues/194#issuecomment-784728683, or unsubscribe https://github.com/notifications/unsubscribe-auth/AC2O6ULGBZPZ3AK4HZNHWQTTARYI7ANCNFSM4TATGYJQ.
Fair enough. Backward-cpp is not signal safe at all. None of the lib used to parse the debug symbols are. Making signal safe code is a pretty serious endeavor. So my take was: better have stacktrace most often, than have nothing.
Nontheless you think it's the fwrite? Any ways you comment the frwite out and test on your program?
I actually have no clue whether it’s the fwrite, and agreed that signal safe is a pain, I hate using C function for doing string manipulation myself …
I hope I can find something and report here.
On Feb 23, 2021, at 7:39 PM, François-Xavier Bourlet notifications@github.com wrote:
Could it be the object being in main is destroyed somehow before being used? Maybe it should be a global? I am just throwing ideas here.
On Tue, 23 Feb 2021, 19:19 Benjamin Sergeant, notifications@github.com wrote:
We use it on Linux with a static binary + elfutils library git:// sourceware.org/git/elfutils.git
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/bombela/backward-cpp/issues/194#issuecomment-784720664, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABUZDDWWJ3M73PUEORDUCLTARV2JANCNFSM4TATGYJQ .
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/bombela/backward-cpp/issues/194#issuecomment-784728683, or unsubscribe https://github.com/notifications/unsubscribe-auth/AC2O6ULGBZPZ3AK4HZNHWQTTARYI7ANCNFSM4TATGYJQ.
If you don't mind me piggy-backing onto this, I'm getting a similar error.
Here's how I'm using it (on an exception I construct an error class and inside the constructor this code is called):
backward::StackTrace st;
st.load_here(32);
backward::TraceResolver tr;
tr.load_stacktrace(st);
for (size_t i = 0; i < st.size(); ++i) {
backward::ResolvedTrace trace = tr.resolve(st[i]);
info_e->addText(fmt::format(
"#{} {} {} [{}] ", i, trace.object_filename, trace.object_function, trace.addr));
}
which results in:
130: tr.load_stacktrace(st);
131:
132: for (size_t i = 0; i < st.size(); ++i) {
> 133: backward::ResolvedTrace trace = tr.resolve(st[i]);
134:
135: info_e->addText(fmt::format(
136: "#{} {} {} [{}] ", i, trace.object_filename, trace.object_function, trace.addr));
#0 Source "/home/dave/Development/wizardry/sorcery-sfml/inc/backwardcpp/backward.hpp", line 1321, in backward::TraceResolverLinuxImpl<backward::trace_resolver_tag::backtrace_symbol>::resolve(backward::ResolvedTrace) [0x556bfa2747a9]
1318: }
1319:
1320: ResolvedTrace resolve(ResolvedTrace trace) override {
>1321: char *filename = _symbols[trace.idx];
1322: char *funcname = filename;
1323: while (*funcname && *funcname != '(') {
1324: funcname += 1;
Segmentation fault (Address not mapped to object [(nil)])
Segmentation fault (core dumped)
That all said, it all works lovely if I don't attempt to do a manual traverse and just let it fail and output to the terminal as normal, but I'd also like to capture the output and do stuff with it,
(edit: I'm running XUbuntu 20.04, gcc11.1, and link in binutils-dev and libunwind-dev and have set the defines correctly)
In your output, backward-cpp is printing the trace on a segfault... caused when accessing a resolved trace from backward-cpp! That's fun.
In your output, backward-cpp is printing the trace on a segfault... caused when accessing a resolved trace from backward-cpp! That's fun.
Its all incredibly meta isn't it?
Incidentally, I'd thought I'd try to be clever and use the Printer object instead but writing it to an ostringsteam. No cigar either, alas:
Source "/home/dave/Development/wizardry/sorcery-sfml/src/error.cpp", line 135, in Sorcery::Error::Error(tgui::Gui*, Sorcery::Enums::System::Error, std::exception&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) [0x5636a6372bf9]
132: p.color_mode = backward::ColorMode::never;
133: p.address = false;
134: std::ostringstream out;
> 135: p.print(st, out);
136: std::string wrapped_notes = WORDWRAP(out.str(), 80);
137: const std::regex regex(R"([@]+)");
138: std::sregex_token_iterator it{wrapped_notes.begin(), wrapped_notes.end(), regex, -1};
#9 Source "/home/dave/Development/wizardry/sorcery-sfml/inc/backwardcpp/backward.hpp", line 3992, in std::ostream& backward::Printer::print<backward::StackTrace>(backward::StackTrace&, std::ostream&) [0x5636a6378c48]
3989: template <typename ST> std::ostream &print(ST &st, std::ostream &os) {
3990: Colorize colorize(os);
3991: colorize.activate(color_mode);
>3992: print_stacktrace(st, os, colorize);
3993: return os;
3994: }
#8 Source "/home/dave/Development/wizardry/sorcery-sfml/inc/backwardcpp/backward.hpp", line 4026, in void backward::Printer::print_stacktrace<backward::StackTrace>(backward::StackTrace&, std::ostream&, backward::Colorize&) [0x5636a62062ea]
4023: print_header(os, st.thread_id());
4024: _resolver.load_stacktrace(st);
4025: for (size_t trace_idx = st.size(); trace_idx > 0; --trace_idx) {
>4026: print_trace(os, _resolver.resolve(st[trace_idx - 1]), colorize);
4027: }
4028: }
#7 Source "/home/dave/Development/wizardry/sorcery-sfml/inc/backwardcpp/backward.hpp", line 4079, in backward::Printer::print_trace(std::ostream&, backward::ResolvedTrace const&, backward::Colorize&) [0x5636a61ffb27]
4076: }
4077: print_source_loc(os, " ", trace.source, trace.addr);
4078: if (snippet) {
>4079: print_snippet(os, " ", trace.source, colorize, Color::yellow,
4080: trace_context_size);
4081: }
4082: }
#6 Source "/home/dave/Development/wizardry/sorcery-sfml/inc/backwardcpp/backward.hpp", line 4093, in backward::Printer::print_snippet(std::ostream&, char const*, backward::ResolvedTrace::SourceLoc const&, backward::Colorize&, backward::Color::type, int) [0x5636a61ffc07]
4090: typedef SnippetFactory::lines_t lines_t;
4091:
4092: lines_t lines = _snippets.get_snippet(source_loc.filename, source_loc.line,
>4093: static_cast<unsigned>(context_size));
4094:
4095: for (lines_t::const_iterator it = lines.begin(); it != lines.end(); ++it) {
4096: if (it->first == source_loc.line) {
#5 Source "/home/dave/Development/wizardry/sorcery-sfml/inc/backwardcpp/backward.hpp", line 3823, in backward::SnippetFactory::get_snippet(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned int, unsigned int) [0x5636a61fefd3]
3820: lines_t get_snippet(const std::string &filename, unsigned line_start,
3821: unsigned context_size) {
3822:
>3823: SourceFile &src_file = get_src_file(filename);
3824: unsigned start = line_start - context_size / 2;
3825: return src_file.get_lines(start, context_size);
3826: }
#4 Source "/home/dave/Development/wizardry/sorcery-sfml/inc/backwardcpp/backward.hpp", line 3863, in backward::SnippetFactory::get_src_file(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) [0x5636a61ff078]
3860: src_files_t _src_files;
3861:
3862: SourceFile &get_src_file(const std::string &filename) {
>3863: src_files_t::iterator it = _src_files.find(filename);
3864: if (it != _src_files.end()) {
3865: return it->second;
3866: }
#3 Source "/usr/include/c++/11/bits/unordered_map.h", line 869, in std::unordered_map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, backward::SourceFile, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, backward::SourceFile> > >::find(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) [0x5636a62028c7]
866: */
867: iterator
868: find(const key_type& __x)
> 869: { return _M_h.find(__x); }
870:
871: #if __cplusplus > 201703L
872: template<typename _Kt>
#2 Source "/usr/include/c++/11/bits/hashtable.h", line 1572, in std::_Hashtable<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, backward::SourceFile>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, backward::SourceFile> >, std::__detail::_Select1st, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, false, true> >::find(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) [0x5636a6205a8b]
1569: {
1570: __hash_code __code = this->_M_hash_code(__k);
1571: std::size_t __bkt = _M_bucket_index(__code);
>1572: return iterator(_M_find_node(__bkt, __k, __code));
1573: }
1574:
1575: template<typename _Key, typename _Value, typename _Alloc,
#1 Source "/usr/include/c++/11/bits/hashtable.h", line 791, in std::_Hashtable<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, backward::SourceFile>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, backward::SourceFile> >, std::__detail::_Select1st, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, false, true> >::_M_find_node(unsigned long, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned long) const [0x5636a6209036]
788: _M_find_node(size_type __bkt, const key_type& __key,
789: __hash_code __c) const
790: {
> 791: __node_base_ptr __before_n = _M_find_before_node(__bkt, __key, __c);
792: if (__before_n)
793: return static_cast<__node_ptr>(__before_n->_M_nxt);
794: return nullptr;
#0 Source "/usr/include/c++/11/bits/hashtable.h", line 1810, in std::_Hashtable<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, backward::SourceFile>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, backward::SourceFile> >, std::__detail::_Select1st, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, false, true> >::_M_find_before_node(unsigned long, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned long) const [0x5636a620b20d]
1807: __hash_code __code) const
1808: -> __node_base_ptr
1809: {
>1810: __node_base_ptr __prev_p = _M_buckets[__bkt];
1811: if (!__prev_p)
1812: return nullptr;
Segmentation fault (Signal sent by the kernel [(nil)])
Segmentation fault (core dumped)
I cannot reproduce the segfault.
Ubuntu 20.04.2 LTS g++ (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0 clang version 10.0.0-4ubuntu1
Testing with: clang/g++ --std=c++11 t.cpp -lunwind -lbfd -ldl
#define BACKWARD_HAS_LIBUNWIND 1
#define BACKWARD_HAS_BFD 1
#include "backward.hpp"
using namespace backward;
void p() {
backward::StackTrace st;
st.load_here(32);
backward::TraceResolver tr;
tr.load_stacktrace(st);
for (size_t i = 0; i < st.size(); ++i) {
backward::ResolvedTrace trace = tr.resolve(st[i]);
std::cout << i
<< " " << trace.object_filename
<< " " << trace.object_function
<< " " << trace.addr
<< " " << std::endl;
}
}
int main() {
p();
return 0;
}
Does it behaves differently with unwind instead of libunwind?
Same error with using both libunwind and the standard unwind.
I'm also using lbfd but would that make a difference?
As I said, it works beautifully if I let it do its thing when an exception occurs and print stuff out to the console and then exit.
But I would like to be handle things a bit more gracefully if possible and grab the stack trace to allow users to send it to me.
I don't think libfd makes a difference. Feel free to try them all. backward-cpp is definitively supposed to work for your use case.
Note that you can store the stacktrace with your exception, and resolve it later. Up to you.
Anyways, I cannot reproduce the segfault. If you could come up with a small reproducible example, it would be great. What about running your program under valgrind?
OK, a smidgeon of clarity achieved. I use both CodeBlocks and VSCode, and I think the seg fault is caused either by something in the way Codeblocks is linking or the way I have the project setup therein; because if I compile using VSCode/make, no seg fault occurs.
That's a bit weird, that said, since as far as I can tell, my build options for both methods are identical and up until now, there's been no difference in what I use to compile and link with regards to the rest of the codebase.
Build options are pretty standard BTW, including backward.cpp for the defines, search path includes backward.hpp, debug symbols are on, and the three libraries mentioned above.
I'll continue to investigate and report back, and see how I get on with valgrind.
Try unwind
instead of libunwind
. I am curious if it makes any significant difference. unwind
is always linked in, because its offered by the compiler runtime.
Also if you could find out the exact compiler command line invocation it would be great.
OK, no difference in CodeBlocks with unwind. :-(
In your first segfault, you are using BACKTRACE, not BFD. But you claim that you intended to use BFD. Your command line also doesn't include the various defines for backward.hpp. This leads me to believe that you are compiling backward.hpp differently in various code object (.o). And then linking the whole thing together. I further believe that because you mentioned some defines in backward.cpp. Which only applies to this very .cpp file. The one that registers unix signal that then give you a nice printed trace. But the backward.hpp you are importing for attaching to the exception is not compiled with the same defines.
In other words: set the defines for your compilation command lines. Or set them atop backward.hpp. But not in .cpp files.
ok, I'll try that!!!
That worked. Removing backward.cpp from my project and moving the defines into backward.hpp was the key. I can now grab the stack to allow the users to send me the info. Thank you!!!
What's the best/preferred way of crediting use of the library btw?
Ah C++... It keeps you on your toes at all time. One tiny slip, and your program will do everything and anything.
If you already have an "about" dialog with a list of open sources credits, you can add a mention there if you would like. No obligation.
For anybody else reading this issue.
Make sure that you are compiling backward.hpp with the exact same defines and compilation flags throughout your program. Otherwise, the generated machine code will be incompatible at runtime.
@bombela i ran into this same issue, but ONLY when executed from inside backward::SignalHandling
and when forcing the segfault by access to a NULL pointer.
Segmentation fault (Address not mapped to object [(nil)])
Segmentation fault (core dumped)
Digging into the source and gdb
i was able to find that it was coming from https://github.com/bombela/backward-cpp/blob/master/backward.hpp#L4250
Simply commenting out that line removes the error message. I did also try using psignal(signo);
instead and simply got an error message:
Segmentation Fault
Segmentation Fault (core dumped)
Some more experimentation, i tried forcefully raise(SIGSEGV)
and got an error message:
Segmentation fault (Signal sent by tkill() [0x3e800063099])
Segmentation fault (core dumped)
Conclusions:
psiginfo()
inside of backward::SignalHandling::handleSignal()
Address not mapped to object [(nil)]
message is basically saying that it was caused by a NULL pointer accessraise()
example)My code to reproduce this is below:
#include "backward.hpp"
using namespace backward;
void p() {
backward::StackTrace st;
st.load_here(32);
backward::TraceResolver tr;
tr.load_stacktrace(st);
for (size_t i = 0; i < st.size(); ++i) {
backward::ResolvedTrace trace = tr.resolve(st[i]);
std::cout << i
<< " " << trace.object_filename
<< " " << trace.object_function
<< " " << trace.addr
<< " " << std::endl;
}
}
int nullSegfault()
{
int* p_junk = 0;
int val = *p_junk;
return val; // have to use `val` to avoid optimizer throwing all this code away
}
void raiseSegfault()
{
raise(SIGSEGV);
}
int main(int argc, char* argv[])
{
// print stacktrace normally to show that it works in-process
p();
// register backward signal handlers to showcase the error message
backward::SignalHandling sh;
// comment these out to choose how to raise the signal
// cause segfault by NULL pointer access, prints:
// Segmentation fault (Address not mapped to object [(nil)])
nullSegfault();
// cause segfault by raising the signal manually, prints:
// Segmentation fault (Signal sent by tkill() [0x3e800063099])
raiseSegfault();
return 0;
}
Hope this helps someone else.
I don't think it is the same issue. You are talking about some output message from psiginfo. They had a memory access error because of incompatible datastructures in memory.
Unless you are saying you got a memory access error during the execution of psiginfo?
The psiginfo() function is like psignal(), except that it displays information about the signal described by pinfo, which should point to a valid siginfo_t structure. As well as the signal description, psiginfo() displays information about the origin of the signal, and other information relevant to the signal (e.g., the relevant memory address for hardware-generated signals, the child process ID for SIGCHLD, and the user ID and process ID of the sender, for signals set using kill(2) or sigqueue(3)).
It segfaults on end of printing stacktrace, on line 3975
raise(info->si_signo);
.And it prints a redefinition warning if I uncomment
#define BACKWARD_HAS_BFD 1
this is what I use now