diff --git a/boost/stacktrace/stacktrace.html b/boost/stacktrace/stacktrace.html index 735658a..7cac170 100644 --- a/boost/stacktrace/stacktrace.html +++ b/boost/stacktrace/stacktrace.html @@ -34,52 +34,60 @@ class stacktrace { public: // construct/copy/destruct - stacktrace() noexcept; - stacktrace(const stacktrace &) noexcept; - stacktrace & operator=(const stacktrace &) noexcept; - ~stacktrace(); + stacktrace() noexcept; + stacktrace(const stacktrace &) noexcept; + stacktrace & operator=(const stacktrace &) noexcept; + ~stacktrace(); - // public member functions - std::size_t size() const noexcept; - std::string operator[](std::size_t) const; + // public member functions + std::size_t size() const noexcept; + std::string operator[](std::size_t) const; + bool operator!() const noexcept; };
-

Description

+

Description

-

+

stacktrace public construct/copy/destruct

  1. -
    stacktrace() noexcept;
    Stores the current function call sequence inside the class.
  2. -
  3. stacktrace(const stacktrace & bt) noexcept;
  4. -
  5. stacktrace & operator=(const stacktrace & bt) noexcept;
  6. -
  7. ~stacktrace();
  8. +
    stacktrace() noexcept;
    Stores the current function call sequence inside the class.

    Complexity: O(N) where N is call seaquence length, O(1) for noop backend.

    + +
  9. +
    stacktrace(const stacktrace & bt) noexcept;
    +Complexity: O(1)
  10. +
  11. +
    stacktrace & operator=(const stacktrace & bt) noexcept;
    +Complexity: O(1)
  12. +
  13. +
    ~stacktrace();
    +Complexity: O(N) for libunwind, O(1) for other backends.
-

-stacktrace public member functions

+

+stacktrace public member functions

  1. -
    std::size_t size() const noexcept;
    +
    std::size_t size() const noexcept;

    -

    +Complexity: O(1)

    - +

    Returns:

    Number of function names stored inside the class.

    Number of function names stored inside the class.

  2. -
    std::string operator[](std::size_t frame) const;
    +
    std::string operator[](std::size_t frame) const;

    -

    +Complexity: Amortized O(1), O(1) for noop backend.

    @@ -99,11 +107,12 @@ - +

    Throws:

    std::bad_alloc if not enough memory. std::bad_alloc if not enough memory to construct resulting string.
  3. +
  4. bool operator!() const noexcept;
diff --git a/boost_stacktrace/getting_started.html b/boost_stacktrace/getting_started.html index 905d268..831500e 100644 --- a/boost_stacktrace/getting_started.html +++ b/boost_stacktrace/getting_started.html @@ -22,9 +22,266 @@
PrevUpHomeNext
-

+ +

+
+
Better + asserts
+
Handle + Terminates and Segmentation Faults
+
Exceptions + with Stacktrace
+
+
+ +

+ Pretty often assertions provide not enougth information to locate the problem. + For example you can see the following message on out-of-range access: +

+
../../../boost/array.hpp:123: T& boost::array<T, N>::operator[](boost::array<T, N>::size_type) [with T = int; long unsigned int N = 5ul]: Assertion '(i < N)&&("out of range")' failed.
+Aborted (core dumped)
+
+

+ That's not enought to locate the problem without debugger. There may be thousends + code lines in real world examples and hundrets places where that assertion + could happen. Let's try to improve the assertions, and make them more informative: +

+
// BOOST_ENABLE_ASSERT_DEBUG_HANDLER is defined for the whole project
+#include <stdexcept>    // std::logic_error
+#include <iostream>     // std::cerr
+#include <boost/stacktrace.hpp>
+
+namespace boost {
+    void assertion_failed_msg(char const* expr, char const* msg, char const* function, char const* file, long line) {
+        std::cerr << "Expression '" << expr << "' is false in function '" << function << "': " << (msg ? msg : "<...>") << ".\n"
+            << "Backtrace:\n" << boost::stacktrace::stacktrace() << '\n';
+        throw std::logic_error("assertion");
+    }
+
+    void assertion_failed(char const* expr, char const* function, char const* file, long line) {
+        ::boost::assertion_failed_msg(expr, 0 /*nullptr*/, function, file, line);
+    }
+} // namespace boost
+
+

+ We've defined the BOOST_ENABLE_ASSERT_DEBUG_HANDLER + macro for the whole project. Now all the BOOST_ASSERT + and BOOST_ASSERT_MSG will + call our functions assertion_failed + and assertion_failed_msg + in case of failure. In assertion_failed_msg + we output information that was provided by the assertion macro and boost::stacktrace::stacktrace: +

+
Expression 'i < N' is false in function 'T& boost::array<T, N>::operator[](boost::array<T, N>::size_type) [with T = int; long unsigned int N = 5ul]': out of range.
+Backtrace:
+ 0# boost::assertion_failed_msg(char const*, char const*, char const*, char const*, long)
+ 1# boost::array<int, 5ul>::operator[](unsigned long)
+ 2# oops(unsigned long)
+ 3# bar(int)
+ 4# foo(int)
+ 5# bar(int)
+ 6# foo(int)
+ 7# bar(int)
+ 8# foo(int)
+ 9# bar(int)
+10# foo(int)
+11# bar(int)
+12# foo(int)
+13# bar(int)
+14# foo(int)
+15# main
+16# __libc_start_main
+17# _start
+18# ??
+
+

+ Now we do know the steps that lead to the assertion and could find the error + without debugger. +

+
+
+ +

+ Segmentation Faults and std::terminate + calls sometimes happen in programs. Programmers usually wish to get as much + information as possible on such incidents, so having a stacktrace will significantly + improve debugging and fixing. +

+

+ To deal with Segmentation Faults and std::terminate + calls we would need to write handlers: +

+
#include <exception>    // std::set_terminate, std::abort
+#include <signal.h>     // ::signal
+#include <boost/stacktrace.hpp>
+#include <iostream>     // std::cerr
+
+void my_terminate_handler() {
+    std::cerr << "Terminate called:\n" << boost::stacktrace::stacktrace() << '\n';
+    std::abort();
+}
+
+void my_signal_handler(int signum) {
+    std::cerr << "Signal " << signum << ", backtrace:\n" << boost::stacktrace::stacktrace() << '\n';
+    std::abort();
+}
+
+

+ After that we can set them as a default handlers and get some more information + on incidents: +

+
std::set_terminate(&my_terminate_handler);
+::signal(SIGSEGV, &my_signal_handler);
+
+

+ Now we'll get the following output on std::terminate + call: +

+
Terminate called:
+ 0# my_terminate_handler()
+ 1# std::rethrow_exception(std::__exception_ptr::exception_ptr)
+ 2# std::terminate()
+ 3# bar(int)
+ 4# bar(int)
+ 5# foo(int)
+ 6# bar(int)
+ 7# foo(int)
+ 8# bar(int)
+ 9# foo(int)
+10# bar(int)
+11# foo(int)
+12# bar(int)
+13# foo(int)
+14# bar(int)
+15# foo(int)
+16# main
+17# __libc_start_main
+18# _start
+19# ??
+
+

+ And the following output on Segmentation Fault: +

+
Signal 11, backtrace:
+ 0# my_signal_handler(int)
+ 1# killpg
+ 2# ??
+ 3# bar(int)
+ 4# foo(int)
+ 5# bar(int)
+ 6# foo(int)
+ 7# bar(int)
+ 8# foo(int)
+ 9# bar(int)
+10# foo(int)
+11# bar(int)
+12# foo(int)
+13# bar(int)
+14# foo(int)
+15# main
+16# __libc_start_main
+17# _start
+18# ??
+
+

+ The output stacktrace may be corrupted by previous actions. But now at least + some basic information is available to work with. +

+
+
+ +

+ You can provide more information along with exception by embedding stacktraces + into the exception. For that we will need: +

+
  • + Basic class that holds the stacktrace: +
+
#include <boost/stacktrace.hpp>
+
+struct traced {
+    const boost::stacktrace::stacktrace trace;
+
+    virtual const char* what() const noexcept = 0;
+    virtual ~traced(){}
+};
+
+
  • + Helper class for appending class traced + to any exception: +
+
template <class Exception>
+struct with_trace : public Exception, public traced {
+    template <class... Args>
+    with_trace(Args&&... args)
+        : Exception(std::forward<Args>(args)...)
+    {}
+
+    const char* what() const noexcept {
+        return Exception::what();
+    }
+};
+
+
  • + Throw with_trace<Exception> + instead of just Exception: +
+
if (i >= 4)
+    throw with_trace<std::out_of_range>("'i' must be less than 4 in oops()");
+if (i == 0)
+    throw with_trace<std::logic_error>("'i' must not be zero in oops()");
+
+
  • + Catch exceptions by traced: +
+
try {
+    foo(5); // testing assert handler
+} catch (const traced& e) {
+    std::cerr << e.what() << '\n';
+    if (e.trace) {
+        std::cerr << "Backtrace:\n" << e.trace << '\n';
+    }
+} catch (const std::exception& e) {
+    std::cerr << e.what() << '\n';
+}
+
+

+ Code from above will output: +

+
'i' must be less than 4 in oops()
+Backtrace:
+ 0# with_trace<std::out_of_range>::with_trace<char const (&) [34]>(char const (&) [34])
+ 1# oops(unsigned long)
+ 2# bar(int)
+ 3# foo(int)
+ 4# bar(int)
+ 5# foo(int)
+ 6# bar(int)
+ 7# foo(int)
+ 8# bar(int)
+ 9# foo(int)
+10# bar(int)
+11# foo(int)
+12# bar(int)
+13# foo(int)
+14# main
+15# __libc_start_main
+16# _start
+17# ??
+
+
+
- +

Last revised: September 08, 2016 at 05:28:10 GMT

Last revised: September 14, 2016 at 20:36:20 GMT