mirror of
https://github.com/boostorg/stacktrace.git
synced 2026-01-21 05:22:12 +00:00
Code deduplicated and simplified, added empty() functions and some explicit bool operators, speed-up and improved the output of the ostream operators, improved tests coverage
This commit is contained in:
@@ -248,10 +248,10 @@ You can define the following macros to explicitly specify backend that you're wi
|
||||
|
||||
[table:configbackend Header only backend specifications
|
||||
[[Macro name] [Effect] [Platforms] [Uses debug information [footnote This will provide more readable backtraces if the binary is built with debug information.]] [Uses dynamic exports information [footnote This will provide readable function names in backtrace for functions that are exported by the binary.]] [Async signal safe[footnote Absolutely safe to construct instances of [classref boost::stacktrace::stacktrace] in async signal handlers using that backend.]]]
|
||||
[[*BOOST_STACKTRACE_USE_UNWIND*] [Use unwind tracing backend. This is the best known backend for POSIX systems that requires LSB Core Specification 4.1 from OS. Requires linking with libdl library.] [POSIX] [yes] [yes] [Constructors]]
|
||||
[[*BOOST_STACKTRACE_USE_UNWIND*] [Use unwind tracing backend. This is the best known backend for POSIX systems that requires LSB Core Specification 4.1 from OS. Requires linking with libdl library.] [POSIX] [yes] [yes] [yes]]
|
||||
[[*BOOST_STACKTRACE_USE_WINDBG*] [Use Windows specific tracing backend that uses DbgHelp. This is the best and only known backend for Windows platform that requires linking with DbgHelp library.] [Windows] [yes] [yes] [???]]
|
||||
[[*BOOST_STACKTRACE_USE_BACKTRACE*] [Use tracing backend that calls POSIX function `backtrace`. Requires linking with libdl library.] [POSIX] [no] [yes] [no]]
|
||||
[[*BOOST_STACKTRACE_USE_NOOP*] [Use noop tracing backend that does nothing. Use this backend if you wish to disable backtracing, `stacktrace::size()` with that backend always return 0. ] [POSIX and Windows] [no] [no] [all functions]]
|
||||
[[*BOOST_STACKTRACE_USE_NOOP*] [Use noop tracing backend that does nothing. Use this backend if you wish to disable backtracing, `stacktrace::size()` with that backend always return 0. ] [POSIX and Windows] [no] [no] [yes]]
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/core/noncopyable.hpp>
|
||||
#include <string>
|
||||
|
||||
// Link or header only
|
||||
@@ -39,7 +38,6 @@
|
||||
# define BOOST_STACKTRACE_USE_WINDBG
|
||||
# else
|
||||
# define BOOST_STACKTRACE_USE_UNWIND
|
||||
//# define BOOST_STACKTRACE_USE_BACKTRACE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@@ -61,25 +59,56 @@
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
struct backtrace_holder;
|
||||
|
||||
// Class that implements the actual backtracing
|
||||
class backend: boost::noncopyable {
|
||||
backtrace_holder* data_;
|
||||
class backend {
|
||||
std::size_t hash_code_;
|
||||
std::size_t frames_count_;
|
||||
void** data_;
|
||||
|
||||
void copy_frames_from(const backend& b) BOOST_NOEXCEPT {
|
||||
if (data_ == b.data_) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < frames_count_; ++i) {
|
||||
data_[i] = b.data_[i];
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
BOOST_STACKTRACE_FUNCTION backend(void* memory, std::size_t size, std::size_t& hash_code) BOOST_NOEXCEPT;
|
||||
BOOST_STACKTRACE_FUNCTION backend(void* memory, std::size_t size) BOOST_NOEXCEPT;
|
||||
BOOST_STACKTRACE_FUNCTION static std::string get_name(const void* addr);
|
||||
BOOST_STACKTRACE_FUNCTION const void* get_address(std::size_t frame_no) const BOOST_NOEXCEPT;
|
||||
const void* get_address(std::size_t frame_no) const BOOST_NOEXCEPT {
|
||||
return frame_no < frames_count_ ? data_[frame_no] : 0;
|
||||
}
|
||||
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);
|
||||
BOOST_STACKTRACE_FUNCTION bool operator< (const backend& rhs) const BOOST_NOEXCEPT;
|
||||
BOOST_STACKTRACE_FUNCTION bool operator==(const backend& rhs) const BOOST_NOEXCEPT;
|
||||
|
||||
BOOST_STACKTRACE_FUNCTION backend(const backend& b, void* memory) BOOST_NOEXCEPT;
|
||||
BOOST_STACKTRACE_FUNCTION backend& operator=(const backend& b) BOOST_NOEXCEPT;
|
||||
BOOST_STACKTRACE_FUNCTION ~backend() BOOST_NOEXCEPT;
|
||||
BOOST_STACKTRACE_FUNCTION std::size_t size() const BOOST_NOEXCEPT;
|
||||
backend(const backend& b, void* memory) BOOST_NOEXCEPT
|
||||
: hash_code_(b.hash_code_)
|
||||
, frames_count_(b.frames_count_)
|
||||
, data_(static_cast<void**>(memory))
|
||||
{
|
||||
copy_frames_from(b);
|
||||
}
|
||||
|
||||
backend& operator=(const backend& b) BOOST_NOEXCEPT {
|
||||
hash_code_ = b.hash_code_;
|
||||
frames_count_ = b.frames_count_;
|
||||
copy_frames_from(b);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::size_t size() const BOOST_NOEXCEPT {
|
||||
return frames_count_;
|
||||
}
|
||||
|
||||
std::size_t hash_code() const BOOST_NOEXCEPT {
|
||||
return hash_code_;
|
||||
}
|
||||
};
|
||||
|
||||
}}} // namespace boost::stacktrace::detail
|
||||
|
||||
@@ -12,35 +12,36 @@
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
backend::backend(const backend& b, void* memory) BOOST_NOEXCEPT
|
||||
: data_(static_cast<backtrace_holder*>(memory))
|
||||
{
|
||||
new(data_) backtrace_holder(
|
||||
*b.data_
|
||||
);
|
||||
}
|
||||
|
||||
backend& backend::operator=(const backend& b) BOOST_NOEXCEPT {
|
||||
if (data_ == b.data_) {
|
||||
return *this;
|
||||
bool backend::operator< (const backend& rhs) const BOOST_NOEXCEPT {
|
||||
if (frames_count_ != rhs.frames_count_) {
|
||||
return frames_count_ < rhs.frames_count_;
|
||||
} else if (hash_code_ != rhs.hash_code_) {
|
||||
return hash_code_ < rhs.hash_code_;
|
||||
} else if (data_ == rhs.data_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
data_->~backtrace_holder();
|
||||
new(data_) backtrace_holder(
|
||||
*b.data_
|
||||
return std::lexicographical_compare(
|
||||
data_, data_ + frames_count_,
|
||||
rhs.data_, rhs.data_ + rhs.frames_count_
|
||||
);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
backend::~backend() BOOST_NOEXCEPT {
|
||||
data_->~backtrace_holder();
|
||||
}
|
||||
bool backend::operator==(const backend& rhs) const BOOST_NOEXCEPT {
|
||||
if (hash_code_ != rhs.hash_code_ || frames_count_ != rhs.frames_count_) {
|
||||
return false;
|
||||
} else if (data_ == rhs.data_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::size_t backend::size() const BOOST_NOEXCEPT {
|
||||
return data_->frames_count;
|
||||
return std::equal(
|
||||
data_, data_ + frames_count_,
|
||||
rhs.data_
|
||||
);
|
||||
}
|
||||
|
||||
}}}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/stacktrace/detail/to_hex_array.hpp>
|
||||
#include <boost/lexical_cast/try_lexical_convert.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
#if defined(BOOST_STACKTRACE_USE_UNWIND)
|
||||
#include <unwind.h>
|
||||
@@ -32,24 +31,6 @@
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpedantic"
|
||||
|
||||
struct backtrace_holder {
|
||||
std::size_t frames_count;
|
||||
void* buffer[];
|
||||
|
||||
backtrace_holder() BOOST_NOEXCEPT {}
|
||||
|
||||
backtrace_holder(const backtrace_holder& d) BOOST_NOEXCEPT
|
||||
: frames_count(d.frames_count)
|
||||
{
|
||||
std::copy(d.buffer, d.buffer + frames_count, buffer);
|
||||
}
|
||||
};
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
class addr2line_pipe {
|
||||
FILE* p;
|
||||
pid_t pid;
|
||||
@@ -193,27 +174,25 @@ inline _Unwind_Reason_Code unwind_callback(struct _Unwind_Context* context, void
|
||||
|
||||
|
||||
|
||||
backend::backend(void* memory, std::size_t size, std::size_t& hash_code) BOOST_NOEXCEPT
|
||||
: data_(static_cast<backtrace_holder*>(memory))
|
||||
backend::backend(void* memory, std::size_t size) BOOST_NOEXCEPT
|
||||
: hash_code_(0)
|
||||
, frames_count_(0)
|
||||
, data_(static_cast<void**>(memory))
|
||||
{
|
||||
new (data_) backtrace_holder();
|
||||
data_->frames_count = 0;
|
||||
hash_code = 0;
|
||||
|
||||
#if defined(BOOST_STACKTRACE_USE_UNWIND)
|
||||
unwind_state state = { data_->buffer, data_->buffer + data_->frames_count };
|
||||
unwind_state state = { data_, data_ + frames_count_ };
|
||||
_Unwind_Backtrace(&unwind_callback, &state);
|
||||
data_->frames_count = state.current - data_->buffer;
|
||||
frames_count_ = state.current - data_;
|
||||
#elif defined(BOOST_STACKTRACE_USE_BACKTRACE)
|
||||
data_->frames_count = ::backtrace(data_->buffer, (size - sizeof(backtrace_holder)) / sizeof(void*));
|
||||
if (data_->buffer[data_->frames_count - 1] == 0) {
|
||||
-- data_->frames_count;
|
||||
frames_count_ = ::backtrace(data_, size / sizeof(void*));
|
||||
if (data_[frames_count_ - 1] == 0) {
|
||||
-- frames_count_;
|
||||
}
|
||||
#else
|
||||
# error No stacktrace backend defined. Define BOOST_STACKTRACE_USE_UNWIND or BOOST_STACKTRACE_USE_BACKTRACE
|
||||
#endif
|
||||
|
||||
hash_code = boost::hash_range(data_->buffer, data_->buffer + data_->frames_count);
|
||||
hash_code_ = boost::hash_range(data_, data_ + frames_count_);
|
||||
}
|
||||
|
||||
std::string backend::get_name(const void* addr) {
|
||||
@@ -228,16 +207,19 @@ std::string backend::get_name(const void* addr) {
|
||||
res = try_demangle(res.c_str());
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
if (res == "??") {
|
||||
res.clear();
|
||||
}
|
||||
|
||||
const void* backend::get_address(std::size_t frame) const BOOST_NOEXCEPT {
|
||||
return frame < data_->frames_count ? data_->buffer[frame] : 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string backend::get_source_file(const void* addr) {
|
||||
std::string res = addr2line("-e", addr);
|
||||
res = res.substr(0, res.find_last_of(':'));
|
||||
if (res == "??") {
|
||||
res.clear();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -257,32 +239,6 @@ std::size_t backend::get_source_line(const void* addr) {
|
||||
return line_num;
|
||||
}
|
||||
|
||||
bool backend::operator< (const backend& rhs) const BOOST_NOEXCEPT {
|
||||
if (data_->frames_count != rhs.data_->frames_count) {
|
||||
return data_->frames_count < rhs.data_->frames_count;
|
||||
} else if (this == &rhs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return std::lexicographical_compare(
|
||||
data_->buffer, data_->buffer + data_->frames_count,
|
||||
rhs.data_->buffer, rhs.data_->buffer + rhs.data_->frames_count
|
||||
);
|
||||
}
|
||||
|
||||
bool backend::operator==(const backend& rhs) const BOOST_NOEXCEPT {
|
||||
if (data_->frames_count != rhs.data_->frames_count) {
|
||||
return false;
|
||||
} else if (this == &rhs) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return std::equal(
|
||||
data_->buffer, data_->buffer + data_->frames_count,
|
||||
rhs.data_->buffer
|
||||
);
|
||||
}
|
||||
|
||||
}}} // namespace boost::stacktrace::detail
|
||||
|
||||
#include <boost/stacktrace/detail/backend_common.ipp>
|
||||
|
||||
@@ -15,20 +15,16 @@
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
|
||||
backend::backend(void* /*memory*/, std::size_t /*size*/, std::size_t& hash_code) BOOST_NOEXCEPT
|
||||
: data_(0)
|
||||
{
|
||||
hash_code = 0;
|
||||
}
|
||||
backend::backend(void* /*memory*/, std::size_t /*size*/) BOOST_NOEXCEPT
|
||||
: hash_code_(0)
|
||||
, frames_count_(0)
|
||||
, data_(0)
|
||||
{}
|
||||
|
||||
std::string backend::get_name(const void* /*addr*/) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
const void* backend::get_address(std::size_t /*frame*/) const BOOST_NOEXCEPT {
|
||||
return data_; // returns 0. Suppressing `private field 'data_' is not used` warning
|
||||
}
|
||||
|
||||
std::string backend::get_source_file(const void* /*addr*/) {
|
||||
return std::string();
|
||||
}
|
||||
@@ -45,20 +41,6 @@ bool backend::operator==(const backend& /*rhs*/) const BOOST_NOEXCEPT {
|
||||
return true;
|
||||
}
|
||||
|
||||
backend::backend(const backend& /*b*/, void* /*memory*/) BOOST_NOEXCEPT
|
||||
: data_(0)
|
||||
{}
|
||||
|
||||
backend& backend::operator=(const backend& /*b*/) BOOST_NOEXCEPT {
|
||||
return *this;
|
||||
}
|
||||
|
||||
backend::~backend() BOOST_NOEXCEPT {}
|
||||
|
||||
std::size_t backend::size() const BOOST_NOEXCEPT {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}}} // namespace boost::stacktrace::detail
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_BACKEND_LIBUNWIND_HPP
|
||||
|
||||
@@ -13,8 +13,7 @@
|
||||
#endif
|
||||
|
||||
#include <boost/core/noncopyable.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <algorithm>
|
||||
#include <boost/functional/hash.hpp>
|
||||
|
||||
#include <windows.h>
|
||||
#include "Dbgeng.h"
|
||||
@@ -95,36 +94,22 @@ inline bool try_init_com(com_holder<IDebugSymbols>& idebug_) BOOST_NOEXCEPT {
|
||||
}
|
||||
|
||||
|
||||
struct backtrace_holder {
|
||||
std::size_t frames_count;
|
||||
void* buffer[];
|
||||
|
||||
backtrace_holder() BOOST_NOEXCEPT {}
|
||||
|
||||
backtrace_holder(const backtrace_holder& d) BOOST_NOEXCEPT
|
||||
: frames_count(d.frames_count)
|
||||
{
|
||||
std::copy(d.buffer, d.buffer + frames_count, buffer);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
backend::backend(void* memory, std::size_t size, std::size_t& hash_code) BOOST_NOEXCEPT
|
||||
: data_(static_cast<backtrace_holder*>(memory))
|
||||
backend::backend(void* memory, std::size_t size) BOOST_NOEXCEPT
|
||||
: hash_code_(0)
|
||||
, frames_count_(0)
|
||||
, data_(static_cast<void**>(memory))
|
||||
{
|
||||
new (data_) backtrace_holder();
|
||||
data_->frames_count = 0;
|
||||
hash_code = 0;
|
||||
boost::detail::winapi::ULONG_ hc = 0;
|
||||
data_->frames_count = CaptureStackBackTrace(
|
||||
frames_count_ = CaptureStackBackTrace(
|
||||
0,
|
||||
static_cast<boost::detail::winapi::ULONG_>((size - sizeof(backtrace_holder)) / sizeof(void*)),
|
||||
data_->buffer,
|
||||
static_cast<boost::detail::winapi::ULONG_>(size / sizeof(void*)),
|
||||
data_,
|
||||
&hc
|
||||
);
|
||||
|
||||
boost::hash_combine(hash_code, hc);
|
||||
boost::hash_combine(hash_code_, hc);
|
||||
}
|
||||
|
||||
std::string backend::get_name(const void* addr) {
|
||||
@@ -166,10 +151,6 @@ std::string backend::get_name(const void* addr) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const void* backend::get_address(std::size_t frame) const BOOST_NOEXCEPT {
|
||||
return frame < data_->frames_count ? data_->buffer[frame] : 0;
|
||||
}
|
||||
|
||||
std::string backend::get_source_file(const void* addr) {
|
||||
std::string result;
|
||||
com_holder<IDebugSymbols> idebug_;
|
||||
@@ -232,31 +213,6 @@ std::size_t backend::get_source_line(const void* addr) {
|
||||
return (is_ok ? line_num : 0);
|
||||
}
|
||||
|
||||
bool backend::operator< (const backend& rhs) const BOOST_NOEXCEPT {
|
||||
if (data_->frames_count != rhs.data_->frames_count) {
|
||||
return data_->frames_count < rhs.data_->frames_count;
|
||||
} else if (this == &rhs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return std::lexicographical_compare(
|
||||
data_->buffer, data_->buffer + data_->frames_count,
|
||||
rhs.data_->buffer, rhs.data_->buffer + rhs.data_->frames_count
|
||||
);
|
||||
}
|
||||
|
||||
bool backend::operator==(const backend& rhs) const BOOST_NOEXCEPT {
|
||||
if (data_->frames_count != rhs.data_->frames_count) {
|
||||
return false;
|
||||
} else if (this == &rhs) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return std::equal(
|
||||
data_->buffer, data_->buffer + data_->frames_count,
|
||||
rhs.data_->buffer
|
||||
);
|
||||
}
|
||||
|
||||
}}} // namespace boost::stacktrace::detail
|
||||
|
||||
|
||||
@@ -15,25 +15,31 @@
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
#include <boost/core/explicit_operator_bool.hpp>
|
||||
#include <boost/stacktrace/detail/backend.hpp>
|
||||
|
||||
namespace boost { namespace stacktrace {
|
||||
|
||||
// Forward declarations
|
||||
class const_iterator;
|
||||
|
||||
/// Non-owning class that references the frame information stored inside the boost::stacktrace::stacktrace class.
|
||||
class frame {
|
||||
/// @cond
|
||||
const void* addr_;
|
||||
|
||||
frame(); // = delete
|
||||
/// @endcond
|
||||
|
||||
public:
|
||||
#ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
|
||||
frame() = delete;
|
||||
/// @brief Constructs frame that references NULL address.
|
||||
/// Calls to source_file() and source_line() wil lreturn empty string.
|
||||
/// Calls to source_line() will return 0.
|
||||
///
|
||||
/// @b Complexity: O(1).
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
/// @throws Nothing.
|
||||
frame() BOOST_NOEXCEPT
|
||||
: addr_(0)
|
||||
{}
|
||||
|
||||
#ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
|
||||
/// @brief Copy constructs frame.
|
||||
///
|
||||
/// @b Complexity: O(1).
|
||||
@@ -93,6 +99,26 @@ public:
|
||||
std::size_t source_line() const {
|
||||
return boost::stacktrace::detail::backend::get_source_line(address());
|
||||
}
|
||||
|
||||
/// @brief Checks that frame is not references NULL address.
|
||||
/// @returns `true` if `this->address() != 0`
|
||||
///
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
|
||||
|
||||
/// @brief Checks that frame references NULL address.
|
||||
/// @returns `true` if `this->address() == 0`
|
||||
///
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
bool empty() const BOOST_NOEXCEPT { return !address(); }
|
||||
|
||||
/// @cond
|
||||
bool operator!() const BOOST_NOEXCEPT { return !address(); }
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
/// Comparison operators that provide platform dependant ordering and have O(1) complexity; are Async-Handler-Safe.
|
||||
@@ -111,10 +137,16 @@ inline std::size_t hash_value(const frame& f) BOOST_NOEXCEPT {
|
||||
/// Outputs stacktrace::frame in a human readable format to output stream; unsafe to use in async handlers.
|
||||
template <class CharT, class TraitsT>
|
||||
std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT>& os, const frame& f) {
|
||||
os << f.name();
|
||||
std::string name = f.name();
|
||||
if (!name.empty()) {
|
||||
os << name;
|
||||
} else {
|
||||
os << f.address();
|
||||
}
|
||||
|
||||
if (f.source_line()) {
|
||||
return os << '\t' << f.source_file() << ':' << f.source_line();
|
||||
const std::size_t source_line = f.source_line();
|
||||
if (source_line) {
|
||||
os << " at " << f.source_file() << ':' << source_line;
|
||||
}
|
||||
|
||||
return os;
|
||||
|
||||
@@ -29,7 +29,6 @@ class stacktrace {
|
||||
/// @cond
|
||||
BOOST_STATIC_CONSTEXPR std::size_t max_implementation_size = sizeof(void*) * 110u;
|
||||
boost::aligned_storage<max_implementation_size>::type impl_;
|
||||
std::size_t hash_code_;
|
||||
boost::stacktrace::detail::backend back_;
|
||||
/// @endcond
|
||||
|
||||
@@ -48,8 +47,7 @@ public:
|
||||
/// @b Async-Handler-Safety: Depends on backend, see "Build, Macros and Backends" section.
|
||||
BOOST_FORCEINLINE stacktrace() BOOST_NOEXCEPT
|
||||
: impl_()
|
||||
, hash_code_()
|
||||
, back_(&impl_, sizeof(impl_), hash_code_)
|
||||
, back_(&impl_, sizeof(impl_))
|
||||
{}
|
||||
|
||||
/// @b Complexity: O(st.size())
|
||||
@@ -57,7 +55,6 @@ public:
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
stacktrace(const stacktrace& st) BOOST_NOEXCEPT
|
||||
: impl_()
|
||||
, hash_code_(st.hash_code_)
|
||||
, back_(st.back_, &impl_)
|
||||
{}
|
||||
|
||||
@@ -65,8 +62,7 @@ public:
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
stacktrace& operator=(const stacktrace& st) BOOST_NOEXCEPT {
|
||||
hash_code_ = st.hash_code_;
|
||||
back_ = back_;
|
||||
back_ = st.back_;
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -141,13 +137,22 @@ public:
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
|
||||
|
||||
|
||||
/// @brief Allows to check that stack trace failed.
|
||||
/// @returns `true` if `this->size() == 0`
|
||||
///
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
bool empty() const BOOST_NOEXCEPT { return !size(); }
|
||||
|
||||
/// @brief Compares stacktraces for less, order is platform dependant.
|
||||
///
|
||||
/// @b Complexity: Amortized O(1); worst case O(size())
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
bool operator< (const stacktrace& rhs) const BOOST_NOEXCEPT {
|
||||
return hash_code_ < rhs.hash_code_ || (hash_code_ == rhs.hash_code_ && back_ < rhs.back_);
|
||||
return back_ < rhs.back_;
|
||||
}
|
||||
|
||||
/// @brief Compares stacktraces for equality.
|
||||
@@ -156,7 +161,7 @@ public:
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
bool operator==(const stacktrace& rhs) const BOOST_NOEXCEPT {
|
||||
return hash_code_ == rhs.hash_code_ && back_ == rhs.back_;
|
||||
return back_ == rhs.back_;
|
||||
}
|
||||
|
||||
/// @brief Returns hashed code of the stacktrace.
|
||||
@@ -164,7 +169,7 @@ public:
|
||||
/// @b Complexity: O(1)
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe.
|
||||
std::size_t hash_code() const BOOST_NOEXCEPT { return hash_code_; }
|
||||
std::size_t hash_code() const BOOST_NOEXCEPT { return back_.hash_code(); }
|
||||
|
||||
/// @cond
|
||||
bool operator!() const BOOST_NOEXCEPT { return !size(); }
|
||||
|
||||
@@ -182,17 +182,25 @@ void test_frame() {
|
||||
BOOST_TEST(st[i] >= st[i]);
|
||||
|
||||
frame fv = nst[2];
|
||||
BOOST_TEST(fv);
|
||||
if (i >= 2 && i < min_size - 3) { // Begin and end of the trace may match, skipping them
|
||||
BOOST_TEST(st[i].name() != fv.name());
|
||||
BOOST_TEST(st[i] != fv);
|
||||
BOOST_TEST(st[i] < fv || st[i] > fv);
|
||||
BOOST_TEST(hash_value(st[i]) != hash_value(fv));
|
||||
BOOST_TEST(st[i].source_line() == 0 || st[i].source_file() != fv.source_file());
|
||||
BOOST_TEST(st[i]);
|
||||
}
|
||||
|
||||
fv = st[i];
|
||||
BOOST_TEST(hash_value(st[i]) == hash_value(fv));
|
||||
}
|
||||
|
||||
boost::stacktrace::frame empty_frame;
|
||||
BOOST_TEST(!empty_frame);
|
||||
BOOST_TEST(empty_frame.source_file() == "");
|
||||
BOOST_TEST(empty_frame.name() == "");
|
||||
BOOST_TEST(empty_frame.source_line() == 0);
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
@@ -21,12 +21,20 @@ void test_deeply_nested_namespaces() {
|
||||
void test_nested() {
|
||||
std::pair<stacktrace, stacktrace> res = foo2(15);
|
||||
|
||||
BOOST_TEST(!res.first);
|
||||
BOOST_TEST(res.first.size() == 0);
|
||||
BOOST_TEST(res.first.begin()->name() == "");
|
||||
BOOST_TEST(res.first.begin()->source_file() == "");
|
||||
BOOST_TEST(res.first.begin()->source_line() == 0);
|
||||
BOOST_TEST(!res.second);
|
||||
BOOST_TEST(res.second.size() == 0);
|
||||
BOOST_TEST(res.second.begin()->name() == "");
|
||||
BOOST_TEST(res.second.begin()->source_file() == "");
|
||||
BOOST_TEST(res.second.begin()->source_line() == 0);
|
||||
|
||||
BOOST_TEST(res.second[0].name() == "");
|
||||
BOOST_TEST(res.second[0].source_file() == "");
|
||||
BOOST_TEST(res.second[0].source_line() == 0);
|
||||
BOOST_TEST(res.second[0].address() == 0);
|
||||
|
||||
BOOST_TEST(res.second <= res.first);
|
||||
@@ -36,10 +44,18 @@ void test_nested() {
|
||||
BOOST_TEST(!(res.second > res.first));
|
||||
}
|
||||
|
||||
void test_empty_frame() {
|
||||
boost::stacktrace::frame empty_frame;
|
||||
BOOST_TEST(!empty_frame);
|
||||
BOOST_TEST(empty_frame.source_file() == "");
|
||||
BOOST_TEST(empty_frame.name() == "");
|
||||
BOOST_TEST(empty_frame.source_line() == 0);
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_deeply_nested_namespaces();
|
||||
test_nested();
|
||||
test_empty_frame();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user