mirror of
https://github.com/boostorg/stacktrace.git
synced 2026-01-27 07:22:09 +00:00
Fixed libunwind exception safety in assignments and construction, changed tests to use boost's lightweight test infrastructure, code cleanup, include guards added
This commit is contained in:
@@ -38,7 +38,6 @@ lib boost_stacktrace_libunwind
|
||||
../src/libunwind.cpp
|
||||
: # requirements
|
||||
<warnings>all
|
||||
<define>BOOST_STACKTRACE_USE_LIBUNWIND=1
|
||||
<library>unwind
|
||||
[ check-target-builds ../build//libunwind : : <build>no ]
|
||||
: # default build
|
||||
@@ -53,7 +52,6 @@ lib boost_stacktrace_backtrace
|
||||
../src/backtrace.cpp
|
||||
: # requirements
|
||||
<warnings>all
|
||||
<define>BOOST_STACKTRACE_USE_BACKTRACE=1
|
||||
<library>dl
|
||||
[ check-target-builds ../build//backtrace : : <build>no ]
|
||||
: # default build
|
||||
@@ -69,7 +67,6 @@ lib boost_stacktrace_windbg
|
||||
: # requirements
|
||||
<warnings>all
|
||||
<library>Dbghelp
|
||||
<define>BOOST_STACKTRACE_USE_WINDBG=1
|
||||
[ check-target-builds ../build//WinDbg : : <build>no ]
|
||||
: # default build
|
||||
: # usage-requirements
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_STACKTRACE_HPP
|
||||
#define BOOST_STACKTRACE_STACKTRACE_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
@@ -27,22 +29,34 @@ namespace boost { namespace stacktrace {
|
||||
class stacktrace {
|
||||
BOOST_STATIC_CONSTEXPR std::size_t max_implementation_size = sizeof(void*) * 110u;
|
||||
boost::aligned_storage<max_implementation_size>::type impl_;
|
||||
|
||||
public:
|
||||
/// Stores the current function call sequence inside the class
|
||||
/// @brief Stores the current function call sequence inside the class.
|
||||
///
|
||||
/// @b Complexity: O(N) where N is call seaquence length
|
||||
BOOST_STACKTRACE_FUNCTION stacktrace() BOOST_NOEXCEPT;
|
||||
|
||||
/// @b Complexity: O(1)
|
||||
BOOST_STACKTRACE_FUNCTION stacktrace(const stacktrace& bt) BOOST_NOEXCEPT;
|
||||
|
||||
/// @b Complexity: O(1)
|
||||
BOOST_STACKTRACE_FUNCTION stacktrace& operator=(const stacktrace& bt) BOOST_NOEXCEPT;
|
||||
|
||||
/// @b Complexity: O(N) for libunwind, O(1) for other backends.
|
||||
BOOST_STACKTRACE_FUNCTION ~stacktrace() BOOST_NOEXCEPT;
|
||||
|
||||
/// @returns Number of function names stored inside the class.
|
||||
///
|
||||
/// @b Complexity: O(1)
|
||||
BOOST_STACKTRACE_FUNCTION std::size_t size() const BOOST_NOEXCEPT;
|
||||
|
||||
/// @param frame Zero based index of function to return. 0
|
||||
/// is the function index where stacktrace was constructed and
|
||||
/// index close to this->size() contains function `main()`.
|
||||
/// @returns Function name in a human readable form.
|
||||
/// @throws std::bad_alloc if not enough memory.
|
||||
/// @throws std::bad_alloc if not enough memory to construct resulting string.
|
||||
///
|
||||
/// @b Complexity: Amortized O(1)
|
||||
BOOST_STACKTRACE_FUNCTION std::string operator[](std::size_t frame) const;
|
||||
};
|
||||
|
||||
@@ -78,3 +92,5 @@ std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT
|
||||
# include <boost/stacktrace/detail/stacktrace.ipp>
|
||||
#endif
|
||||
/// @endcond
|
||||
|
||||
#endif // BOOST_STACKTRACE_STACKTRACE_HPP
|
||||
|
||||
@@ -4,15 +4,18 @@
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_STACKTRACE_IPP
|
||||
#define BOOST_STACKTRACE_DETAIL_STACKTRACE_IPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/predef/os/windows.h>
|
||||
|
||||
#if BOOST_OS_WINDOWS
|
||||
#if defined(BOOST_WINDOWS) || defined(BOOST_STACKTRACE_USE_WINDBG)
|
||||
# include <boost/stacktrace/detail/stacktrace_windows.hpp>
|
||||
#elif defined(BOOST_STACKTRACE_USE_LIBUNWIND)
|
||||
# include <boost/stacktrace/detail/stacktrace_libunwind.hpp>
|
||||
@@ -30,15 +33,17 @@
|
||||
|
||||
namespace boost { namespace stacktrace {
|
||||
|
||||
template <class T>
|
||||
inline boost::stacktrace::detail::backtrace_holder& to_bt(T& data) BOOST_NOEXCEPT {
|
||||
return *reinterpret_cast<boost::stacktrace::detail::backtrace_holder*>(&data);
|
||||
}
|
||||
namespace detail {
|
||||
template <class T>
|
||||
inline boost::stacktrace::detail::backtrace_holder& to_bt(T& data) BOOST_NOEXCEPT {
|
||||
return *reinterpret_cast<boost::stacktrace::detail::backtrace_holder*>(&data);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline const boost::stacktrace::detail::backtrace_holder& to_bt(const T& data) BOOST_NOEXCEPT {
|
||||
return *reinterpret_cast<const boost::stacktrace::detail::backtrace_holder*>(&data);
|
||||
}
|
||||
template <class T>
|
||||
inline const boost::stacktrace::detail::backtrace_holder& to_bt(const T& data) BOOST_NOEXCEPT {
|
||||
return *reinterpret_cast<const boost::stacktrace::detail::backtrace_holder*>(&data);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
|
||||
stacktrace::stacktrace() BOOST_NOEXCEPT {
|
||||
@@ -46,26 +51,30 @@ stacktrace::stacktrace() BOOST_NOEXCEPT {
|
||||
}
|
||||
|
||||
stacktrace::stacktrace(const stacktrace& bt) BOOST_NOEXCEPT {
|
||||
new (&impl_) boost::stacktrace::detail::backtrace_holder(to_bt(bt.impl_));
|
||||
new (&impl_) boost::stacktrace::detail::backtrace_holder(
|
||||
boost::stacktrace::detail::to_bt(bt.impl_)
|
||||
);
|
||||
}
|
||||
|
||||
stacktrace& stacktrace::operator=(const stacktrace& bt) BOOST_NOEXCEPT {
|
||||
to_bt(impl_) = to_bt(bt.impl_);
|
||||
boost::stacktrace::detail::to_bt(impl_) = boost::stacktrace::detail::to_bt(bt.impl_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
stacktrace::~stacktrace() BOOST_NOEXCEPT {
|
||||
BOOST_STATIC_ASSERT_MSG(sizeof(impl_) >= sizeof(boost::stacktrace::detail::backtrace_holder), "Too small storage for holding backtrace");
|
||||
to_bt(impl_).~backtrace_holder();
|
||||
boost::stacktrace::detail::to_bt(impl_).~backtrace_holder();
|
||||
}
|
||||
|
||||
std::size_t stacktrace::size() const BOOST_NOEXCEPT {
|
||||
return to_bt(impl_).size();
|
||||
return boost::stacktrace::detail::to_bt(impl_).size();
|
||||
}
|
||||
|
||||
std::string stacktrace::operator[](std::size_t frame) const BOOST_NOEXCEPT {
|
||||
return to_bt(impl_).get_frame(frame);
|
||||
std::string stacktrace::operator[](std::size_t frame) const {
|
||||
return boost::stacktrace::detail::to_bt(impl_).get_frame(frame);
|
||||
}
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_STACKTRACE_IPP
|
||||
|
||||
@@ -4,12 +4,14 @@
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_STACKTRACE_HELPERS_HPP
|
||||
#define BOOST_STACKTRACE_DETAIL_STACKTRACE_HELPERS_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/type_traits/is_pointer.hpp>
|
||||
|
||||
@@ -42,3 +44,5 @@ inline boost::array<char, 2 + sizeof(void*) * 2 + 1> to_hex(T addr) BOOST_NOEXCE
|
||||
}*/
|
||||
|
||||
}}} // namespace boost::stacktrace::detail
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_STACKTRACE_HELPERS_HPP
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_STACKTRACE_LIBUNWIND_HPP
|
||||
#define BOOST_STACKTRACE_DETAIL_STACKTRACE_LIBUNWIND_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
@@ -13,7 +16,7 @@
|
||||
#include <boost/core/demangle.hpp>
|
||||
#include <cstring>
|
||||
#include <boost/core/no_exceptions_support.hpp>
|
||||
#include <vector>
|
||||
#include <boost/make_shared.hpp>
|
||||
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include <libunwind.h>
|
||||
@@ -22,45 +25,72 @@ namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
struct backtrace_holder {
|
||||
BOOST_STATIC_CONSTEXPR std::size_t skip_frames = 1u;
|
||||
std::vector<std::string> frames;
|
||||
std::size_t frames_count;
|
||||
boost::shared_ptr<std::string[]> frames;
|
||||
|
||||
backtrace_holder() BOOST_NOEXCEPT {
|
||||
backtrace_holder() BOOST_NOEXCEPT
|
||||
: frames_count(0)
|
||||
{
|
||||
unw_context_t uc;
|
||||
if (unw_getcontext(&uc) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
{ // Counting frames_count
|
||||
unw_cursor_t cursor;
|
||||
if (unw_init_local(&cursor, &uc) != 0) {
|
||||
return;
|
||||
}
|
||||
while (unw_step(&cursor) > 0) {
|
||||
++ frames_count;
|
||||
}
|
||||
if (frames_count <= skip_frames) {
|
||||
frames_count = 0;
|
||||
return;
|
||||
}
|
||||
frames_count -= skip_frames;
|
||||
}
|
||||
|
||||
unw_cursor_t cursor;
|
||||
if (unw_init_local(&cursor, &uc) != 0) {
|
||||
frames_count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < skip_frames; ++i) {
|
||||
if (unw_step(&cursor) <= 0) {
|
||||
frames_count = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_TRY {
|
||||
frames = boost::make_shared<std::string[]>(frames_count);
|
||||
std::size_t i = 0;
|
||||
while (unw_step(&cursor) > 0){
|
||||
frames.push_back(get_frame_impl(cursor));
|
||||
frames[i] = get_frame_impl(cursor);
|
||||
++ i;
|
||||
}
|
||||
} BOOST_CATCH(...) {}
|
||||
BOOST_CATCH_END
|
||||
}
|
||||
|
||||
std::size_t size() const BOOST_NOEXCEPT {
|
||||
return frames.size();
|
||||
return frames_count;
|
||||
}
|
||||
|
||||
std::string get_frame(std::size_t frame) const {
|
||||
return frames[frame];
|
||||
if (frame < frames_count) {
|
||||
return frames[frame];
|
||||
} else {
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
|
||||
static std::string get_frame_impl(unw_cursor_t& cursor) {
|
||||
std::string res;
|
||||
unw_word_t offp;
|
||||
char data[128];
|
||||
char data[256];
|
||||
const int ret = unw_get_proc_name (&cursor, data, sizeof(data) / sizeof(char), &offp);
|
||||
|
||||
if (ret == -UNW_ENOMEM) {
|
||||
@@ -94,3 +124,5 @@ struct backtrace_holder {
|
||||
};
|
||||
|
||||
}}} // namespace boost::stacktrace::detail
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_STACKTRACE_LIBUNWIND_HPP
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_STACKTRACE_LINUX_HPP
|
||||
#define BOOST_STACKTRACE_DETAIL_STACKTRACE_LINUX_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
@@ -26,7 +29,7 @@ struct backtrace_holder {
|
||||
#ifdef BOOST_STACKTRACE_HEADER_ONLY
|
||||
BOOST_STATIC_CONSTEXPR std::size_t skip_frames = 0u;
|
||||
#else
|
||||
BOOST_STATIC_CONSTEXPR std::size_t skip_frames = 1u;
|
||||
BOOST_STATIC_CONSTEXPR std::size_t skip_frames = 2u;
|
||||
#endif
|
||||
|
||||
inline backtrace_holder() BOOST_NOEXCEPT {
|
||||
@@ -64,3 +67,5 @@ struct backtrace_holder {
|
||||
|
||||
|
||||
}}} // namespace boost::stacktrace::detail
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_STACKTRACE_LINUX_HPP
|
||||
|
||||
@@ -4,12 +4,17 @@
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_STACKTRACE_WINDOWS_HPP
|
||||
#define BOOST_STACKTRACE_DETAIL_STACKTRACE_WINDOWS_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace.hpp>
|
||||
#include <boost/stacktrace/detail/stacktrace_helpers.hpp>
|
||||
#include <boost/core/no_exceptions_support.hpp>
|
||||
|
||||
#include <cstring>
|
||||
#include <windows.h>
|
||||
#include "DbgHelp.h"
|
||||
#include <WinBase.h>
|
||||
@@ -17,8 +22,9 @@
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
struct symbol_info_with_stack {
|
||||
BOOST_STATIC_CONSTEXPR std::size_t max_name_length = MAX_SYM_NAME * sizeof(char);
|
||||
SYMBOL_INFO symbol;
|
||||
char name_part[MAX_SYM_NAME * sizeof(TCHAR)];
|
||||
char name_part[max_name_length];
|
||||
};
|
||||
|
||||
struct backtrace_holder {
|
||||
@@ -44,7 +50,7 @@ struct backtrace_holder {
|
||||
return frames_count;
|
||||
}
|
||||
|
||||
inline std::string get_frame(std::size_t frame) const BOOST_NOEXCEPT {
|
||||
inline std::string get_frame(std::size_t frame) const {
|
||||
std::string res;
|
||||
|
||||
if (frame >= frames_count || !process) {
|
||||
@@ -52,14 +58,10 @@ struct backtrace_holder {
|
||||
}
|
||||
|
||||
symbol_info_with_stack s;
|
||||
s.symbol.MaxNameLen = f.name.size() - 1;
|
||||
s.symbol.MaxNameLen = symbol_info_with_stack::max_name_length;
|
||||
s.symbol.SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
|
||||
SymFromAddr(process, reinterpret_cast<DWORD64>(buffer[frame]), 0, &s.symbol);
|
||||
BOOST_TRY {
|
||||
res = s.symbol.Name;
|
||||
} BOOST_CATCH(...) {}
|
||||
BOOST_CATCH_END
|
||||
res = s.symbol.Name;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -67,3 +69,4 @@ struct backtrace_holder {
|
||||
|
||||
}}} // namespace boost::stacktrace::detail
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_STACKTRACE_WINDOWS_HPP
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#define BOOST_STACKTRACE_USE_BACKTRACE
|
||||
#include <boost/stacktrace/detail/stacktrace.ipp>
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#define BOOST_STACKTRACE_USE_LIBUNWIND
|
||||
#include <boost/stacktrace/detail/stacktrace.ipp>
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#define BOOST_STACKTRACE_USE_WINDBG
|
||||
#include <boost/stacktrace/detail/stacktrace.ipp>
|
||||
|
||||
@@ -35,10 +35,32 @@ void test_nested() {
|
||||
|
||||
assert(ss1.str().find("main") != std::string::npos);
|
||||
assert(ss2.str().find("main") != std::string::npos);
|
||||
|
||||
|
||||
assert(ss2.str().find("stacktrace") == std::string::npos);
|
||||
|
||||
#if !defined(BOOST_STACKTRACE_HEADER_ONLY) || !defined(BOOST_STACKTRACE_USE_BACKTRACE)
|
||||
assert(ss1.str().find("stacktrace") != std::string::npos);
|
||||
assert(ss1.str().find("pair") != std::string::npos);
|
||||
|
||||
assert(ss1.str().find("foo1") != std::string::npos);
|
||||
assert(ss1.str().find("foo2") != std::string::npos);
|
||||
assert(ss2.str().find("foo1") != std::string::npos);
|
||||
assert(ss2.str().find("foo2") != std::string::npos);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
std::cout << return_from_nested_namespaces();
|
||||
std::stringstream ss;
|
||||
ss << return_from_nested_namespaces();
|
||||
std::cout << ss.str() << '\n';
|
||||
assert(ss.str().find("main") != std::string::npos);
|
||||
assert(ss.str().find("stacktrace") == std::string::npos);
|
||||
|
||||
#if !defined(BOOST_STACKTRACE_HEADER_ONLY) || !defined(BOOST_STACKTRACE_USE_BACKTRACE)
|
||||
assert(ss.str().find("get_backtrace_from_nested_namespaces") != std::string::npos);
|
||||
#endif
|
||||
|
||||
test_nested();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user