From ad611b90699afda0dc22c7fef002d538a0ac33b4 Mon Sep 17 00:00:00 2001 From: Manu343726 Date: Wed, 24 Aug 2016 12:29:52 +0200 Subject: [PATCH 1/7] Fix memory leak in linux demangler The __cxa_demangle() call was leaking the demangled name buffer (Confirmed by valgrind). If I understood the __cxa_demangle() docs right, the issue was that you were mixing the two operating modes (User buffer vs __cxa_demangle() allocated buffer). You passed a garbage pointer to __cxa_demangle(), which expects null or a pointer to a malloc() allocated block of *size* bytes. Note also size is 0 in your implementation. Basically the leak comes from __cxa_demangle() doing a realloc() on your garbage pointer. The fix is as simple as telling __cxa_demangle() to allocate the buffer itself. Just for reference, here is the __cxa_demangle() documentation explaining this behavior: https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.3/a01696.html --- backward.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backward.hpp b/backward.hpp index c360f22..c1e80eb 100644 --- a/backward.hpp +++ b/backward.hpp @@ -404,7 +404,7 @@ struct demangler_impl { std::string demangle(const char* funcname) { using namespace details; _demangle_buffer.reset( - abi::__cxa_demangle(funcname, _demangle_buffer.release(), + abi::__cxa_demangle(funcname, NULL, &_demangle_buffer_length, 0) ); if (_demangle_buffer) { From d9ccae063e37c4cbe8837c3ce49d2e70246c14a7 Mon Sep 17 00:00:00 2001 From: Stephan Beyer Date: Tue, 25 Oct 2016 20:09:29 +0200 Subject: [PATCH 2/7] Make Printer::print methods available for streams --- backward.hpp | 140 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 95 insertions(+), 45 deletions(-) diff --git a/backward.hpp b/backward.hpp index c1e80eb..8cd6f4e 100644 --- a/backward.hpp +++ b/backward.hpp @@ -61,6 +61,7 @@ #include #include +#include #include #include #include @@ -1673,19 +1674,23 @@ namespace Color { class Colorize { public: - Colorize(std::FILE* os): - _os(os), _reset(false), _istty(false) {} + Colorize(std::ostream& os): + _os(os), _reset(false), _use_colors(false) {} - void init() { - _istty = isatty(fileno(_os)); + void activate() { + _use_colors = true; + } + + void activate_if_tty(std::FILE *desc) { + _use_colors = isatty(fileno(desc)); } void set_color(Color::type ccode) { - if (!_istty) return; + if (!_use_colors) return; // I assume that the terminal can handle basic colors. Seriously I // don't want to deal with all the termcap shit. - fprintf(_os, "\033[%im", static_cast(ccode)); + _os << "\033[" << static_cast(ccode) << "m"; _reset = (ccode != Color::reset); } @@ -1696,9 +1701,9 @@ class Colorize { } private: - std::FILE* _os; - bool _reset; - bool _istty; + std::ostream& _os; + bool _reset; + bool _use_colors; }; #else // ndef BACKWARD_SYSTEM_LINUX @@ -1714,8 +1719,9 @@ namespace Color { class Colorize { public: - Colorize(std::FILE*) {} - void init() {} + Colorize(std::ostream&) {} + void activate() {} + void activate_if_tty() {} void set_color(Color::type) {} }; @@ -1737,59 +1743,97 @@ class Printer { template FILE* print(ST& st, FILE* os = stderr) { + std::stringstream ss; + Colorize colorize(ss); + if (color) { + colorize.activate_if_tty(os); + } + print(st, ss, colorize); + fprintf(os, "%s", ss.str().c_str()); + return os; + } + + template + void print(ST& st, std::ostream& os) { Colorize colorize(os); if (color) { - colorize.init(); + colorize.activate(); } - print_header(os, st.thread_id()); - _resolver.load_stacktrace(st); - for (size_t trace_idx = st.size(); trace_idx > 0; --trace_idx) { - print_trace(os, _resolver.resolve(st[trace_idx-1]), colorize); + print(st, os, colorize); + } + + template + FILE* print(IT begin, IT end, FILE* os = stderr, size_t thread_id = 0) { + std::stringstream ss; + Colorize colorize(ss); + if (color) { + colorize.activate_if_tty(os); } + print(begin, end, ss, thread_id, colorize); + fprintf(os, "%s", ss.str().c_str()); return os; } template - FILE* print(IT begin, IT end, FILE* os = stderr, size_t thread_id = 0) { + void print(IT begin, IT end, std::ostream& os, size_t thread_id = 0) { Colorize colorize(os); if (color) { - colorize.init(); + colorize.activate(); } + print(begin, end, os, thread_id, colorize); + } + +private: + TraceResolver _resolver; + SnippetFactory _snippets; + + template + void print(ST& st, std::ostream& os, Colorize& colorize) { + print_header(os, st.thread_id()); + _resolver.load_stacktrace(st); + for (size_t trace_idx = st.size(); trace_idx > 0; --trace_idx) { + print_trace(os, _resolver.resolve(st[trace_idx-1]), colorize); + } + } + + template + void print(IT begin, IT end, std::ostream& os, size_t thread_id, Colorize& colorize) { print_header(os, thread_id); for (; begin != end; ++begin) { print_trace(os, *begin, colorize); } - return os; } -private: - TraceResolver _resolver; - SnippetFactory _snippets; - void print_header(FILE* os, unsigned thread_id) { - fprintf(os, "Stack trace (most recent call last)"); + void print_header(std::ostream& os, unsigned thread_id) { + os << "Stack trace (most recent call last)"; if (thread_id) { - fprintf(os, " in thread %u:\n", thread_id); - } else { - fprintf(os, ":\n"); + os << " in thread " << thread_id; } + os << ":\n"; } - void print_trace(FILE* os, const ResolvedTrace& trace, + void print_trace(std::ostream& os, const ResolvedTrace& trace, Colorize& colorize) { - fprintf(os, "#%-2u", trace.idx); + os << "#" + << std::left << std::setw(2) << trace.idx + << std::right; bool already_indented = true; if (!trace.source.filename.size() || object) { - fprintf(os, " Object \"%s\", at %p, in %s\n", - trace.object_filename.c_str(), trace.addr, - trace.object_function.c_str()); + os << " Object \"" + << trace.object_filename + << ", at " + << trace.addr + << ", in " + << trace.object_function + << "\n"; already_indented = false; } for (size_t inliner_idx = trace.inliners.size(); inliner_idx > 0; --inliner_idx) { if (!already_indented) { - fprintf(os, " "); + os << " "; } const ResolvedTrace::SourceLoc& inliner_loc = trace.inliners[inliner_idx-1]; @@ -1803,7 +1847,7 @@ class Printer { if (trace.source.filename.size()) { if (!already_indented) { - fprintf(os, " "); + os << " "; } print_source_loc(os, " ", trace.source, trace.addr); if (snippet) { @@ -1813,7 +1857,7 @@ class Printer { } } - void print_snippet(FILE* os, const char* indent, + void print_snippet(std::ostream& os, const char* indent, const ResolvedTrace::SourceLoc& source_loc, Colorize& colorize, Color::type color_code, int context_size) @@ -1828,29 +1872,35 @@ class Printer { it != lines.end(); ++it) { if (it-> first == source_loc.line) { colorize.set_color(color_code); - fprintf(os, "%s>", indent); + os << indent << ">"; } else { - fprintf(os, "%s ", indent); + os << indent << " "; } - fprintf(os, "%4u: %s\n", it->first, it->second.c_str()); + os << std::setw(4) << it->first + << ": " + << it->second + << "\n"; if (it-> first == source_loc.line) { colorize.set_color(Color::reset); } } } - void print_source_loc(FILE* os, const char* indent, + void print_source_loc(std::ostream& os, const char* indent, const ResolvedTrace::SourceLoc& source_loc, void* addr=0) { - fprintf(os, "%sSource \"%s\", line %i, in %s", - indent, source_loc.filename.c_str(), (int)source_loc.line, - source_loc.function.c_str()); + os << indent + << "Source \"" + << source_loc.filename + << "\", line " + << source_loc.line + << ", in " + << source_loc.function; if (address && addr != 0) { - fprintf(os, " [%p]\n", addr); - } else { - fprintf(os, "\n"); + os << " [" << addr << "]"; } + os << "\n"; } }; From 025539915eafcfb7bc9130849a87e560a0879728 Mon Sep 17 00:00:00 2001 From: Stephan Beyer Date: Tue, 25 Oct 2016 20:16:16 +0200 Subject: [PATCH 3/7] Let Colorizer reset on initialization --- backward.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/backward.hpp b/backward.hpp index 8cd6f4e..8ff6f5d 100644 --- a/backward.hpp +++ b/backward.hpp @@ -1679,10 +1679,14 @@ class Colorize { void activate() { _use_colors = true; + // in a colorful environment, reset at the beginning + set_color(Color::reset); } void activate_if_tty(std::FILE *desc) { - _use_colors = isatty(fileno(desc)); + if (isatty(fileno(desc))) { + activate(); + } } void set_color(Color::type ccode) { From 7182ac57849dd224807e5f5e407eed83f495f6a3 Mon Sep 17 00:00:00 2001 From: Stephan Beyer Date: Thu, 27 Oct 2016 17:32:43 +0200 Subject: [PATCH 4/7] Printer: Make context sizes configurable --- backward.hpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/backward.hpp b/backward.hpp index 8ff6f5d..fd70361 100644 --- a/backward.hpp +++ b/backward.hpp @@ -1737,12 +1737,16 @@ class Printer { bool color; bool address; bool object; + int inliner_context_size; + int trace_context_size; Printer(): snippet(true), color(true), address(false), - object(false) + object(false), + inliner_context_size(5), + trace_context_size(7) {} template @@ -1844,7 +1848,7 @@ class Printer { print_source_loc(os, " | ", inliner_loc); if (snippet) { print_snippet(os, " | ", inliner_loc, - colorize, Color::purple, 5); + colorize, Color::purple, inliner_context_size); } already_indented = false; } @@ -1856,7 +1860,7 @@ class Printer { print_source_loc(os, " ", trace.source, trace.addr); if (snippet) { print_snippet(os, " ", trace.source, - colorize, Color::yellow, 7); + colorize, Color::yellow, trace_context_size); } } } From 5eaddb6c70c10db6b4b585849f008437996559fe Mon Sep 17 00:00:00 2001 From: Stephan Beyer Date: Fri, 28 Oct 2016 18:51:00 +0200 Subject: [PATCH 5/7] Make StackTraceImpl*::skip_n_firsts() setter public When the stack trace is used directly (and not by a signal), one may want to hide some of the first stack items because they will always be the same calls. --- backward.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backward.hpp b/backward.hpp index fd70361..c819117 100644 --- a/backward.hpp +++ b/backward.hpp @@ -497,6 +497,7 @@ class StackTraceImpl { size_t load_here(size_t=0) { return 0; } size_t load_from(void*, size_t=0) { return 0; } unsigned thread_id() const { return 0; } + void skip_n_firsts(size_t) { } }; #ifdef BACKWARD_SYSTEM_LINUX @@ -509,6 +510,8 @@ class StackTraceLinuxImplBase { return _thread_id; } + void skip_n_firsts(size_t n) { _skip = n; } + protected: void load_thread_info() { _thread_id = syscall(SYS_gettid); @@ -519,7 +522,6 @@ class StackTraceLinuxImplBase { } } - void skip_n_firsts(size_t n) { _skip = n; } size_t skip_n_firsts() const { return _skip; } private: From c15787fcd7041443afcbe1fe64a2c0b36baa74aa Mon Sep 17 00:00:00 2001 From: Ivo Hedtke Date: Tue, 20 Dec 2016 23:12:32 +0100 Subject: [PATCH 6/7] Change typedef to using --- backward.hpp | 46 ++++++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/backward.hpp b/backward.hpp index c819117..258db24 100644 --- a/backward.hpp +++ b/backward.hpp @@ -226,7 +226,7 @@ extern "C" uintptr_t _Unwind_GetIPInfo(_Unwind_Context*, int*); namespace details { template struct hashtable { - typedef std::unordered_map type; + using type = std::unordered_map; }; using std::move; } // namespace details @@ -237,7 +237,7 @@ extern "C" uintptr_t _Unwind_GetIPInfo(_Unwind_Context*, int*); namespace details { template struct hashtable { - typedef std::map type; + using type = std::map; }; template const T& move(const T& v) { return v; } @@ -255,9 +255,9 @@ namespace system_tag { struct unknown_tag; #if defined(BACKWARD_SYSTEM_LINUX) - typedef linux_tag current_tag; + using current_tag = linux_tag; #elif defined(BACKWARD_SYSTEM_UNKNOWN) - typedef unknown_tag current_tag; + using current_tag = unknown_tag; #else # error "May I please get my system defines?" #endif @@ -271,11 +271,11 @@ namespace trace_resolver_tag { struct backtrace_symbol; # if BACKWARD_HAS_DW == 1 - typedef libdw current; + using current = libdw; # elif BACKWARD_HAS_BFD == 1 - typedef libbfd current; + using current = libbfd; # elif BACKWARD_HAS_BACKTRACE_SYMBOL == 1 - typedef backtrace_symbol current; + using current = backtrace_symbol; # else # error "You shall not pass, until you know what you want." # endif @@ -286,13 +286,13 @@ namespace trace_resolver_tag { namespace details { template - struct rm_ptr { typedef T type; }; + struct rm_ptr { using type = T; }; template - struct rm_ptr { typedef T type; }; + struct rm_ptr { using type = T; }; template - struct rm_ptr { typedef const T type; }; + struct rm_ptr { using type = const T; }; template struct deleter { @@ -375,8 +375,8 @@ class handle { T operator->() { return _val; } const T operator->() const { return _val; } - typedef typename rm_ptr::type& ref_t; - typedef const typename rm_ptr::type& const_ref_t; + using ref_t = typename rm_ptr::type&; + using const_ref_t = const typename rm_ptr::type&; ref_t operator*() { return *_val; } const_ref_t operator*() const { return *_val; } ref_t operator[](size_t idx) { return _val[idx]; } @@ -477,7 +477,7 @@ struct ResolvedTrace: public Trace { // An optionals list of "inliners". All the successive sources location // from where the source location of the trace (the attribute right above) // is inlined. It is especially useful when you compiled with optimization. - typedef std::vector source_locs_t; + using source_locs_t = std::vector; source_locs_t inliners; ResolvedTrace(): @@ -926,11 +926,11 @@ class TraceResolverLinuxImpl: private: bool _bfd_loaded; - typedef details::handle - > bfd_handle_t; + >; - typedef details::handle bfd_symtab_t; + using bfd_symtab_t = details::handle; struct bfd_fileobject { @@ -940,8 +940,7 @@ class TraceResolverLinuxImpl: bfd_symtab_t dynamic_symtab; }; - typedef details::hashtable::type - fobj_bfd_map_t; + using fobj_bfd_map_t = details::hashtable::type; fobj_bfd_map_t _fobj_bfd_map; bfd_fileobject& load_object_with_bfd(const std::string& filename_object) { @@ -1299,8 +1298,7 @@ class TraceResolverLinuxImpl: } private: - typedef details::handle > - dwfl_handle_t; + using dwfl_handle_t = details::handle>; details::handle > _dwfl_cb; dwfl_handle_t _dwfl_handle; @@ -1487,7 +1485,7 @@ class TraceResolver: class SourceFile { public: - typedef std::vector > lines_t; + using lines_t = std::vector>; SourceFile() {} SourceFile(const std::string& path): _file(new std::ifstream(path.c_str())) {} @@ -1603,7 +1601,7 @@ class SourceFile { class SnippetFactory { public: - typedef SourceFile::lines_t lines_t; + using lines_t = SourceFile::lines_t; lines_t get_snippet(const std::string& filename, unsigned line_start, unsigned context_size) { @@ -1648,7 +1646,7 @@ class SnippetFactory { private: - typedef details::hashtable::type src_files_t; + using src_files_t = details::hashtable::type; src_files_t _src_files; SourceFile& get_src_file(const std::string& filename) { @@ -1873,7 +1871,7 @@ class Printer { int context_size) { using namespace std; - typedef SnippetFactory::lines_t lines_t; + using lines_t = SnippetFactory::lines_t; lines_t lines = _snippets.get_snippet(source_loc.filename, source_loc.line, context_size); From eb3ee96abcb4605b5683793667f1a513e66a6187 Mon Sep 17 00:00:00 2001 From: Stephan Beyer Date: Fri, 24 Feb 2017 11:21:01 +0100 Subject: [PATCH 7/7] Remove useless comments after curly braces --- backward.hpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/backward.hpp b/backward.hpp index 258db24..9c2720b 100644 --- a/backward.hpp +++ b/backward.hpp @@ -229,8 +229,8 @@ extern "C" uintptr_t _Unwind_GetIPInfo(_Unwind_Context*, int*); using type = std::unordered_map; }; using std::move; - } // namespace details - } // namespace backward + } + } #else // NOT BACKWARD_ATLEAST_CXX11 # include namespace backward { @@ -243,8 +243,8 @@ extern "C" uintptr_t _Unwind_GetIPInfo(_Unwind_Context*, int*); const T& move(const T& v) { return v; } template T& move(T& v) { return v; } - } // namespace details - } // namespace backward + } + } #endif // BACKWARD_ATLEAST_CXX11 namespace backward { @@ -261,7 +261,7 @@ namespace system_tag { #else # error "May I please get my system defines?" #endif -} // namespace system_tag +} namespace trace_resolver_tag { @@ -280,7 +280,7 @@ namespace trace_resolver_tag { # error "You shall not pass, until you know what you want." # endif #endif // BACKWARD_SYSTEM_LINUX -} // namespace trace_resolver_tag +} namespace details { @@ -424,7 +424,7 @@ struct demangler_impl { struct demangler: public demangler_impl {}; -} // namespace details +} /*************** A TRACE ***************/ @@ -602,7 +602,7 @@ size_t unwind(F f, size_t depth) { return unwinder(f, depth); } -} // namespace details +} template <> @@ -1670,7 +1670,7 @@ namespace Color { purple = 35, reset = 39 }; -} // namespace Color +} class Colorize { public: @@ -1719,7 +1719,7 @@ namespace Color { purple = 0, reset = 0 }; -} // namespace Color +} class Colorize { public: @@ -2042,6 +2042,6 @@ class SignalHandling { #endif // BACKWARD_SYSTEM_UNKNOWN -} // namespace backward +} #endif /* H_GUARD */