Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Segmentation fault (Address not mapped to object [(nil)]) on printing end #194

Closed
xgdgsc opened this issue Oct 27, 2020 · 25 comments
Closed

Comments

@xgdgsc
Copy link
Contributor

xgdgsc commented Oct 27, 2020

It segfaults on end of printing stacktrace, on line 3975 raise(info->si_signo); .

      >  52:   LOG_INFO << reinterpret_cast<DataPipe *>(pipes[0])->print();
         53: }
         54: 
         55: int main(int argc, char **argv) {
Segmentation fault (Address not mapped to object [(nil)])

And it prints a redefinition warning if I uncomment #define BACKWARD_HAS_BFD 1

#define BACKWARD_HAS_DW 1
#define BACKWARD_HAS_BFD 1
#include "backward.hpp"

this is what I use now

@bombela
Copy link
Owner

bombela commented Dec 4, 2020

You must select a single symbol resolver implementation. Take a look at the top of backward.hpp for a better understanding.

@bsergean
Copy link

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 ?

@bsergean
Copy link

We use it on Linux with a static binary + elfutils library git://sourceware.org/git/elfutils.git

@bombela
Copy link
Owner

bombela commented Feb 24, 2021 via email

@bsergean
Copy link

bsergean commented Feb 24, 2021 via email

@bombela
Copy link
Owner

bombela commented Feb 24, 2021

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?

@bsergean
Copy link

bsergean commented Feb 24, 2021 via email

@davemoore22
Copy link

davemoore22 commented May 26, 2021

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)

@bombela
Copy link
Owner

bombela commented May 26, 2021

In your output, backward-cpp is printing the trace on a segfault... caused when accessing a resolved trace from backward-cpp! That's fun.

@davemoore22
Copy link

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)

@bombela
Copy link
Owner

bombela commented May 26, 2021

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;
}

@bombela
Copy link
Owner

bombela commented May 26, 2021

Does it behaves differently with unwind instead of libunwind?

@davemoore22
Copy link

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.

@bombela
Copy link
Owner

bombela commented May 27, 2021

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?

@davemoore22
Copy link

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.

@bombela
Copy link
Owner

bombela commented May 27, 2021

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.

@bombela
Copy link
Owner

bombela commented May 27, 2021

Also if you could find out the exact compiler command line invocation it would be great.

@davemoore22
Copy link

OK, no difference in CodeBlocks with unwind. :-(

Compilation example:

g++ -Wredundant-decls -Wcast-align -Wunreachable-code -Wmissing-declarations -Wmissing-include-dirs -Wswitch-default -Wfatal-errors -Wextra -Wall -g -pthread -Wl,-rpath=/usr/local/lib -fpic -std=c++20 -Wpedantic -Wunused -Wignored-qualifiers -Wformat-nonliteral -Wformat=2 -Winvalid-pch -Wmissing-format-attribute -Wodr -pg -g -Iinc -Iinc/simpleini -Iinc/sqlitemoderncpp -Iinc/magicenum -Iinc/backwardcpp -Iinc/cereal -Iinc/cereal/archives -c /home/dave/Development/wizardry/sorcery-sfml/src/window.cpp -o obj/debug/src/window.o

Linkage:
g++ -Linc/backwardcpp -o bin/debug/sorcery obj/debug/inc/backwardcpp/backward.o obj/debug/src/allocatepanel.o obj/debug/src/animation.o obj/debug/src/application.o obj/debug/src/attractmode.o obj/debug/src/attributedisplay.o obj/debug/src/banner.o obj/debug/src/camera.o obj/debug/src/castle.o obj/debug/src/character.o obj/debug/src/compendium.o obj/debug/src/component.o obj/debug/src/config.o obj/debug/src/confirm.o obj/debug/src/controloverlay.o obj/debug/src/create.o obj/debug/src/database.o obj/debug/src/dialog.o obj/debug/src/display.o obj/debug/src/edgeoftown.o obj/debug/src/engine.o obj/debug/src/entity.o obj/debug/src/error.o obj/debug/src/file.o obj/debug/src/frame.o obj/debug/src/game.o obj/debug/src/graphics.o obj/debug/src/iconstore.o obj/debug/src/infopanel.o obj/debug/src/input.o obj/debug/src/keyboard.o obj/debug/src/layout.o obj/debug/src/license.o obj/debug/src/main.o obj/debug/src/mainmenu.o obj/debug/src/manage.o obj/debug/src/map.o obj/debug/src/maptile.o obj/debug/src/menu.o obj/debug/src/operator.o obj/debug/src/options.o obj/debug/src/platform.o obj/debug/src/random.o obj/debug/src/raycaster.o obj/debug/src/resourcemanager.o obj/debug/src/roster.o obj/debug/src/spellsummary.o obj/debug/src/splash.o obj/debug/src/statusbar.o obj/debug/src/string.o obj/debug/src/system.o obj/debug/src/textfile.o obj/debug/src/tile.o obj/debug/src/tooltip.o obj/debug/src/training.o obj/debug/src/window.o -lstdc++fs -lX11 -lsfml-graphics -lsfml-audio -lsfml-network -lsfml-window -lsfml-system -lsqlite3 -lsfeMovie -ljsoncpp -lthor -lpthread -lfmt -luuid -lbfd -ldl -ltgui -lunwind -pg

@bombela
Copy link
Owner

bombela commented May 27, 2021

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.

@davemoore22
Copy link

ok, I'll try that!!!

@davemoore22
Copy link

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!!!

image

What's the best/preferred way of crediting use of the library btw?

@bombela
Copy link
Owner

bombela commented May 27, 2021

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.

@bombela bombela closed this as completed May 27, 2021
@bombela
Copy link
Owner

bombela commented May 27, 2021

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.

@nmaludy
Copy link

nmaludy commented Dec 7, 2021

@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:

  • In my case these messages seem to be coming from psiginfo() inside of backward::SignalHandling::handleSignal()
  • The Address not mapped to object [(nil)] message is basically saying that it was caused by a NULL pointer access
  • If signal is raised in another way, it will print details related to how it was raised (see the raise() 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.

@bombela
Copy link
Owner

bombela commented Dec 7, 2021

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)).

https://linux.die.net/man/3/psiginfo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants