diff --git a/include/boost/stacktrace/detail/backend.hpp b/include/boost/stacktrace/detail/backend.hpp index 1f376b1..ab57d1b 100644 --- a/include/boost/stacktrace/detail/backend.hpp +++ b/include/boost/stacktrace/detail/backend.hpp @@ -63,7 +63,7 @@ namespace boost { namespace stacktrace { namespace detail { // Class that implements the actual backtracing class backend { public: - BOOST_STACKTRACE_FUNCTION static std::size_t collect(void** memory, std::size_t size) BOOST_NOEXCEPT; + BOOST_NOINLINE BOOST_STACKTRACE_FUNCTION static std::size_t collect(void** memory, std::size_t size) BOOST_NOEXCEPT; BOOST_STACKTRACE_FUNCTION static std::string get_name(const void* addr); BOOST_STACKTRACE_FUNCTION static std::string get_source_file(const void* addr); BOOST_STACKTRACE_FUNCTION static std::size_t get_source_line(const void* addr); diff --git a/include/boost/stacktrace/stacktrace.hpp b/include/boost/stacktrace/stacktrace.hpp index 3f1c2a0..23d70ff 100644 --- a/include/boost/stacktrace/stacktrace.hpp +++ b/include/boost/stacktrace/stacktrace.hpp @@ -36,7 +36,7 @@ class basic_stacktrace { boost::container::vector impl_; /// @cond - static const std::size_t frames_to_skip = 0; + static const std::size_t frames_to_skip = 2; void fill(void** begin, std::size_t size) { if (size < frames_to_skip) { @@ -50,14 +50,43 @@ class basic_stacktrace { ); } } + /// @endcond - BOOST_NOINLINE void init(std::size_t max_depth) BOOST_NOEXCEPT { +public: + typedef typename boost::container::vector::value_type value_type; + typedef typename boost::container::vector::allocator_type allocator_type; + typedef typename boost::container::vector::const_pointer pointer; + typedef typename boost::container::vector::const_pointer const_pointer; + typedef typename boost::container::vector::const_reference reference; + typedef typename boost::container::vector::const_reference const_reference; + typedef typename boost::container::vector::size_type size_type; + typedef typename boost::container::vector::difference_type difference_type; + typedef typename boost::container::vector::const_iterator iterator; + typedef typename boost::container::vector::const_iterator const_iterator; + typedef typename boost::container::vector::const_reverse_iterator reverse_iterator; + typedef typename boost::container::vector::const_reverse_iterator const_reverse_iterator; + + /// @brief Stores the current function call sequence inside the class. + /// + /// @b Complexity: O(N) where N is call sequence length, O(1) for noop backend. + /// + /// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe. + /// + /// @param max_depth max stack depth + /// + /// @throws Nothing. Note that default construction of allocator may throw, hovewer it is + /// performed outside the constructor and exception in `allocator_type()` would not result in calling `std::terminate`. + BOOST_NOINLINE explicit basic_stacktrace(std::size_t max_depth = static_cast(-1), const allocator_type& a = allocator_type()) BOOST_NOEXCEPT + : impl_(a) + { const size_t buffer_size = 128; if (!max_depth) { return; } - max_depth += frames_to_skip; + if (static_cast(-1) - frames_to_skip >= max_depth) { + max_depth += frames_to_skip; + } try { { // Fast path without additional allocations @@ -83,47 +112,10 @@ class basic_stacktrace { buf.resize(buf.size() * 2); } while (1); - - } catch (...) { // ignore exception } } - /// @endcond - -public: - typedef typename boost::container::vector::value_type value_type; - typedef typename boost::container::vector::allocator_type allocator_type; - typedef typename boost::container::vector::const_pointer pointer; - typedef typename boost::container::vector::const_pointer const_pointer; - typedef typename boost::container::vector::const_reference reference; - typedef typename boost::container::vector::const_reference const_reference; - typedef typename boost::container::vector::size_type size_type; - typedef typename boost::container::vector::difference_type difference_type; - typedef typename boost::container::vector::const_iterator iterator; - typedef typename boost::container::vector::const_iterator const_iterator; - typedef typename boost::container::vector::const_reverse_iterator reverse_iterator; - typedef typename boost::container::vector::const_reverse_iterator const_reverse_iterator; - - /// @brief Stores the current function call sequence inside the class. - /// - /// @b Complexity: O(N) where N is call sequence length, O(1) for noop backend. - /// - /// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe. - /// - /// @throws Nothing. Note that default construction of allocator may throw, hovewer it is - /// performed outside the constructor and exception in `allocator_type()` would not result in calling `std::terminate`. - BOOST_FORCEINLINE explicit basic_stacktrace(const allocator_type& a = allocator_type()) BOOST_NOEXCEPT - : impl_(a) - { - init(static_cast(-1)); - } - - BOOST_FORCEINLINE explicit basic_stacktrace(std::size_t max_depth, const allocator_type& a = allocator_type()) BOOST_NOEXCEPT - : impl_(a) - { - init(max_depth); - } #ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED /// @b Complexity: O(st.size()) @@ -136,22 +128,26 @@ public: /// @b Async-Handler-Safety: Safe if Allocator construction and copying are async signal safe. basic_stacktrace(basic_stacktrace&& st) = default; + /// @b Complexity: O(1) + /// + /// @b Async-Handler-Safety: Safe if Allocator::deallocate is async signal safe. + ~basic_stacktrace() BOOST_NOEXCEPT = default; +#endif + /// @b Complexity: O(st.size()) /// /// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe. - basic_stacktrace& operator=(const basic_stacktrace& st) = default; + basic_stacktrace& operator=(const basic_stacktrace& st) { + impl_ = st.impl_; + return *this; + } +/* TODO: /// @b Complexity: O(st.size()) /// /// @b Async-Handler-Safety: Safe if Allocator construction and copying are async signal safe. basic_stacktrace& operator=(basic_stacktrace&& st) = default; - - /// @b Complexity: O(1) - /// - /// @b Async-Handler-Safety: Safe if Allocator::deallocate are async signal safe.. - ~basic_stacktrace() BOOST_NOEXCEPT = default; -#endif - +*/ /// @returns Number of function names stored inside the class. /// /// @b Complexity: O(1) diff --git a/test/test.cpp b/test/test.cpp index 5416683..a34106c 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -36,10 +36,8 @@ void test_deeply_nested_namespaces() { std::cout << ss.str() << '\n'; BOOST_TEST(ss.str().find("main") != std::string::npos); -#if defined(BOOST_STACKTRACE_DYN_LINK) - BOOST_TEST(ss.str().find("get_backtrace_from_nested_namespaces") != std::string::npos - || ss.str().find("return_from_nested_namespaces") != std::string::npos); -#endif + BOOST_TEST(ss.str().find("get_backtrace_from_nested_namespaces") != std::string::npos); + BOOST_TEST(ss.str().find("return_from_nested_namespaces") != std::string::npos); stacktrace ns1 = return_from_nested_namespaces(); BOOST_TEST(ns1 != return_from_nested_namespaces()); // Different addresses in test_deeply_nested_namespaces() function @@ -193,9 +191,9 @@ void test_frame() { BOOST_TEST(st[i] <= st[i]); BOOST_TEST(st[i] >= st[i]); - frame fv = nst[2]; + frame fv = nst[0]; BOOST_TEST(fv); - if (i >= 2 && i < min_size - 3) { // Begin and end of the trace may match, skipping them + if (i < min_size - 3) { // End of the trace may match, skipping BOOST_TEST(st[i] != fv); BOOST_TEST(st[i].name() != fv.name()); BOOST_TEST(st[i] != fv); @@ -215,7 +213,7 @@ void test_frame() { BOOST_TEST(empty_frame.name() == ""); BOOST_TEST(empty_frame.source_line() == 0); } -/* + void test_empty_basic_stacktrace() { typedef boost::stacktrace::stacktrace st_t; st_t st(0); @@ -233,11 +231,11 @@ void test_empty_basic_stacktrace() { BOOST_TEST(st.crbegin() == st.crend()); BOOST_TEST(st.rbegin() == st.crend()); - BOOST_TEST(hash_value(st) == hash_value(st_t())); - BOOST_TEST(st == st_t()); - BOOST_TEST(!(st < st_t())); - BOOST_TEST(!(st > st_t())); -}*/ + BOOST_TEST(hash_value(st) == hash_value(st_t(0))); + BOOST_TEST(st == st_t(0)); + BOOST_TEST(!(st < st_t(0))); + BOOST_TEST(!(st > st_t(0))); +} int main() { test_deeply_nested_namespaces(); @@ -245,7 +243,7 @@ int main() { test_comparisons(); test_iterators(); test_frame(); - //test_empty_basic_stacktrace(); + test_empty_basic_stacktrace(); BOOST_TEST(&bar1 != &bar2); boost::stacktrace::stacktrace b1 = bar1();