diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
commit | 483eb2f56657e8e7f419ab1a4fab8dce9ade8609 (patch) | |
tree | e5d88d25d870d5dedacb6bbdbe2a966086a0a5cf /src/boost/libs/stacktrace | |
parent | Initial commit. (diff) | |
download | ceph-upstream.tar.xz ceph-upstream.zip |
Adding upstream version 14.2.21.upstream/14.2.21upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/boost/libs/stacktrace')
30 files changed, 1977 insertions, 0 deletions
diff --git a/src/boost/libs/stacktrace/README.md b/src/boost/libs/stacktrace/README.md new file mode 100644 index 00000000..a80427aa --- /dev/null +++ b/src/boost/libs/stacktrace/README.md @@ -0,0 +1,15 @@ +### Stacktrace +Library for storing and printing backtraces. + +[Documentation and examples.](http://boostorg.github.io/stacktrace/index.html) + + +### Test results +@ | Build | Tests coverage | More info +----------------|-------------- | -------------- |----------- +Develop branch: | [![Build Status](https://travis-ci.org/boostorg/stacktrace.svg?branch=develop)](https://travis-ci.org/boostorg/stacktrace) [![Build status](https://ci.appveyor.com/api/projects/status/l3aak4j8k39rx08t/branch/develop?svg=true)](https://ci.appveyor.com/project/apolukhin/stacktrace/branch/develop) | [![Coverage Status](https://coveralls.io/repos/github/boostorg/stacktrace/badge.svg?branch=develop)](https://coveralls.io/github/boostorg/stacktrace?branch=develop) | [details...](http://www.boost.org/development/tests/develop/developer/stacktrace.html) +Master branch: | [![Build Status](https://travis-ci.org/boostorg/stacktrace.svg?branch=master)](https://travis-ci.org/boostorg/stacktrace) [![Build status](https://ci.appveyor.com/api/projects/status/l3aak4j8k39rx08t/branch/master?svg=true)](https://ci.appveyor.com/project/apolukhin/stacktrace/branch/master) | [![Coverage Status](https://coveralls.io/repos/github/boostorg/stacktrace/badge.svg?branch=master)](https://coveralls.io/github/boostorg/stacktrace?branch=master) | [details...](http://www.boost.org/development/tests/master/developer/stacktrace.html) + + +### License +Distributed under the [Boost Software License, Version 1.0](http://boost.org/LICENSE_1_0.txt). diff --git a/src/boost/libs/stacktrace/build/Jamfile.v2 b/src/boost/libs/stacktrace/build/Jamfile.v2 new file mode 100644 index 00000000..6d6d85a9 --- /dev/null +++ b/src/boost/libs/stacktrace/build/Jamfile.v2 @@ -0,0 +1,145 @@ +# Copyright (C) 2016-2019, Antony Polukhin. +# +# Use, modification and distribution is subject to the Boost Software License, +# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +# + +project + : source-location . + : requirements + <visibility>hidden + ; + +lib dl ; +lib gcc_s ; +lib Dbgeng ; +lib ole32 ; + + +local LIBBACKTRACE_PATH = [ modules.peek : LIBBACKTRACE_PATH ] ; +lib backtrace + : + : <search>$(LIBBACKTRACE_PATH)/lib <link>static + : + : <include>$(LIBBACKTRACE_PATH)/include + ; + +actions mp_simple_run_action +{ + $(>) > $(<) +} + +rule mp-run-simple ( sources + : args * : input-files * : requirements * : target-name ) +{ + exe $(target-name)_exe : $(sources) : $(requirements) ; + explicit $(target-name)_exe ; + make $(target-name).output : $(target-name)_exe : @mp_simple_run_action ; + explicit $(target-name).output ; + alias $(target-name) : $(target-name).output ; +} + +mp-run-simple has_backtrace.cpp : : : <library>backtrace : libbacktrace ; +explicit libbacktrace ; + +mp-run-simple has_addr2line.cpp : : : : addr2line ; +explicit addr2line ; + +mp-run-simple has_windbg.cpp : : : <library>Dbgeng <library>ole32 : WinDbg ; +explicit WinDbg ; + +mp-run-simple has_windbg_cached.cpp : : : <library>Dbgeng <library>ole32 : WinDbgCached ; +explicit WinDbgCached ; + +local libraries ; + +lib boost_stacktrace_noop + : # sources + ../src/noop.cpp + : # requirements + <warnings>all + <link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1 + : # default build + : # usage-requirements + #<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1 + ; + +libraries += boost_stacktrace_noop ; + +lib boost_stacktrace_backtrace + : # sources + ../src/backtrace.cpp + : # requirements + <warnings>all + <target-os>linux:<library>dl + <library>backtrace + <link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1 + [ check-target-builds ../build//libbacktrace : : <build>no ] + : # default build + : # usage-requirements + #<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1 + ; + +libraries += boost_stacktrace_backtrace ; + +lib boost_stacktrace_addr2line + : # sources + ../src/addr2line.cpp + : # requirements + <warnings>all + <target-os>linux:<library>dl + <link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1 + [ check-target-builds ../build//addr2line : : <build>no ] + : # default build + : # usage-requirements + #<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1 + ; + +libraries += boost_stacktrace_addr2line ; + +lib boost_stacktrace_basic + : # sources + ../src/basic.cpp + : # requirements + <warnings>all + <target-os>linux:<library>dl + <link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1 + [ check-target-builds ../build//WinDbg : <build>no ] + : # default build + : # usage-requirements + #<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1 + ; + +libraries += boost_stacktrace_basic ; + +lib boost_stacktrace_windbg + : # sources + ../src/windbg.cpp + : # requirements + <warnings>all + <library>Dbgeng <library>ole32 + <link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1 + [ check-target-builds ../build//WinDbg : : <build>no ] + : # default build + : # usage-requirements + #<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1 + ; + +libraries += boost_stacktrace_windbg ; + +lib boost_stacktrace_windbg_cached + : # sources + ../src/windbg_cached.cpp + : # requirements + <warnings>all + <library>Dbgeng <library>ole32 + <link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1 + [ check-target-builds ../build//WinDbgCached : : <build>no ] + : # default build + : # usage-requirements + #<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1 + ; + +libraries += boost_stacktrace_windbg_cached ; + +boost-install $(libraries) ; diff --git a/src/boost/libs/stacktrace/build/has_addr2line.cpp b/src/boost/libs/stacktrace/build/has_addr2line.cpp new file mode 100644 index 00000000..8a8c0f76 --- /dev/null +++ b/src/boost/libs/stacktrace/build/has_addr2line.cpp @@ -0,0 +1,25 @@ +// Copyright Antony Polukhin, 2016-2019. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <cstdlib> +#include <string> + +#include <boost/config.hpp> +#include <unwind.h> +#include <sys/types.h> +#include <sys/wait.h> + +int main() { + +#ifdef BOOST_STACKTRACE_ADDR2LINE_LOCATION + std::string s = BOOST_STRINGIZE( BOOST_STACKTRACE_ADDR2LINE_LOCATION ); + s += " -h"; +#else + std::string s = "/usr/bin/addr2line -h"; +#endif + + return std::system(s.c_str()); +} diff --git a/src/boost/libs/stacktrace/build/has_backtrace.cpp b/src/boost/libs/stacktrace/build/has_backtrace.cpp new file mode 100644 index 00000000..9a99074c --- /dev/null +++ b/src/boost/libs/stacktrace/build/has_backtrace.cpp @@ -0,0 +1,15 @@ +// Copyright Antony Polukhin, 2016-2019. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <backtrace.h> +#include <unwind.h> + +int main() { + backtrace_state* state = backtrace_create_state( + 0, 1, 0, 0 + ); + (void)state; +} diff --git a/src/boost/libs/stacktrace/build/has_windbg.cpp b/src/boost/libs/stacktrace/build/has_windbg.cpp new file mode 100644 index 00000000..17408be2 --- /dev/null +++ b/src/boost/libs/stacktrace/build/has_windbg.cpp @@ -0,0 +1,13 @@ +// Copyright Antony Polukhin, 2016-2019. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <cstring> +#include <windows.h> +#include "dbgeng.h" + +int main() { + ::CoInitializeEx(0, COINIT_MULTITHREADED); +} diff --git a/src/boost/libs/stacktrace/build/has_windbg_cached.cpp b/src/boost/libs/stacktrace/build/has_windbg_cached.cpp new file mode 100644 index 00000000..71a6ab57 --- /dev/null +++ b/src/boost/libs/stacktrace/build/has_windbg_cached.cpp @@ -0,0 +1,28 @@ +// Copyright Antony Polukhin, 2016-2019. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/config.hpp> + +#include <string> +#include <cstring> +#include <windows.h> +#include "dbgeng.h" + +#ifdef BOOST_NO_CXX11_THREAD_LOCAL +# error Your compiler does not support C++11 thread_local storage. It`s impossible to build with BOOST_STACKTRACE_USE_WINDBG_CACHED. +#endif + +int foo() { + static thread_local std::string i = std::string(); + + return static_cast<int>(i.size()); +} + +int main() { + ::CoInitializeEx(0, COINIT_MULTITHREADED); + + return foo(); +} diff --git a/src/boost/libs/stacktrace/example/assert_handler.cpp b/src/boost/libs/stacktrace/example/assert_handler.cpp new file mode 100644 index 00000000..200fe049 --- /dev/null +++ b/src/boost/libs/stacktrace/example/assert_handler.cpp @@ -0,0 +1,57 @@ +// Copyright Antony Polukhin, 2016-2019. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_ENABLE_ASSERT_HANDLER + +#include <cstdlib> // std::exit +#include <boost/array.hpp> +BOOST_NOINLINE void foo(int i); +BOOST_NOINLINE void bar(int i); + +BOOST_NOINLINE void bar(int i) { + boost::array<int, 5> a = {{101, 100, 123, 23, 32}}; + if (i >= 0) { + foo(a[i]); + } else { + std::exit(1); + } +} + +BOOST_NOINLINE void foo(int i) { + bar(--i); +} + +namespace std { inline void ignore_abort(){ std::exit(0); } } +#define abort ignore_abort + +//[getting_started_assert_handlers + +// 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 { + inline 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'; + std::abort(); + } + + inline 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 +//] + + +int main() { + foo(5); + + return 2; +} + + diff --git a/src/boost/libs/stacktrace/example/debug_function.cpp b/src/boost/libs/stacktrace/example/debug_function.cpp new file mode 100644 index 00000000..7b14db80 --- /dev/null +++ b/src/boost/libs/stacktrace/example/debug_function.cpp @@ -0,0 +1,33 @@ +// Copyright Antony Polukhin, 2016-2019. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +//[getting_started_debug_function +#include <signal.h> // ::signal +#include <boost/stacktrace/frame.hpp> +#include <iostream> // std::cerr +#include <cstdlib> // std::exit + +void print_signal_handler_and_exit() { + typedef void(*function_t)(int); + + function_t old_signal_function = ::signal(SIGSEGV, SIG_DFL); + boost::stacktrace::frame f(old_signal_function); + std::cout << f << std::endl; + std::exit(0); +} +//] + + +void my_signal_handler(int /*signum*/) { + std::exit(1); +} + +int main() { + ::signal(SIGSEGV, &my_signal_handler); + print_signal_handler_and_exit(); +} + + diff --git a/src/boost/libs/stacktrace/example/terminate_handler.cpp b/src/boost/libs/stacktrace/example/terminate_handler.cpp new file mode 100644 index 00000000..3c2b4858 --- /dev/null +++ b/src/boost/libs/stacktrace/example/terminate_handler.cpp @@ -0,0 +1,326 @@ +// Copyright Antony Polukhin, 2016-2019. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/array.hpp> +BOOST_NOINLINE void foo(int i); +BOOST_NOINLINE void bar(int i); + +BOOST_NOINLINE void bar(int i) { + boost::array<int, 5> a = {{-1, -231, -123, -23, -32}}; + if (i >= 0) { + foo(a[i]); + } else { + std::terminate(); + } +} + +BOOST_NOINLINE void foo(int i) { + bar(--i); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//[getting_started_terminate_handlers + +#include <signal.h> // ::signal, ::raise +#include <boost/stacktrace.hpp> + +void my_signal_handler(int signum) { + ::signal(signum, SIG_DFL); + boost::stacktrace::safe_dump_to("./backtrace.dump"); + ::raise(SIGABRT); +} +//] + +void setup_handlers() { +//[getting_started_setup_handlers + ::signal(SIGSEGV, &my_signal_handler); + ::signal(SIGABRT, &my_signal_handler); +//] +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +BOOST_CONSTEXPR_OR_CONST std::size_t shared_memory_size = 4096 * 8; + +//[getting_started_terminate_handlers_shmem +#include <boost/stacktrace.hpp> +#include <boost/interprocess/shared_memory_object.hpp> +#include <boost/interprocess/mapped_region.hpp> + +boost::interprocess::shared_memory_object g_shm; // inited at program start +boost::interprocess::mapped_region g_region; // inited at program start + + +void my_signal_handler2(int signum) { + ::signal(signum, SIG_DFL); + void** f = static_cast<void**>(g_region.get_address()); + *f = reinterpret_cast<void*>(1); // Setting flag that shared memory now constains stacktrace. + boost::stacktrace::safe_dump_to(f + 1, g_region.get_size() - sizeof(void*)); + + ::raise(SIGABRT); +} +//] + +#include <iostream> // std::cerr +#include <fstream> // std::ifstream +#include <boost/filesystem/path.hpp> +#include <boost/filesystem/operations.hpp> + + +inline void copy_and_run(const char* exec_name, char param, bool not_null) { + std::cout << "Running with param " << param << std::endl; + boost::filesystem::path command = exec_name; + command = command.parent_path() / (command.stem().string() + param + command.extension().string()); + boost::filesystem::copy_file(exec_name, command, boost::filesystem::copy_option::overwrite_if_exists); + + boost::filesystem::path command_args = command; + command_args += ' '; + command_args += param; + const int ret = std::system(command_args.string().c_str()); + + std::cout << "End Running with param " << param << "; ret code is " << ret << std::endl; + boost::system::error_code ignore; + boost::filesystem::remove(command, ignore); + if (not_null && !ret) { + std::exit(97); + } else if (!not_null && ret) { + std::exit(ret); + } +} + +int run_1(const char* /*argv*/[]) { + setup_handlers(); + foo(5); + return 11; +} + +int run_2(const char* argv[]) { + if (!boost::filesystem::exists("./backtrace.dump")) { + if (std::string(argv[0]).find("noop") == std::string::npos) { + return 21; + } + + boost::stacktrace::stacktrace st = boost::stacktrace::stacktrace::from_dump(std::cin); + if (st) { + return 22; + } + return 0; + } + +//[getting_started_on_program_restart + if (boost::filesystem::exists("./backtrace.dump")) { + // there is a backtrace + std::ifstream ifs("./backtrace.dump"); + + boost::stacktrace::stacktrace st = boost::stacktrace::stacktrace::from_dump(ifs); + std::cout << "Previous run crashed:\n" << st << std::endl; /*<-*/ + + if (!st) { + return 23; + } /*->*/ + + // cleaning up + ifs.close(); + boost::filesystem::remove("./backtrace.dump"); + } +//] + + return 0; +} + + +int run_3(const char* /*argv*/[]) { + using namespace boost::interprocess; + { + shared_memory_object shm_obj(open_or_create, "shared_memory", read_write); + shm_obj.swap(g_shm); + } + g_shm.truncate(shared_memory_size); + + { + mapped_region m(g_shm, read_write, 0, shared_memory_size); + m.swap(g_region); + } + void** f = static_cast<void**>(g_region.get_address()); + *f = 0; + + ::signal(SIGSEGV, &my_signal_handler2); + ::signal(SIGABRT, &my_signal_handler2); + foo(5); + return 31; +} + +int run_4(const char* argv[]) { + using namespace boost::interprocess; + { + shared_memory_object shm_obj(open_only, "shared_memory", read_write); + shm_obj.swap(g_shm); + } + + { + mapped_region m(g_shm, read_write, 0, shared_memory_size); + m.swap(g_region); + } + +//[getting_started_on_program_restart_shmem + void** f = static_cast<void**>(g_region.get_address()); + if (*f) { // Checking if memory constains stacktrace. + boost::stacktrace::stacktrace st + = boost::stacktrace::stacktrace::from_dump(f + 1, g_region.get_size() - sizeof(bool)); + + std::cout << "Previous run crashed and left trace in shared memory:\n" << st << std::endl; + *f = 0; /*<-*/ + shared_memory_object::remove("shared_memory"); + if (std::string(argv[0]).find("noop") == std::string::npos) { + if (!st) { + return 43; + } + } else { + if (st) { + return 44; + } + } + } else { + return 42; /*->*/ + } +//] + + + return 0; +} + +#include <sstream> + +int test_inplace() { + const bool is_noop = !boost::stacktrace::stacktrace(); + + { + // This is very dependent on compiler and link flags. No sane way to make it work, because: + // * BOOST_NOINLINE could be ignored by MSVC compiler if link-time optimization is enabled. + // * BOOST_FORCEINLINE could be ignored by GCC depending on the std::vector default constructor length. + const std::size_t frames_ss1 = boost::stacktrace::safe_dump_to("./backtrace2.dump"); + boost::stacktrace::stacktrace ss2; + std::ifstream ifs("./backtrace2.dump"); + boost::stacktrace::stacktrace ss1 = boost::stacktrace::stacktrace::from_dump(ifs); + ifs.close(); + boost::filesystem::remove("./backtrace2.dump"); + + if (ss1.size() + 1 != frames_ss1 || ss2.size() != ss1.size()) { + std::cerr << "51: Stacktraces differ. Dumped size == " << frames_ss1 << ".\n" << ss1 << "\n vs \n" << ss2 << '\n'; + } else if (ss1.size() > 1 && ss1[1].name() != ss2[1].name()) { + std::cerr << "52: Stacktraces differ:\n" << ss1 << "\n vs \n" << ss2 << '\n'; + } + } + + { + // This is very dependent on compiler and link flags. No sane way to make it work, because: + // * BOOST_NOINLINE could be ignored by MSVC compiler if link-time optimization is enabled. + // * BOOST_FORCEINLINE could be ignored by GCC depending on the std::vector default constructor length. + void* data[1024]; + const std::size_t frames_ss1 = boost::stacktrace::safe_dump_to(data, sizeof(data)); + boost::stacktrace::stacktrace ss2; + boost::stacktrace::stacktrace ss1 = boost::stacktrace::stacktrace::from_dump(data, sizeof(data)); + + if (ss1.size() + 1 != frames_ss1 || ss1.size() != ss2.size()) { + std::cerr << "53: Stacktraces differ. Dumped size == " << frames_ss1 << ".\n" << ss1 << "\n vs \n" << ss2 << '\n'; + } else if (ss1.size() > 1 && ss1[1].name() != ss2[1].name()) { + std::cerr << "54: Stacktraces differ:\n" << ss1 << "\n vs \n" << ss2 << '\n'; + } + } + + { + void* data[1024]; + boost::stacktrace::safe_dump_to(1024, data, sizeof(data)); + if (boost::stacktrace::stacktrace::from_dump(data, sizeof(data))) { + std::cerr << "Stacktrace not empty!\n"; + return 55; + } + } + + { + void* data[1024]; + boost::stacktrace::safe_dump_to(1, data, sizeof(data)); + if (!is_noop && !boost::stacktrace::stacktrace::from_dump(data, sizeof(data))) { + std::cerr << "Stacktrace empty!\n"; + return 56; + } + const std::size_t size_1_skipped = boost::stacktrace::stacktrace::from_dump(data, sizeof(data)).size(); + boost::stacktrace::safe_dump_to(0, data, sizeof(data)); + const std::size_t size_0_skipped = boost::stacktrace::stacktrace::from_dump(data, sizeof(data)).size(); + + if (!is_noop && (size_1_skipped + 1 != size_0_skipped)) { + std::cerr << "failed to skip 1 frame!\n"; + return 57; + } + } + + { + boost::stacktrace::safe_dump_to(0, 1, "./backtrace3.dump"); + std::ifstream ifs("./backtrace3.dump"); + boost::stacktrace::stacktrace ss1 = boost::stacktrace::stacktrace::from_dump(ifs); + ifs.close(); + + boost::stacktrace::safe_dump_to(1, 1, "./backtrace3.dump"); + ifs.open("./backtrace3.dump"); + boost::stacktrace::stacktrace ss2 = boost::stacktrace::stacktrace::from_dump(ifs); + ifs.close(); + + boost::filesystem::remove("./backtrace3.dump"); + +#ifdef BOOST_WINDOWS + // `ss2` could be empty on some combinations of Windows+MSVC. + if (!ss2) { + return 0; + } +#endif + + if (ss1.size() != ss2.size()) { + std::cerr << "Stacktraces differ:\n" << ss1 << "\n vs \n" << ss2 << '\n'; + return 58; + } + + if (!is_noop && ss1.size() != 1) { + std::cerr << "Stacktraces does not have size 1:\n" << ss1 << '\n'; + return 59; + } + + if (ss1 && ss1[0].address() == ss2[0].address()) { + std::cerr << "Stacktraces must differ:\n" << ss1 << "\n vs \n" << ss2 << '\n'; + return 60; + } + } + + return 0; +} + + +int main(int argc, const char* argv[]) { + if (argc < 2) { +#ifndef BOOST_WINDOWS + // We are copying files to make sure that stacktrace printing works independently from executable name + copy_and_run(argv[0], '1', true); + copy_and_run(argv[0], '2', false); + + // There are some issues with async-safety of shared memory writes on Windows. + copy_and_run(argv[0], '3', true); + copy_and_run(argv[0], '4', false); +#endif + + return test_inplace(); + } + + switch (argv[1][0]) { + case '1': return run_1(argv); + case '2': return run_2(argv); + case '3': return run_3(argv); + case '4': return run_4(argv); + } + + return 404; +} + + diff --git a/src/boost/libs/stacktrace/example/throwing_st.cpp b/src/boost/libs/stacktrace/example/throwing_st.cpp new file mode 100644 index 00000000..632abb90 --- /dev/null +++ b/src/boost/libs/stacktrace/example/throwing_st.cpp @@ -0,0 +1,78 @@ +// Copyright Antony Polukhin, 2016-2019. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/config.hpp> + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//[getting_started_class_traced +#include <boost/stacktrace.hpp> +#include <boost/exception/all.hpp> + +typedef boost::error_info<struct tag_stacktrace, boost::stacktrace::stacktrace> traced; +//] + +//[getting_started_class_with_trace +template <class E> +void throw_with_trace(const E& e) { + throw boost::enable_error_info(e) + << traced(boost::stacktrace::stacktrace()); +} +//] + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +BOOST_NOINLINE void oops(int i); +BOOST_NOINLINE void foo(int i); +BOOST_NOINLINE void bar(int i); + +#include <stdexcept> +BOOST_NOINLINE void oops(int i) { + //[getting_started_throwing_with_trace + 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 be greater than zero in oops()")); + //] + foo(i); + std::exit(1); +} + +#include <boost/array.hpp> +BOOST_NOINLINE void bar(int i) { + boost::array<int, 5> a = {{0, 0, 0, 0, 0}}; + if (i < 5) { + if (i >= 0) { + foo(a[i]); + } else { + oops(i); + } + } + std::exit(2); +} + +BOOST_NOINLINE void foo(int i) { + bar(--i); +} + +#include <iostream> +int main() { + + //[getting_started_catching_trace + try { + foo(5); // testing assert handler + } catch (const std::exception& e) { + std::cerr << e.what() << '\n'; + const boost::stacktrace::stacktrace* st = boost::get_error_info<traced>(e); + if (st) { + std::cerr << *st << '\n'; /*<-*/ return 0; /*->*/ + } /*<-*/ return 3; /*->*/ + } + //] + + return 5; +} + diff --git a/src/boost/libs/stacktrace/example/trace_addresses.cpp b/src/boost/libs/stacktrace/example/trace_addresses.cpp new file mode 100644 index 00000000..0ad30a5b --- /dev/null +++ b/src/boost/libs/stacktrace/example/trace_addresses.cpp @@ -0,0 +1,63 @@ +// Copyright Antony Polukhin, 2016-2019. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/config.hpp> + +#ifdef BOOST_NO_CXX11_RANGE_BASED_FOR +#include <boost/stacktrace.hpp> +#include <iostream> // std::cout + +namespace bs = boost::stacktrace; +void dump_compact(const bs::stacktrace& st) { + for (unsigned i = 0; i < st.size(); ++i) { + bs::frame frame = st[i]; + std::cout << frame.address() << ','; + } + + std::cout << std::endl; +} +#else +//[getting_started_trace_addresses +#include <boost/stacktrace.hpp> +#include <iostream> // std::cout + +namespace bs = boost::stacktrace; +void dump_compact(const bs::stacktrace& st) { + for (bs::frame frame: st) { + std::cout << frame.address() << ','; + } + + std::cout << std::endl; +} +//] +#endif + +BOOST_NOINLINE boost::stacktrace::stacktrace rec1(int i); +BOOST_NOINLINE boost::stacktrace::stacktrace rec2(int i); + +BOOST_NOINLINE boost::stacktrace::stacktrace rec1(int i) { + if (i < 5) { + if (!i) return boost::stacktrace::stacktrace(); + return rec2(--i); + } + + return rec2(i - 2); +} + +BOOST_NOINLINE boost::stacktrace::stacktrace rec2(int i) { + if (i < 5) { + if (!i) return boost::stacktrace::stacktrace(); + return rec2(--i); + } + + return rec2(i - 2); +} + +int main() { + dump_compact(rec1(8)); +} + + diff --git a/src/boost/libs/stacktrace/example/user_config.cpp b/src/boost/libs/stacktrace/example/user_config.cpp new file mode 100644 index 00000000..f675b100 --- /dev/null +++ b/src/boost/libs/stacktrace/example/user_config.cpp @@ -0,0 +1,38 @@ +// Copyright Antony Polukhin, 2016-2019. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_USER_CONFIG <libs/stacktrace/example/user_config.hpp> + +#include <boost/array.hpp> +#include <exception> // std::set_terminate, std::abort +#include <boost/stacktrace.hpp> +#include <iostream> // std::cerr +BOOST_NOINLINE void foo(int i); +BOOST_NOINLINE void bar(int i); + +BOOST_NOINLINE void bar(int i) { + boost::array<int, 5> a = {{-1, -231, -123, -23, -32}}; + if (i >= 0) { + foo(a[i]); + } else { + std::cerr << "Terminate called:\n" << boost::stacktrace::stacktrace() << '\n'; + std::exit(0); + } +} + +BOOST_NOINLINE void foo(int i) { + bar(--i); +} + +int main() { + foo(5); + + return 2; +} + + + + diff --git a/src/boost/libs/stacktrace/example/user_config.hpp b/src/boost/libs/stacktrace/example/user_config.hpp new file mode 100644 index 00000000..eae9713f --- /dev/null +++ b/src/boost/libs/stacktrace/example/user_config.hpp @@ -0,0 +1,58 @@ +// Copyright Antony Polukhin, 2016-2019. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + + +//[getting_started_user_config +#ifndef USER_CONFIG_HPP +#define USER_CONFIG_HPP + +#include <boost/stacktrace/stacktrace_fwd.hpp> + +#include <iosfwd> + +namespace boost { namespace stacktrace { + +template <class CharT, class TraitsT, class Allocator> +std::basic_ostream<CharT, TraitsT>& do_stream_st(std::basic_ostream<CharT, TraitsT>& os, const basic_stacktrace<Allocator>& bt); + +template <class CharT, class TraitsT> +std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT>& os, const stacktrace& bt) { + return do_stream_st(os, bt); +} + +}} // namespace boost::stacktrace +#endif // USER_CONFIG_HPP +//] + +#ifndef USER_CONFIG2_HPP +#define USER_CONFIG2_HPP + +#include <ios> // std::streamsize + +//[getting_started_user_config_impl +namespace boost { namespace stacktrace { + +template <class CharT, class TraitsT, class Allocator> +std::basic_ostream<CharT, TraitsT>& do_stream_st(std::basic_ostream<CharT, TraitsT>& os, const basic_stacktrace<Allocator>& bt) { + const std::streamsize w = os.width(); + const std::size_t frames = bt.size(); + for (std::size_t i = 0; i < frames; ++i) { + os.width(2); + os << i; + os.width(w); + os << "# "; + os << bt[i].name(); + os << '\n'; + } + + return os; +} + +}} // namespace boost::stacktrace +//] + +#endif // USER_CONFIG2_HPP + diff --git a/src/boost/libs/stacktrace/index.html b/src/boost/libs/stacktrace/index.html new file mode 100644 index 00000000..ee7ddb8e --- /dev/null +++ b/src/boost/libs/stacktrace/index.html @@ -0,0 +1,35 @@ +<!DOCTYPE html> +<!-- + Copyright (c) 2014-2019 Antony Polukhin + antoshkka at gmail dot com + + Distributed under the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt + or copy at http://boost.org/LICENSE_1_0.txt) +--> +<html> +<head> +<meta charset="utf-8"> +<meta http-equiv="refresh" content="0; url=../../doc/html/stacktrace.html"> +<title>Boost.Stacktrace</title> +<style> + body { + background: #fff; + color: #000; + } + a { + color: #00f; + text-decoration: none; + } +</style> +</head> +<body> + <p> + Automatic redirection failed, please go to + <a href="../../doc/html/stacktrace.html">../../doc/html/stacktrace.html</a> + </p> + <p> + © 2014-2019 Antony Polukhin + </p> +</body> +</html> diff --git a/src/boost/libs/stacktrace/meta/libraries.json b/src/boost/libs/stacktrace/meta/libraries.json new file mode 100644 index 00000000..7f7a8cd7 --- /dev/null +++ b/src/boost/libs/stacktrace/meta/libraries.json @@ -0,0 +1,15 @@ +{ + "key": "stacktrace", + "name": "Stacktrace", + "authors": [ + "Antony Polukhin" + ], + "maintainers": [ + "Antony Polukhin <antoshkka -at- gmail.com>" + ], + "description": "Gather, store, copy and print backtraces.", + "std": [ "proposal" ], + "category": [ + "System", "Correctness" + ] +} diff --git a/src/boost/libs/stacktrace/src/addr2line.cpp b/src/boost/libs/stacktrace/src/addr2line.cpp new file mode 100644 index 00000000..732a9dc9 --- /dev/null +++ b/src/boost/libs/stacktrace/src/addr2line.cpp @@ -0,0 +1,16 @@ +// Copyright Antony Polukhin, 2016-2019. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS +#define BOOST_STACKTRACE_USE_ADDR2LINE +#define BOOST_STACKTRACE_LINK + +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + +#include <boost/stacktrace/detail/frame_unwind.ipp> +#include <boost/stacktrace/safe_dump_to.hpp> diff --git a/src/boost/libs/stacktrace/src/backtrace.cpp b/src/boost/libs/stacktrace/src/backtrace.cpp new file mode 100644 index 00000000..9860aa96 --- /dev/null +++ b/src/boost/libs/stacktrace/src/backtrace.cpp @@ -0,0 +1,16 @@ +// Copyright Antony Polukhin, 2016-2019. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS +#define BOOST_STACKTRACE_USE_BACKTRACE +#define BOOST_STACKTRACE_LINK + +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + +#include <boost/stacktrace/detail/frame_unwind.ipp> +#include <boost/stacktrace/safe_dump_to.hpp> diff --git a/src/boost/libs/stacktrace/src/basic.cpp b/src/boost/libs/stacktrace/src/basic.cpp new file mode 100644 index 00000000..60d8d329 --- /dev/null +++ b/src/boost/libs/stacktrace/src/basic.cpp @@ -0,0 +1,15 @@ +// Copyright Antony Polukhin, 2016-2019. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS +#define BOOST_STACKTRACE_LINK + +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + +#include <boost/stacktrace/detail/frame_unwind.ipp> +#include <boost/stacktrace/safe_dump_to.hpp> diff --git a/src/boost/libs/stacktrace/src/noop.cpp b/src/boost/libs/stacktrace/src/noop.cpp new file mode 100644 index 00000000..86449063 --- /dev/null +++ b/src/boost/libs/stacktrace/src/noop.cpp @@ -0,0 +1,11 @@ +// Copyright Antony Polukhin, 2016-2019. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS +#define BOOST_STACKTRACE_LINK +#define BOOST_STACKTRACE_USE_NOOP +#include <boost/stacktrace/detail/frame_noop.ipp> +#include <boost/stacktrace/detail/safe_dump_noop.ipp> diff --git a/src/boost/libs/stacktrace/src/windbg.cpp b/src/boost/libs/stacktrace/src/windbg.cpp new file mode 100644 index 00000000..c659a7bf --- /dev/null +++ b/src/boost/libs/stacktrace/src/windbg.cpp @@ -0,0 +1,10 @@ +// Copyright Antony Polukhin, 2016-2019. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS +#define BOOST_STACKTRACE_LINK +#include <boost/stacktrace/detail/frame_msvc.ipp> +#include <boost/stacktrace/safe_dump_to.hpp> diff --git a/src/boost/libs/stacktrace/src/windbg_cached.cpp b/src/boost/libs/stacktrace/src/windbg_cached.cpp new file mode 100644 index 00000000..611ed43c --- /dev/null +++ b/src/boost/libs/stacktrace/src/windbg_cached.cpp @@ -0,0 +1,11 @@ +// Copyright Antony Polukhin, 2016-2019. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_STACKTRACE_INTERNAL_BUILD_LIBS +#define BOOST_STACKTRACE_LINK +#define BOOST_STACKTRACE_USE_WINDBG_CACHED +#include <boost/stacktrace/detail/frame_msvc.ipp> +#include <boost/stacktrace/safe_dump_to.hpp> diff --git a/src/boost/libs/stacktrace/test/Jamfile.v2 b/src/boost/libs/stacktrace/test/Jamfile.v2 new file mode 100644 index 00000000..aa1adaaa --- /dev/null +++ b/src/boost/libs/stacktrace/test/Jamfile.v2 @@ -0,0 +1,236 @@ +# Copyright (C) 2016-2019, Antony Polukhin. +# +# Use, modification and distribution is subject to the Boost Software License, +# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +# + +lib dl : : <link>shared ; +lib gcc_s ; +lib rt ; +lib Dbgeng ; +lib ole32 ; + +local LIBBACKTRACE_PATH = [ modules.peek : LIBBACKTRACE_PATH ] ; +lib backtrace + : + : <search>$(LIBBACKTRACE_PATH)/lib <link>static + : + : <include>$(LIBBACKTRACE_PATH)/include + ; + + +project + : requirements + <toolset>msvc:<asynch-exceptions>on + <toolset>intel:<cxxflags>-wd2196 + <target-os>linux:<linkflags>-lpthread + <warnings>all + <test-info>always_show_run_output + <visibility>hidden + ; + +local FORCE_SYMBOL_EXPORT = <target-os>freebsd:<linkflags>"-rdynamic" <target-os>solaris:<linkflags>"-Bdynamic" <target-os>aix:<linkflags>"-rdynamic" + <target-os>qnxnto,<toolset>qcc:<linkflags>"-Bdynamic" <target-os>qnxnto,<toolset>gcc:<linkflags>"-rdynamic" + <target-os>android:<linkflags>"-rdynamic" <target-os>linux:<linkflags>"-rdynamic" <target-os>darwin,<toolset>gcc:<linkflags>"-dynamic" + <target-os>darwin,<toolset>clang:<linkflags>"-rdynamic" <target-os>iphone:<linkflags>"-rdynamic" + <define>BOOST_STACKTRACE_TEST_EXPORTS_TABLE_USAGE ; + +local BT_DEPS = <target-os>linux:<library>dl <library>backtrace [ check-target-builds ../build//libbacktrace : : <build>no ] ; +local AD2L_DEPS = <target-os>linux:<library>dl [ check-target-builds ../build//addr2line : : <build>no ] ; +local WIND_DEPS = <library>Dbgeng <library>ole32 [ check-target-builds ../build//WinDbg : : <build>no ] ; +local WICA_DEPS = <library>Dbgeng <library>ole32 [ check-target-builds ../build//WinDbgCached : : <build>no ] ; +local NOOP_DEPS = ; +local BASIC_DEPS = <target-os>linux:<library>dl [ check-target-builds ../build//WinDbg : <build>no ] ; + +local LINKSHARED_BT = <link>shared <define>BOOST_STACKTRACE_DYN_LINK <library>/boost/stacktrace//boost_stacktrace_backtrace $(BT_DEPS) ; +local LINKSHARED_AD2L = <link>shared <define>BOOST_STACKTRACE_DYN_LINK <library>/boost/stacktrace//boost_stacktrace_addr2line $(AD2L_DEPS) ; +local LINKSHARED_WIND = <link>shared <define>BOOST_STACKTRACE_DYN_LINK <library>/boost/stacktrace//boost_stacktrace_windbg $(WIND_DEPS) ; +local LINKSHARED_WIND_CACHED = <link>shared <define>BOOST_STACKTRACE_DYN_LINK <library>/boost/stacktrace//boost_stacktrace_windbg_cached $(WICA_DEPS) ; +local LINKSHARED_NOOP = <link>shared <define>BOOST_STACKTRACE_DYN_LINK <library>/boost/stacktrace//boost_stacktrace_noop $(NOOP_DEPS) ; +local LINKSHARED_BASIC = <link>shared <define>BOOST_STACKTRACE_DYN_LINK <library>/boost/stacktrace//boost_stacktrace_basic $(BASIC_DEPS) $(FORCE_SYMBOL_EXPORT) ; + +# Libs with debug symbols +lib test_impl_lib_backtrace : test_impl.cpp : <debug-symbols>on $(LINKSHARED_BT) ; +lib test_impl_lib_addr2line : test_impl.cpp : <debug-symbols>on $(LINKSHARED_AD2L) ; +lib test_impl_lib_windbg : test_impl.cpp : <debug-symbols>on $(LINKSHARED_WIND) ; +lib test_impl_lib_windbg_cached : test_impl.cpp : <debug-symbols>on $(LINKSHARED_WIND_CACHED) ; +lib test_impl_lib_noop : test_impl.cpp : <debug-symbols>on $(LINKSHARED_NOOP) ; + +obj test_impl_nohide-obj : test_impl.cpp : <debug-symbols>on $(LINKSHARED_BASIC) ; +lib test_impl_lib_basic : test_impl_nohide-obj : <debug-symbols>on $(LINKSHARED_BASIC) ; + + +# Libs without debug symbols +lib test_impl_lib_backtrace_no_dbg : test_impl.cpp : <debug-symbols>off $(LINKSHARED_BT) ; +lib test_impl_lib_addr2line_no_dbg : test_impl.cpp : <debug-symbols>off $(LINKSHARED_AD2L) ; +lib test_impl_lib_windbg_no_dbg : test_impl.cpp : <debug-symbols>off $(LINKSHARED_WIND) ; +lib test_impl_lib_windbg_cached_no_dbg : test_impl.cpp : <debug-symbols>off $(LINKSHARED_WIND_CACHED) ; +lib test_impl_lib_noop_no_dbg : test_impl.cpp : <debug-symbols>off $(LINKSHARED_NOOP) ; + +obj test_impl_nohide_no_dbg-obj : test_impl.cpp : <debug-symbols>off $(LINKSHARED_BASIC) ; +lib test_impl_lib_basic_no_dbg : test_impl_nohide_no_dbg-obj : <debug-symbols>off $(LINKSHARED_BASIC) ; + + +test-suite stacktrace_tests + : + + # Header only tests with debug symbols + [ run test.cpp test_impl.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_BACKTRACE $(BT_DEPS) : backtrace_ho ] + [ run test.cpp test_impl.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_ADDR2LINE $(AD2L_DEPS) : addr2line_ho ] + [ run test_noop.cpp test_impl.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_NOOP $(NOOP_DEPS) : noop_ho ] + [ run test.cpp test_impl.cpp : : : <debug-symbols>on $(WIND_DEPS) : windbg_ho ] + [ run test.cpp test_impl.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_WINDBG_CACHED $(WICA_DEPS) : windbg_cached_ho ] + [ run test.cpp test_impl.cpp : : : <debug-symbols>on $(FORCE_SYMBOL_EXPORT) $(BASIC_DEPS) : basic_ho ] + [ run test.cpp test_impl.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_TEST_NO_DEBUG_AT_ALL $(BASIC_DEPS) : basic_ho_empty ] + + # Test with shared linked implementations with debug symbols + [ run test.cpp : : : <debug-symbols>on <library>.//test_impl_lib_backtrace $(LINKSHARED_BT) : backtrace_lib ] + [ run test.cpp : : : <debug-symbols>on <library>.//test_impl_lib_addr2line $(LINKSHARED_AD2L) : addr2line_lib ] + [ run test.cpp : : : <debug-symbols>on <library>.//test_impl_lib_windbg $(LINKSHARED_WIND) : windbg_lib ] + [ run test.cpp : : : <debug-symbols>on <library>.//test_impl_lib_windbg_cached $(LINKSHARED_WIND_CACHED) : windbg_cached_lib ] + [ run test_noop.cpp : : : <debug-symbols>on <library>.//test_impl_lib_noop $(LINKSHARED_NOOP) : noop_lib ] + [ run test.cpp : : : <debug-symbols>on <library>.//test_impl_lib_basic $(LINKSHARED_BASIC) : basic_lib ] + + # Thread safety with debug symbols + [ run thread_safety_checking.cpp + : : : <debug-symbols>on <library>/boost/thread//boost_thread <library>/boost/timer//boost_timer <library>.//test_impl_lib_backtrace $(LINKSHARED_BT) + : backtrace_lib_threaded ] + [ run thread_safety_checking.cpp + : : : <debug-symbols>on <library>/boost/thread//boost_thread <library>/boost/timer//boost_timer <library>.//test_impl_lib_windbg $(LINKSHARED_WIND) + : windbg_lib_threaded ] + [ run thread_safety_checking.cpp + : : : <debug-symbols>on <library>/boost/thread//boost_thread <library>/boost/timer//boost_timer <library>.//test_impl_lib_windbg_cached $(LINKSHARED_WIND_CACHED) + : windbg_cached_lib_threaded ] + [ run thread_safety_checking.cpp + : : : <debug-symbols>on <library>/boost/thread//boost_thread <library>/boost/timer//boost_timer <library>.//test_impl_lib_basic $(LINKSHARED_BASIC) + : basic_lib_threaded ] + + [ run thread_safety_checking.cpp + : : : <debug-symbols>on <library>/boost/thread//boost_thread <library>/boost/timer//boost_timer <library>.//test_impl_lib_windbg + $(LINKSHARED_WIND) <define>BOOST_STACKTRACE_TEST_COM_PREINIT_MT + : windbg_lib_threaded_com_mt ] + [ run thread_safety_checking.cpp + : : : <debug-symbols>on <library>/boost/thread//boost_thread <library>/boost/timer//boost_timer <library>.//test_impl_lib_windbg_cached + $(LINKSHARED_WIND_CACHED) <define>BOOST_STACKTRACE_TEST_COM_PREINIT_ST + : windbg_cached_lib_threaded_com_st ] + + ##### Tests with disabled debug symbols ##### + + # Header only tests without debug symbols + [ run test.cpp test_impl.cpp : : : <debug-symbols>off <define>BOOST_STACKTRACE_USE_BACKTRACE $(FORCE_SYMBOL_EXPORT) $(BT_DEPS) : backtrace_ho_no_dbg ] + [ run test_noop.cpp test_impl.cpp : : : <debug-symbols>off <define>BOOST_STACKTRACE_USE_NOOP $(NOOP_DEPS) : noop_ho_no_dbg ] + [ run test.cpp test_impl.cpp : : : <debug-symbols>off <define>BOOST_STACKTRACE_TEST_NO_DEBUG_AT_ALL $(WIND_DEPS) : windbg_ho_no_dbg ] + [ run test.cpp test_impl.cpp : : : <debug-symbols>off <define>BOOST_STACKTRACE_USE_WINDBG_CACHED <define>BOOST_STACKTRACE_TEST_NO_DEBUG_AT_ALL $(WICA_DEPS) : windbg_cached_ho_no_dbg ] + [ run test.cpp test_impl.cpp : : : <debug-symbols>off $(FORCE_SYMBOL_EXPORT) $(BASIC_DEPS) : basic_ho_no_dbg ] + [ run test.cpp test_impl.cpp : : : <debug-symbols>off <define>BOOST_STACKTRACE_TEST_NO_DEBUG_AT_ALL $(BASIC_DEPS) : basic_ho_no_dbg_empty ] + [ run test.cpp test_impl.cpp + : : : <debug-symbols>off <define>BOOST_STACKTRACE_USE_ADDR2LINE <define>BOOST_STACKTRACE_ADDR2LINE_LOCATION="/usr/bin/addr2line" $(AD2L_DEPS) + : addr2line_ho_no_dbg ] + + # Test with shared linked implementations without debug symbols + [ run test.cpp : : : <debug-symbols>off <library>.//test_impl_lib_backtrace_no_dbg $(LINKSHARED_BT) $(FORCE_SYMBOL_EXPORT) : backtrace_lib_no_dbg ] + [ run test.cpp : : : <debug-symbols>off <library>.//test_impl_lib_addr2line_no_dbg $(LINKSHARED_AD2L) : addr2line_lib_no_dbg ] + [ run test.cpp : : : <debug-symbols>off <library>.//test_impl_lib_windbg_no_dbg $(LINKSHARED_WIND) <define>BOOST_STACKTRACE_TEST_NO_DEBUG_AT_ALL : windbg_lib_no_dbg ] + [ run test.cpp : : : <debug-symbols>off <library>.//test_impl_lib_windbg_cached_no_dbg $(LINKSHARED_WIND_CACHED) <define>BOOST_STACKTRACE_TEST_NO_DEBUG_AT_ALL : windbg_cached_lib_no_dbg ] + [ run test_noop.cpp : : : <debug-symbols>off <library>.//test_impl_lib_noop_no_dbg $(LINKSHARED_NOOP) : noop_lib_no_dbg ] + [ run test.cpp : : : <debug-symbols>off <library>.//test_impl_lib_basic_no_dbg $(LINKSHARED_BASIC) : basic_lib_no_dbg ] + + # Thread safety without debug symbols + [ run thread_safety_checking.cpp + : : : <debug-symbols>off + <library>/boost/thread//boost_thread + <library>/boost/timer//boost_timer + <library>.//test_impl_lib_backtrace_no_dbg + $(LINKSHARED_BT) + : backtrace_lib_no_dbg_threaded ] + [ run thread_safety_checking.cpp + : : : <debug-symbols>off + <library>/boost/thread//boost_thread + <library>/boost/timer//boost_timer + <library>.//test_impl_lib_windbg_no_dbg + $(LINKSHARED_WIND) + : windbg_lib_no_dbg_threaded ] + [ run thread_safety_checking.cpp + : : : <debug-symbols>off + <library>/boost/thread//boost_thread + <library>/boost/timer//boost_timer + <library>.//test_impl_lib_windbg_cached_no_dbg + $(LINKSHARED_WIND_CACHED) + : windbg_cached_lib_no_dbg_threaded ] + [ run thread_safety_checking.cpp + : : : <debug-symbols>off + <library>/boost/thread//boost_thread + <library>/boost/timer//boost_timer + <library>.//test_impl_lib_basic_no_dbg + $(LINKSHARED_BASIC) + : basic_lib_no_dbg_threaded ] + + [ run thread_safety_checking.cpp + : : : <debug-symbols>off + <library>/boost/thread//boost_thread + <library>/boost/timer//boost_timer + <library>.//test_impl_lib_windbg + $(LINKSHARED_WIND) + <define>BOOST_STACKTRACE_TEST_COM_PREINIT_MT + : windbg_lib_threaded_com_mt ] + [ run thread_safety_checking.cpp + : : : <debug-symbols>off + <library>/boost/thread//boost_thread + <library>/boost/timer//boost_timer + <library>.//test_impl_lib_windbg_cached + $(LINKSHARED_WIND_CACHED) + <define>BOOST_STACKTRACE_TEST_COM_PREINIT_ST + : windbg_cached_lib_threaded_com_st ] + + [ run test_void_ptr_cast.cpp ] + [ run test_num_conv.cpp ] + ; + +# Assuring that examples compile and run. Adding sources from `examples` directory to the `type_index` test suite. +for local p in [ glob ../example/*.cpp ] +{ + local target_name = $(p[1]:B) ; + local additional_dependency = ; + if $(target_name) = "terminate_handler" + { + additional_dependency = <library>/boost/filesystem//boost_filesystem <library>/boost/system//boost_system <target-os>linux:<library>rt ; + } + + stacktrace_tests += [ run $(p) : : : <debug-symbols>on $(LINKSHARED_BT) $(additional_dependency) : backtrace_$(p2[1]:B) ] ; + stacktrace_tests += [ run $(p) : : : <debug-symbols>on $(LINKSHARED_AD2L) $(additional_dependency) : addr2line_$(p[1]:B) ] ; + stacktrace_tests += [ run $(p) : : : <debug-symbols>on $(LINKSHARED_WIND) $(additional_dependency) : windbg_$(p[1]:B) ] ; + stacktrace_tests += [ run $(p) : : : <debug-symbols>on $(LINKSHARED_WIND_CACHED) $(additional_dependency) : windbg_cached_$(p[1]:B) ] ; + stacktrace_tests += [ run $(p) : : : <debug-symbols>on $(LINKSHARED_NOOP) $(additional_dependency) : noop_$(p[1]:B) ] ; + stacktrace_tests += [ run $(p) : : : <debug-symbols>on $(LINKSHARED_BASIC) $(additional_dependency) : basic_$(p[1]:B) ] ; + + + ##### Tests with disabled debug symbols ##### + + stacktrace_tests += [ run $(p) : : : <debug-symbols>off $(LINKSHARED_BT) $(additional_dependency) : backtrace_$(p[1]:B)_no_dbg ] ; + stacktrace_tests += [ run $(p) : : : <debug-symbols>off $(LINKSHARED_AD2L) $(additional_dependency) : addr2line_$(p[1]:B)_no_dbg ] ; + stacktrace_tests += [ run $(p) : : : <debug-symbols>off $(LINKSHARED_WIND) $(additional_dependency) : windbg_$(p[1]:B)_no_dbg ] ; + stacktrace_tests += [ run $(p) : : : <debug-symbols>off $(LINKSHARED_WIND_CACHED) $(additional_dependency) : windbg_cached_$(p[1]:B)_no_dbg ] ; + stacktrace_tests += [ run $(p) : : : <debug-symbols>off $(LINKSHARED_NOOP) $(additional_dependency) : noop_$(p[1]:B)_no_dbg ] ; + stacktrace_tests += [ run $(p) : : : <debug-symbols>off $(LINKSHARED_BASIC) $(additional_dependency) : basic_$(p[1]:B)_no_dbg ] ; + +} + +# Very long tests for detecting memory leaks and corruptions +test-suite stacktrace_torture + : + [ run torture.cpp test_impl.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_BACKTRACE $(BT_DEPS) : torture_backtrace_ho ] + #[ run torture.cpp test_impl.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_ADDR2LINE $(AD2L_DEPS) : torture_addr2line_ho ] + [ run torture.cpp test_impl.cpp : : : <debug-symbols>on $(WIND_DEPS) : torture_windbg_ho ] + [ run torture.cpp test_impl.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_WINDBG_CACHED $(WICA_DEPS) : torture_windbg_cached_ho ] + [ run torture.cpp test_impl.cpp : : : <debug-symbols>on $(FORCE_SYMBOL_EXPORT) $(BASIC_DEPS) : torture_basic_ho ] + [ run torture.cpp test_impl.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_TEST_NO_DEBUG_AT_ALL $(BASIC_DEPS) : torture_basic_ho_empty ] + + [ run torture.cpp test_impl.cpp : : : <debug-symbols>on <library>.//test_impl_lib_backtrace $(LINKSHARED_BT) : torture_backtrace_lib ] + #[ run torture.cpp test_impl.cpp : : : <debug-symbols>on <library>.//test_impl_lib_addr2line $(LINKSHARED_AD2L) : torture_addr2line_lib ] + [ run torture.cpp test_impl.cpp : : : <debug-symbols>on <library>.//test_impl_lib_windbg $(LINKSHARED_WIND) : torture_windbg_lib ] + [ run torture.cpp test_impl.cpp : : : <debug-symbols>on <library>.//test_impl_lib_windbg_cached $(LINKSHARED_WIND_CACHED) : torture_windbg_cached_lib ] + [ run torture.cpp test_impl.cpp : : : <debug-symbols>on <library>.//test_impl_lib_basic $(LINKSHARED_BASIC) : torture_basic_lib ] + ; +explicit stacktrace_torture ; + diff --git a/src/boost/libs/stacktrace/test/test.cpp b/src/boost/libs/stacktrace/test/test.cpp new file mode 100644 index 00000000..949bef4a --- /dev/null +++ b/src/boost/libs/stacktrace/test/test.cpp @@ -0,0 +1,282 @@ +// Copyright Antony Polukhin, 2016-2019. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/stacktrace/stacktrace_fwd.hpp> + +#include <boost/stacktrace.hpp> +#include <stdexcept> +#include <iostream> +#include <sstream> +#include <cctype> + +#include <boost/core/lightweight_test.hpp> + +#include <boost/functional/hash.hpp> + +#include "test_impl.hpp" + +using boost::stacktrace::stacktrace; +using boost::stacktrace::frame; + + +#if (defined(BOOST_GCC) && defined(BOOST_WINDOWS) && !defined(BOOST_STACKTRACE_USE_BACKTRACE) && !defined(BOOST_STACKTRACE_USE_ADDR2LINE)) \ + || defined(BOOST_STACKTRACE_TEST_NO_DEBUG_AT_ALL) + +# define BOOST_STACKTRACE_TEST_SHOULD_OUTPUT_READABLE_NAMES 0 +#else +# define BOOST_STACKTRACE_TEST_SHOULD_OUTPUT_READABLE_NAMES 1 +#endif + +void test_deeply_nested_namespaces() { + std::stringstream ss; + ss << return_from_nested_namespaces(); + std::cout << ss.str() << '\n'; +#if BOOST_STACKTRACE_TEST_SHOULD_OUTPUT_READABLE_NAMES + BOOST_TEST(ss.str().find("main") != std::string::npos); + + BOOST_TEST(ss.str().find("get_backtrace_from_nested_namespaces") != std::string::npos + || ss.str().find("1# return_from_nested_namespaces") != std::string::npos); // GCC with -O1 has strange inlining, so this line is true while the prev one is false. + + BOOST_TEST(ss.str().find("return_from_nested_namespaces") != std::string::npos); +#endif + + stacktrace ns1 = return_from_nested_namespaces(); + BOOST_TEST(ns1 != return_from_nested_namespaces()); // Different addresses in test_deeply_nested_namespaces() function +} + +std::size_t count_unprintable_chars(const std::string& s) { + std::size_t result = 0; + for (std::size_t i = 0; i < s.size(); ++i) { + result += (std::isprint(s[i]) ? 0 : 1); + } + + return result; +} + +void test_frames_string_data_validity() { + stacktrace trace = return_from_nested_namespaces(); + for (std::size_t i = 0; i < trace.size(); ++i) { + BOOST_TEST_EQ(count_unprintable_chars(trace[i].source_file()), 0); + BOOST_TEST_EQ(count_unprintable_chars(trace[i].name()), 0); + } + + BOOST_TEST(to_string(trace).find('\0') == std::string::npos); +} + +// Template parameter Depth is to produce different functions on each Depth. This simplifies debugging when one of the tests catches error +template <std::size_t Depth> +void test_nested(bool print = true) { + std::pair<stacktrace, stacktrace> res = function_from_library(Depth, function_from_main_translation_unit); + + std::stringstream ss1, ss2; + + ss1 << res.first; + ss2 << res.second; + if (print) { + std::cout << "'" << ss1.str() << "'\n\n" << ss2.str() << std::endl; + } + BOOST_TEST(!ss1.str().empty()); + BOOST_TEST(!ss2.str().empty()); + + BOOST_TEST(ss1.str().find(" 0# ") != std::string::npos); + BOOST_TEST(ss2.str().find(" 0# ") != std::string::npos); + + BOOST_TEST(ss1.str().find(" 1# ") != std::string::npos); + BOOST_TEST(ss2.str().find(" 1# ") != std::string::npos); + + BOOST_TEST(ss1.str().find(" in ") != std::string::npos); + BOOST_TEST(ss2.str().find(" in ") != std::string::npos); + +#if BOOST_STACKTRACE_TEST_SHOULD_OUTPUT_READABLE_NAMES + BOOST_TEST(ss1.str().find("main") != std::string::npos); + BOOST_TEST(ss2.str().find("main") != std::string::npos); + + BOOST_TEST(ss1.str().find("function_from_library") != std::string::npos); + BOOST_TEST(ss2.str().find("function_from_library") != std::string::npos); + + BOOST_TEST(ss1.str().find("function_from_main_translation_unit") != std::string::npos); + BOOST_TEST(ss2.str().find("function_from_main_translation_unit") != std::string::npos); +#endif +} + +template <class Bt> +void test_comparisons_base(Bt nst, Bt st) { + Bt cst(st); + st = st; + cst = cst; + BOOST_TEST(nst); + BOOST_TEST(st); +#if !defined(BOOST_MSVC) && !defined(BOOST_STACKTRACE_USE_WINDBG) + // This is very dependent on compiler and link flags. No sane way to make it work, because + // BOOST_NOINLINE could be ignored by MSVC compiler if link-time optimization is enabled. + BOOST_TEST(nst[0] != st[0]); +#endif + + BOOST_TEST(nst != st); + BOOST_TEST(st != nst); + BOOST_TEST(st == st); + BOOST_TEST(nst == nst); + + BOOST_TEST(nst != cst); + BOOST_TEST(cst != nst); + BOOST_TEST(cst == st); + BOOST_TEST(cst == cst); + + BOOST_TEST(nst < st || nst > st); + BOOST_TEST(st < nst || nst < st); + BOOST_TEST(st <= st); + BOOST_TEST(nst <= nst); + BOOST_TEST(st >= st); + BOOST_TEST(nst >= nst); + + BOOST_TEST(nst < cst || cst < nst); + BOOST_TEST(nst > cst || cst > nst); + + + BOOST_TEST(hash_value(nst) == hash_value(nst)); + BOOST_TEST(hash_value(cst) == hash_value(st)); + + BOOST_TEST(hash_value(nst) != hash_value(cst)); + BOOST_TEST(hash_value(st) != hash_value(nst)); +} + +void test_comparisons() { + stacktrace nst = return_from_nested_namespaces(); + stacktrace st; + test_comparisons_base(nst, st); +} + +void test_iterators() { + stacktrace st; + + BOOST_TEST(st.begin() == st.begin()); + BOOST_TEST(st.cbegin() == st.cbegin()); + BOOST_TEST(st.crbegin() == st.crbegin()); + BOOST_TEST(st.rbegin() == st.rbegin()); + + BOOST_TEST(st.begin() + 1 == st.begin() + 1); + BOOST_TEST(st.cbegin() + 1 == st.cbegin() + 1); + BOOST_TEST(st.crbegin() + 1 == st.crbegin() + 1); + BOOST_TEST(st.rbegin() + 1 == st.rbegin() + 1); + + BOOST_TEST(st.end() == st.end()); + BOOST_TEST(st.cend() == st.cend()); + BOOST_TEST(st.crend() == st.crend()); + BOOST_TEST(st.rend() == st.rend()); + + BOOST_TEST(st.end() > st.begin()); + BOOST_TEST(st.end() > st.cbegin()); + BOOST_TEST(st.cend() > st.cbegin()); + BOOST_TEST(st.cend() > st.begin()); + + BOOST_TEST(st.size() == static_cast<std::size_t>(st.end() - st.begin())); + BOOST_TEST(st.size() == static_cast<std::size_t>(st.end() - st.cbegin())); + BOOST_TEST(st.size() == static_cast<std::size_t>(st.cend() - st.cbegin())); + BOOST_TEST(st.size() == static_cast<std::size_t>(st.cend() - st.begin())); + + BOOST_TEST(st.size() == static_cast<std::size_t>(std::distance(st.rbegin(), st.rend()))); + BOOST_TEST(st.size() == static_cast<std::size_t>(std::distance(st.crbegin(), st.rend()))); + BOOST_TEST(st.size() == static_cast<std::size_t>(std::distance(st.crbegin(), st.crend()))); + BOOST_TEST(st.size() == static_cast<std::size_t>(std::distance(st.rbegin(), st.crend()))); + + + boost::stacktrace::stacktrace::iterator it = st.begin(); + ++ it; + BOOST_TEST(it == st.begin() + 1); +} + +void test_frame() { + stacktrace nst = return_from_nested_namespaces(); + stacktrace st = make_some_stacktrace1(); + + const std::size_t min_size = (nst.size() < st.size() ? nst.size() : st.size()); + BOOST_TEST(min_size > 2); + + for (std::size_t i = 0; i < min_size; ++i) { + BOOST_TEST(st[i] == st[i]); + BOOST_TEST(st[i].source_file() == st[i].source_file()); + BOOST_TEST(st[i].source_line() == st[i].source_line()); + BOOST_TEST(st[i] <= st[i]); + BOOST_TEST(st[i] >= st[i]); + + frame fv = nst[i]; + BOOST_TEST(fv); + if (i > 1 && i < min_size - 3) { // Begin ...and end of the trace may match, skipping + BOOST_TEST(st[i] != fv); + +#if !(defined(BOOST_STACKTRACE_TEST_NO_DEBUG_AT_ALL) && defined(BOOST_MSVC)) + // MSVC can not get function name withhout debug symbols even if it is exported + 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)); +#endif + + if (st[i].source_line()) { + BOOST_TEST(st[i].source_file() != fv.source_file() || st[i].source_line() != fv.source_line()); + } + 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_EQ(empty_frame.source_file(), ""); + BOOST_TEST_EQ(empty_frame.name(), ""); + BOOST_TEST_EQ(empty_frame.source_line(), 0); +} + +// Template parameter bool BySkip is to produce different functions on each BySkip. This simplifies debugging when one of the tests catches error +template <bool BySkip> +void test_empty_basic_stacktrace() { + typedef boost::stacktrace::stacktrace st_t; + st_t st = BySkip ? st_t(100500, 1024) : st_t(0, 0); + + BOOST_TEST(!st); + BOOST_TEST(st.empty()); + BOOST_TEST(st.size() == 0); + BOOST_TEST(st.begin() == st.end()); + BOOST_TEST(st.cbegin() == st.end()); + BOOST_TEST(st.cbegin() == st.cend()); + BOOST_TEST(st.begin() == st.cend()); + + BOOST_TEST(st.rbegin() == st.rend()); + BOOST_TEST(st.crbegin() == st.rend()); + BOOST_TEST(st.crbegin() == st.crend()); + BOOST_TEST(st.rbegin() == st.crend()); + + BOOST_TEST(hash_value(st) == hash_value(st_t(0, 0))); + BOOST_TEST(st == st_t(0, 0)); + BOOST_TEST(!(st < st_t(0, 0))); + BOOST_TEST(!(st > st_t(0, 0))); +} + +int main() { + test_deeply_nested_namespaces(); + test_frames_string_data_validity(); + test_nested<15>(); + test_comparisons(); + test_iterators(); + test_frame(); + test_empty_basic_stacktrace<true>(); + test_empty_basic_stacktrace<false>(); + + BOOST_TEST(&make_some_stacktrace1 != &make_some_stacktrace2); + boost::stacktrace::stacktrace b1 = make_some_stacktrace1(); + BOOST_TEST(b1.size() == 4); + boost::stacktrace::stacktrace b2 = make_some_stacktrace2(); + BOOST_TEST(b2.size() == 4); + test_comparisons_base(make_some_stacktrace1(), make_some_stacktrace2()); + + test_nested<260>(false); + BOOST_TEST(boost::stacktrace::stacktrace(0, 1).size() == 1); + BOOST_TEST(boost::stacktrace::stacktrace(1, 1).size() == 1); + + return boost::report_errors(); +} diff --git a/src/boost/libs/stacktrace/test/test_impl.cpp b/src/boost/libs/stacktrace/test/test_impl.cpp new file mode 100644 index 00000000..9078cc50 --- /dev/null +++ b/src/boost/libs/stacktrace/test/test_impl.cpp @@ -0,0 +1,72 @@ +// Copyright Antony Polukhin, 2016-2019. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_STACKTRACE_TEST_IMPL_LIB 1 +#include "test_impl.hpp" + +using namespace boost::stacktrace; + +BOOST_ST_API BOOST_NOINLINE std::pair<stacktrace, stacktrace> function_from_library(int i, foo1_t foo1) { + if (i) { + return foo1(--i); + } else { + return foo1(i); + } +} + + +namespace very_very_very_very_very_very_long_namespace { +namespace very_very_very_very_very_very_long_namespace { +namespace very_very_very_very_very_very_long_namespace { +namespace very_very_very_very_very_very_long_namespace { +namespace very_very_very_very_very_very_long_namespace { +namespace very_very_very_very_very_very_long_namespace { +namespace very_very_very_very_very_very_long_namespace { +namespace very_very_very_very_very_very_long_namespace { +namespace very_very_very_very_very_very_long_namespace { +namespace very_very_very_very_very_very_long_namespace { + BOOST_ST_API BOOST_NOINLINE stacktrace get_backtrace_from_nested_namespaces() { + return stacktrace(); + } +}}}}}}}}}} + +BOOST_ST_API BOOST_NOINLINE stacktrace return_from_nested_namespaces() { + using very_very_very_very_very_very_long_namespace::very_very_very_very_very_very_long_namespace::very_very_very_very_very_very_long_namespace + ::very_very_very_very_very_very_long_namespace::very_very_very_very_very_very_long_namespace::very_very_very_very_very_very_long_namespace + ::very_very_very_very_very_very_long_namespace::very_very_very_very_very_very_long_namespace::very_very_very_very_very_very_long_namespace + ::very_very_very_very_very_very_long_namespace::get_backtrace_from_nested_namespaces; + + return get_backtrace_from_nested_namespaces(); +} + +BOOST_ST_API BOOST_NOINLINE boost::stacktrace::stacktrace make_some_stacktrace1_impl(int d = 0) { + boost::stacktrace::stacktrace result(0, 4); + if (result.size() < 4) { + if (d > 4) throw std::runtime_error("Stack is not growing in test OR stacktrace fails to work in `bar1` function."); + return make_some_stacktrace1_impl(d + 1); + } + return result; +} + +BOOST_ST_API BOOST_NOINLINE boost::stacktrace::stacktrace make_some_stacktrace2_impl(int d = 0) { + boost::stacktrace::stacktrace result(0, 4); + if (result.size() < 4) { + if (d > 4) throw std::runtime_error("Stack is not growing in test OR stacktrace fails to work in `bar2` function."); + return make_some_stacktrace2_impl(d + 1); + } + return result; +} + +BOOST_ST_API BOOST_NOINLINE boost::stacktrace::stacktrace make_some_stacktrace1() { + boost::stacktrace::stacktrace result = make_some_stacktrace1_impl(); + return result; +} + +BOOST_ST_API BOOST_NOINLINE boost::stacktrace::stacktrace make_some_stacktrace2() { + boost::stacktrace::stacktrace result = make_some_stacktrace2_impl(); + return result; +} + diff --git a/src/boost/libs/stacktrace/test/test_impl.hpp b/src/boost/libs/stacktrace/test/test_impl.hpp new file mode 100644 index 00000000..e7a34981 --- /dev/null +++ b/src/boost/libs/stacktrace/test/test_impl.hpp @@ -0,0 +1,58 @@ +// Copyright Antony Polukhin, 2016-2019. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + + +#include <boost/stacktrace/stacktrace.hpp> + +#if defined(BOOST_LEXICAL_CAST_TRY_LEXICAL_CONVERT_HPP) || defined(BOOST_LEXICAL_CAST_BAD_LEXICAL_CAST_HPP) +#error "LexicalCast headers leaked into the boost/stacktrace/stacktrace.hpp" +#endif + +#if !defined(BOOST_USE_WINDOWS_H) && defined(_WINDOWS_H) +#error "windows.h header leaked into the boost/stacktrace/stacktrace.hpp" +#endif + +#include <stdexcept> + +using namespace boost::stacktrace; + +#ifdef BOOST_STACKTRACE_DYN_LINK +# ifdef BOOST_STACKTRACE_TEST_IMPL_LIB +# define BOOST_ST_API BOOST_SYMBOL_EXPORT +# else +# define BOOST_ST_API BOOST_SYMBOL_IMPORT +# endif +#else +# ifdef BOOST_STACKTRACE_TEST_EXPORTS_TABLE_USAGE +# define BOOST_ST_API BOOST_SYMBOL_VISIBLE +# else +# define BOOST_ST_API +# endif +#endif + +typedef std::pair<boost::stacktrace::stacktrace, boost::stacktrace::stacktrace> st_pair; +typedef st_pair (*foo1_t)(int i); +BOOST_ST_API st_pair function_from_library(int i, foo1_t foo1); +BOOST_ST_API boost::stacktrace::stacktrace return_from_nested_namespaces(); +BOOST_ST_API boost::stacktrace::stacktrace make_some_stacktrace1(); +BOOST_ST_API boost::stacktrace::stacktrace make_some_stacktrace2(); + +#ifdef BOOST_STACKTRACE_TEST_EXPORTS_TABLE_USAGE + BOOST_SYMBOL_VISIBLE +#endif +inline st_pair function_from_main_translation_unit(int i) { + if (i) { + return function_from_library(i - 1, function_from_main_translation_unit); + } + + std::pair<stacktrace, stacktrace> ret; + try { + throw std::logic_error("test"); + } catch (const std::logic_error& /*e*/) { + ret.second = stacktrace(); + return ret; + } +} diff --git a/src/boost/libs/stacktrace/test/test_noop.cpp b/src/boost/libs/stacktrace/test/test_noop.cpp new file mode 100644 index 00000000..057a635a --- /dev/null +++ b/src/boost/libs/stacktrace/test/test_noop.cpp @@ -0,0 +1,58 @@ +// Copyright Antony Polukhin, 2016-2019. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include "test_impl.hpp" + +#include <boost/stacktrace.hpp> +#include <boost/core/lightweight_test.hpp> +#include <stdexcept> + + +#include <boost/functional/hash.hpp> + +using boost::stacktrace::stacktrace; +using boost::stacktrace::frame; + +void test_deeply_nested_namespaces() { + BOOST_TEST(return_from_nested_namespaces().size() == 0); + BOOST_TEST(return_from_nested_namespaces().empty()); + BOOST_TEST(!return_from_nested_namespaces()); +} + +void test_nested() { + std::pair<stacktrace, stacktrace> res = function_from_library(15, function_from_main_translation_unit); + + BOOST_TEST(!res.first); + BOOST_TEST(res.first.empty()); + BOOST_TEST(res.first.size() == 0); + + BOOST_TEST(res.second <= res.first); + BOOST_TEST(res.second >= res.first); + BOOST_TEST(res.second == res.first); + BOOST_TEST(res.second == res.first); + 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); + + boost::stacktrace::frame f(0); + BOOST_TEST(f.name() == ""); + BOOST_TEST(f.source_file() == ""); + BOOST_TEST(f.source_line() == 0); +} + +int main() { + test_deeply_nested_namespaces(); + test_nested(); + test_empty_frame(); + + return boost::report_errors(); +} diff --git a/src/boost/libs/stacktrace/test/test_num_conv.cpp b/src/boost/libs/stacktrace/test/test_num_conv.cpp new file mode 100644 index 00000000..abad6d5f --- /dev/null +++ b/src/boost/libs/stacktrace/test/test_num_conv.cpp @@ -0,0 +1,71 @@ +// Copyright Antony Polukhin, 2016-2019. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/stacktrace/detail/to_dec_array.hpp> +#include <boost/stacktrace/detail/to_hex_array.hpp> +#include <boost/stacktrace/detail/try_dec_convert.hpp> + +#include <boost/core/lightweight_test.hpp> +#include <string> +#include <iostream> + + +void test_to_hex_array() { + const void* ptr = 0; + BOOST_TEST(std::string(boost::stacktrace::detail::to_hex_array(ptr).data()).find("0x0") != std::string::npos); + + ptr = reinterpret_cast<const void*>(0x10); + BOOST_TEST(std::string(boost::stacktrace::detail::to_hex_array(ptr).data()).find("10") != std::string::npos); + + ptr = reinterpret_cast<void*>(0x19); + BOOST_TEST(std::string(boost::stacktrace::detail::to_hex_array(ptr).data()).find("19") != std::string::npos); + + ptr = reinterpret_cast<void*>(0x999999); + BOOST_TEST(std::string(boost::stacktrace::detail::to_hex_array(ptr).data()).find("999999") != std::string::npos); +} + +void test_to_dec_array() { + BOOST_TEST_EQ(std::string(boost::stacktrace::detail::to_dec_array(0).data()), std::string("0")); + BOOST_TEST_EQ(std::string(boost::stacktrace::detail::to_dec_array(10).data()), std::string("10")); + BOOST_TEST_EQ(std::string(boost::stacktrace::detail::to_dec_array(19).data()), std::string("19")); + BOOST_TEST_EQ(std::string(boost::stacktrace::detail::to_dec_array(999999).data()), std::string("999999")); +} + +void test_try_dec_convert() { + std::size_t res = 0; + + BOOST_TEST(boost::stacktrace::detail::try_dec_convert("0", res)); + BOOST_TEST(res == 0); + + BOOST_TEST(boost::stacktrace::detail::try_dec_convert("+0", res)); + BOOST_TEST(res == 0); + + BOOST_TEST(boost::stacktrace::detail::try_dec_convert("10", res)); + BOOST_TEST(res == 10); + + BOOST_TEST(boost::stacktrace::detail::try_dec_convert("19", res)); + BOOST_TEST(res == 19); + + BOOST_TEST(boost::stacktrace::detail::try_dec_convert("+19", res)); + BOOST_TEST(res == 19); + + BOOST_TEST(boost::stacktrace::detail::try_dec_convert("9999", res)); + BOOST_TEST(res == 9999); + + BOOST_TEST(!boost::stacktrace::detail::try_dec_convert("q", res)); + BOOST_TEST(!boost::stacktrace::detail::try_dec_convert("0z", res)); + BOOST_TEST(!boost::stacktrace::detail::try_dec_convert("0u", res)); + BOOST_TEST(!boost::stacktrace::detail::try_dec_convert("+0u", res)); +} + + +int main() { + test_to_hex_array(); + test_to_dec_array(); + test_try_dec_convert(); + + return boost::report_errors(); +} diff --git a/src/boost/libs/stacktrace/test/test_void_ptr_cast.cpp b/src/boost/libs/stacktrace/test/test_void_ptr_cast.cpp new file mode 100644 index 00000000..5e569649 --- /dev/null +++ b/src/boost/libs/stacktrace/test/test_void_ptr_cast.cpp @@ -0,0 +1,79 @@ +// Copyright 2017 Antony Polukhin. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/stacktrace/detail/void_ptr_cast.hpp> + +#include <boost/core/lightweight_test.hpp> + +int foo1_func(int) { return 0; } +void foo2_func(int, int, ...) {} + +struct test_struct { + int foo1_memb(int) const { return 0; } + void foo2_memb(int, int, ...) {} +}; + +template <class F1, class F2> +void test(F1 foo1, F2 foo2) { + using boost::stacktrace::detail::void_ptr_cast; + + typedef void(*void_f_ptr)(); + + // Function/variable to void(*)() + void_f_ptr fp1 = void_ptr_cast<void_f_ptr>(foo1); + void_f_ptr fp2 = void_ptr_cast<void_f_ptr>(foo2); + BOOST_TEST(fp1); + BOOST_TEST(fp2); + BOOST_TEST(fp1 != fp2); + + // Function/variable to void* + void* vp1 = void_ptr_cast<void*>(foo1); + void* vp2 = void_ptr_cast<void*>(foo2); + BOOST_TEST(vp1); + BOOST_TEST(vp2); + BOOST_TEST(vp1 != vp2); + + // void* to void(*)() + void_f_ptr fp1_2 = void_ptr_cast<void_f_ptr>(vp1); + void_f_ptr fp2_2 = void_ptr_cast<void_f_ptr>(vp2); + BOOST_TEST(fp1_2); + BOOST_TEST(fp2_2); + BOOST_TEST(fp1_2 != fp2_2); + BOOST_TEST(fp1 == fp1_2); + BOOST_TEST(fp2 == fp2_2); + + // void(*)() to void* + BOOST_TEST(void_ptr_cast<void*>(fp1) == vp1); + BOOST_TEST(void_ptr_cast<void*>(fp2) == vp2); + + // void(*)() to function/variable + BOOST_TEST(void_ptr_cast<F1>(fp1) == foo1); + BOOST_TEST(void_ptr_cast<F2>(fp2) == foo2); + + // void* to function/variable + BOOST_TEST(void_ptr_cast<F1>(vp1) == foo1); + BOOST_TEST(void_ptr_cast<F2>(vp2) == foo2); +} + +int main() { + // Testing for functions + test(foo1_func, foo2_func); + + typedef void(func_t)(); + test( + boost::stacktrace::detail::void_ptr_cast<func_t* const>(foo1_func), + boost::stacktrace::detail::void_ptr_cast<func_t* const>(foo2_func) + ); + + // Testing for variables (just in case...) + int i = 0; + double j= 1; + test(&i, &j); + + + + return boost::report_errors(); +} diff --git a/src/boost/libs/stacktrace/test/thread_safety_checking.cpp b/src/boost/libs/stacktrace/test/thread_safety_checking.cpp new file mode 100644 index 00000000..98d9c23a --- /dev/null +++ b/src/boost/libs/stacktrace/test/thread_safety_checking.cpp @@ -0,0 +1,72 @@ +// Copyright Antony Polukhin, 2016-2019. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include "test_impl.hpp" +#include <boost/stacktrace/stacktrace_fwd.hpp> + +#include <sstream> + +#include <boost/stacktrace.hpp> +#include <boost/thread.hpp> +#include <boost/optional.hpp> +#include <boost/core/lightweight_test.hpp> + +#include <boost/timer/timer.hpp> + +using boost::stacktrace::stacktrace; + + +void main_test_loop() { + std::size_t loops = 100; + int Depth = 25; + + boost::optional<std::pair<stacktrace, stacktrace> > ethalon; + std::stringstream ss_ethalon; + + while (--loops) { + std::pair<stacktrace, stacktrace> res = function_from_library(Depth, function_from_main_translation_unit); + if (ethalon) { + BOOST_TEST(res == *ethalon); + + std::stringstream ss; + ss << res.first; + BOOST_TEST(ss.str() == ss_ethalon.str()); + } else { + ethalon = res; + ss_ethalon << ethalon->first; + } + } +} + +#if defined(BOOST_STACKTRACE_TEST_COM_PREINIT_MT) || defined(BOOST_STACKTRACE_TEST_COM_PREINIT_ST) +# include <windows.h> +# include "dbgeng.h" +#endif + +int main() { +#if defined(BOOST_STACKTRACE_TEST_COM_PREINIT_MT) + ::CoInitializeEx(0, COINIT_MULTITHREADED); +#elif defined(BOOST_STACKTRACE_TEST_COM_PREINIT_ST) + ::CoInitializeEx(0, COINIT_APARTMENTTHREADED); +#endif + + boost::timer::auto_cpu_timer t; + + boost::thread t1(main_test_loop); + boost::thread t2(main_test_loop); + boost::thread t3(main_test_loop); + main_test_loop(); + + t1.join(); + t2.join(); + t3.join(); + +#if defined(BOOST_STACKTRACE_TEST_COM_PREINIT_MT) || defined(BOOST_STACKTRACE_TEST_COM_PREINIT_ST) + ::CoUninitialize(); +#endif + + return boost::report_errors(); +} diff --git a/src/boost/libs/stacktrace/test/torture.cpp b/src/boost/libs/stacktrace/test/torture.cpp new file mode 100644 index 00000000..2df475de --- /dev/null +++ b/src/boost/libs/stacktrace/test/torture.cpp @@ -0,0 +1,26 @@ +// Copyright Antony Polukhin, 2018. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + + +// This file tests for memory leaks. Some of the backtrace implementations +// consume memory for internal needs and incorrect usage of those implementations +// could lead to segfaults. Sanitizers do not detect such misuse, but this +// test and `top` does. + + +#include <boost/stacktrace.hpp> +#include <iostream> + +#include "test_impl.hpp" + +int main() { + int result = 0; + for (unsigned i = 0; i < 10000000; ++i) { + result += make_some_stacktrace1()[0].source_line(); + } + + std::cerr << "OK\nLines count " << result; +} |