Compare commits

...

191 Commits

Author SHA1 Message Date
Antony Polukhin
a33e198cf6 More clarifications for async-signal-safety (refs #131) (#156) 2024-03-04 11:45:49 +03:00
Antony Polukhin
824f0c0ea7 Clarify the async-signal-safety guarantees in docs (refs #131) (#154) 2024-02-29 20:47:13 +03:00
Antony Polukhin
f783534b0f Fix frame_msvc.ipp compilation 2024-02-23 14:04:26 +03:00
Antony Polukhin
27093f24cb Update frame_msvc.ipp 2024-02-23 13:50:11 +03:00
Antony Polukhin
12e07fcca1 CI fixes (#153)
* Update thread_safety_checking.cpp to use Standard Library types
* Remove MinGW runs due to https://github.com/boostorg/system/issues/116
* Delete the shared memory example sources
2024-02-22 09:12:00 +03:00
Antony Polukhin
95caaeaf99 Option to disable boost_stacktrace_from_exception library build 2024-02-17 10:26:49 +03:00
Antony Polukhin
906bb0b551 Add unignorable info on memory leaks for affected platforms (#150) 2024-02-16 08:49:57 +03:00
Antony Polukhin
87ef7f6950 Fix build (failure was noted in #147) (#151) 2024-02-15 09:19:27 +03:00
Antony Polukhin
f6d4e117cd Add missing include 2024-02-12 22:21:35 +03:00
Antony Polukhin
0d8aed6bc9 Library for getting stacktraces from arbitrary exceptions (#147) 2024-02-07 11:27:45 +03:00
Antony Polukhin
3de5aea554 Merge pull request #149 from Lastique/feature/update_filesystem_usage
Update Boost.Filesystem usage
2024-01-27 11:54:24 +03:00
Andrey Semashev
e9e0b6c3d4 Updated Boost.Filesystem usage.
Removed usage of Boost.Filesystem APIs that were deprecated and
then removed.
2024-01-27 01:28:50 +03:00
Antony Polukhin
1fd3665a71 Allow building stacktrace libraries with global visibility (fixes #146) 2024-01-20 11:03:31 +03:00
Antony Polukhin
0ec802df84 Update copyright years 2024-01-07 13:03:02 +03:00
Antony Polukhin
4f2da0e653 Merge pull request #143 from francesco-ballarin/develop
Add missing cstdint include to detail/addr_base.hpp
2023-10-20 19:02:54 +03:00
Francesco Ballarin
8b1699c9d3 Add missing cstdint include to detail/addr_base.hpp 2023-10-01 10:14:34 +02:00
yhsb2k
dc5cd9d1f3 Fix build with MinGW-w64 12+. (#140)
For more details see: https://github.com/boostorg/stacktrace/issues/133

Accommodate mingw-llvm to this fix as well

macros defined by mingw-llvm 16 (https://github.com/mstorsjo/llvm-mingw):
#define __GNUC_MINOR__ 2
#define __GNUC_PATCHLEVEL__ 1
#define __GNUC__ 4

#define __clang_major__ 16
#define __clang_minor__ 0
#define __clang_patchlevel__ 0
2023-09-02 16:36:27 +03:00
ja2142
fbcd543b51 fix addr2line for pie binaries (#138) 2023-08-27 21:34:56 +03:00
Antony Polukhin
d849b145a6 disable some of the CI tests (2) 2023-08-27 18:27:41 +03:00
Antony Polukhin
760203fde5 disable some of the CI tests 2023-08-27 15:38:09 +03:00
Antony Polukhin
6a7510bd5e Do not produce and explicit hard error if compiler may not support some of the C++11 features 2023-08-27 15:26:56 +03:00
Antony Polukhin
959b65f303 CI fix attempt (3) 2023-08-26 21:18:46 +03:00
Antony Polukhin
d6320cc5a7 CI fix attempt (2) 2023-08-26 17:10:23 +03:00
Antony Polukhin
22a2c3920b CI fix attempt 2023-08-26 10:42:57 +03:00
Antony Polukhin
fc21c82b27 do not run tests on old MSVC in appveyor 2023-08-25 14:14:40 +03:00
Antony Polukhin
ae87ac9bcf update appveyor CI setup 2023-08-25 12:36:33 +03:00
Antony Polukhin
15b12e6e95 run tests on more compilers 2023-08-25 12:09:31 +03:00
Mohammad Nejati
34441a64c8 Use relative URL for redirect in index.html (#137) 2023-08-12 11:27:01 +03:00
Alex
abba18524f Modernize to cpp11 (#139)
Drop support for C++03

Boost.Stacktrace 1.84 now requires C++11.
2023-08-11 21:32:41 +03:00
Antony Polukhin
c6e7712868 update CI (1) 2023-05-21 12:42:28 +03:00
Antony Polukhin
c836328054 update CI setup 2023-05-21 10:45:29 +03:00
Antony Polukhin
71da3cfd56 add C++03 deprecation warnings 2023-05-14 20:06:38 +03:00
Antony Polukhin
95065ca638 Merge pull request #132 from Chocobo1/typo
Fix typos
2023-02-21 14:27:08 +03:00
Chocobo1
b9a0a12f1c Fix typo 2023-02-08 17:45:10 +08:00
Antony Polukhin
4cf47389c1 Update copyright years 2023-01-19 10:21:22 +03:00
Antony Polukhin
d904d26f4f Fix multithreading flag detection for backtrace_create_state if BOOST_STACKTRACE_BACKTRACE_FORCE_STATIC is defined 2023-01-18 17:16:51 +03:00
Antony Polukhin
cd4c5fe554 fix a type that was noted in https://github.com/boostorg/stacktrace/issues/118#issuecomment-1315142952 2023-01-18 17:14:49 +03:00
Antony Polukhin
12e3743e58 Simplify Jamfile a little-bit
Relates: https://github.com/boostorg/stacktrace/issues/119
2022-09-12 16:29:05 +03:00
Antony Polukhin
6db6fd0c01 Use BOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE while detecting the libbacktrace availability in b2
Fixes: https://github.com/boostorg/stacktrace/issues/115
2022-09-12 15:46:46 +03:00
Antony Polukhin
57db1f511e Update CI 2022-09-02 17:40:44 +03:00
Antony Polukhin
308b7f6b08 allow forcing the static backtrace_state
References: https://github.com/boostorg/stacktrace/issues/118
2022-09-02 12:20:30 +03:00
Antony Polukhin
b856a99f9f fix and make sure that boost/stacktrace/stacktrace.hpp header has no unresolved references
Fixes: https://github.com/boostorg/stacktrace/issues/116
2022-09-02 10:38:17 +03:00
Antony Polukhin
6bf1a98d97 Merge pull request #127 from boostorg/antoshkka/no-more-strlen
avoid strlen() calls by using the size-1 from GetNameByOffset
2022-09-01 19:45:36 +03:00
Antony Polukhin
cc4d16e2ad avoid strlen() calls by using the size-1 from GetNameByOffset
Refs: https://github.com/boostorg/stacktrace/issues/122
2022-09-01 19:02:46 +03:00
Antony Polukhin
7c6778e9f4 Merge pull request #126 from boostorg/antoshkka/no-more-com-init
remove COM-initialization related tests and notes in docs
2022-09-01 18:51:16 +03:00
Antony Polukhin
e5940e7103 remove COM-initialization related tests and notes in docs 2022-09-01 17:51:22 +03:00
Antony Polukhin
bac3611ad8 Merge pull request #123 from AlexGuteniev/windows-dbgeng-tweak
Don't initialize COM, as it is not required
2022-09-01 17:42:13 +03:00
Alex Guteniev
9e8510076d BOOST_STACKTRACE_USE_WINDBG_CACHED support 2022-02-18 20:08:31 +02:00
Alex Guteniev
a60ee55b36 Don't initialize COM
Resolve #121
2022-02-18 19:45:26 +02:00
Antony Polukhin
75b7986f97 update copyright years 2022-01-30 14:47:24 +03:00
Antony Polukhin
3f3f9020fb do not use depth 1 for checkouts in CI 2021-09-20 21:55:43 +03:00
Antony Polukhin
898fedac41 modernize CI setup 2021-09-11 18:15:38 +03:00
Peter Dimov
79aff77771 Fix checks and build to work on Cygwin 2021-06-01 04:26:35 +03:00
Peter Dimov
1be59df18e Do not use find_package(Backtrace) 2021-06-01 03:39:23 +03:00
Peter Dimov
1dae3faf43 Check for backtrace both with Backtrace_HEADER and without it (it's set to execinfo.h on Linux and doesn't work, whereas backtrace.h does) 2021-06-01 02:59:06 +03:00
Peter Dimov
99b7015508 Define BOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE 2021-06-01 01:56:34 +03:00
Peter Dimov
18012f81da Fix spelling of Backtrace_FOUND 2021-06-01 01:38:58 +03:00
Peter Dimov
76f902f366 Add CMakeLists.txt 2021-05-31 23:04:04 +03:00
Antony Polukhin
b37e0d8e9f use HTTPS links in Readme 2021-04-27 11:19:55 +03:00
Antony Polukhin
9a114f8256 update links in Readme, add badges, run coverage reports only from GithubActions 2021-04-24 21:46:32 +03:00
Antony Polukhin
b75a37dc48 do not run on MacOs in GithubActions CI 2021-04-24 20:25:35 +03:00
Antony Polukhin
1631213c0c update CI: fixes 2021-04-24 11:18:22 +03:00
Antony Polukhin
cadf1bc311 update CI: add depinst.py dirs 2021-04-24 10:38:35 +03:00
Antony Polukhin
26f66b58e9 update CIs 2021-04-23 20:38:10 +03:00
Antony Polukhin
7b19672b67 fix broken link 2021-04-23 20:29:34 +03:00
Antony Polukhin
67cc2e9017 Merge pull request #107 from sdarwin/githubactions
GitHub Actions config
2021-04-18 14:10:00 +03:00
sdarwin
4b4472cccb Add GitHub Actions config [ci skip] 2021-03-05 16:25:14 +00:00
Antony Polukhin
08d720adbd attempt to fix coverage reports 2021-01-04 19:08:40 +03:00
Antony Polukhin
a00587f4d7 update copyright years 2021-01-03 19:24:15 +03:00
Antony Polukhin
9c462940b1 Merge pull request #104 from sdarwin/lcov
update lcov in .travis.yml
2021-01-03 12:51:27 +03:00
sdarwin
7fdaebb8ef update lcov in .travis.yml 2020-12-30 15:51:38 +00:00
Antony Polukhin
15f6b30f12 Better support for pre-C++11 builds on clang (fixes #102) 2020-12-19 14:35:28 +03:00
Antony Polukhin
4a8b14b2d7 disable test on Windows 2020-12-18 11:04:34 +03:00
Antony Polukhin
e4576bfae2 attempt to deal with hangs on some platforms 2020-12-16 12:09:01 +03:00
Antony Polukhin
7985a04380 bigger warning for signal handlers (fixes #71) 2020-12-15 17:00:34 +03:00
Antony Polukhin
d84457e2a0 update meta info on stacktrace 2020-12-15 16:51:07 +03:00
Antony Polukhin
66aba44f79 do not recommend safe_dump_to (fixes #98) 2020-12-15 16:48:29 +03:00
Antony Polukhin
e75d2ff93b Merge pull request #91 from jeremiahar/develop
Add support for disabled exceptions
2020-05-28 16:48:43 +03:00
Jeremiah Rodriguez
a8a4cefb52 Add support for disabled exceptions 2020-05-26 13:28:32 -07:00
Antony Polukhin
f931528c87 CI fixes 2020-04-06 18:47:50 +03:00
Antony Polukhin
9b5bc54fe3 provide documentation on distribution of PDBs (fixes #55, #47) 2020-01-23 23:56:01 +03:00
Antony Polukhin
178d2875d7 Remove ugly things from the test (refs #86) 2020-01-21 09:14:40 +03:00
Antony Polukhin
ade7d54dc7 update copyright year 2020-01-18 14:11:02 +03:00
Antony Polukhin
211d291253 Merge pull request #84 from doj/develop
fix typo in stacktrace.qbk
2019-11-17 09:13:49 +03:00
Antony Polukhin
b72cc6cdfd Adjust coverage reports in CI (3) 2019-11-16 17:28:44 +03:00
Antony Polukhin
99e07cbea6 Adjust coverage reports in CI (2) 2019-11-16 13:11:08 +03:00
Antony Polukhin
922305ea7d Adjust CI coverage reports 2019-11-16 12:44:01 +03:00
Antony Polukhin
2fce6957d6 More CI workarounds 2019-11-16 10:51:49 +03:00
Antony Polukhin
2cfcbf4247 Update Jamfile.v2 2019-11-15 19:07:10 +03:00
Dirk Jagdmann
0bddb90c1d fix typo in stacktrace.qbk 2019-11-14 13:29:33 -08:00
Antony Polukhin
b6bc847b0c Fine tune inspect tool 2019-11-12 20:02:46 +03:00
Antony Polukhin
6c5b7e51d5 Install binutils 2019-11-12 19:28:48 +03:00
Antony Polukhin
acf5b12d02 Replace tabs with spaces 2019-11-12 10:16:57 +03:00
Antony Polukhin
9c3bdd4d0e Update .travis.yml 2019-11-12 10:14:53 +03:00
Antony Polukhin
dc0f0c752b CI fixes 2019-11-12 09:51:14 +03:00
Antony Polukhin
09255fc94b Update .travis.yml 2019-11-11 19:21:10 +03:00
Antony Polukhin
293e1f43f6 Typo fix 2019-07-26 19:01:10 +03:00
Antony Polukhin
7379a5cc08 Fix msvc-9 build 2019-07-26 17:12:52 +03:00
Antony Polukhin
7c7271d9bc CI coverage fixes (5) 2019-06-30 15:26:11 +03:00
Antony Polukhin
6007c216b9 CI coverage fixes (4) 2019-06-30 13:16:12 +03:00
Antony Polukhin
d5bbf7853a CI coverage fixes (3) 2019-06-30 12:30:30 +03:00
Antony Polukhin
0be61ab0b8 CI coverage fix (2) 2019-06-30 10:14:44 +03:00
Antony Polukhin
43b837d181 Attempt to fix coverage 2019-06-29 20:43:33 +03:00
Antony Polukhin
2f75119cd0 Use lcov 1.14 2019-06-29 11:40:10 +03:00
Antony Polukhin
36734b1531 Trim null characters on Windows (fixes #78) 2019-06-29 10:44:27 +03:00
Antony Polukhin
2d810e294f Try to reproduce the error from #78 in tests 2019-06-28 22:38:49 +03:00
Antony Polukhin
6e79da7420 Fix frame info output with TSAN 2019-06-28 11:12:35 +03:00
Antony Polukhin
71acd94944 Fix empty frame info output with TSAN 2019-06-28 10:41:44 +03:00
Antony Polukhin
324a303fb0 Better diagnostics for test 2019-06-27 13:17:08 +03:00
Antony Polukhin
876349f0d6 Use gold linker for TSAN 2019-06-27 10:38:37 +03:00
Antony Polukhin
63d5d2730f Fix CI runs with thread sanitizer 2019-06-26 18:11:26 +03:00
Antony Polukhin
248eedd52f Fix ubsan library version 2019-06-26 14:50:20 +03:00
Antony Polukhin
c906a69c1d Test on GCC-8 because of tsan issues in GCC-6 2019-06-26 13:46:45 +03:00
Antony Polukhin
4f9da2ae71 Manually force rebuild for thread sanitizer tests 2019-06-26 13:12:34 +03:00
Antony Polukhin
1ad62e582a Add comment about async signal safety for PR #70 2019-01-12 22:37:31 +03:00
Antony Polukhin
5c6740b680 Merge branch 'develop' of github.com:boostorg/stacktrace into develop 2019-01-12 22:15:24 +03:00
Antony Polukhin
d9d6512743 Update copyright years 2019-01-12 22:15:16 +03:00
Antony Polukhin
158a59ae51 Merge pull request #70 from ivanarh/use_execinfo_backtrace
Added an option to use libc backtrace function from execinfo.h
2019-01-11 21:59:44 +03:00
Antony Polukhin
839a1a127d Update collect_unwind.ipp 2019-01-11 13:27:43 +03:00
Ivan Ponomarev
411d92cbf3 Forced backtrace() function usage on iOS, 32-bit ARM architecture. Used macros from Boost predef. 2019-01-09 23:07:37 +03:00
Ivan Ponomarev
1b7956a40d Added an ability to use libc backtrace() function (from execinfo.h) instead of _Unwind_Backtrace on Unix-like systems. Useful on iOS 32-bit ARM where _Unwind_Backtrace symbol is undefined. 2019-01-09 01:04:47 +03:00
Antony Polukhin
d708d17ecd Suppress warning (fixes #69) 2019-01-05 13:48:53 +03:00
Antony Polukhin
d946b124ba Fix typo noted by Telegram user PRoSToC0der 2018-12-13 11:00:33 +03:00
Antony Polukhin
39486260ae Merge pull request #67 from JanEisenhauer/develop
Collect at most as many frames as requested.
2018-10-30 10:49:47 +03:00
Jan Eisenhauer
cbd625bd91 fixup! Postprocessing to limit the trace to max_depth is no longer necessary. 2018-10-29 15:12:34 +01:00
Jan Eisenhauer
b08dab1c44 Postprocessing to limit the trace to max_depth is no longer necessary. 2018-10-29 14:34:16 +01:00
Jan Eisenhauer
77405d8d7f Collect at most as many frames as requested. 2018-10-29 14:30:59 +01:00
Jan Eisenhauer
324a24abba Evade the min macro from Windows headers. 2018-10-29 14:06:42 +01:00
Jan Eisenhauer
5e85e7414a Collect at most as many frames as requested. 2018-10-29 13:27:36 +01:00
Antony Polukhin
4123beb4af fix memory consumption when using libbacktrace and speedup trace decoding 2018-10-07 20:08:27 +03:00
Antony Polukhin
f0a9ba6809 Add long tests that detect leaks 2018-10-06 20:39:13 +03:00
Antony Polukhin
b414d35518 Add missing include 2018-10-05 11:10:17 +03:00
Antony Polukhin
42bf318144 Make the traces comparison test more reliable 2018-10-05 10:58:36 +03:00
Antony Polukhin
61c94e65e1 force the hidden visibility using new b2 feature 2018-09-22 22:05:30 +03:00
Antony Polukhin
d573d2a405 add tests for basic impl for cases when symbols are not exported 2018-09-19 23:12:47 +03:00
Antony Polukhin
9f232606cb make tests less verbose 2018-09-19 23:03:47 +03:00
Antony Polukhin
d6f0c65a83 fix typos and use BOOST_SYMBOL_VISIBLE 2018-09-17 09:56:24 +03:00
Antony Polukhin
3089b733a8 Win related issues in tests fixed 2018-09-17 00:12:46 +03:00
Antony Polukhin
99da94f5bd Rework the tests, deal with visibility issues, make sure that libbacktrace implementation now uses export tables 2018-09-16 23:23:33 +03:00
Antony Polukhin
3f047cbfc4 Fix damn web ui artifacts 2018-09-13 20:25:59 +03:00
Antony Polukhin
e14dd6560a Fixes for tests run with hidden visibility
Related to the changes in https://github.com/boostorg/boost/pull/190
2018-09-13 19:58:55 +03:00
Antony Polukhin
f328647e45 More docs improvemnts for the #62 2018-09-13 18:23:37 +03:00
Antony Polukhin
6d101ba4d6 Improve docs for #62 2018-09-13 18:19:56 +03:00
Antony Polukhin
c63afe54a2 Fix #61 2018-08-29 12:37:40 +03:00
Antony Polukhin
745c6aa7a0 Merge pull request #60 from driesdeschout/develop
Libbacktrace fallback to sym info when debug info is missing or incomplete
2018-08-20 10:18:19 +03:00
Dries Deschout
7a595a164f Fix style 2018-08-20 09:03:12 +02:00
Dries Deschout
b4b84780b1 Libbacktrace fallback to sym info in name_impl 2018-08-20 09:02:29 +02:00
Dries Deschout
1289134b6d Libbacktrace fallback to sym info when debug info is missing or incomplete 2018-08-13 14:58:21 +02:00
Antony Polukhin
819f2b1c86 bump copyright years 2018-08-07 22:41:22 +03:00
Antony Polukhin
fb47f17836 Allow to specify exact location of the backtrace.h header. Fixes #59 2018-08-07 22:29:00 +03:00
Antony Polukhin
b8dec8b126 Added to_string function for the boost::stacktrace::basic_stacktrace classes. Fixes #57 2018-07-28 17:12:03 +03:00
Antony Polukhin
7fedfa1265 Add info that the library is proposed for C++20 2018-06-11 18:55:06 +03:00
Antony Polukhin
4a5471a239 const_cast address to void* to avoid compile issues on platforms that have dladdr(void*, Dl_info*). Issue #54 2018-05-23 22:27:46 +03:00
Antony Polukhin
e4e2d4c3c1 Add missing include for tests 2018-04-15 14:19:01 +03:00
Antony Polukhin
14852ad597 Merge pull request #51 from boostorg/droping_dependencies
Drop dependency on lexical_cast and add more tests
2018-04-15 13:02:02 +03:00
Antony Polukhin
87b4789289 Drop dependency on lexical_cast and add more tests 2018-03-14 22:33:04 +03:00
Antony Polukhin
e99f858990 CI linkage fixes (4) 2018-02-23 22:02:22 +03:00
Antony Polukhin
c8165e7cf1 CI linkage fixes(3) 2018-02-23 10:55:01 +03:00
Antony Polukhin
d6e2a56825 CI linkage fixes(2) 2018-02-23 10:40:30 +03:00
Antony Polukhin
f8b8a806ed CI linkage fixes 2018-02-23 10:10:56 +03:00
Antony Polukhin
4603c1725d Fix warning, noted by Daniela Engert 2018-02-20 23:02:00 +03:00
Antony Polukhin
a0f948e9f5 Fix a typo. Fixes #42 2018-02-20 22:55:35 +03:00
Antony Polukhin
7f20c8c676 Disable async unsafe code 2018-01-29 23:22:31 +03:00
Antony Polukhin
31a630ced5 Use boost/container_hash/hash_fwd.hpp instead of manually forward declaring the hash_range function 2018-01-14 23:28:22 +03:00
Antony Polukhin
5b34577683 Relax some tests on Windows (refs #33) 2018-01-14 23:12:44 +03:00
Antony Polukhin
7cf669eaa6 Workaround for Boost.Exception+asan+exit(0) 2018-01-14 22:57:37 +03:00
Antony Polukhin
910fe6ea4e Disable more safe_dump tests for Windows 2018-01-11 22:39:23 +03:00
Antony Polukhin
40b792c7e4 Merge pull request #31 from Lastique/update_winapi
Update Boost.WinAPI usage to the new location and namespace
2018-01-11 22:37:25 +03:00
Antony Polukhin
b658a12183 Merge branch 'develop' into update_winapi 2018-01-11 22:08:11 +03:00
Antony Polukhin
caaea11dfa Merge branch 'develop' into update_winapi 2018-01-11 22:00:14 +03:00
Antony Polukhin
998334c3b5 Checking that safe_dump was causing hangs on Windows 2018-01-11 21:38:04 +03:00
Antony Polukhin
57699543e8 Comment out some C calls that seem to be signal unsafe on Windows 2018-01-11 11:08:07 +03:00
Antony Polukhin
940440bd3e Merge pull request #40 from DanielaE/fix/replace-deprecated-allocator-members
Most members of std::allocate are deprecated in C++17
2018-01-10 23:13:32 +03:00
Daniela Engert
168d9a7544 Most members of std::allocate are deprecated in C++17
Replace them by their cousins from std::allocator_traits.

Signed-off-by: Daniela Engert <dani@ngrt.de>
2017-12-27 18:56:33 +01:00
Antony Polukhin
4fef2cb469 Merge pull request #39 from boostorg/pr/fix-boost-install
Only use boost-install once
2017-12-20 10:53:56 +03:00
Peter Dimov
9523e26aad Only use boost-install once 2017-12-16 21:31:13 +02:00
Antony Polukhin
b7f4710c70 Merge pull request #38 from bebuch/develop
Include winapi only on windows
2017-11-24 23:28:22 +03:00
Benjamin Buch
8f0735d9bd Include winapi only on windows 2017-11-20 10:44:06 +01:00
Antony Polukhin
75f79a1177 Updated the docs to better reflect the MinGW situation. Refs #14, #34, #36 2017-11-12 22:31:35 +03:00
Antony Polukhin
8ab572d823 Docs improved. Fixes #35 2017-11-05 20:13:05 +03:00
Antony Polukhin
cdfac8033e Disable invalid test (refs #33) 2017-10-31 08:50:19 +03:00
Antony Polukhin
c2ac4b28ba Updated docs to describe stacktrace usage with MinGW (refs #14) 2017-10-31 08:44:26 +03:00
Antony Polukhin
8558ac9112 Added missing include. Fixes #32 2017-10-26 22:14:45 +03:00
Andrey Semashev
eba6db7bde Updated Boost.WinAPI usage to the new location and namespace. 2017-10-24 23:51:14 +03:00
Antony Polukhin
87a1285540 Some workarounds for MinGW+libbacktrace (refs #14) 2017-10-24 23:05:28 +03:00
Antony Polukhin
fd3b8c2784 Separate MinGW from MinGW-w64. This fixes some MinGW-w64 issues and simplifies fixage of #14 2017-10-13 21:36:16 +03:00
Antony Polukhin
8364ad1f5e Do not check for _GNU_SOURCE on Windows 2017-08-29 21:34:25 +03:00
Antony Polukhin
b5e2058ec5 Fixes for FreeBSD and other OSes that do not define _GNU_SOURCE but have _Unwind_Backtrace function 2017-08-29 20:27:18 +03:00
Antony Polukhin
af78623e8a Fix installations by renaming the preprocessor files (now uses extension .h instead of .pp). Issue #29 2017-08-27 00:11:43 +03:00
Antony Polukhin
b84d6533f5 Update build testing file (again) to deal with incorrect workaround for mingw 2017-08-08 01:29:06 +03:00
Antony Polukhin
cd420b37ae Update build testing file to deal with MinGW issue https://sourceforge.net/p/mingw-w64/bugs/527/ 2017-08-08 01:18:13 +03:00
67 changed files with 2293 additions and 905 deletions

167
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,167 @@
name: CI
on:
pull_request:
push:
branches:
- master
- develop
- feature/**
env:
UBSAN_OPTIONS: print_stacktrace=1
jobs:
posix:
strategy:
fail-fast: false
matrix:
include:
- toolset: gcc-12
cxxstd: "03,11,14,17,2a"
os: ubuntu-22.04
cxxflags: "cxxflags=--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined"
linkflags: "linkflags=--coverage -lasan -lubsan"
gcov_tool: "gcov-12"
launcher: "testing.launcher=LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libasan.so.8"
- toolset: gcc-9
cxxstd: "03,11,14,17,2a"
os: ubuntu-22.04
- toolset: clang-15
cxxstd: "03,11,14,17,2a"
os: ubuntu-22.04
# TODO: fix and uncomment
#- toolset: clang
# cxxstd: "03,11,14,17,2a"
# os: macos-10.15
# cxxflags: "cxxflags=-fsanitize=address,undefined -fno-sanitize-recover=undefined -D_GNU_SOURCE=1"
# linkflags: "linkflags=-fsanitize=address,undefined"
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
- name: Setup Boost
run: |
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
LIBRARY=${GITHUB_REPOSITORY#*/}
echo LIBRARY: $LIBRARY
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
echo GITHUB_REF: $GITHUB_REF
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
REF=${REF#refs/heads/}
echo REF: $REF
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
echo BOOST_BRANCH: $BOOST_BRANCH
cd ..
git clone -b $BOOST_BRANCH --depth 10 https://github.com/boostorg/boost.git boost-root
cd boost-root
git submodule update --init --depth 10 --jobs 2 tools/boostdep tools/inspect libs/filesystem
python tools/boostdep/depinst/depinst.py --git_args "--depth 10 --jobs 3" filesystem
rm -rf libs/$LIBRARY/*
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
python tools/boostdep/depinst/depinst.py --include benchmark --include example --include examples --include tools --git_args "--depth 10 --jobs 3" $LIBRARY
./bootstrap.sh
./b2 -d0 headers
./b2 -j4 variant=debug tools/inspect/build
- name: Run tests
run: |
cd ../boost-root
./b2 -j3 libs/$LIBRARY/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} variant=debug,release "${{matrix.cxxflags}}" "${{matrix.linkflags}}" "${{matrix.launcher}}"
dist/bin/inspect libs/$LIBRARY
- name: Prepare coverage data
if: matrix.gcov_tool
run: |
mkdir -p $GITHUB_WORKSPACE/coveralls
echo -e "#!/bin/bash\nexec ${{matrix.gcov_tool}} \"\$@\"" > $GITHUB_WORKSPACE/coveralls/gcov_wrapper.sh
chmod +x $GITHUB_WORKSPACE/coveralls/gcov_wrapper.sh
wget https://github.com/linux-test-project/lcov/archive/v1.16.zip
unzip v1.16.zip
LCOV="`pwd`/lcov-1.16/bin/lcov --gcov-tool $GITHUB_WORKSPACE/coveralls/gcov_wrapper.sh"
echo "$LCOV --directory ../boost-root/bin.v2/libs/$LIBRARY/ --base-directory `pwd`/libs/$LIBRARY/test --capture --output-file $GITHUB_WORKSPACE/coveralls/coverage.info"
$LCOV --directory ../boost-root/bin.v2/libs/$LIBRARY/ --base-directory ../boost-root/ --capture --output-file $GITHUB_WORKSPACE/coveralls/coverage.info
$LCOV --remove $GITHUB_WORKSPACE/coveralls/coverage.info "/usr*" "*/$LIBRARY/test/*" ${{matrix.ignore_coverage}} "*/$LIBRARY/tests/*" "*/$LIBRARY/examples/*" "*/$LIBRARY/example/*" -o $GITHUB_WORKSPACE/coveralls/coverage.info
cd ../boost-root
OTHER_LIBS=`grep "submodule .*" .gitmodules | sed 's/\[submodule\ "\(.*\)"\]/"\*\/boost\/\1\.hpp" "\*\/boost\/\1\/\*"/g'| sed "/\"\*\/boost\/$LIBRARY\/\*\"/d" | sed ':a;N;$!ba;s/\n/ /g'`
echo $OTHER_LIBS
eval "$LCOV --remove $GITHUB_WORKSPACE/coveralls/coverage.info $OTHER_LIBS -o $GITHUB_WORKSPACE/coveralls/coverage.info"
- name: Coveralls
uses: coverallsapp/github-action@master
if: matrix.gcov_tool
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: ./coveralls/coverage.info
parallel: true
windows:
strategy:
fail-fast: false
matrix:
include:
- toolset: msvc
cxxstd: "14,17,latest"
addrmd: 64
os: windows-2022
- toolset: msvc-14.2
cxxstd: "14,17,latest"
addrmd: 64
os: windows-2019
#- toolset: gcc
# cxxstd: "03,11,14,17,2a"
# addrmd: 64
# os: windows-2019
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Setup Boost
shell: cmd
run: |
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
echo LIBRARY: %LIBRARY%
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
echo GITHUB_REF: %GITHUB_REF%
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
set BOOST_BRANCH=develop
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
echo BOOST_BRANCH: %BOOST_BRANCH%
cd ..
git clone -b %BOOST_BRANCH% --depth 10 https://github.com/boostorg/boost.git boost-root
cd boost-root
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --include benchmark --include example --include examples --include tools --git_args "--jobs 3" %LIBRARY%
cmd /c bootstrap
b2 -d0 headers
- name: Run tests
shell: cmd
run: |
cd ../boost-root
b2 -j3 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release
finish:
needs: posix
runs-on: ubuntu-latest
steps:
- name: Coveralls Finished
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.github_token }}
parallel-finished: true

View File

@@ -1,123 +0,0 @@
# Use, modification, and distribution are
# 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)
#
# Copyright Antony Polukhin 2014-2016.
#
# See https://svn.boost.org/trac/boost/wiki/TravisCoverals for description of this file
# and how it can be used with Boost libraries.
#
# File revision #7
sudo: false
language: cpp
compiler:
- gcc
# - clang
os:
- linux
env:
global:
# Autodetect Boost branch by using the following code: - BRANCH_TO_TEST=$TRAVIS_BRANCH
# or just directly specify it
#- BRANCH_TO_TEST=$TRAVIS_BRANCH
- BRANCH_TO_TEST=develop
# Files, which coverage results must be ignored (files from other projects).
# Example: - IGNORE_COVERAGE='*/boost/progress.hpp */filesystem/src/*'
- IGNORE_COVERAGE='*/numeric/conversion/converter_policies.hpp */boost/progress.hpp */filesystem/src/* */libs/timer/src/* */thread/src/* */pthread/once_atomic.cpp */src/pthread/thread.cpp */thread/src/future.cpp */boost/operators.hpp'
# Explicitly remove the following library from Boost. This may be usefull, if you're for example running Travis
# from `Boost.DLL` repo, while Boost already has `dll`.
#
# By default is eaual to - BOOST_REMOVE=$(basename $TRAVIS_BUILD_DIR)
# This will force to use local repo content, instead of the Boost's default.
- BOOST_REMOVE=$(basename $TRAVIS_BUILD_DIR)
matrix:
# Note that "--coverage -fsanitize=address,leak,undefined -DBOOST_TRAVISCI_BUILD" are added automatically lower in code
- CXX_FLAGS="-std=c++98" LINK_FLAGS="" TOOLSET=gcc-6
- CXX_FLAGS="-std=c++11" LINK_FLAGS="" TOOLSET=gcc-6
- CXX_FLAGS="-std=c++1y" LINK_FLAGS="" TOOLSET=gcc-6
- CXX_FLAGS="-std=c++11 -O0" LINK_FLAGS="" TOOLSET=gcc-6
- CXX_FLAGS="-std=c++11 -O1" LINK_FLAGS="" TOOLSET=gcc-6
#- CXX_FLAGS="-std=c++11 -stdlib=libc++" LINK_FLAGS="-stdlib=libc++" TOOLSET=clang
#- CXX_FLAGS="-std=c++1y -stdlib=libc++" LINK_FLAGS="-stdlib=libc++" TOOLSET=clang
###############################################################################################################
# From this point and below code is same for all the Boost libs
###############################################################################################################
# Installing additional tools
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- git-core
packages:
- git
- python-yaml
- gcc-6
- g++-6
- clang
- libc++-dev
before_install:
# Set this to the name of the library
- PROJECT_TO_TEST=`basename $TRAVIS_BUILD_DIR`
# Cloning Boost libraries (fast nondeep cloning)
- BOOST=$HOME/boost-local
- echo "Testing $PROJECT_TO_TEST, to remove $BOOST/libs/$BOOST_REMOVE, testing branch $BRANCH_TO_TEST"
- git init $BOOST
- cd $BOOST
- git remote add --no-tags -t $BRANCH_TO_TEST origin https://github.com/boostorg/boost.git
- git fetch --depth=1
- git checkout $BRANCH_TO_TEST
- git submodule update --jobs=3 --init --merge
- git remote set-branches --add origin $BRANCH_TO_TEST
- git pull --recurse-submodules
- git status
- rm -rf $BOOST/libs/$BOOST_REMOVE
- mv $TRAVIS_BUILD_DIR $BOOST/libs/$PROJECT_TO_TEST
- TRAVIS_BUILD_DIR=$BOOST/libs/$PROJECT_TO_TEST
- ./bootstrap.sh
- ./b2 headers
- cd $BOOST/libs/$PROJECT_TO_TEST/test/
script:
# `--coverage` flags required to generate coverage info for Coveralls
- ../../../b2 -a "testing.launcher=LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libasan.so.3 " address-model=64 architecture=x86 toolset=$TOOLSET cxxflags="--coverage -fsanitize=address,leak,undefined -DBOOST_TRAVISCI_BUILD $CXX_FLAGS" linkflags="$LINK_FLAGS --coverage -lasan -lubsan"
- ../../../b2 -a address-model=64 architecture=x86 toolset=$TOOLSET cxxflags="-fsanitize=thread -DBOOST_TRAVISCI_BUILD $CXX_FLAGS" linkflags="$LINK_FLAGS -ltsan"
after_success:
# Copying Coveralls data to a separate folder
- mkdir -p $TRAVIS_BUILD_DIR/coverals
- find ../../../bin.v2/ -name "*.gcda" -exec cp "{}" $TRAVIS_BUILD_DIR/coverals/ \;
- find ../../../bin.v2/ -name "*.gcno" -exec cp "{}" $TRAVIS_BUILD_DIR/coverals/ \;
- find ../../../bin.v2/ -name "*.da" -exec cp "{}" $TRAVIS_BUILD_DIR/coverals/ \;
- find ../../../bin.v2/ -name "*.no" -exec cp "{}" $TRAVIS_BUILD_DIR/coverals/ \;
- wget https://github.com/linux-test-project/lcov/archive/v1.12.zip
- unzip v1.12.zip
- LCOV="`pwd`/lcov-1.12/bin/lcov --gcov-tool gcov-6"
# Preparing Coveralls data by changind data format to a readable one
- echo "$LCOV --directory $TRAVIS_BUILD_DIR/coverals --base-directory `pwd` --capture --output-file $TRAVIS_BUILD_DIR/coverals/coverage.info"
- $LCOV --directory $TRAVIS_BUILD_DIR/coverals --base-directory `pwd` --capture --output-file $TRAVIS_BUILD_DIR/coverals/coverage.info
# ... erasing /test/ /example/ folder data
- cd $BOOST
- $LCOV --remove $TRAVIS_BUILD_DIR/coverals/coverage.info "/usr*" "*/$PROJECT_TO_TEST/test/*" $IGNORE_COVERAGE "*/$PROJECT_TO_TEST/tests/*" "*/$PROJECT_TO_TEST/examples/*" "*/$PROJECT_TO_TEST/example/*" -o $TRAVIS_BUILD_DIR/coverals/coverage.info
# ... erasing data that is not related to this project directly
- OTHER_LIBS=`grep "submodule .*" .gitmodules | sed 's/\[submodule\ "\(.*\)"\]/"\*\/boost\/\1\.hpp" "\*\/boost\/\1\/\*"/g'| sed "/\"\*\/boost\/$PROJECT_TO_TEST\/\*\"/d" | sed ':a;N;$!ba;s/\n/ /g'`
- echo $OTHER_LIBS
- eval "$LCOV --remove $TRAVIS_BUILD_DIR/coverals/coverage.info $OTHER_LIBS -o $TRAVIS_BUILD_DIR/coverals/coverage.info"
# Sending data to Coveralls
- cd $TRAVIS_BUILD_DIR
- gem install coveralls-lcov
- coveralls-lcov coverals/coverage.info

103
CMakeLists.txt Normal file
View File

@@ -0,0 +1,103 @@
# Copyright 2020, 2021 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt
cmake_minimum_required(VERSION 3.5...3.16)
project(boost_stacktrace VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
function(stacktrace_add_library suffix opt libs defs)
if(NOT opt)
return()
endif()
add_library(boost_stacktrace_${suffix}
src/${suffix}.cpp
)
add_library(Boost::stacktrace_${suffix} ALIAS boost_stacktrace_${suffix})
target_include_directories(boost_stacktrace_${suffix} PUBLIC include)
target_link_libraries(boost_stacktrace_${suffix}
PUBLIC
Boost::config
Boost::container_hash
Boost::core
Boost::predef
Boost::winapi
PRIVATE
${libs}
)
target_compile_definitions(boost_stacktrace_${suffix}
PUBLIC BOOST_STACKTRACE_NO_LIB
PRIVATE BOOST_STACKTRACE_SOURCE ${defs}
)
if(BUILD_SHARED_LIBS)
target_compile_definitions(boost_stacktrace_${suffix} PUBLIC BOOST_STACKTRACE_DYN_LINK)
else()
target_compile_definitions(boost_stacktrace_${suffix} PUBLIC BOOST_STACKTRACE_STATIC_LINK)
endif()
if(BOOST_SUPERPROJECT_VERSION AND NOT CMAKE_VERSION VERSION_LESS 3.13)
boost_install(TARGETS boost_stacktrace_${suffix} VERSION ${BOOST_SUPERPROJECT_VERSION} HEADER_DIRECTORY include)
endif()
endfunction()
include(CheckCXXSourceCompiles)
function(stacktrace_check var source incs libs defs)
set(CMAKE_REQUIRED_INCLUDES "${incs}")
list(APPEND CMAKE_REQUIRED_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/build")
set(CMAKE_REQUIRED_LIBRARIES "${libs}")
set(CMAKE_REQUIRED_DEFINITIONS "${defs}")
check_cxx_source_compiles("#include \"${source}\"" ${var})
set(${var} ${${var}} PARENT_SCOPE)
endfunction()
stacktrace_check(BOOST_STACKTRACE_HAS_BACKTRACE has_backtrace.cpp "" "backtrace" "")
set(_default_addr2line ON)
if(WIN32 AND NOT CMAKE_CXX_PLATFORM_ID MATCHES "Cygwin")
set(_default_addr2line OFF)
endif()
stacktrace_check(BOOST_STACKTRACE_HAS_WINDBG has_windbg.cpp "" "dbgeng;ole32" "")
stacktrace_check(BOOST_STACKTRACE_HAS_WINDBG_CACHED has_windbg_cached.cpp "${CMAKE_CURRENT_SOURCE_DIR}/../config/include" "dbgeng;ole32" "")
option(BOOST_STACKTRACE_ENABLE_NOOP "Boost.Stacktrace: build boost_stacktrace_noop" ON)
option(BOOST_STACKTRACE_ENABLE_BACKTRACE "Boost.Stacktrace: build boost_stacktrace_backtrace" ${BOOST_STACKTRACE_HAS_BACKTRACE})
option(BOOST_STACKTRACE_ENABLE_ADDR2LINE "Boost.Stacktrace: build boost_stacktrace_addr2line" ${_default_addr2line})
option(BOOST_STACKTRACE_ENABLE_BASIC "Boost.Stacktrace: build boost_stacktrace_basic" ON)
option(BOOST_STACKTRACE_ENABLE_WINDBG "Boost.Stacktrace: build boost_stacktrace_windbg" ${BOOST_STACKTRACE_HAS_WINDBG})
option(BOOST_STACKTRACE_ENABLE_WINDBG_CACHED "Boost.Stacktrace: build boost_stacktrace_windbg_cached" ${BOOST_STACKTRACE_HAS_WINDBG_CACHED})
unset(_default_addr2line)
message(STATUS "Boost.Stacktrace: "
"noop ${BOOST_STACKTRACE_ENABLE_NOOP}, "
"backtrace ${BOOST_STACKTRACE_ENABLE_BACKTRACE}, "
"addr2line ${BOOST_STACKTRACE_ENABLE_ADDR2LINE}, "
"basic ${BOOST_STACKTRACE_ENABLE_BASIC}, "
"windbg ${BOOST_STACKTRACE_ENABLE_WINDBG}, "
"windbg_cached ${BOOST_STACKTRACE_ENABLE_WINDBG_CACHED}"
)
stacktrace_add_library(noop ${BOOST_STACKTRACE_ENABLE_NOOP} "" "")
stacktrace_add_library(backtrace ${BOOST_STACKTRACE_ENABLE_BACKTRACE} "backtrace" "")
stacktrace_add_library(addr2line ${BOOST_STACKTRACE_ENABLE_ADDR2LINE} "" "")
stacktrace_add_library(basic ${BOOST_STACKTRACE_ENABLE_BASIC} "" "")
stacktrace_add_library(windbg ${BOOST_STACKTRACE_ENABLE_WINDBG} "dbgeng;ole32" "_GNU_SOURCE=1")
stacktrace_add_library(windbg_cached ${BOOST_STACKTRACE_ENABLE_WINDBG_CACHED} "dbgeng;ole32" "_GNU_SOURCE=1")
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
add_subdirectory(test)
endif()

View File

@@ -1,15 +1,17 @@
### Stacktrace
# [Boost.Stacktrace](https://boost.org/libs/stacktrace)
Library for storing and printing backtraces.
[Documentation and examples.](http://boostorg.github.io/stacktrace/index.html)
Boost.Stacktrace is a part of the [Boost C++ Libraries](https://github.com/boostorg).
### 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)
Develop branch: | [![CI](https://github.com/boostorg/stacktrace/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/boostorg/stacktrace/actions/workflows/ci.yml) [![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...](https://www.boost.org/development/tests/develop/developer/stacktrace.html)
Master branch: | [![CI](https://github.com/boostorg/stacktrace/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/boostorg/stacktrace/actions/workflows/ci.yml) [![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...](https://www.boost.org/development/tests/master/developer/stacktrace.html)
[Latest developer documentation](https://www.boost.org/doc/libs/develop/doc/html/stacktrace.html)
### License
Distributed under the [Boost Software License, Version 1.0](http://boost.org/LICENSE_1_0.txt).
Distributed under the [Boost Software License, Version 1.0](https://boost.org/LICENSE_1_0.txt).

View File

@@ -1,14 +1,19 @@
# Copyright (C) 2016-2017, Antony Polukhin.
# Copyright (C) 2016-2024, 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)
#
import feature ;
import ../../config/checks/config : requires ;
project
: source-location .
: requirements
<target-os>linux:<cxxflags>"-fvisibility=hidden"
[ requires cxx11_rvalue_references ]
: default-build
<visibility>hidden
;
lib dl ;
@@ -16,6 +21,7 @@ lib gcc_s ;
lib Dbgeng ;
lib ole32 ;
feature.feature boost.stacktrace.from_exception : on off : optional propagated ;
local LIBBACKTRACE_PATH = [ modules.peek : LIBBACKTRACE_PATH ] ;
lib backtrace
@@ -62,8 +68,6 @@ lib boost_stacktrace_noop
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
;
boost-install boost_stacktrace_noop ;
lib boost_stacktrace_backtrace
: # sources
../src/backtrace.cpp
@@ -78,8 +82,6 @@ lib boost_stacktrace_backtrace
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
;
boost-install boost_stacktrace_backtrace ;
lib boost_stacktrace_addr2line
: # sources
../src/addr2line.cpp
@@ -93,8 +95,6 @@ lib boost_stacktrace_addr2line
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
;
boost-install boost_stacktrace_addr2line ;
lib boost_stacktrace_basic
: # sources
../src/basic.cpp
@@ -108,8 +108,6 @@ lib boost_stacktrace_basic
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
;
boost-install boost_stacktrace_basic ;
lib boost_stacktrace_windbg
: # sources
../src/windbg.cpp
@@ -123,8 +121,6 @@ lib boost_stacktrace_windbg
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
;
boost-install boost_stacktrace_windbg ;
lib boost_stacktrace_windbg_cached
: # sources
../src/windbg_cached.cpp
@@ -138,5 +134,22 @@ lib boost_stacktrace_windbg_cached
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
;
boost-install boost_stacktrace_windbg_cached ;
lib boost_stacktrace_from_exception
: # sources
../src/from_exception.cpp
: # requirements
<warnings>all
<target-os>linux:<library>dl
<target-os>windows:<build>no # not supported at the moment
# Command line option to disable build
<boost.stacktrace.from_exception>off:<build>no
# Require usable libbacktrace on other platforms
[ check-target-builds ../build//libbacktrace : : <build>no ]
: # default build
: # usage-requirements
#<link>shared:<define>BOOST_STACKTRACE_DYN_LINK=1
;
boost-install boost_stacktrace_noop boost_stacktrace_backtrace boost_stacktrace_addr2line boost_stacktrace_basic boost_stacktrace_windbg boost_stacktrace_windbg_cached boost_stacktrace_from_exception ;

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2020.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at

View File

@@ -1,10 +1,15 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// 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>
#ifdef BOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE
# include BOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE
#else
# include <backtrace.h>
#endif
#include <unwind.h>
int main() {

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2020.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at

View File

@@ -1,17 +1,24 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2020.
//
// 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 int i = 0;
static thread_local std::string i = std::string();
return i;
return static_cast<int>(i.size());
}
int main() {

View File

@@ -1,4 +1,4 @@
# Copyright Antony Polukhin 2016-2017.
# Copyright Antony Polukhin, 2016-2024.
# Use, modification, and distribution are
# 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)
@@ -22,6 +22,9 @@ doxygen autodoc
<doxygen:param>SEARCH_INCLUDES=YES
<doxygen:param>SHORT_NAMES=NO
<doxygen:param>INCLUDE_PATH=../../../
<doxygen:param>"ALIASES= \\
\"asyncsafe=\\xmlonly<link linkend='stacktrace.theoretical_async_signal_safety'>\\endxmlonly Theoretically async signal safe \\xmlonly</link>\\endxmlonly\" \\
"
<doxygen:param>"PREDEFINED=\"stl_type_info=std::type_info\" \\
\"BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()=explicit operator bool() const noexcept;\" \\
\"BOOST_CONSTEXPR_EXPLICIT_OPERATOR_BOOL()=explicit constexpr operator bool() const noexcept;\" \\
@@ -39,9 +42,9 @@ boostbook standalone
:
stacktrace
:
<xsl:param>boost.root=http://www.boost.org/doc/libs/1_63_0
<xsl:param>boost.root=http\://www.boost.org/doc/libs/1_84_0
# <xsl:param>boost.root=../../../..
<format>pdf:<xsl:param>boost.url.prefix=http://www.boost.org/doc/libs/release/doc/html
<format>pdf:<xsl:param>boost.url.prefix=http\://www.boost.org/doc/libs/release/doc/html
;
###############################################################################

View File

@@ -2,7 +2,7 @@
[quickbook 1.6]
[version 1.0]
[id stacktrace]
[copyright 2016-2017 Antony Polukhin]
[copyright 2016-2024 Antony Polukhin]
[category Language Features Emulation]
[license
Distributed under the Boost Software License, Version 1.0.
@@ -57,51 +57,6 @@ Code from above will output something like this:
[note By default the Stacktrace library is very conservative in methods to decode stacktrace. If your output does not look as fancy as in example from above, see [link stacktrace.configuration_and_build section "Configuration and Build"] for allowing advanced features of the library. ]
[endsect]
[section Handle terminates, aborts and Segmentation Faults]
Segmentation Faults and `std::terminate` calls sometimes happen in programs. Programmers usually wish to get as much information as possible on such incidents, so having a stacktrace will significantly improve debugging and fixing.
`std::terminate` calls `std::abort`, so we need to capture stack traces on Segmentation Faults and Abort signals.
[warning Writing a signal handler requires high attention! Only a few system calls allowed in signal handlers, so there's no cross platform way to print a stacktrace without a risk of deadlocking. The only way to deal with the problem - [*dump raw stacktrace into file/socket and parse it on program restart].]
Let's write a handler to safely dump stacktrace:
[getting_started_terminate_handlers]
Registering our handler:
[getting_started_setup_handlers]
At program start we check for a file with stacktrace and if it exist - we're writing it in human readable format:
[getting_started_on_program_restart]
Now we'll get the following output on `std::terminate` call after the program restarts:
```
Previous run crashed:
0# 0x00007F2EC0A6A8EF
1# my_signal_handler(int) at ../example/terminate_handler.cpp:37
2# 0x00007F2EBFD84CB0
3# 0x00007F2EBFD84C37
4# 0x00007F2EBFD88028
5# 0x00007F2EC0395BBD
6# 0x00007F2EC0393B96
7# 0x00007F2EC0393BE1
8# bar(int) at ../example/terminate_handler.cpp:18
9# foo(int) at ../example/terminate_handler.cpp:22
10# bar(int) at ../example/terminate_handler.cpp:14
11# foo(int) at ../example/terminate_handler.cpp:22
12# main at ../example/terminate_handler.cpp:84
13# 0x00007F2EBFD6FF45
14# 0x0000000000402209
```
[note Function names from shared libraries may not be decoded due to address space layout randomization. Still better than nothing.]
[endsect]
[section Better asserts]
@@ -137,10 +92,114 @@ Now we do know the steps that led to the assertion and can find the error withou
[endsect]
[section Handle terminates]
`std::terminate` calls sometimes happen in programs. Programmers usually wish to get as much information as possible on such incidents, so having a stacktrace significantly improves debugging and fixing.
Here's how to write a terminate handler that dumps stacktrace:
[getting_started_terminate_handlers]
Here's how to register it:
[getting_started_setup_terminate_handlers]
Now we'll get the following output on `std::terminate` call:
```
Previous run crashed:
0# my_terminate_handler(int) at ../example/terminate_handler.cpp:37
1# __cxxabiv1::__terminate(void (*)()) at ../../../../src/libstdc++-v3/libsupc++/eh_terminate.cc:48
2# 0x00007F3CE65E5901 in /usr/lib/x86_64-linux-gnu/libstdc++.so.6
3# bar(int) at ../example/terminate_handler.cpp:18
4# foo(int) at ../example/terminate_handler.cpp:22
5# bar(int) at ../example/terminate_handler.cpp:14
6# foo(int) at ../example/terminate_handler.cpp:22
7# main at ../example/terminate_handler.cpp:84
8# __libc_start_main in /lib/x86_64-linux-gnu/libc.so.6
9# 0x0000000000402209
```
[warning There's a temptation to write a signal handler that prints the stacktrace on `SIGSEGV` or abort. Unfortunately,
there's no cross platform way to do that without a risk of deadlocking.
Not all the platforms provide means for even getting stacktrace in async signal safe way.
Signal handler is often invoked on a separate stack and trash is returned on attempt to get a trace!
Generic recommendation is to *avoid signal handlers! Use* platform specific ways to store and decode *core files*.
See [link stacktrace.theoretical_async_signal_safety "Theoretical async signal safety"] for more info.
]
[endsect]
[section Stacktrace from arbitrary exception]
[warning At the moment the functionality is only available for some of the
popular C++ runtimes for POSIX systems and requires *libbacktrace*.
Make sure that your platform is supported by running some tests.
]
The library provides a way to get stacktrace from an exception as if the
stacktrace was captured at the point the exception was thrown. Works even if
the exception was thrown from a third party binary library.
Link with
`boost_stacktrace_from_exception` library (or just `LD_PRELOAD` it!) and call
boost::stacktrace::stacktrace::from_current_exception() to get the trace:
```
#include <iostream>
#include <stdexcept>
#include <string_view>
#include <boost/stacktrace.hpp>
void foo(std::string_view key);
void bar(std::string_view key);
int main() {
try {
foo("test1");
bar("test2");
} catch (const std::exception& exc) {
boost::stacktrace::stacktrace trace = std::stacktrace::from_current_exception(); // <---
std::cerr << "Caught exception: " << exc.what() << ", trace:\n" << trace;
}
}
```
The output of the above sample may be the following:
```
Caught exception: std::map::at, trace:
0# get_data_from_config(std::string_view) at /home/axolm/basic.cpp:600
1# bar(std::string_view) at /home/axolm/basic.cpp:6
2# main at /home/axolm/basic.cpp:17
```
With the above technique a developer can locate the source file and the function
that has thrown the exception without a debugger help. it is especially useful
for testing in containers (github CI, other CIs), where the developer has no
direct access to the testing environment and reproducing the issue is
complicated.
Note that linking with `boost_stacktrace_from_exception` may increase memory
consumption of the application, as the exceptions now additionally store traces.
At runtime switch boost::stacktrace::this_thread::set_capture_stacktraces_at_throw()
allows to disable/enable capturing and storing traces in exceptions.
To disable the `boost_stacktrace_from_exception` library builds the
`boost.stacktrace.from_exception=off` option, for example
`./b2 boost.stacktrace.from_exception=off`.
[endsect]
[section Exceptions with stacktrace]
You can provide more information along with exception by embedding stacktraces into the exception. There are many ways to do that, here's how to doe that using Boost.Exception:
You can provide more information along with exception by embedding stacktraces into the exception. There are many ways to do that, here's how to do that using Boost.Exception:
* Declare a `boost::error_info` typedef that holds the stacktrace:
@@ -240,43 +299,6 @@ Terminate called:
[endsect]
[/
[section Store stacktraces into shared memory]
There's a way to serialize stacktrace in async safe manner and share that serialized representation with another process. Here's another example with signal handlers.
This example is very close to the [link stacktrace.getting_started.handle_terminates_aborts_and_seg "Handle terminates, aborts and Segmentation Faults"], but this time we are dumping stacktrace into shared memory:
[getting_started_terminate_handlers_shmem]
After registering signal handlers and catching a signal, we may print stacktrace dumps on program restart:
[getting_started_on_program_restart_shmem]
The program output will be the following:
```
Previous run crashed and left trace in shared memory:
0# 0x00007FD51C7218EF
1# my_signal_handler2(int) at ../example/terminate_handler.cpp:68
2# 0x00007FD51B833CB0
3# 0x00007FD51B833C37
4# 0x00007FD51B837028
5# 0x00007FD51BE44BBD
6# 0x00007FD51BE42B96
7# 0x00007FD51BE42BE1
8# bar(int) at ../example/terminate_handler.cpp:18
9# foo(int) at ../example/terminate_handler.cpp:22
10# bar(int) at ../example/terminate_handler.cpp:14
11# foo(int) at ../example/terminate_handler.cpp:22
12# run_3(char const**) at ../example/terminate_handler.cpp:152
13# main at ../example/terminate_handler.cpp:207
14# 0x00007FD51B81EF45
15# 0x0000000000402999
```
[endsect]
]
[endsect]
@@ -292,26 +314,82 @@ By default Boost.Stacktrace is a header-only library, but you may change that an
In header only mode library could be tuned by macro. If one of the link macro from above is defined, you have to manually link with one of the libraries:
[table:libconfig Config
[[Macro name or default] [Library] [Effect] [Platforms] [Uses debug information [footnote This will provide more readable backtraces with *source code locations* 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. Compiling with `-rdynamic` flag, without `-fisibility=hidden` or marking functions as exported produce a better stacktraces.]] ]
[[['default for MSVC] / *BOOST_STACKTRACE_USE_WINDBG*] [*boost_stacktrace_windbg*] [ Uses COM to show debug info. ] [Windows] [yes] [no]]
[[['default other platforms]] [*boost_stacktrace_basic*] [Uses compiler intrinsics to collect stacktrace and if possible `::dladdr` to show information about the symbol. Requires linking with *libdl* library on POSIX platforms.] [Not MSVC compiler on POSIX or Windows] [no] [yes]]
[[*BOOST_STACKTRACE_USE_WINDBG_CACHED*] [*boost_stacktrace_windbg_cached*] [ Uses COM to show debug info and caches COM instances in TLS for better performance. Useful only for cases when traces are gathered very often. [footnote This may affect other components of your program that use COM, because this mode calls the `CoInitializeEx(0, COINIT_MULTITHREADED)` on first use and does not call `::CoUninitialize();` until the current thread is destroyed. ] ] [Windows] [yes] [no]]
[[*BOOST_STACKTRACE_USE_BACKTRACE*] [*boost_stacktrace_backtrace*] [Requires linking with *libdl* on POSIX and *libbacktrace* libraries. *libbacktrace* is probably already installed in your system, or built into your compiler.
[[Macro name or default] [Library] [Effect] [Platforms] [Uses debug information [footnote This will provide more readable backtraces with *source code locations* 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. Compiling with `-rdynamic` flag, without `-fvisibility=hidden` or marking functions as exported produce a better stacktraces.]] ]
[[['default for MSVC, Intel on Windows, MinGW-w64] / *BOOST_STACKTRACE_USE_WINDBG*] [*boost_stacktrace_windbg*] [ Uses `dbgeng.h` to show debug info, stores the implementation internals in a static varaible protected with mutex. May require linking with *ole32* and *dbgeng*. ] [MSVC, MinGW-w64, Intel on Windows] [yes] [no]]
[[['default for other platforms]] [*boost_stacktrace_basic*] [Uses compiler intrinsics to collect stacktrace and if possible `::dladdr` to show information about the symbol. Requires linking with *libdl* library on POSIX platforms.] [Any compiler on POSIX or MinGW] [no] [yes]]
[[*BOOST_STACKTRACE_USE_WINDBG_CACHED*] [*boost_stacktrace_windbg_cached*] [ Uses `dbgeng.h` to show debug info and caches implementation internals in TLS for better performance. Useful only for cases when traces are gathered very often. May require linking with *ole32* and *dbgeng*. ] [MSVC, Intel on Windows] [yes] [no]]
[[*BOOST_STACKTRACE_USE_BACKTRACE*] [*boost_stacktrace_backtrace*] [Requires linking with *libdl* on POSIX and *libbacktrace* libraries[footnote Some *libbacktrace* packages SEGFAULT if there's a concurrent work with the same `backtrace_state` instance. To avoid that issue the Boost.Stacktrace library uses `thread_local` states, unfortunately this may consume a lot of memory if you often create and destroy execution threads in your application. Define *BOOST_STACKTRACE_BACKTRACE_FORCE_STATIC* to force single instance, but make sure that [@https://github.com/boostorg/stacktrace/blob/develop/test/thread_safety_checking.cpp thread_safety_checking.cpp] works well in your setup. ]. *libbacktrace* is probably already installed in your system[footnote If you are using Clang with libstdc++ you could get into troubles of including `<backtrace.h>`, because on some platforms Clang does not search for headers in the GCC's include paths and any attempt to add GCC's include path leads to linker errors. To explicitly specify a path to the `<backtrace.h>` header you could define the *BOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE* to a full path to the header. For example on Ubuntu Xenial use the command line option *-DBOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE=</usr/lib/gcc/x86_64-linux-gnu/5/include/backtrace.h>* while building with Clang. ], or built into your compiler.
Otherwise (if you are a *MinGW* user for example) it can be downloaded [@https://github.com/ianlancetaylor/libbacktrace from here] or [@https://github.com/gcc-mirror/gcc/tree/master/libbacktrace from here]. ] [GCC/MinGW/Clang... on POSIX or Windows] [yes] [yes]]
[[*BOOST_STACKTRACE_USE_ADDR2LINE*] [*boost_stacktrace_addr2line*] [Use *addr2line* program to retrieve stacktrace. Requires linking with *libdl* library and `::fork` system call. Macro *BOOST_STACKTRACE_ADDR2LINE_LOCATION* must be defined to the absolute path to the addr2line executable if it is not located in /usr/bin/addr2line. ] [GCC/MinGW/Clang... on POSIX] [yes] [yes]]
Otherwise (if you are a *MinGW*/*MinGW-w64* user for example) it can be downloaded [@https://github.com/ianlancetaylor/libbacktrace from here] or [@https://github.com/gcc-mirror/gcc/tree/master/libbacktrace from here]. ] [Any compiler on POSIX, or MinGW, or MinGW-w64] [yes] [yes]]
[[*BOOST_STACKTRACE_USE_ADDR2LINE*] [*boost_stacktrace_addr2line*] [Use *addr2line* program to retrieve stacktrace. Requires linking with *libdl* library and `::fork` system call. Macro *BOOST_STACKTRACE_ADDR2LINE_LOCATION* must be defined to the absolute path to the addr2line executable if it is not located in /usr/bin/addr2line. ] [Any compiler on POSIX] [yes] [yes]]
[[*BOOST_STACKTRACE_USE_NOOP*] [*boost_stacktrace_noop*] [Use this if you wish to disable backtracing. `stacktrace::size()` with that macro always returns 0. ] [All] [no] [no]]
]
[*Examples:]
* if you wish to switch to more powerful implementation on Clang/MinGW and *BOOST_STACKTRACE_LINK* is defined, you just need link with "*-lboost_stacktrace_backtrace -ldl -lbacktrace*" or "*-lboost_stacktrace_addr2line -ldl*"
* if you wish to disable backtracing and you use the library in header only mode, you just need to define *BOOST_STACKTRACE_USE_NOOP* for the whole project
* if you wish to disable backtracing and *BOOST_STACKTRACE_LINK* is defined, you just need link with *-lboost_stacktrace_noop*
* if you wish to disable backtracing and you use the library in header only mode, you just need to define *BOOST_STACKTRACE_USE_NOOP* for the whole project and recompile it
[section MinGW and MinGW-w64 specific notes]
MinGW-w64 and MinGW (without -w64) users have to install libbacktrace for getting better stacktraces. Follow the instruction:
Let's assume that you've installed MinGW into C:\MinGW and downloaded [@https://github.com/ianlancetaylor/libbacktrace libbacktrace sources] into C:\libbacktrace-master
* Configure & build libbacktrace from console:
* C:\MinGW\msys\1.0\bin\sh.exe
* cd /c/libbacktrace-master
* ./configure CC=/c/MinGW/bin/gcc.exe CXX=/c/MinGW/bin/g++.exe
* make
* ./libtool --mode=install /usr/bin/install -c libbacktrace.la '/c/libbacktrace-master'
* Add info to the project-config.jam in the Boost folder:
* using gcc : 6 : "C:\\MinGW\\bin\\g++.exe" : <compileflags>-I"C:\\libbacktrace-master\\" <linkflags>-L"C:\\libbacktrace-master\\" ;
* Now you can use a header only version by defining *BOOST_STACKTRACE_USE_BACKTRACE* for your project or build the stacktrace library from Boost folder:
* b2.exe toolset=gcc-6 --with-stacktrace
[endsect]
[section Acknowledgements]
[section Windows deployment and symbol files]
Function names may not be resolved after deployment of your application to a different system.
There are multiple ways to deal with that issue if you distribute PDB files along with your application:
* Link your application and shared libraries with a properly set `/PDBALTPATH` flag, for example `/PDBALTPATH:%_PDB%`. See [@https://docs.microsoft.com/en-us/cpp/build/reference/pdbaltpath-use-alternate-pdb-path official documentation for more info].
* Set the `_NT_ALT_SYMBOL_PATH` or `_NT_SYMBOL_PATH` environment variables of the target system to the path of the PDBs. See [@https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/symbol-path#controlling-the-symbol-path official documentation for more info].
[endsect]
[endsect]
[section Theoretical async signal safety]
In theory, walking the stack without decoding and demangling should be async signal safe.
In practice, it is not:
* Looks like a page fault while dumping the trace on a containerized/virtualized
Windows system has a chance to deadlock. Page fault could happen easily
as we have to write the dump either to memory or to a file.
* On POSIX systems a deadlock could happen if a signal is received when throwing
an exception [@https://github.com/boostorg/stacktrace/issues/131 #131].
Theoretically this could be worked around by bypassing the mutex locking
in C++-runtime at exception throw
([@https://github.com/userver-framework/userver/blob/4246909c99506d3ab34bd130a5154b4acc8e87de/core/src/engine/task/exception_hacks.cpp#L241-L244 sample implementation]
in the 🐙 userver framework), or by using a very modern runtime
(glibc-2.35+ with [@https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71744#c32 modern]
libgcc or [@https://reviews.llvm.org/D130668 modern] LLVM's libunwind).
* `-fomit-frame-pointer` like flags add additional complexity to the stack
walking implementation, which may also negatively affect the signal safety.
As a rule of thumb: do *not* capture stack traces in signal handlers unless you
are absolutely sure in your environment and inspected all of its source codes.
[endsect]
[section Acknowledgments]
In order of helping and advising:
@@ -319,6 +397,8 @@ In order of helping and advising:
* Great thanks to Nat Goodspeed for requesting [classref boost::stacktrace::frame] like class.
* Great thanks to Niall Douglas for making an initial review, helping with some platforms and giving great hints on library design.
* Great thanks to all the library reviewers.
* Great thanks to Andrei Nekrashevich for prototyping the idea of stacktraces
from arbitrary exception in `libsfe`.
[endsect]

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -24,9 +24,6 @@ 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
@@ -38,7 +35,8 @@ 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();
/*<-*/ std::exit(0); /*->*/
/*=std::abort();*/
}
inline void assertion_failed(char const* expr, char const* function, char const* file, long line) {

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -28,8 +28,6 @@ void my_signal_handler(int /*signum*/) {
int main() {
::signal(SIGSEGV, &my_signal_handler);
print_signal_handler_and_exit();
return 2;
}

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -23,59 +23,57 @@ BOOST_NOINLINE void foo(int i) {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//[getting_started_terminate_handlers
//[getting_started_signal_handlers
#include <signal.h> // ::signal, ::raise
#include <boost/stacktrace.hpp>
void my_signal_handler(int signum) {
::signal(signum, SIG_DFL);
// Outputs nothing or trash on majority of platforms
boost::stacktrace::safe_dump_to("./backtrace.dump");
::raise(SIGABRT);
}
//]
void setup_handlers() {
//[getting_started_setup_handlers
//[getting_started_setup_signel_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
#include <cstdlib> // std::abort
#include <exception> // std::set_terminate
#include <iostream> // std::cerr
//[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);
void my_terminate_handler() {
try {
std::cerr << boost::stacktrace::stacktrace();
} catch (...) {}
std::abort();
}
//]
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <iostream> // std::cerr
#include <fstream> // std::ifstream
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#ifndef BOOST_WINDOWS
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::copy_file(exec_name, command, boost::filesystem::copy_options::overwrite_existing);
boost::filesystem::path command_args = command;
command_args += ' ';
@@ -91,6 +89,16 @@ inline void copy_and_run(const char* exec_name, char param, bool not_null) {
std::exit(ret);
}
}
#endif
int run_0(const char* /*argv*/[]) {
//[getting_started_setup_terminate_handlers
std::set_terminate(&my_terminate_handler);
//]
foo(5);
return 1;
}
int run_1(const char* /*argv*/[]) {
setup_handlers();
@@ -132,67 +140,6 @@ int run_2(const char* argv[]) {
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() {
@@ -271,6 +218,13 @@ int test_inplace() {
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;
@@ -293,20 +247,21 @@ int test_inplace() {
int main(int argc, const char* argv[]) {
if (argc < 2) {
// On Windows the debugger could be active. In that case tests hang and the CI run fails.
#ifndef BOOST_WINDOWS
copy_and_run(argv[0], '0', true);
// 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);
copy_and_run(argv[0], '3', true);
copy_and_run(argv[0], '4', false);
#endif
return test_inplace();
}
switch (argv[1][0]) {
case '0': return run_0(argv);
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;

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -35,7 +35,7 @@ BOOST_NOINLINE void oops(int i) {
if (i >= 4)
throw_with_trace(std::out_of_range("'i' must be less than 4 in oops()"));
if (i <= 0)
throw_with_trace(std::logic_error("'i' must not be greater than zero in oops()"));
throw_with_trace(std::logic_error("'i' must be greater than zero in oops()"));
//]
foo(i);
std::exit(1);
@@ -68,8 +68,8 @@ int main() {
std::cerr << e.what() << '\n';
const boost::stacktrace::stacktrace* st = boost::get_error_info<traced>(e);
if (st) {
std::cerr << *st << '\n'; /*<-*/ std::exit(0); /*->*/
} /*<-*/ std::exit(3); /*->*/
std::cerr << *st << '\n'; /*<-*/ return 0; /*->*/
} /*<-*/ return 3; /*->*/
}
//]

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -29,6 +29,9 @@ std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT
#ifndef USER_CONFIG2_HPP
#define USER_CONFIG2_HPP
#include <ios> // std::streamsize
//[getting_started_user_config_impl
namespace boost { namespace stacktrace {

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -15,5 +15,6 @@
#include <boost/stacktrace/frame.hpp>
#include <boost/stacktrace/stacktrace.hpp>
#include <boost/stacktrace/safe_dump_to.hpp>
#include <boost/stacktrace/this_thread.hpp>
#endif // BOOST_STACKTRACE_HPP

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -12,9 +12,11 @@
# pragma once
#endif
#include <boost/stacktrace/detail/addr_base.hpp>
#include <boost/stacktrace/detail/to_hex_array.hpp>
#include <boost/stacktrace/detail/to_dec_array.hpp>
#include <boost/stacktrace/detail/try_dec_convert.hpp>
#include <boost/core/demangle.hpp>
#include <boost/lexical_cast.hpp>
#include <cstdio>
#include <sys/types.h>
@@ -27,7 +29,7 @@ namespace boost { namespace stacktrace { namespace detail {
#if defined(BOOST_STACKTRACE_ADDR2LINE_LOCATION) && !defined(BOOST_NO_CXX11_CONSTEXPR)
constexpr bool is_abs_path(const char* path) BOOST_NOEXCEPT {
constexpr bool is_abs_path(const char* path) noexcept {
return *path != '\0' && (
*path == ':' || *path == '/' || is_abs_path(path + 1)
);
@@ -40,7 +42,7 @@ class addr2line_pipe {
::pid_t pid;
public:
explicit addr2line_pipe(const char *flag, const char* exec_path, const char* addr) BOOST_NOEXCEPT
explicit addr2line_pipe(const char *flag, const char* exec_path, const char* addr) noexcept
: p(0)
, pid(0)
{
@@ -96,11 +98,11 @@ public:
::close(pdes[1]);
}
operator ::FILE*() const BOOST_NOEXCEPT {
operator ::FILE*() const noexcept {
return p;
}
~addr2line_pipe() BOOST_NOEXCEPT {
~addr2line_pipe() noexcept {
if (p) {
::fclose(p);
int pstat = 0;
@@ -154,6 +156,19 @@ inline std::string addr2line(const char* flag, const void* addr) {
return res;
}
inline std::string source_location(const void* addr, bool position_independent) {
uintptr_t addr_base = 0;
if (position_independent) {
addr_base = boost::stacktrace::detail::get_own_proc_addr_base(addr);
}
const void* offset = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) - addr_base);
std::string source_line = boost::stacktrace::detail::addr2line("-Cpe", reinterpret_cast<const void*>(offset));
if (source_line.empty() || source_line[0] == '?') {
return "";
}
return source_line;
}
struct to_string_using_addr2line {
std::string res;
@@ -162,9 +177,20 @@ struct to_string_using_addr2line {
}
bool prepare_source_location(const void* addr) {
//return addr2line("-Cfipe", addr); // Does not seem to work in all cases
std::string source_line = boost::stacktrace::detail::addr2line("-Cpe", addr);
if (!source_line.empty() && source_line[0] != '?') {
// general idea in all addr2line uses:
// in each case:
// - try to resolve whole address as if it was a non-pie binary
// - if that didn't work, try to resolve just an offset from binary base address
// this is needed because:
// - in pie binaries just passing an address to addr2line won't work (it needs an offset in this case)
// - in non-pie binaries whole address is needed (offset won't work)
// - there is no easy way to test if binary is position independent (that I know of)
std::string source_line = boost::stacktrace::detail::source_location(addr, false);
if(source_line.empty()) {
source_line = boost::stacktrace::detail::source_location(addr, true);
}
if (!source_line.empty()) {
res += " at ";
res += source_line;
return true;
@@ -177,8 +203,13 @@ struct to_string_using_addr2line {
template <class Base> class to_string_impl_base;
typedef to_string_impl_base<to_string_using_addr2line> to_string_impl;
inline std::string name_impl(const void* addr) {
std::string res = boost::stacktrace::detail::addr2line("-fe", addr);
inline std::string name(const void* addr, bool position_independent) {
uintptr_t addr_base = 0;
if(position_independent){
addr_base = boost::stacktrace::detail::get_own_proc_addr_base(addr);
}
const void* offset = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) - addr_base);
std::string res = boost::stacktrace::detail::addr2line("-fe", offset);
res = res.substr(0, res.find_last_of('\n'));
res = boost::core::demangle(res.c_str());
@@ -189,11 +220,23 @@ inline std::string name_impl(const void* addr) {
return res;
}
} // namespace detail
inline std::string name_impl(const void* addr) {
std::string res = boost::stacktrace::detail::name(addr, false);
if (res.empty()) {
res = boost::stacktrace::detail::name(addr, true);
}
std::string frame::source_file() const {
return res;
}
inline std::string source_file(const void* addr, bool position_independent) {
std::string res;
res = boost::stacktrace::detail::addr2line("-e", addr_);
uintptr_t addr_base = 0;
if(position_independent){
addr_base = boost::stacktrace::detail::get_own_proc_addr_base(addr);
}
const void* offset = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) - addr_base);
res = boost::stacktrace::detail::addr2line("-e", offset);
res = res.substr(0, res.find_last_of(':'));
if (res == "??") {
res.clear();
@@ -202,23 +245,48 @@ std::string frame::source_file() const {
return res;
}
std::size_t frame::source_line() const {
inline std::size_t source_line(const void* addr, bool position_independent) {
std::size_t line_num = 0;
std::string res = boost::stacktrace::detail::addr2line("-e", addr_);
uintptr_t addr_base = 0;
if(position_independent){
addr_base = boost::stacktrace::detail::get_own_proc_addr_base(addr);
}
const void* offset = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) - addr_base);
std::string res = boost::stacktrace::detail::addr2line("-e", offset);
const std::size_t last = res.find_last_of(':');
if (last == std::string::npos) {
return 0;
}
res = res.substr(last + 1);
if (!boost::conversion::try_lexical_convert(res, line_num)) {
if (!boost::stacktrace::detail::try_dec_convert(res.c_str(), line_num)) {
return 0;
}
return line_num;
}
} // namespace detail
std::string frame::source_file() const {
std::string res = boost::stacktrace::detail::source_file(addr_, false);
if (res.empty()) {
res = boost::stacktrace::detail::source_file(addr_, true);
}
return res;
}
std::size_t frame::source_line() const {
std::size_t line_num = boost::stacktrace::detail::source_line(addr_, false);
if (line_num == 0) {
line_num = boost::stacktrace::detail::source_line(addr_, true);
}
return line_num;
}
}} // namespace boost::stacktrace

View File

@@ -0,0 +1,89 @@
// Copyright Antony Polukhin, 2016-2024.
//
// 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)
#ifndef BOOST_STACKTRACE_DETAIL_ADDR_BASE_HPP
#define BOOST_STACKTRACE_DETAIL_ADDR_BASE_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <fstream>
#include <sstream>
#include <cstdint>
#include <cstdlib>
namespace boost { namespace stacktrace { namespace detail {
struct mapping_entry_t {
uintptr_t start = 0;
uintptr_t end = 0;
uintptr_t offset_from_base = 0;
inline bool contains_addr(const void* addr) const {
uintptr_t addr_uint = reinterpret_cast<uintptr_t>(addr);
return addr_uint >= start && addr_uint < end;
}
};
inline uintptr_t hex_str_to_int(const std::string& str) {
uintptr_t out;
std::stringstream ss;
ss << std::hex << str;
ss >> out;
if(ss.eof() && !ss.fail()) { // whole stream read, with no errors
return out;
} else {
throw std::invalid_argument(std::string("can't convert '") + str + "' to hex");
}
}
// parse line from /proc/<id>/maps
// format:
// 7fb60d1ea000-7fb60d20c000 r--p 00000000 103:02 120327460 /usr/lib/libc.so.6
// only parts 0 and 2 are interesting, these are:
// 0. mapping address range
// 2. mapping offset from base
inline mapping_entry_t parse_proc_maps_line(const std::string& line) {
std::string mapping_range_str, permissions_str, offset_from_base_str;
std::istringstream line_stream(line);
if(!std::getline(line_stream, mapping_range_str, ' ') ||
!std::getline(line_stream, permissions_str, ' ') ||
!std::getline(line_stream, offset_from_base_str, ' ')) {
return mapping_entry_t{};
}
std::string mapping_start_str, mapping_end_str;
std::istringstream mapping_range_stream(mapping_range_str);
if(!std::getline(mapping_range_stream, mapping_start_str, '-') ||
!std::getline(mapping_range_stream, mapping_end_str)) {
return mapping_entry_t{};
}
mapping_entry_t mapping{};
try {
mapping.start = hex_str_to_int(mapping_start_str);
mapping.end = hex_str_to_int(mapping_end_str);
mapping.offset_from_base = hex_str_to_int(offset_from_base_str);
return mapping;
} catch(std::invalid_argument& e) {
return mapping_entry_t{};
}
}
inline uintptr_t get_own_proc_addr_base(const void* addr) {
std::ifstream maps_file("/proc/self/maps");
for (std::string line; std::getline(maps_file, line); ) {
const mapping_entry_t mapping = parse_proc_maps_line(line);
if (mapping.contains_addr(addr)) {
return mapping.start - mapping.offset_from_base;
}
}
return 0;
}
}}} // namespace boost::stacktrace::detail
#endif // BOOST_STACKTRACE_DETAIL_ADDR_BASE_HPP

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -14,15 +14,15 @@
#include <boost/stacktrace/safe_dump_to.hpp>
#include <boost/detail/winapi/stack_backtrace.hpp>
#include <boost/winapi/stack_backtrace.hpp>
namespace boost { namespace stacktrace { namespace detail {
std::size_t this_thread_frames::collect(native_frame_ptr_t* out_frames, std::size_t max_frames_count, std::size_t skip) BOOST_NOEXCEPT {
return boost::detail::winapi::RtlCaptureStackBackTrace(
static_cast<boost::detail::winapi::ULONG_>(skip),
static_cast<boost::detail::winapi::ULONG_>(max_frames_count),
const_cast<boost::detail::winapi::PVOID_*>(out_frames),
std::size_t this_thread_frames::collect(native_frame_ptr_t* out_frames, std::size_t max_frames_count, std::size_t skip) noexcept {
return boost::winapi::RtlCaptureStackBackTrace(
static_cast<boost::winapi::ULONG_>(skip),
static_cast<boost::winapi::ULONG_>(max_frames_count),
const_cast<boost::winapi::PVOID_*>(out_frames),
0
);
}

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -16,7 +16,7 @@
namespace boost { namespace stacktrace { namespace detail {
std::size_t this_thread_frames::collect(native_frame_ptr_t* /*out_frames*/, std::size_t /*max_frames_count*/, std::size_t /*skip*/) BOOST_NOEXCEPT {
std::size_t this_thread_frames::collect(native_frame_ptr_t* /*out_frames*/, std::size_t /*max_frames_count*/, std::size_t /*skip*/) noexcept {
return 0;
}

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -14,11 +14,28 @@
#include <boost/stacktrace/safe_dump_to.hpp>
// On iOS 32-bit ARM architecture _Unwind_Backtrace function doesn't exist, symbol is undefined.
// Forcing libc backtrace() function usage.
#include <boost/predef.h>
#if defined(BOOST_OS_IOS_AVAILABLE) && defined(BOOST_ARCH_ARM_AVAILABLE) && BOOST_VERSION_NUMBER_MAJOR(BOOST_ARCH_ARM) < 8
#define BOOST_STACKTRACE_USE_LIBC_BACKTRACE_FUNCTION
#endif
#if defined(BOOST_STACKTRACE_USE_LIBC_BACKTRACE_FUNCTION)
#include <execinfo.h>
#include <algorithm>
#else
#include <unwind.h>
#endif
#include <cstdio>
#if !defined(_GNU_SOURCE) && !defined(BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED) && !defined(BOOST_WINDOWS)
#error "Boost.Stacktrace requires `_Unwind_Backtrace` function. Define `_GNU_SOURCE` macro or `BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED` if _Unwind_Backtrace is available without `_GNU_SOURCE`."
#endif
namespace boost { namespace stacktrace { namespace detail {
#if !defined(BOOST_STACKTRACE_USE_LIBC_BACKTRACE_FUNCTION)
struct unwind_state {
std::size_t frames_to_skip;
native_frame_ptr_t* current;
@@ -44,16 +61,35 @@ inline _Unwind_Reason_Code unwind_callback(::_Unwind_Context* context, void* arg
}
return ::_URC_NO_REASON;
}
#endif //!defined(BOOST_STACKTRACE_USE_LIBC_BACKTRACE_FUNCTION)
std::size_t this_thread_frames::collect(native_frame_ptr_t* out_frames, std::size_t max_frames_count, std::size_t skip) BOOST_NOEXCEPT {
std::size_t this_thread_frames::collect(native_frame_ptr_t* out_frames, std::size_t max_frames_count, std::size_t skip) noexcept {
std::size_t frames_count = 0;
if (!max_frames_count) {
return frames_count;
}
skip += 1;
boost::stacktrace::detail::unwind_state state = { skip + 1, out_frames, out_frames + max_frames_count };
#if defined(BOOST_STACKTRACE_USE_LIBC_BACKTRACE_FUNCTION)
// According to https://opensource.apple.com/source/Libc/Libc-1272.200.26/gen/backtrace.c.auto.html
// it looks like the `::backtrace` is async signal safe.
frames_count = static_cast<size_t>(::backtrace(const_cast<void **>(out_frames), static_cast<int>(max_frames_count)));
// NOTE: There is no way to pass "skip" count to backtrace function so we need to perform left shift operation.
// If number of elements in result backtrace is >= max_frames_count then "skip" elements are wasted.
if (frames_count && skip) {
if (skip >= frames_count) {
frames_count = 0;
} else {
std::copy(out_frames + skip, out_frames + frames_count, out_frames);
frames_count -= skip;
}
}
#else
boost::stacktrace::detail::unwind_state state = { skip, out_frames, out_frames + max_frames_count };
::_Unwind_Backtrace(&boost::stacktrace::detail::unwind_callback, &state);
frames_count = state.current - out_frames;
#endif //defined(BOOST_STACKTRACE_USE_LIBC_BACKTRACE_FUNCTION)
if (frames_count && out_frames[frames_count - 1] == 0) {
-- frames_count;
@@ -65,4 +101,6 @@ std::size_t this_thread_frames::collect(native_frame_ptr_t* out_frames, std::siz
}}} // namespace boost::stacktrace::detail
#undef BOOST_STACKTRACE_USE_LIBC_BACKTRACE_FUNCTION
#endif // BOOST_STACKTRACE_DETAIL_COLLECT_UNWIND_IPP

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -15,12 +15,10 @@
#include <iosfwd>
#include <string>
#include <boost/core/explicit_operator_bool.hpp>
#include <boost/stacktrace/safe_dump_to.hpp> // boost::stacktrace::detail::native_frame_ptr_t
#include <boost/stacktrace/detail/void_ptr_cast.hpp>
#include <boost/stacktrace/detail/push_options.pp>
#include <boost/stacktrace/detail/push_options.h>
/// @file boost/stacktrace/detail/frame_decl.hpp
/// Use <boost/stacktrace/frame.hpp> header instead of this one!
@@ -47,7 +45,7 @@ public:
///
/// @b Async-Handler-Safety: Safe.
/// @throws Nothing.
BOOST_CONSTEXPR frame() BOOST_NOEXCEPT
constexpr frame() noexcept
: addr_(0)
{}
@@ -75,7 +73,7 @@ public:
///
/// @b Async-Handler-Safety: Safe.
/// @throws Nothing.
BOOST_CONSTEXPR explicit frame(native_frame_ptr_t addr) BOOST_NOEXCEPT
constexpr explicit frame(native_frame_ptr_t addr) noexcept
: addr_(addr)
{}
@@ -86,7 +84,7 @@ public:
/// @b Async-Handler-Safety: Safe.
/// @throws Nothing.
template <class T>
explicit frame(T* function_addr) BOOST_NOEXCEPT
explicit frame(T* function_addr) noexcept
: addr_(boost::stacktrace::detail::void_ptr_cast<native_frame_ptr_t>(function_addr))
{}
@@ -104,7 +102,7 @@ public:
///
/// @b Async-Handler-Safety: Safe.
/// @throws Nothing.
BOOST_CONSTEXPR native_frame_ptr_t address() const BOOST_NOEXCEPT {
constexpr native_frame_ptr_t address() const noexcept {
return addr_;
}
@@ -131,7 +129,7 @@ public:
/// @b Complexity: O(1)
///
/// @b Async-Handler-Safety: Safe.
BOOST_EXPLICIT_OPERATOR_BOOL()
constexpr explicit operator bool () const noexcept { return !empty(); }
/// @brief Checks that frame references NULL address.
/// @returns `true` if `this->address() == 0`
@@ -139,11 +137,7 @@ public:
/// @b Complexity: O(1)
///
/// @b Async-Handler-Safety: Safe.
BOOST_CONSTEXPR bool empty() const BOOST_NOEXCEPT { return !address(); }
/// @cond
BOOST_CONSTEXPR bool operator!() const BOOST_NOEXCEPT { return !address(); }
/// @endcond
constexpr bool empty() const noexcept { return !address(); }
};
@@ -154,6 +148,6 @@ namespace detail {
}} // namespace boost::stacktrace
#include <boost/stacktrace/detail/pop_options.pp>
#include <boost/stacktrace/detail/pop_options.h>
#endif // BOOST_STACKTRACE_DETAIL_FRAME_DECL_HPP

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -16,12 +16,12 @@
#include <boost/core/demangle.hpp>
#include <boost/core/noncopyable.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/stacktrace/detail/to_dec_array.hpp>
#include <boost/stacktrace/detail/to_hex_array.hpp>
#include <windows.h>
#include "dbgeng.h"
#include <boost/detail/winapi/get_current_process.hpp>
#include <mutex>
#ifdef BOOST_MSVC
# pragma comment(lib, "ole32.lib")
@@ -30,9 +30,13 @@
#ifdef __CRT_UUID_DECL // for __MINGW32__
#if !defined(__MINGW32__) || \
(!defined(__clang__) && __GNUC__ < 12) || \
(defined(__clang__) && __clang_major__ < 16)
__CRT_UUID_DECL(IDebugClient,0x27fe5639,0x8407,0x4f47,0x83,0x64,0xee,0x11,0x8f,0xb0,0x8a,0xc8)
__CRT_UUID_DECL(IDebugControl,0x5182e668,0x105e,0x416e,0xad,0x92,0x24,0xef,0x80,0x04,0x24,0xba)
__CRT_UUID_DECL(IDebugSymbols,0x8c31e98c,0x983a,0x48a5,0x90,0x16,0x6f,0xe5,0xd6,0x67,0xa9,0x50)
#endif
#elif defined(DEFINE_GUID) && !defined(BOOST_MSVC)
DEFINE_GUID(IID_IDebugClient,0x27fe5639,0x8407,0x4f47,0x83,0x64,0xee,0x11,0x8f,0xb0,0x8a,0xc8);
DEFINE_GUID(IID_IDebugControl,0x5182e668,0x105e,0x416e,0xad,0x92,0x24,0xef,0x80,0x04,0x24,0xba);
@@ -46,53 +50,28 @@
namespace boost { namespace stacktrace { namespace detail {
class com_global_initer: boost::noncopyable {
bool ok_;
public:
com_global_initer() BOOST_NOEXCEPT
: ok_(false)
{
// COINIT_MULTITHREADED means that we must serialize access to the objects manually.
// This is the fastest way to work. If user calls CoInitializeEx before us - we
// can end up with other mode (which is OK for us).
//
// If we call CoInitializeEx befire user - user may end up with different mode, which is a problem.
// So we need to call that initialization function as late as possible.
const boost::detail::winapi::DWORD_ res = ::CoInitializeEx(0, COINIT_MULTITHREADED);
ok_ = (res == S_OK || res == S_FALSE);
}
~com_global_initer() BOOST_NOEXCEPT {
if (ok_) {
::CoUninitialize();
}
}
};
template <class T>
class com_holder: boost::noncopyable {
T* holder_;
public:
com_holder(const com_global_initer&) BOOST_NOEXCEPT
com_holder() noexcept
: holder_(0)
{}
T* operator->() const BOOST_NOEXCEPT {
T* operator->() const noexcept {
return holder_;
}
void** to_void_ptr_ptr() BOOST_NOEXCEPT {
void** to_void_ptr_ptr() noexcept {
return reinterpret_cast<void**>(&holder_);
}
bool is_inited() const BOOST_NOEXCEPT {
bool is_inited() const noexcept {
return !!holder_;
}
~com_holder() BOOST_NOEXCEPT {
~com_holder() noexcept {
if (holder_) {
holder_->Release();
}
@@ -100,7 +79,7 @@ public:
};
static std::string minwg_demangling_workaround(const std::string& s) {
inline std::string mingw_demangling_workaround(const std::string& s) {
#ifdef BOOST_GCC
if (s.empty()) {
return s;
@@ -116,14 +95,25 @@ static std::string minwg_demangling_workaround(const std::string& s) {
#endif
}
inline void trim_right_zeroes(std::string& s) {
// MSVC-9 does not have back() and pop_back() functions in std::string
while (!s.empty()) {
const std::size_t last = static_cast<std::size_t>(s.size() - 1);
if (s[last] != '\0') {
break;
}
s.resize(last);
}
}
class debugging_symbols: boost::noncopyable {
static void try_init_com(com_holder< ::IDebugSymbols>& idebug, const com_global_initer& com) BOOST_NOEXCEPT {
com_holder< ::IDebugClient> iclient(com);
static void try_init_com(com_holder< ::IDebugSymbols>& idebug) noexcept {
com_holder< ::IDebugClient> iclient;
if (S_OK != ::DebugCreate(__uuidof(IDebugClient), iclient.to_void_ptr_ptr())) {
return;
}
com_holder< ::IDebugControl> icontrol(com);
com_holder< ::IDebugControl> icontrol;
const bool res0 = (S_OK == iclient->QueryInterface(
__uuidof(IDebugControl),
icontrol.to_void_ptr_ptr()
@@ -145,36 +135,48 @@ class debugging_symbols: boost::noncopyable {
return;
}
// No cheking: QueryInterface sets the output parameter to NULL in case of error.
// No checking: QueryInterface sets the output parameter to NULL in case of error.
iclient->QueryInterface(__uuidof(IDebugSymbols), idebug.to_void_ptr_ptr());
}
#ifndef BOOST_STACKTRACE_USE_WINDBG_CACHED
boost::stacktrace::detail::com_global_initer com_;
com_holder< ::IDebugSymbols> idebug_;
public:
debugging_symbols() BOOST_NOEXCEPT
: com_()
, idebug_(com_)
{
try_init_com(idebug_, com_);
static std::mutex& get_mutex_inst() noexcept {
static std::mutex m;
return m;
}
static com_holder< ::IDebugSymbols>& get_static_debug_inst() noexcept {
// [class.mfct]: A static local variable or local type in a member function always refers to the same entity, whether
// or not the member function is inline.
static com_holder< ::IDebugSymbols> idebug;
if (!idebug.is_inited()) {
try_init_com(idebug);
}
return idebug;
}
std::lock_guard<std::mutex> guard_;
com_holder< ::IDebugSymbols>& idebug_;
public:
debugging_symbols() noexcept
: guard_( get_mutex_inst() )
, idebug_( get_static_debug_inst() )
{}
#else
#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.
# error Your compiler does not support C++11 thread_local storage. It`s impossible to build with BOOST_STACKTRACE_USE_WINDBG_CACHED.
#endif
static com_holder< ::IDebugSymbols>& get_thread_local_debug_inst() BOOST_NOEXCEPT {
static com_holder< ::IDebugSymbols>& get_thread_local_debug_inst() noexcept {
// [class.mfct]: A static local variable or local type in a member function always refers to the same entity, whether
// or not the member function is inline.
static thread_local boost::stacktrace::detail::com_global_initer com;
static thread_local com_holder< ::IDebugSymbols> idebug(com);
static thread_local com_holder< ::IDebugSymbols> idebug;
if (!idebug.is_inited()) {
try_init_com(idebug, com);
try_init_com(idebug);
}
return idebug;
@@ -182,13 +184,13 @@ public:
com_holder< ::IDebugSymbols>& idebug_;
public:
debugging_symbols() BOOST_NOEXCEPT
debugging_symbols() noexcept
: idebug_( get_thread_local_debug_inst() )
{}
#endif // #ifndef BOOST_STACKTRACE_USE_WINDBG_CACHED
bool is_inited() const BOOST_NOEXCEPT {
bool is_inited() const noexcept {
return idebug_.is_inited();
}
@@ -219,8 +221,12 @@ public:
&size,
0
));
// According to https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/dbgeng/nf-dbgeng-idebugsymbols-getnamebyoffset
// "This size includes the space for the '\0' terminating character."
result.resize(size - 1);
} else if (res) {
result = name;
result.assign(name, size - 1);
}
if (!res) {
@@ -239,14 +245,14 @@ public:
return result;
}
result = minwg_demangling_workaround(
result = mingw_demangling_workaround(
result.substr(delimiter + 1)
);
return result;
}
std::size_t get_line_impl(const void* addr) const BOOST_NOEXCEPT {
std::size_t get_line_impl(const void* addr) const noexcept {
ULONG result = 0;
if (!is_inited()) {
return result;
@@ -303,6 +309,7 @@ public:
&size,
0
));
trim_right_zeroes(result.first);
result.second = line_num;
if (!res) {
@@ -331,7 +338,7 @@ public:
res += " at ";
res += source_line.first;
res += ':';
res += boost::lexical_cast<boost::array<char, 40> >(source_line.second).data();
res += boost::stacktrace::detail::to_dec_array(source_line.second).data();
} else if (!module_name.empty()) {
res += " in ";
res += module_name;
@@ -351,7 +358,7 @@ std::string to_string(const frame* frames, std::size_t size) {
if (i < 10) {
res += ' ';
}
res += boost::lexical_cast<boost::array<char, 40> >(i).data();
res += boost::stacktrace::detail::to_dec_array(i).data();
res += '#';
res += ' ';
idebug.to_string_impl(frames[i].address(), res);

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -16,8 +16,8 @@
#include <boost/stacktrace/detail/to_hex_array.hpp>
#include <boost/stacktrace/detail/location_from_symbol.hpp>
#include <boost/stacktrace/detail/to_dec_array.hpp>
#include <boost/core/demangle.hpp>
#include <boost/lexical_cast.hpp>
#include <cstdio>
@@ -59,6 +59,9 @@ public:
std::string to_string(const frame* frames, std::size_t size) {
std::string res;
if (size == 0) {
return res;
}
res.reserve(64 * size);
to_string_impl impl;
@@ -67,7 +70,7 @@ std::string to_string(const frame* frames, std::size_t size) {
if (i < 10) {
res += ' ';
}
res += boost::lexical_cast<boost::array<char, 40> >(i).data();
res += boost::stacktrace::detail::to_dec_array(i).data();
res += '#';
res += ' ';
res += impl(frames[i].address());
@@ -82,9 +85,13 @@ std::string to_string(const frame* frames, std::size_t size) {
std::string frame::name() const {
if (!addr_) {
return std::string();
}
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
::Dl_info dli;
const bool dl_ok = !!::dladdr(addr_, &dli);
const bool dl_ok = !!::dladdr(const_cast<void*>(addr_), &dli); // `dladdr` on Solaris accepts nonconst addresses
if (dl_ok && dli.dli_sname) {
return boost::core::demangle(dli.dli_sname);
}
@@ -93,6 +100,10 @@ std::string frame::name() const {
}
std::string to_string(const frame& f) {
if (!f) {
return std::string();
}
boost::stacktrace::detail::to_string_impl impl;
return impl(f.address());
}

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -13,10 +13,15 @@
#endif
#include <boost/stacktrace/detail/to_hex_array.hpp>
#include <boost/stacktrace/detail/to_dec_array.hpp>
#include <boost/stacktrace/detail/location_from_symbol.hpp>
#include <boost/core/demangle.hpp>
#include <boost/lexical_cast.hpp>
#include <backtrace.h>
#ifdef BOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE
# include BOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE
#else
# include <backtrace.h>
#endif
namespace boost { namespace stacktrace { namespace detail {
@@ -27,6 +32,18 @@ struct pc_data {
std::size_t line;
};
inline void libbacktrace_syminfo_callback(void *data, uintptr_t /*pc*/, const char *symname, uintptr_t /*symval*/, uintptr_t /*symsize*/) {
pc_data& d = *static_cast<pc_data*>(data);
if (d.function && symname) {
*d.function = symname;
}
}
// Old versions of libbacktrace have different signature for the callback
inline void libbacktrace_syminfo_callback(void *data, uintptr_t pc, const char *symname, uintptr_t symval) {
boost::stacktrace::detail::libbacktrace_syminfo_callback(data, pc, symname, symval, 0);
}
inline int libbacktrace_full_callback(void *data, uintptr_t /*pc*/, const char *filename, int lineno, const char *function) {
pc_data& d = *static_cast<pc_data*>(data);
if (d.filename && filename) {
@@ -39,36 +56,67 @@ inline int libbacktrace_full_callback(void *data, uintptr_t /*pc*/, const char *
return 0;
}
inline void libbacktrace_error_callback(void* /*data*/, const char* /*msg*/, int /*errnum*/) BOOST_NOEXCEPT {
inline void libbacktrace_error_callback(void* /*data*/, const char* /*msg*/, int /*errnum*/) noexcept {
// Do nothing, just return.
}
extern inline ::backtrace_state* construct_state() BOOST_NOEXCEPT {
return ::backtrace_create_state(
0, 0 /*thread-safe*/, boost::stacktrace::detail::libbacktrace_error_callback, 0
);
// TODO: this does not seem to work well when this function is in .so:
// Not async-signal-safe, so this method is not called from async-safe functions.
//
// This function is not async signal safe because:
// * Dynamic initialization of a block-scope variable with static storage duration could lock a mutex
// * No guarantees on `backtrace_create_state` function.
// Not async-signal-safe, so this method is not called from async-safe functions.
//
// This function is not async signal safe because:
// * Dynamic initialization of a block-scope variable with static storage duration could lock a mutex
// * No guarantees on `backtrace_create_state` function.
//
// Currently `backtrace_create_state` can not detect file name on Windows https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82543
// That's why we provide a `prog_location` here.
BOOST_SYMBOL_VISIBLE inline ::backtrace_state* construct_state(const program_location& prog_location) noexcept {
// [dcl.inline]: A static local variable in an inline function with external linkage always refers to the same object.
/*
static ::backtrace_state* state = ::backtrace_create_state(
0, 1 , boost::stacktrace::detail::libbacktrace_error_callback, 0
// TODO: The most obvious solution:
//
//static ::backtrace_state* state = ::backtrace_create_state(
// prog_location.name(),
// 1, // allow safe concurrent usage of the same state
// boost::stacktrace::detail::libbacktrace_error_callback,
// 0 // pointer to data that will be passed to callback
//);
//
//
// Unfortunately, that solution segfaults when `construct_state()` function is in .so file
// and multiple threads concurrently work with state. I failed to localize the root cause:
// https://gcc.gnu.org/bugzilla//show_bug.cgi?id=87653
#define BOOST_STACKTRACE_DETAIL_IS_MT 1
#if !defined(BOOST_HAS_THREADS)
# define BOOST_STACKTRACE_DETAIL_STORAGE static
# undef BOOST_STACKTRACE_DETAIL_IS_MT
# define BOOST_STACKTRACE_DETAIL_IS_MT 0
#elif defined(BOOST_STACKTRACE_BACKTRACE_FORCE_STATIC)
# define BOOST_STACKTRACE_DETAIL_STORAGE static
#elif !defined(BOOST_NO_CXX11_THREAD_LOCAL)
# define BOOST_STACKTRACE_DETAIL_STORAGE thread_local
#elif defined(__GNUC__) && !defined(__clang__)
# define BOOST_STACKTRACE_DETAIL_STORAGE static __thread
#else
# define BOOST_STACKTRACE_DETAIL_STORAGE /* just a local variable */
#endif
BOOST_STACKTRACE_DETAIL_STORAGE ::backtrace_state* state = ::backtrace_create_state(
prog_location.name(),
BOOST_STACKTRACE_DETAIL_IS_MT,
boost::stacktrace::detail::libbacktrace_error_callback,
0
);
#undef BOOST_STACKTRACE_DETAIL_IS_MT
#undef BOOST_STACKTRACE_DETAIL_STORAGE
return state;
*/
}
struct to_string_using_backtrace {
std::string res;
boost::stacktrace::detail::program_location prog_location;
::backtrace_state* state;
std::string filename;
std::size_t line;
@@ -82,6 +130,14 @@ struct to_string_using_backtrace {
boost::stacktrace::detail::libbacktrace_full_callback,
boost::stacktrace::detail::libbacktrace_error_callback,
&data
)
||
::backtrace_syminfo(
state,
reinterpret_cast<uintptr_t>(addr),
boost::stacktrace::detail::libbacktrace_syminfo_callback,
boost::stacktrace::detail::libbacktrace_error_callback,
&data
);
}
line = data.line;
@@ -95,12 +151,12 @@ struct to_string_using_backtrace {
res += " at ";
res += filename;
res += ':';
res += boost::lexical_cast<boost::array<char, 40> >(line).data();
res += boost::stacktrace::detail::to_dec_array(line).data();
return true;
}
to_string_using_backtrace() BOOST_NOEXCEPT {
state = boost::stacktrace::detail::construct_state();
to_string_using_backtrace() noexcept {
state = boost::stacktrace::detail::construct_state(prog_location);
}
};
@@ -110,7 +166,8 @@ typedef to_string_impl_base<to_string_using_backtrace> to_string_impl;
inline std::string name_impl(const void* addr) {
std::string res;
::backtrace_state* state = boost::stacktrace::detail::construct_state();
boost::stacktrace::detail::program_location prog_location;
::backtrace_state* state = boost::stacktrace::detail::construct_state(prog_location);
boost::stacktrace::detail::pc_data data = {&res, 0, 0};
if (state) {
@@ -120,6 +177,14 @@ inline std::string name_impl(const void* addr) {
boost::stacktrace::detail::libbacktrace_full_callback,
boost::stacktrace::detail::libbacktrace_error_callback,
&data
)
||
::backtrace_syminfo(
state,
reinterpret_cast<uintptr_t>(addr),
boost::stacktrace::detail::libbacktrace_syminfo_callback,
boost::stacktrace::detail::libbacktrace_error_callback,
&data
);
}
if (!res.empty()) {
@@ -134,7 +199,12 @@ inline std::string name_impl(const void* addr) {
std::string frame::source_file() const {
std::string res;
::backtrace_state* state = boost::stacktrace::detail::construct_state();
if (!addr_) {
return res;
}
boost::stacktrace::detail::program_location prog_location;
::backtrace_state* state = boost::stacktrace::detail::construct_state(prog_location);
boost::stacktrace::detail::pc_data data = {0, &res, 0};
if (state) {
@@ -151,7 +221,12 @@ std::string frame::source_file() const {
}
std::size_t frame::source_line() const {
::backtrace_state* state = boost::stacktrace::detail::construct_state();
if (!addr_) {
return 0;
}
boost::stacktrace::detail::program_location prog_location;
::backtrace_state* state = boost::stacktrace::detail::construct_state(prog_location);
boost::stacktrace::detail::pc_data data = {0, 0, 0};
if (state) {

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -15,62 +15,91 @@
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
# include <dlfcn.h>
#else
# include <boost/detail/winapi/dll.hpp>
# include <boost/winapi/dll.hpp>
#endif
namespace boost { namespace stacktrace { namespace detail {
class location_from_symbol {
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
class location_from_symbol {
::Dl_info dli_;
public:
explicit location_from_symbol(const void* addr) BOOST_NOEXCEPT
explicit location_from_symbol(const void* addr) noexcept
: dli_()
{
if (!::dladdr(addr, &dli_)) {
if (!::dladdr(const_cast<void*>(addr), &dli_)) { // `dladdr` on Solaris accepts nonconst addresses
dli_.dli_fname = 0;
}
}
bool empty() const BOOST_NOEXCEPT {
bool empty() const noexcept {
return !dli_.dli_fname;
}
const char* name() const BOOST_NOEXCEPT {
const char* name() const noexcept {
return dli_.dli_fname;
}
#else
BOOST_STATIC_CONSTEXPR boost::detail::winapi::DWORD_ DEFAULT_PATH_SIZE_ = 260;
};
class program_location {
public:
const char* name() const noexcept {
return 0;
}
};
#else
class location_from_symbol {
BOOST_STATIC_CONSTEXPR boost::winapi::DWORD_ DEFAULT_PATH_SIZE_ = 260;
char file_name_[DEFAULT_PATH_SIZE_];
public:
explicit location_from_symbol(const void* addr) BOOST_NOEXCEPT {
explicit location_from_symbol(const void* addr) noexcept {
file_name_[0] = '\0';
boost::detail::winapi::MEMORY_BASIC_INFORMATION_ mbi;
if (!boost::detail::winapi::VirtualQuery(addr, &mbi, sizeof(mbi))) {
boost::winapi::MEMORY_BASIC_INFORMATION_ mbi;
if (!boost::winapi::VirtualQuery(addr, &mbi, sizeof(mbi))) {
return;
}
boost::detail::winapi::HMODULE_ handle = reinterpret_cast<boost::detail::winapi::HMODULE_>(mbi.AllocationBase);
if (!boost::detail::winapi::GetModuleFileNameA(handle, file_name_, DEFAULT_PATH_SIZE_)) {
boost::winapi::HMODULE_ handle = reinterpret_cast<boost::winapi::HMODULE_>(mbi.AllocationBase);
if (!boost::winapi::GetModuleFileNameA(handle, file_name_, DEFAULT_PATH_SIZE_)) {
file_name_[0] = '\0';
return;
}
}
bool empty() const BOOST_NOEXCEPT {
bool empty() const noexcept {
return file_name_[0] == '\0';
}
const char* name() const BOOST_NOEXCEPT {
const char* name() const noexcept {
return file_name_;
}
#endif
};
class program_location {
BOOST_STATIC_CONSTEXPR boost::winapi::DWORD_ DEFAULT_PATH_SIZE_ = 260;
char file_name_[DEFAULT_PATH_SIZE_];
public:
program_location() noexcept {
file_name_[0] = '\0';
const boost::winapi::HMODULE_ handle = 0;
if (!boost::winapi::GetModuleFileNameA(handle, file_name_, DEFAULT_PATH_SIZE_)) {
file_name_[0] = '\0';
}
}
const char* name() const noexcept {
return file_name_[0] ? file_name_ : 0;
}
};
#endif
}}} // namespace boost::stacktrace::detail
#endif // BOOST_STACKTRACE_DETAIL_LOCATION_FROM_SYMBOL_HPP

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -18,17 +18,17 @@ namespace boost { namespace stacktrace { namespace detail {
#if defined(BOOST_WINDOWS)
std::size_t dump(void* /*fd*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) BOOST_NOEXCEPT {
std::size_t dump(void* /*fd*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) noexcept {
return 0;
}
#else
std::size_t dump(int /*fd*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) BOOST_NOEXCEPT {
std::size_t dump(int /*fd*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) noexcept {
return 0;
}
#endif
std::size_t dump(const char* /*file*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) BOOST_NOEXCEPT {
std::size_t dump(const char* /*file*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) noexcept {
return 0;
}

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -16,11 +16,12 @@
#include <unistd.h> // ::write
#include <fcntl.h> // ::open
#include <sys/stat.h> // S_IWUSR and friends
namespace boost { namespace stacktrace { namespace detail {
std::size_t dump(int fd, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT {
std::size_t dump(int fd, const native_frame_ptr_t* frames, std::size_t frames_count) noexcept {
// We do not retry, because this function must be typically called from signal handler so it's:
// * to scary to continue in case of EINTR
// * EAGAIN or EWOULDBLOCK may occur only in case of O_NONBLOCK is set for fd,
@@ -32,7 +33,7 @@ std::size_t dump(int fd, const native_frame_ptr_t* frames, std::size_t frames_co
return frames_count;
}
std::size_t dump(const char* file, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT {
std::size_t dump(const char* file, const native_frame_ptr_t* frames, std::size_t frames_count) noexcept {
const int fd = ::open(
file,
O_CREAT | O_WRONLY | O_TRUNC,

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -16,43 +16,49 @@
#include <boost/core/noncopyable.hpp>
#include <boost/detail/winapi/get_current_process.hpp>
#include <boost/detail/winapi/file_management.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/access_rights.hpp>
#include <boost/winapi/get_current_process.hpp>
#include <boost/winapi/file_management.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/winapi/access_rights.hpp>
namespace boost { namespace stacktrace { namespace detail {
std::size_t dump(void* fd, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT {
boost::detail::winapi::DWORD_ written;
const boost::detail::winapi::DWORD_ bytes_to_write = static_cast<boost::detail::winapi::DWORD_>(
std::size_t dump(void* /*fd*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) noexcept {
#if 0 // This code potentially could cause deadlocks (according to the MSDN). Disabled
boost::winapi::DWORD_ written;
const boost::winapi::DWORD_ bytes_to_write = static_cast<boost::winapi::DWORD_>(
sizeof(native_frame_ptr_t) * frames_count
);
if (!boost::detail::winapi::WriteFile(fd, frames, bytes_to_write, &written, 0)) {
if (!boost::winapi::WriteFile(fd, frames, bytes_to_write, &written, 0)) {
return 0;
}
return frames_count;
#endif
return 0;
}
std::size_t dump(const char* file, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT {
void* const fd = boost::detail::winapi::CreateFileA(
std::size_t dump(const char* /*file*/, const native_frame_ptr_t* /*frames*/, std::size_t /*frames_count*/) noexcept {
#if 0 // This code causing deadlocks on some platforms. Disabled
void* const fd = boost::winapi::CreateFileA(
file,
boost::detail::winapi::GENERIC_WRITE_,
boost::winapi::GENERIC_WRITE_,
0,
0,
boost::detail::winapi::CREATE_ALWAYS_,
boost::detail::winapi::FILE_ATTRIBUTE_NORMAL_,
boost::winapi::CREATE_ALWAYS_,
boost::winapi::FILE_ATTRIBUTE_NORMAL_,
0
);
if (fd == boost::detail::winapi::invalid_handle_value) {
if (fd == boost::winapi::invalid_handle_value) {
return 0;
}
const std::size_t size = boost::stacktrace::detail::dump(fd, frames, frames_count);
boost::detail::winapi::CloseHandle(fd);
boost::winapi::CloseHandle(fd);
return size;
#endif
return 0;
}
}}} // namespace boost::stacktrace::detail

View File

@@ -0,0 +1,47 @@
// Copyright Antony Polukhin, 2016-2024.
//
// 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)
#ifndef BOOST_STACKTRACE_DETAIL_TO_DEC_ARRAY_HPP
#define BOOST_STACKTRACE_DETAIL_TO_DEC_ARRAY_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <array>
#include <cstddef> // std::size_t
namespace boost { namespace stacktrace { namespace detail {
// We do not use boost::lexical_cast in this function to reduce module dependencies
inline std::array<char, 40> to_dec_array(std::size_t value) noexcept {
std::array<char, 40> ret;
if (!value) {
ret[0] = '0';
ret[1] = '\0';
return ret;
}
std::size_t digits = 0;
for (std::size_t value_copy = value; value_copy; value_copy /= 10) {
++ digits;
}
for (std::size_t i = 1; i <= digits; ++i) {
ret[digits - i] = static_cast<char>('0' + (value % 10));
value /= 10;
}
ret[digits] = '\0';
return ret;
}
}}} // namespace boost::stacktrace::detail
#endif // BOOST_STACKTRACE_DETAIL_TO_DEC_ARRAY_HPP

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -12,20 +12,18 @@
# pragma once
#endif
#include <boost/array.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_pointer.hpp>
#include <boost/type_traits/make_unsigned.hpp>
#include <array>
#include <type_traits>
namespace boost { namespace stacktrace { namespace detail {
BOOST_STATIC_CONSTEXPR char to_hex_array_bytes[] = "0123456789ABCDEF";
template <class T>
inline boost::array<char, 2 + sizeof(void*) * 2 + 1> to_hex_array(T addr) BOOST_NOEXCEPT {
boost::array<char, 2 + sizeof(void*) * 2 + 1> ret = {"0x"};
inline std::array<char, 2 + sizeof(void*) * 2 + 1> to_hex_array(T addr) noexcept {
std::array<char, 2 + sizeof(void*) * 2 + 1> ret = {"0x"};
ret.back() = '\0';
BOOST_STATIC_ASSERT_MSG(!boost::is_pointer<T>::value, "");
static_assert(!std::is_pointer<T>::value, "");
const std::size_t s = sizeof(T);
@@ -43,9 +41,9 @@ inline boost::array<char, 2 + sizeof(void*) * 2 + 1> to_hex_array(T addr) BOOST_
return ret;
}
inline boost::array<char, 2 + sizeof(void*) * 2 + 1> to_hex_array(const void* addr) BOOST_NOEXCEPT {
inline std::array<char, 2 + sizeof(void*) * 2 + 1> to_hex_array(const void* addr) noexcept {
return to_hex_array(
reinterpret_cast< boost::make_unsigned<std::ptrdiff_t>::type >(addr)
reinterpret_cast< std::make_unsigned<std::ptrdiff_t>::type >(addr)
);
}

View File

@@ -0,0 +1,29 @@
// Copyright Antony Polukhin, 2016-2024.
//
// 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)
#ifndef BOOST_STACKTRACE_DETAIL_TRY_DEC_CONVERT_HPP
#define BOOST_STACKTRACE_DETAIL_TRY_DEC_CONVERT_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <cstdlib>
namespace boost { namespace stacktrace { namespace detail {
// We do not use boost::lexical_cast in this function to reduce module dependencies
inline bool try_dec_convert(const char* s, std::size_t& res) noexcept {
char* end_ptr = 0;
res = std::strtoul(s, &end_ptr, 10);
return *end_ptr == '\0';
}
}}} // namespace boost::stacktrace::detail
#endif // BOOST_STACKTRACE_DETAIL_TRY_DEC_CONVERT_HPP

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -23,7 +23,7 @@ struct to_string_using_nothing {
res = boost::stacktrace::frame(addr).name();
}
bool prepare_source_location(const void* /*addr*/) const BOOST_NOEXCEPT {
bool prepare_source_location(const void* /*addr*/) const noexcept {
return false;
}
};

View File

@@ -1,5 +1,5 @@
// Copyright 2014 Renato Tegon Forti, Antony Polukhin.
// Copyright 2015-2017 Antony Polukhin.
// Copyright Antony Polukhin, 2015-2024.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
@@ -13,8 +13,7 @@
# pragma once
#endif
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_pointer.hpp>
#include <type_traits>
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && (__GNUC__ * 100 + __GNUC_MINOR__ > 301)
# pragma GCC system_header
@@ -25,13 +24,13 @@ namespace boost { namespace stacktrace { namespace detail {
// GCC warns when reinterpret_cast between function pointer and object pointer occur.
// This functionsuppress the warnings and ensures that such casts are safe.
template <class To, class From>
To void_ptr_cast(From* v) BOOST_NOEXCEPT {
BOOST_STATIC_ASSERT_MSG(
boost::is_pointer<To>::value,
To void_ptr_cast(From* v) noexcept {
static_assert(
std::is_pointer<To>::value,
"`void_ptr_cast` function must be used only for casting to or from void pointers."
);
BOOST_STATIC_ASSERT_MSG(
static_assert(
sizeof(From*) == sizeof(To),
"Pointer to function and pointer to object differ in size on your platform."
);

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -15,25 +15,23 @@
#include <iosfwd>
#include <string>
#include <boost/core/explicit_operator_bool.hpp>
#include <boost/stacktrace/safe_dump_to.hpp> // boost::stacktrace::detail::native_frame_ptr_t
#include <boost/stacktrace/detail/frame_decl.hpp>
#include <boost/stacktrace/detail/push_options.pp>
#include <boost/stacktrace/detail/push_options.h>
namespace boost { namespace stacktrace {
/// Comparison operators that provide platform dependant ordering and have O(1) complexity; are Async-Handler-Safe.
BOOST_CONSTEXPR inline bool operator< (const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return lhs.address() < rhs.address(); }
BOOST_CONSTEXPR inline bool operator> (const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return rhs < lhs; }
BOOST_CONSTEXPR inline bool operator<=(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return !(lhs > rhs); }
BOOST_CONSTEXPR inline bool operator>=(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return !(lhs < rhs); }
BOOST_CONSTEXPR inline bool operator==(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return lhs.address() == rhs.address(); }
BOOST_CONSTEXPR inline bool operator!=(const frame& lhs, const frame& rhs) BOOST_NOEXCEPT { return !(lhs == rhs); }
constexpr inline bool operator< (const frame& lhs, const frame& rhs) noexcept { return lhs.address() < rhs.address(); }
constexpr inline bool operator> (const frame& lhs, const frame& rhs) noexcept { return rhs < lhs; }
constexpr inline bool operator<=(const frame& lhs, const frame& rhs) noexcept { return !(lhs > rhs); }
constexpr inline bool operator>=(const frame& lhs, const frame& rhs) noexcept { return !(lhs < rhs); }
constexpr inline bool operator==(const frame& lhs, const frame& rhs) noexcept { return lhs.address() == rhs.address(); }
constexpr inline bool operator!=(const frame& lhs, const frame& rhs) noexcept { return !(lhs == rhs); }
/// Fast hashing support, O(1) complexity; Async-Handler-Safe.
inline std::size_t hash_value(const frame& f) BOOST_NOEXCEPT {
inline std::size_t hash_value(const frame& f) noexcept {
return reinterpret_cast<std::size_t>(f.address());
}
@@ -50,7 +48,7 @@ std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT
/// @cond
#include <boost/stacktrace/detail/pop_options.pp>
#include <boost/stacktrace/detail/pop_options.h>
#ifndef BOOST_STACKTRACE_LINK
# if defined(BOOST_STACKTRACE_USE_NOOP)

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -12,15 +12,23 @@
# pragma once
#endif
#include <boost/stacktrace/detail/push_options.pp>
#include <cstddef>
#if defined(BOOST_WINDOWS)
#include <boost/winapi/config.hpp>
#endif
#include <boost/stacktrace/detail/push_options.h>
#ifdef BOOST_INTEL
# pragma warning(push)
# pragma warning(disable:2196) // warning #2196: routine is both "inline" and "noinline"
#endif
/// @file safe_dump_to.hpp This header contains low-level async-signal-safe functions for dumping call stacks. Dumps are binary serialized arrays of `void*`,
/// so you could read them by using 'od -tx8 -An stacktrace_dump_failename' Linux command or using boost::stacktrace::stacktrace::from_dump functions.
/// @file safe_dump_to.hpp \asyncsafe low-level
/// functions for dumping call stacks. Dumps are binary serialized arrays of `void*`,
/// so you could read them by using 'od -tx8 -An stacktrace_dump_failename'
/// Linux command or using boost::stacktrace::stacktrace::from_dump functions.
namespace boost { namespace stacktrace {
@@ -31,19 +39,19 @@ namespace detail {
enum helper{ max_frames_dump = 128 };
BOOST_STACKTRACE_FUNCTION std::size_t from_dump(const char* filename, native_frame_ptr_t* out_frames);
BOOST_STACKTRACE_FUNCTION std::size_t dump(const char* file, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT;
BOOST_STACKTRACE_FUNCTION std::size_t dump(const char* file, const native_frame_ptr_t* frames, std::size_t frames_count) noexcept;
#if defined(BOOST_WINDOWS)
BOOST_STACKTRACE_FUNCTION std::size_t dump(void* fd, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT;
BOOST_STACKTRACE_FUNCTION std::size_t dump(void* fd, const native_frame_ptr_t* frames, std::size_t frames_count) noexcept;
#else
// POSIX
BOOST_STACKTRACE_FUNCTION std::size_t dump(int fd, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT;
BOOST_STACKTRACE_FUNCTION std::size_t dump(int fd, const native_frame_ptr_t* frames, std::size_t frames_count) noexcept;
#endif
struct this_thread_frames { // struct is required to avoid warning about usage of inline+BOOST_NOINLINE
BOOST_NOINLINE BOOST_STACKTRACE_FUNCTION static std::size_t collect(native_frame_ptr_t* out_frames, std::size_t max_frames_count, std::size_t skip) BOOST_NOEXCEPT;
BOOST_NOINLINE BOOST_STACKTRACE_FUNCTION static std::size_t collect(native_frame_ptr_t* out_frames, std::size_t max_frames_count, std::size_t skip) noexcept;
BOOST_NOINLINE static std::size_t safe_dump_to_impl(void* memory, std::size_t size, std::size_t skip) BOOST_NOEXCEPT {
BOOST_NOINLINE static std::size_t safe_dump_to_impl(void* memory, std::size_t size, std::size_t skip) noexcept {
typedef boost::stacktrace::detail::native_frame_ptr_t native_frame_ptr_t;
if (size < sizeof(native_frame_ptr_t)) {
@@ -57,7 +65,7 @@ struct this_thread_frames { // struct is required to avoid warning about usage o
}
template <class T>
BOOST_NOINLINE static std::size_t safe_dump_to_impl(T file, std::size_t skip, std::size_t max_depth) BOOST_NOEXCEPT {
BOOST_NOINLINE static std::size_t safe_dump_to_impl(T file, std::size_t skip, std::size_t max_depth) noexcept {
typedef boost::stacktrace::detail::native_frame_ptr_t native_frame_ptr_t;
native_frame_ptr_t buffer[boost::stacktrace::detail::max_frames_dump + 1];
@@ -78,14 +86,14 @@ struct this_thread_frames { // struct is required to avoid warning about usage o
///
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
///
/// @b Async-Handler-Safety: Safe.
/// @b Async-Handler-Safety: \asyncsafe.
///
/// @returns Stored call sequence depth including terminating zero frame.
/// @returns Stored call sequence depth including terminating zero frame. To get the actually consumed bytes multiply this value by the sizeof(boost::stacktrace::frame::native_frame_ptr_t)
///
/// @param memory Preallocated buffer to store current function call sequence into.
///
/// @param size Size of the preallocated buffer.
BOOST_FORCEINLINE std::size_t safe_dump_to(void* memory, std::size_t size) BOOST_NOEXCEPT {
BOOST_FORCEINLINE std::size_t safe_dump_to(void* memory, std::size_t size) noexcept {
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(memory, size, 0);
}
@@ -93,38 +101,38 @@ BOOST_FORCEINLINE std::size_t safe_dump_to(void* memory, std::size_t size) BOOST
///
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
///
/// @b Async-Handler-Safety: Safe.
/// @b Async-Handler-Safety: \asyncsafe.
///
/// @returns Stored call sequence depth including terminating zero frame.
/// @returns Stored call sequence depth including terminating zero frame. To get the actually consumed bytes multiply this value by the sizeof(boost::stacktrace::frame::native_frame_ptr_t)
///
/// @param skip How many top calls to skip and do not store.
///
/// @param memory Preallocated buffer to store current function call sequence into.
///
/// @param size Size of the preallocated buffer.
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, void* memory, std::size_t size) BOOST_NOEXCEPT {
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, void* memory, std::size_t size) noexcept {
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(memory, size, skip);
}
/// @brief Opens a file and rewrites its content with current function call sequence.
/// @brief Opens a file and rewrites its content with current function call sequence if such operations are async signal safe.
///
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
///
/// @b Async-Handler-Safety: Safe.
/// @b Async-Handler-Safety: \asyncsafe.
///
/// @returns Stored call sequence depth including terminating zero frame.
///
/// @param file File to store current function call sequence.
BOOST_FORCEINLINE std::size_t safe_dump_to(const char* file) BOOST_NOEXCEPT {
BOOST_FORCEINLINE std::size_t safe_dump_to(const char* file) noexcept {
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(file, 0, boost::stacktrace::detail::max_frames_dump);
}
/// @brief Opens a file and rewrites its content with current function call sequence.
/// @brief Opens a file and rewrites its content with current function call sequence if such operations are async signal safe.
///
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
///
/// @b Async-Handler-Safety: Safe.
/// @b Async-Handler-Safety: \asyncsafe.
///
/// @returns Stored call sequence depth including terminating zero frame.
///
@@ -133,28 +141,28 @@ BOOST_FORCEINLINE std::size_t safe_dump_to(const char* file) BOOST_NOEXCEPT {
/// @param max_depth Max call sequence depth to collect.
///
/// @param file File to store current function call sequence.
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, const char* file) BOOST_NOEXCEPT {
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, const char* file) noexcept {
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(file, skip, max_depth);
}
#ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
/// @brief Writes into the provided file descriptor the current function call sequence.
/// @brief Writes into the provided file descriptor the current function call sequence if such operation is async signal safe.
///
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
///
/// @b Async-Handler-Safety: Safe.
/// @b Async-Handler-Safety: \asyncsafe.
///
/// @returns Stored call sequence depth including terminating zero frame.
///
/// @param file File to store current function call sequence.
BOOST_FORCEINLINE std::size_t safe_dump_to(platform_specific_descriptor fd) BOOST_NOEXCEPT;
BOOST_FORCEINLINE std::size_t safe_dump_to(platform_specific_descriptor fd) noexcept;
/// @brief Writes into the provided file descriptor the current function call sequence.
/// @brief Writes into the provided file descriptor the current function call sequence if such operation is async signal safe.
///
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
///
/// @b Async-Handler-Safety: Safe.
/// @b Async-Handler-Safety: \asyncsafe.
///
/// @returns Stored call sequence depth including terminating zero frame.
///
@@ -163,26 +171,26 @@ BOOST_FORCEINLINE std::size_t safe_dump_to(platform_specific_descriptor fd) BOOS
/// @param max_depth Max call sequence depth to collect.
///
/// @param file File to store current function call sequence.
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, platform_specific_descriptor fd) BOOST_NOEXCEPT;
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, platform_specific_descriptor fd) noexcept;
#elif defined(BOOST_WINDOWS)
BOOST_FORCEINLINE std::size_t safe_dump_to(void* fd) BOOST_NOEXCEPT {
BOOST_FORCEINLINE std::size_t safe_dump_to(void* fd) noexcept {
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(fd, 0, boost::stacktrace::detail::max_frames_dump);
}
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, void* fd) BOOST_NOEXCEPT {
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, void* fd) noexcept {
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(fd, skip, max_depth);
}
#else
// POSIX
BOOST_FORCEINLINE std::size_t safe_dump_to(int fd) BOOST_NOEXCEPT {
BOOST_FORCEINLINE std::size_t safe_dump_to(int fd) noexcept {
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(fd, 0, boost::stacktrace::detail::max_frames_dump);
}
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, int fd) BOOST_NOEXCEPT {
BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, int fd) noexcept {
return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(fd, skip, max_depth);
}
@@ -195,7 +203,7 @@ BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_dep
# pragma warning(pop)
#endif
#include <boost/stacktrace/detail/pop_options.pp>
#include <boost/stacktrace/detail/pop_options.h>
#if !defined(BOOST_STACKTRACE_LINK) || defined(BOOST_STACKTRACE_INTERNAL_BUILD_LIBS)
# if defined(BOOST_STACKTRACE_USE_NOOP)
@@ -207,7 +215,7 @@ BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_dep
# else
# include <boost/stacktrace/detail/safe_dump_posix.ipp>
# endif
# if defined(BOOST_WINDOWS) && !defined(BOOST_GCC)
# if defined(BOOST_WINDOWS) && !defined(BOOST_WINAPI_IS_MINGW) // MinGW does not provide RtlCaptureStackBackTrace. MinGW-w64 does.
# include <boost/stacktrace/detail/collect_msvc.ipp>
# else
# include <boost/stacktrace/detail/collect_unwind.ipp>

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -12,7 +12,8 @@
# pragma once
#endif
#include <boost/core/explicit_operator_bool.hpp>
#include <boost/core/no_exceptions_support.hpp>
#include <boost/container_hash/hash_fwd.hpp>
#include <iosfwd>
#include <string>
@@ -25,21 +26,29 @@
#include <boost/stacktrace/stacktrace_fwd.hpp>
#include <boost/stacktrace/safe_dump_to.hpp>
#include <boost/stacktrace/detail/frame_decl.hpp>
#include <boost/stacktrace/frame.hpp>
#ifdef BOOST_INTEL
# pragma warning(push)
# pragma warning(disable:2196) // warning #2196: routine is both "inline" and "noinline"
#endif
/// @cond
namespace boost {
// Forward declaration
template <class It> std::size_t hash_range(It, It);
}
/// @endcond
namespace boost { namespace stacktrace {
namespace impl {
#if defined(__GNUC__) && defined(__ELF__)
BOOST_NOINLINE BOOST_SYMBOL_VISIBLE __attribute__((weak))
const char* current_exception_stacktrace() noexcept;
BOOST_NOINLINE BOOST_SYMBOL_VISIBLE __attribute__((weak))
bool& ref_capture_stacktraces_at_throw() noexcept;
#endif
} // namespace impl
/// Class that on construction copies minimal information about call stack into its internals and provides access to that information.
/// @tparam Allocator Allocator to use during stack capture.
template <class Allocator>
@@ -64,44 +73,47 @@ class basic_stacktrace {
}
}
static std::size_t frames_count_from_buffer_size(std::size_t buffer_size) BOOST_NOEXCEPT {
static std::size_t frames_count_from_buffer_size(std::size_t buffer_size) noexcept {
const std::size_t ret = (buffer_size > sizeof(native_frame_ptr_t) ? buffer_size / sizeof(native_frame_ptr_t) : 0);
return (ret > 1024 ? 1024 : ret); // Dealing with suspiciously big sizes
}
BOOST_NOINLINE void init(std::size_t frames_to_skip, std::size_t max_depth) {
BOOST_CONSTEXPR_OR_CONST std::size_t buffer_size = 128;
constexpr std::size_t buffer_size = 128;
if (!max_depth) {
return;
}
try {
BOOST_TRY {
{ // Fast path without additional allocations
native_frame_ptr_t buffer[buffer_size];
const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(buffer, buffer_size, frames_to_skip + 1);
if (buffer_size > frames_count || frames_count >= max_depth) {
const std::size_t size = (max_depth < frames_count ? max_depth : frames_count);
fill(buffer, size);
const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(buffer, buffer_size < max_depth ? buffer_size : max_depth, frames_to_skip + 1);
if (buffer_size > frames_count || frames_count == max_depth) {
fill(buffer, frames_count);
return;
}
}
// Failed to fit in `buffer_size`. Allocating memory:
#ifdef BOOST_NO_CXX11_ALLOCATOR
typedef typename Allocator::template rebind<native_frame_ptr_t>::other allocator_void_t;
#else
typedef typename std::allocator_traits<Allocator>::template rebind_alloc<native_frame_ptr_t> allocator_void_t;
#endif
std::vector<native_frame_ptr_t, allocator_void_t> buf(buffer_size * 2, 0, impl_.get_allocator());
do {
const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(&buf[0], buf.size(), frames_to_skip + 1);
if (buf.size() > frames_count || frames_count >= max_depth) {
const std::size_t size = (max_depth < frames_count ? max_depth : frames_count);
fill(&buf[0], size);
const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(&buf[0], buf.size() < max_depth ? buf.size() : max_depth, frames_to_skip + 1);
if (buf.size() > frames_count || frames_count == max_depth) {
fill(&buf[0], frames_count);
return;
}
buf.resize(buf.size() * 2);
} while (buf.size() < buf.max_size()); // close to `true`, but suppresses `C4127: conditional expression is constant`.
} catch (...) {
} BOOST_CATCH (...) {
// ignore exception
}
BOOST_CATCH_END
}
/// @endcond
@@ -123,8 +135,8 @@ public:
///
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
///
/// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
BOOST_FORCEINLINE basic_stacktrace() BOOST_NOEXCEPT
/// @b Async-Handler-Safety: \asyncsafe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
BOOST_FORCEINLINE basic_stacktrace() noexcept
: impl_()
{
init(0 , static_cast<std::size_t>(-1));
@@ -134,10 +146,10 @@ public:
///
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
///
/// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
/// @b Async-Handler-Safety: \asyncsafe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
///
/// @param a Allocator that would be passed to underlying storeage.
BOOST_FORCEINLINE explicit basic_stacktrace(const allocator_type& a) BOOST_NOEXCEPT
/// @param a Allocator that would be passed to underlying storage.
BOOST_FORCEINLINE explicit basic_stacktrace(const allocator_type& a) noexcept
: impl_(a)
{
init(0 , static_cast<std::size_t>(-1));
@@ -147,17 +159,17 @@ public:
///
/// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
///
/// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
/// @b Async-Handler-Safety: \asyncsafe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
///
/// @param skip How many top calls to skip and do not store in *this.
///
/// @param max_depth Max call sequence depth to collect.
///
/// @param a Allocator that would be passed to underlying storeage.
/// @param a Allocator that would be passed to underlying storage.
///
/// @throws Nothing. Note that default construction of allocator may throw, however it is
/// performed outside the constructor and exception in `allocator_type()` would not result in calling `std::terminate`.
BOOST_FORCEINLINE basic_stacktrace(std::size_t skip, std::size_t max_depth, const allocator_type& a = allocator_type()) BOOST_NOEXCEPT
BOOST_FORCEINLINE basic_stacktrace(std::size_t skip, std::size_t max_depth, const allocator_type& a = allocator_type()) noexcept
: impl_(a)
{
init(skip , max_depth);
@@ -165,14 +177,14 @@ public:
/// @b Complexity: O(st.size())
///
/// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
/// @b Async-Handler-Safety: \asyncsafe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
basic_stacktrace(const basic_stacktrace& st)
: impl_(st.impl_)
{}
/// @b Complexity: O(st.size())
///
/// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
/// @b Async-Handler-Safety: \asyncsafe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
basic_stacktrace& operator=(const basic_stacktrace& st) {
impl_ = st.impl_;
return *this;
@@ -181,26 +193,26 @@ public:
#ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
/// @b Complexity: O(1)
///
/// @b Async-Handler-Safety: Safe if Allocator::deallocate is async signal safe.
~basic_stacktrace() BOOST_NOEXCEPT = default;
/// @b Async-Handler-Safety: \asyncsafe if Allocator::deallocate is async signal safe.
~basic_stacktrace() noexcept = default;
#endif
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
/// @b Complexity: O(1)
///
/// @b Async-Handler-Safety: Safe if Allocator construction and copying are async signal safe.
basic_stacktrace(basic_stacktrace&& st) BOOST_NOEXCEPT
/// @b Async-Handler-Safety: \asyncsafe if Allocator construction and copying are async signal safe.
basic_stacktrace(basic_stacktrace&& st) noexcept
: impl_(std::move(st.impl_))
{}
/// @b Complexity: O(st.size())
///
/// @b Async-Handler-Safety: Safe if Allocator construction and copying are async signal safe.
/// @b Async-Handler-Safety: \asyncsafe if Allocator construction and copying are async signal safe.
basic_stacktrace& operator=(basic_stacktrace&& st)
#ifndef BOOST_NO_CXX11_HDR_TYPE_TRAITS
BOOST_NOEXCEPT_IF(( std::is_nothrow_move_assignable< std::vector<boost::stacktrace::frame, Allocator> >::value ))
noexcept(( std::is_nothrow_move_assignable< std::vector<boost::stacktrace::frame, Allocator> >::value ))
#else
BOOST_NOEXCEPT
noexcept
#endif
{
impl_ = std::move(st.impl_);
@@ -212,8 +224,8 @@ public:
///
/// @b Complexity: O(1)
///
/// @b Async-Handler-Safety: Safe.
size_type size() const BOOST_NOEXCEPT {
/// @b Async-Handler-Safety: \asyncsafe.
size_type size() const noexcept {
return impl_.size();
}
@@ -224,44 +236,44 @@ public:
///
/// @b Complexity: O(1).
///
/// @b Async-Handler-Safety: Safe.
const_reference operator[](std::size_t frame_no) const BOOST_NOEXCEPT {
/// @b Async-Handler-Safety: \asyncsafe.
const_reference operator[](std::size_t frame_no) const noexcept {
return impl_[frame_no];
}
/// @b Complexity: O(1)
///
/// @b Async-Handler-Safety: Safe.
const_iterator begin() const BOOST_NOEXCEPT { return impl_.begin(); }
/// @b Async-Handler-Safety: \asyncsafe.
const_iterator begin() const noexcept { return impl_.begin(); }
/// @b Complexity: O(1)
///
/// @b Async-Handler-Safety: Safe.
const_iterator cbegin() const BOOST_NOEXCEPT { return impl_.begin(); }
/// @b Async-Handler-Safety: \asyncsafe.
const_iterator cbegin() const noexcept { return impl_.begin(); }
/// @b Complexity: O(1)
///
/// @b Async-Handler-Safety: Safe.
const_iterator end() const BOOST_NOEXCEPT { return impl_.end(); }
/// @b Async-Handler-Safety: \asyncsafe.
const_iterator end() const noexcept { return impl_.end(); }
/// @b Complexity: O(1)
///
/// @b Async-Handler-Safety: Safe.
const_iterator cend() const BOOST_NOEXCEPT { return impl_.end(); }
/// @b Async-Handler-Safety: \asyncsafe.
const_iterator cend() const noexcept { return impl_.end(); }
/// @b Complexity: O(1)
///
/// @b Async-Handler-Safety: Safe.
const_reverse_iterator rbegin() const BOOST_NOEXCEPT { return impl_.rbegin(); }
/// @b Async-Handler-Safety: \asyncsafe.
const_reverse_iterator rbegin() const noexcept { return impl_.rbegin(); }
/// @b Complexity: O(1)
///
/// @b Async-Handler-Safety: Safe.
const_reverse_iterator crbegin() const BOOST_NOEXCEPT { return impl_.rbegin(); }
/// @b Async-Handler-Safety: \asyncsafe.
const_reverse_iterator crbegin() const noexcept { return impl_.rbegin(); }
/// @b Complexity: O(1)
///
/// @b Async-Handler-Safety: Safe.
const_reverse_iterator rend() const BOOST_NOEXCEPT { return impl_.rend(); }
/// @b Async-Handler-Safety: \asyncsafe.
const_reverse_iterator rend() const noexcept { return impl_.rend(); }
/// @b Complexity: O(1)
///
/// @b Async-Handler-Safety: Safe.
const_reverse_iterator crend() const BOOST_NOEXCEPT { return impl_.rend(); }
/// @b Async-Handler-Safety: \asyncsafe.
const_reverse_iterator crend() const noexcept { return impl_.rend(); }
/// @brief Allows to check that stack trace capturing was successful.
@@ -269,22 +281,18 @@ public:
///
/// @b Complexity: O(1)
///
/// @b Async-Handler-Safety: Safe.
BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
/// @b Async-Handler-Safety: \asyncsafe.
constexpr explicit operator bool () const noexcept { return !empty(); }
/// @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(); }
/// @b Async-Handler-Safety: \asyncsafe.
bool empty() const noexcept { return !size(); }
/// @cond
bool operator!() const BOOST_NOEXCEPT { return !size(); }
/// @endcond
const std::vector<boost::stacktrace::frame, Allocator>& as_vector() const BOOST_NOEXCEPT {
const std::vector<boost::stacktrace::frame, Allocator>& as_vector() const noexcept {
return impl_;
}
@@ -321,6 +329,10 @@ public:
/// Constructs stacktrace from raw memory dump. Terminating zero frame is discarded.
///
/// @param begin Beginning of the memory where the stacktrace was saved using the boost::stacktrace::safe_dump_to
///
/// @param buffer_size_in_bytes Size of the memory. Usually the same value that was passed to the boost::stacktrace::safe_dump_to
///
/// @b Complexity: O(size) in worst case
static basic_stacktrace from_dump(const void* begin, std::size_t buffer_size_in_bytes, const allocator_type& a = allocator_type()) {
basic_stacktrace ret(0, 0, a);
@@ -342,15 +354,53 @@ public:
return ret;
}
/// Returns a basic_stacktrace object containing a stacktrace captured at
/// the point where the currently handled exception was thrown by its
/// initial throw-expression (i.e. not a rethrow), or an empty
/// basic_stacktrace object if:
///
/// - the `boost_stacktrace_from_exception` library is not linked to the
/// current binary, or
/// - the initialization of stacktrace failed, or
/// - stacktrace captures are not enabled for the throwing thread, or
/// - no exception is being handled, or
/// - due to implementation-defined reasons.
///
/// `alloc` is passed to the constructor of the stacktrace object.
/// Rethrowing an exception using a throw-expression with no operand does
/// not alter the captured stacktrace.
///
/// Implements https://wg21.link/p2370r1
static basic_stacktrace<Allocator> from_current_exception(const allocator_type& alloc = allocator_type()) noexcept {
// Matches the constant from implementation
constexpr std::size_t kStacktraceDumpSize = 4096;
const char* trace = nullptr;
#if defined(__GNUC__) && defined(__ELF__)
if (impl::current_exception_stacktrace) {
trace = impl::current_exception_stacktrace();
}
#endif
if (trace) {
try {
return basic_stacktrace<Allocator>::from_dump(trace, kStacktraceDumpSize, alloc);
} catch (const std::exception&) {
// ignore
}
}
return basic_stacktrace<Allocator>{0, 0, alloc};
}
};
/// @brief Compares stacktraces for less, order is platform dependent.
///
/// @b Complexity: Amortized O(1); worst case O(size())
///
/// @b Async-Handler-Safety: Safe.
/// @b Async-Handler-Safety: \asyncsafe.
template <class Allocator1, class Allocator2>
bool operator< (const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
bool operator< (const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
return lhs.size() < rhs.size() || (lhs.size() == rhs.size() && lhs.as_vector() < rhs.as_vector());
}
@@ -358,48 +408,54 @@ bool operator< (const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<
///
/// @b Complexity: Amortized O(1); worst case O(size())
///
/// @b Async-Handler-Safety: Safe.
/// @b Async-Handler-Safety: \asyncsafe.
template <class Allocator1, class Allocator2>
bool operator==(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
bool operator==(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
return lhs.as_vector() == rhs.as_vector();
}
/// Comparison operators that provide platform dependant ordering and have amortized O(1) complexity; O(size()) worst case complexity; are Async-Handler-Safe.
template <class Allocator1, class Allocator2>
bool operator> (const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
bool operator> (const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
return rhs < lhs;
}
template <class Allocator1, class Allocator2>
bool operator<=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
bool operator<=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
return !(lhs > rhs);
}
template <class Allocator1, class Allocator2>
bool operator>=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
bool operator>=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
return !(lhs < rhs);
}
template <class Allocator1, class Allocator2>
bool operator!=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) BOOST_NOEXCEPT {
bool operator!=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
return !(lhs == rhs);
}
/// Fast hashing support, O(st.size()) complexity; Async-Handler-Safe.
template <class Allocator>
std::size_t hash_value(const basic_stacktrace<Allocator>& st) BOOST_NOEXCEPT {
std::size_t hash_value(const basic_stacktrace<Allocator>& st) noexcept {
return boost::hash_range(st.as_vector().begin(), st.as_vector().end());
}
/// Outputs stacktrace in a human readable format to output stream; unsafe to use in async handlers.
template <class CharT, class TraitsT, class Allocator>
std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT>& os, const basic_stacktrace<Allocator>& bt) {
if (bt) {
os << boost::stacktrace::detail::to_string(&bt.as_vector()[0], bt.size());
/// Returns std::string with the stacktrace in a human readable format; unsafe to use in async handlers.
template <class Allocator>
std::string to_string(const basic_stacktrace<Allocator>& bt) {
if (!bt) {
return std::string();
}
return os;
return boost::stacktrace::detail::to_string(&bt.as_vector()[0], bt.size());
}
/// Outputs stacktrace in a human readable format to the output stream `os`; unsafe to use in async handlers.
template <class CharT, class TraitsT, class Allocator>
std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT>& os, const basic_stacktrace<Allocator>& bt) {
return os << boost::stacktrace::to_string(bt);
}
/// This is the typedef to use unless you'd like to provide a specific allocator to boost::stacktrace::basic_stacktrace.

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at

View File

@@ -0,0 +1,54 @@
// Copyright Antony Polukhin, 2023-2024.
//
// 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)
#ifndef BOOST_STACKTRACE_THIS_THREAD_HPP
#define BOOST_STACKTRACE_THIS_THREAD_HPP
#include <boost/config.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif
#include <boost/stacktrace/stacktrace.hpp>
namespace boost { namespace stacktrace { namespace this_thread {
/// @brief Invoking the function with the enable parameter equal to `true`
/// enables capturing of stacktraces by the current thread of execution at
/// exception object construction if the `boost_stacktrace_from_exception`
/// library is linked to the current binary; disables otherwise.
///
/// Implements https://wg21.link/p2370r1
inline void set_capture_stacktraces_at_throw(bool enable = true) noexcept {
#if defined(__GNUC__) && defined(__ELF__)
if (impl::ref_capture_stacktraces_at_throw) {
impl::ref_capture_stacktraces_at_throw() = enable;
}
#endif
(void)enable;
}
/// @return whether the capturing of stacktraces by the current thread of
/// execution is enabled and
/// boost::stacktrace::basic_stacktrace::from_current_exception may return a
/// non empty stacktrace.
///
/// Returns true if set_capture_stacktraces_at_throw(false) was not called
/// and the `boost_stacktrace_from_exception` is linked to the current binary.
///
/// Implements https://wg21.link/p2370r1
inline bool get_capture_stacktraces_at_throw() noexcept {
#if defined(__GNUC__) && defined(__ELF__)
if (impl::ref_capture_stacktraces_at_throw) {
return impl::ref_capture_stacktraces_at_throw();
}
#endif
return false;
}
}}} // namespace boost::stacktrace::this_thread
#endif // BOOST_STACKTRACE_THIS_THREAD_HPP

View File

@@ -1,11 +1,13 @@
<!DOCTYPE html>
<!--
Copyright (c) 2014-2017 Antony Polukhin
Copyright (c) Antony Polukhin, 2014-2024
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)
boost-no-inspect
-->
<html>
<head>
@@ -29,7 +31,7 @@
<a href="../../doc/html/stacktrace.html">../../doc/html/stacktrace.html</a>
</p>
<p>
&copy; 2014-2017 Antony Polukhin
&copy; Antony Polukhin, 2014-2024
</p>
</body>
</html>

View File

@@ -8,7 +8,9 @@
"Antony Polukhin <antoshkka -at- gmail.com>"
],
"description": "Gather, store, copy and print backtraces.",
"std": [ "c++23" ],
"category": [
"System", "Correctness"
]
],
"cxxstd": "11"
}

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2020.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -7,5 +7,10 @@
#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>

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2020.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -7,5 +7,10 @@
#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>

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2020.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -6,5 +6,10 @@
#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>

54
src/exception_headers.h Normal file
View File

@@ -0,0 +1,54 @@
// Copyright Antony Polukhin, 2023-2024.
//
// 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 <stddef.h>
#if defined(__x86_64__) || defined(_M_X64) || defined(__MINGW32__)
#define BOOST_STACKTRACE_ALWAYS_STORE_IN_PADDING 1
#else
#define BOOST_STACKTRACE_ALWAYS_STORE_IN_PADDING 0
#endif
extern "C" {
// Developer note: helper to experiment with layouts of different
// exception headers https://godbolt.org/z/rrcdPbh1P
// https://github.com/llvm/llvm-project/blob/b3dd14ce07f2750ae1068fe62abbf2f3bd2cade8/libcxxabi/src/cxa_exception.h
struct cxa_exception_begin_llvm {
const char* reserve;
size_t referenceCount;
};
static cxa_exception_begin_llvm* exception_begin_llvm_ptr(void* ptr) {
size_t kExceptionBeginOffset = (
sizeof(void*) == 8 ? 128 : 80
);
return (cxa_exception_begin_llvm*)((char*)ptr - kExceptionBeginOffset);
}
// https://github.com/gcc-mirror/gcc/blob/5d2a360f0a541646abb11efdbabc33c6a04de7ee/libstdc%2B%2B-v3/libsupc%2B%2B/unwind-cxx.h#L100
struct cxa_exception_begin_gcc {
size_t referenceCount;
const char* reserve;
};
static cxa_exception_begin_gcc* exception_begin_gcc_ptr(void* ptr) {
size_t kExceptionBeginOffset = (
sizeof(void*) == 8 ? 128 : 96
);
return (cxa_exception_begin_gcc*)((char*)ptr - kExceptionBeginOffset);
}
static void* get_current_exception_raw_ptr(void* exc_ptr) {
// https://github.com/gcc-mirror/gcc/blob/16e2427f50c208dfe07d07f18009969502c25dc8/libstdc%2B%2B-v3/libsupc%2B%2B/eh_ptr.cc#L147
return *static_cast<void**>(exc_ptr);
}
} // extern "C"

224
src/from_exception.cpp Normal file
View File

@@ -0,0 +1,224 @@
// Copyright Antony Polukhin, 2023-2024.
//
// 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 "exception_headers.h"
// At the moment the file is used only on POSIX. _Unwind_Backtrace may be
// available on some platforms only if _GNU_SOURCE is defined.
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#include <boost/assert.hpp>
#include <boost/stacktrace/safe_dump_to.hpp>
#include <cstddef>
#include <dlfcn.h>
#if !BOOST_STACKTRACE_ALWAYS_STORE_IN_PADDING
#include <mutex>
#include <unordered_map>
#ifndef BOOST_STACKTRACE_LIBCXX_RUNTIME_MAY_CAUSE_MEMORY_LEAK
#ifdef BOOST_HAS_THREADS
#error On this platform memory leaks are possible if capturing stacktrace from \
exceptions is enabled and exceptions are thrown concurrently \
and libc++ runtime is used. \
\
Define `BOOST_STACKTRACE_LIBCXX_RUNTIME_MAY_CAUSE_MEMORY_LEAK` to \
suppress this error if the library would not be used with libc++ \
runtime (for example, it would be only used with GCC runtime). \
\
Otherwise, disable the boost_stacktrace_from_exception library build \
(for example by `./b2 boost.stacktrace.from_exception=off` option).
#endif
#endif
#endif
namespace {
constexpr std::size_t kStacktraceDumpSize = 4096;
struct decrement_on_destroy {
std::size_t& to_decrement;
~decrement_on_destroy() { --to_decrement; }
};
#if !BOOST_STACKTRACE_ALWAYS_STORE_IN_PADDING
// Inspired by the coursework by Andrei Nekrashevich in the `libsfe`
/*constinit*/ std::mutex g_mapping_mutex;
std::unordered_map<void*, const char*> g_exception_to_dump_mapping;
#endif
} // namespace
namespace boost { namespace stacktrace { namespace impl {
BOOST_SYMBOL_EXPORT bool& ref_capture_stacktraces_at_throw() noexcept {
/*constinit*/ thread_local bool g_capture_stacktraces_at_throw{true};
return g_capture_stacktraces_at_throw;
}
}}} // namespace boost::stacktrace::impl
namespace __cxxabiv1 {
#if defined(__GNUC__) && defined(__ELF__)
// libc++-runtime specific function
extern "C" BOOST_NOINLINE BOOST_SYMBOL_VISIBLE __attribute__((weak))
void __cxa_increment_exception_refcount(void *primary_exception) throw();
static bool is_libcpp_runtime() noexcept {
return __cxa_increment_exception_refcount;
}
#else
static bool is_libcpp_runtime() noexcept { return false; }
#endif
static const char*& reference_to_empty_padding(void* ptr) noexcept {
if (is_libcpp_runtime()) {
// libc++-runtime
BOOST_ASSERT_MSG(
sizeof(void*) == 4,
"32bit platforms are unsupported with libc++ runtime padding reusage. "
"Please report this issue to the library maintainters."
);
return exception_begin_llvm_ptr(ptr)->reserve;
}
return exception_begin_gcc_ptr(ptr)->reserve;
}
extern "C" BOOST_SYMBOL_EXPORT
void* __cxa_allocate_exception(size_t thrown_size) throw() {
static const auto orig_allocate_exception = []() {
void* const ptr = ::dlsym(RTLD_NEXT, "__cxa_allocate_exception");
BOOST_ASSERT_MSG(ptr, "Failed to find '__cxa_allocate_exception'");
return reinterpret_cast<void*(*)(size_t)>(ptr);
}();
if (!boost::stacktrace::impl::ref_capture_stacktraces_at_throw()) {
return orig_allocate_exception(thrown_size);
}
#ifndef NDEBUG
static thread_local std::size_t in_allocate_exception = 0;
BOOST_ASSERT_MSG(in_allocate_exception < 10, "Suspicious recursion");
++in_allocate_exception;
const decrement_on_destroy guard{in_allocate_exception};
#endif
static constexpr std::size_t kAlign = alignof(std::max_align_t);
thrown_size = (thrown_size + kAlign - 1) & (~(kAlign - 1));
void* const ptr = orig_allocate_exception(thrown_size + kStacktraceDumpSize);
char* const dump_ptr = static_cast<char*>(ptr) + thrown_size;
constexpr size_t kSkip = 1;
boost::stacktrace::safe_dump_to(kSkip, dump_ptr, kStacktraceDumpSize);
#if !BOOST_STACKTRACE_ALWAYS_STORE_IN_PADDING
if (is_libcpp_runtime()) {
const std::lock_guard<std::mutex> guard{g_mapping_mutex};
g_exception_to_dump_mapping[ptr] = dump_ptr;
} else
#endif
{
BOOST_ASSERT_MSG(
reference_to_empty_padding(ptr) == nullptr,
"Not zeroed out, unsupported implementation"
);
reference_to_empty_padding(ptr) = dump_ptr;
}
return ptr;
}
#if !BOOST_STACKTRACE_ALWAYS_STORE_IN_PADDING
// __cxa_free_exception is not called in libc++ as the
// __cxa_decrement_exception_refcount has an inlined call to
// __cxa_free_exception. Overriding libc++ specific function
extern "C" BOOST_SYMBOL_EXPORT
void __cxa_decrement_exception_refcount(void *thrown_object) throw() {
BOOST_ASSERT(is_libcpp_runtime());
if (!thrown_object) {
return;
}
static const auto orig_decrement_refcount = []() {
void* const ptr = ::dlsym(RTLD_NEXT, "__cxa_decrement_exception_refcount");
BOOST_ASSERT_MSG(ptr, "Failed to find '__cxa_decrement_exception_refcount'");
return reinterpret_cast<void(*)(void*)>(ptr);
}();
const auto* exception_header = exception_begin_llvm_ptr(thrown_object);
// The following line has a race and could give false positives and false
// negatives. In first case we remove the trace earlier, in the second case
// we get a memory leak.
if (exception_header->referenceCount == 1) {
const std::lock_guard<std::mutex> guard{g_mapping_mutex};
g_exception_to_dump_mapping.erase(thrown_object);
}
orig_decrement_refcount(thrown_object);
}
#endif
} // namespace __cxxabiv1
namespace boost { namespace stacktrace { namespace impl {
BOOST_SYMBOL_EXPORT const char* current_exception_stacktrace() noexcept {
if (!ref_capture_stacktraces_at_throw()) {
return nullptr;
}
auto exc_ptr = std::current_exception();
void* const exc_raw_ptr = get_current_exception_raw_ptr(&exc_ptr);
if (!exc_raw_ptr) {
return nullptr;
}
#if !BOOST_STACKTRACE_ALWAYS_STORE_IN_PADDING
if (__cxxabiv1::is_libcpp_runtime()) {
const std::lock_guard<std::mutex> guard{g_mapping_mutex};
const auto it = g_exception_to_dump_mapping.find(exc_raw_ptr);
if (it != g_exception_to_dump_mapping.end()) {
return it->second;
} else {
return nullptr;
}
} else
#endif
{
return __cxxabiv1::reference_to_empty_padding(exc_raw_ptr);
}
}
BOOST_SYMBOL_EXPORT void assert_no_pending_traces() noexcept {
#if !BOOST_STACKTRACE_ALWAYS_STORE_IN_PADDING
if (__cxxabiv1::is_libcpp_runtime()) {
const std::lock_guard<std::mutex> guard{g_mapping_mutex};
BOOST_ASSERT(g_exception_to_dump_mapping.empty());
}
#endif
}
}}} // namespace boost::stacktrace::impl

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2020.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2020.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2020.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at

View File

@@ -1,10 +1,12 @@
# Copyright (C) 2016-2017, Antony Polukhin.
# Copyright (C) 2016-2024, 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)
#
import ../../config/checks/config : requires ;
lib dl : : <link>shared ;
lib gcc_s ;
lib rt ;
@@ -22,32 +24,36 @@ lib backtrace
project
: requirements
[ requires cxx11_rvalue_references ]
<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 RDYNAMIC = <target-os>freebsd:<linkflags>"-rdynamic" <target-os>solaris:<linkflags>"-Bdynamic" <target-os>aix:<linkflags>"-rdynamic"
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" ;
<target-os>darwin,<toolset>clang:<linkflags>"-rdynamic" <target-os>iphone:<linkflags>"-rdynamic"
<define>BOOST_STACKTRACE_TEST_EXPORTS_TABLE_USAGE ;
local HIDE_SYMBS = <target-os>linux:<cxxflags>"-fvisibility=hidden" ;
local BT_DEPS = $(HIDE_SYMBS) <target-os>linux:<library>dl <library>backtrace [ check-target-builds ../build//libbacktrace : : <build>no ] ;
local AD2L_DEPS = $(HIDE_SYMBS) <target-os>linux:<library>dl [ check-target-builds ../build//addr2line : : <build>no ] ;
local WIND_DEPS = $(HIDE_SYMBS) <library>Dbgeng <library>ole32 [ check-target-builds ../build//WinDbg : : <build>no ] ;
local WICA_DEPS = $(HIDE_SYMBS) <library>Dbgeng <library>ole32 [ check-target-builds ../build//WinDbgCached : : <build>no ] ;
local NOOP_DEPS = $(HIDE_SYMBS) ;
local BASIC_DEPS = $(RDYNAMIC) <target-os>linux:<library>dl [ check-target-builds ../build//WinDbg : <build>no ] ;
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 ]
<define>BOOST_STACKTRACE_TEST_NO_DEBUG_AT_ALL # Some old versions of addr2line may not produce readable names for a modern compilers
;
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) ;
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) ;
@@ -75,12 +81,23 @@ 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 $(BASIC_DEPS) : basic_ho ]
[ 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_BACKTRACE <define>BOOST_STACKTRACE_BACKTRACE_FORCE_STATIC $(BT_DEPS) : backtrace_ho_static ]
[ 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 ]
# Header only trivial
[ run test_trivial.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_BACKTRACE $(BT_DEPS) : trivial_backtrace_ho ]
[ run test_trivial.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_ADDR2LINE $(AD2L_DEPS) : trivial_addr2line_ho ]
[ run test_trivial.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_NOOP $(NOOP_DEPS) : trivial_noop_ho ]
[ run test_trivial.cpp : : : <debug-symbols>on $(WIND_DEPS) : trivial_windbg_ho ]
[ run test_trivial.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_USE_WINDBG_CACHED $(WICA_DEPS) : trivial_windbg_cached_ho ]
[ run test_trivial.cpp : : : <debug-symbols>on $(FORCE_SYMBOL_EXPORT) $(BASIC_DEPS) : trivial_basic_ho ]
[ run test_trivial.cpp : : : <debug-symbols>on <define>BOOST_STACKTRACE_TEST_NO_DEBUG_AT_ALL $(BASIC_DEPS) : trivial_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 ]
@@ -90,73 +107,93 @@ test-suite stacktrace_tests
[ 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 ]
# Trivial test with shared linked implementations with debug symbols
[ run test_trivial.cpp : : : <debug-symbols>on <library>.//test_impl_lib_backtrace $(LINKSHARED_BT) : trivial_backtrace_lib ]
[ run test_trivial.cpp : : : <debug-symbols>on <library>.//test_impl_lib_addr2line $(LINKSHARED_AD2L) : trivial_addr2line_lib ]
[ run test_trivial.cpp : : : <debug-symbols>on <library>.//test_impl_lib_windbg $(LINKSHARED_WIND) : trivial_windbg_lib ]
[ run test_trivial.cpp : : : <debug-symbols>on <library>.//test_impl_lib_windbg_cached $(LINKSHARED_WIND_CACHED) : trivial_windbg_cached_lib ]
[ run test_trivial.cpp : : : <debug-symbols>on <library>.//test_impl_lib_noop $(LINKSHARED_NOOP) : trivial_noop_lib ]
[ run test_trivial.cpp : : : <debug-symbols>on <library>.//test_impl_lib_basic $(LINKSHARED_BASIC) : trivial_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)
: : : <debug-symbols>on <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)
: : : <debug-symbols>on <library>.//test_impl_lib_backtrace $(LINKSHARED_BT)
<define>BOOST_STACKTRACE_BACKTRACE_FORCE_STATIC
: backtrace_lib_threaded_static ]
[ run thread_safety_checking.cpp
: : : <debug-symbols>on <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)
: : : <debug-symbols>on <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)
: : : <debug-symbols>on <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 <define>BOOST_STACKTRACE_TEST_NO_DEBUG_AT_ALL $(BT_DEPS) : backtrace_ho_no_dbg ]
[ 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 $(BASIC_DEPS) : basic_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) <define>BOOST_STACKTRACE_TEST_NO_DEBUG_AT_ALL : 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 ]
[ 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)
: : : <debug-symbols>off
<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)
: : : <debug-symbols>off
<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)
: : : <debug-symbols>off
<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)
: : : <debug-symbols>off
<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 ]
[ run test_from_exception_none.cpp : : : $(LINKSHARED_BASIC) <debug-symbols>on : from_exception_none_basic ]
[ run test_from_exception_none.cpp : : : $(FORCE_SYMBOL_EXPORT) $(BASIC_DEPS) <debug-symbols>on : from_exception_none_basic_ho ]
[ run test_from_exception_none.cpp : : : $(LINKSHARED_BT) <debug-symbols>on : from_exception_none_bt ]
[ run test_from_exception_none.cpp : : : <define>BOOST_STACKTRACE_USE_BACKTRACE $(BT_DEPS) <debug-symbols>on : from_exception_none_bt_ho ]
[ run test_from_exception_none.cpp : : : <library>/boost/stacktrace//boost_stacktrace_from_exception $(LINKSHARED_BASIC) <debug-symbols>on : from_exception_disabled_basic ]
[ run test_from_exception_none.cpp : : : <library>/boost/stacktrace//boost_stacktrace_from_exception $(FORCE_SYMBOL_EXPORT) $(BASIC_DEPS) <debug-symbols>on : from_exception_disabled_basic_ho ]
[ run test_from_exception_none.cpp : : : <library>/boost/stacktrace//boost_stacktrace_from_exception $(LINKSHARED_BT) <debug-symbols>on : from_exception_disabled_bt ]
[ run test_from_exception_none.cpp : : : <library>/boost/stacktrace//boost_stacktrace_from_exception <define>BOOST_STACKTRACE_USE_BACKTRACE $(BT_DEPS) : from_exception_disabled_bt_ho ]
[ link test_from_exception.cpp : <library>/boost/stacktrace//boost_stacktrace_from_exception $(LINKSHARED_BASIC) <debug-symbols>on : from_exception_basic ]
[ run test_from_exception.cpp : : : <library>/boost/stacktrace//boost_stacktrace_from_exception $(LINKSHARED_BT) <debug-symbols>on : from_exception_bt ]
[ link test_from_exception.cpp : <library>/boost/stacktrace//boost_stacktrace_from_exception $(FORCE_SYMBOL_EXPORT) $(BASIC_DEPS) <debug-symbols>on : from_exception_basic_ho ]
[ run test_from_exception.cpp : : : <library>/boost/stacktrace//boost_stacktrace_from_exception <define>BOOST_STACKTRACE_USE_BACKTRACE $(BT_DEPS) <debug-symbols>on : from_exception_bt_ho ]
;
# Assuring that examples compile and run. Adding sources from `examples` directory to the `type_index` test suite.
@@ -169,6 +206,11 @@ for local p in [ glob ../example/*.cpp ]
additional_dependency = <library>/boost/filesystem//boost_filesystem <library>/boost/system//boost_system <target-os>linux:<library>rt ;
}
if $(target_name) = "throwing_st"
{
additional_dependency = [ requires rtti ] ;
}
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) ] ;
@@ -188,3 +230,21 @@ for local p in [ glob ../example/*.cpp ]
}
# 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 ;

View File

@@ -2,23 +2,26 @@
# 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)
#
# Copyright Antony Polukhin 2016-2017.
# Copyright Antony Polukhin, 2016-2024.
#
# See https://svn.boost.org/trac/boost/wiki/TravisCoverals for description of this file
# and how it can be used with Boost libraries.
#
# File revision #5
# File revision #6
init:
- set BRANCH_TO_TEST=%APPVEYOR_REPO_BRANCH% # Change to branch you wish to test. Use %APPVEYOR_REPO_BRANCH% for current branch.
- set BOOST_REMOVE=stacktrace # Remove this folder from lib from full clone of Boost. If you are testing `any` repo, write here `any`.
# boost-local/libs/ folder to put this library into. This may be useful, if you're for example running Travis
# from `Boost.DLL` repo while Boost already has `dll` and with to replace `dll` with content of`Boost.DLL`.
#
# Otherwise just leave the default value - set BOOST_LIBS_FOLDER=%APPVEYOR_PROJECT_NAME%
- set BOOST_LIBS_FOLDER=%APPVEYOR_PROJECT_NAME%
###############################################################################################################
# From this point and below code is same for all the Boost libs
###############################################################################################################
version: 1.64.{build}-{branch}
version: 1.84.{build}-{branch}
# branches to build
branches:
@@ -27,32 +30,60 @@ branches:
skip_tags: true
environment:
matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
TOOLSET: msvc-14.1 #,clang-win
CXXSTD: 14,17
ADDRMD: 64
#- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
# ADDPATH: C:\cygwin\bin;
# TOOLSET: gcc
# CXXSTD: 03,11,14,1z
#- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
# ADDPATH: C:\cygwin64\bin;
# TOOLSET: gcc
# CXXSTD: 03,11,14,1z
# Waiting for https://github.com/boostorg/system/issues/116
#- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
# ADDPATH: C:\mingw\bin;
# TOOLSET: gcc
# CXXSTD: 03,11,14,1z
#- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
# ADDPATH: C:\mingw-w64\x86_64-7.2.0-posix-seh-rt_v5-rev1\mingw64\bin;
# TOOLSET: gcc
# CXXSTD: 03,11,14,1z
before_build:
- set PATH=%PATH%;C:\\MinGW\\bin
- set BOOST_BRANCH=develop
- if "%APPVEYOR_REPO_BRANCH%" == "master" set BOOST_BRANCH=master
- echo "Testing %APPVEYOR_PROJECT_NAME%"
# Cloning Boost libraries (fast nondeep cloning)
- set BOOST=C:/boost-local
- git init %BOOST%
- git clone -b %BOOST_BRANCH% --depth 10 https://github.com/boostorg/boost.git %BOOST%
- cd %BOOST%
- git remote add --no-tags -t %BRANCH_TO_TEST% origin https://github.com/boostorg/boost.git
- git fetch --depth=1
- git checkout %BRANCH_TO_TEST%
- git submodule update --init --merge --jobs 16
- git remote set-branches --add origin %BRANCH_TO_TEST%
#- git pull --recurse-submodules # Updaes submodules to most recent version. Not required
- rm -rf %BOOST%/libs/%BOOST_REMOVE%
- mv %APPVEYOR_BUILD_FOLDER% %BOOST%/libs/%APPVEYOR_PROJECT_NAME%
- git submodule update --init --depth 10 tools/build tools/boostdep
libs/filesystem libs/atomic libs/system libs/interprocess libs/array
libs/iterator libs/detail libs/exception libs/smart_ptr libs/mpl
libs/align libs/container libs/tuple libs/intrusive libs/scope
- rm -rf %BOOST%/libs/%BOOST_LIBS_FOLDER%
- mv -f %APPVEYOR_BUILD_FOLDER% %BOOST%/libs/%BOOST_LIBS_FOLDER%
- python tools/boostdep/depinst/depinst.py --git_args "--depth 10 --jobs 2" %BOOST_LIBS_FOLDER%
build_script:
- call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64
- bootstrap.bat
- cmd /c bootstrap
- b2.exe headers
- cd %BOOST%/libs/%APPVEYOR_PROJECT_NAME%/test
- cd %BOOST%/libs/%BOOST_LIBS_FOLDER%/test
after_build:
before_test:
test_script:
- ..\..\..\b2.exe address-model=32 architecture=x86 toolset=msvc,gcc cxxflags="-DBOOST_TRAVISCI_BUILD" -sBOOST_BUILD_PATH=.
- PATH=%ADDPATH%%PATH%
- if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD%
- if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD%
- echo "Running command ..\..\..\b2 -j3 toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release"
- ..\..\..\b2.exe -j3 toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release cxxflags="-DBOOST_TRAVISCI_BUILD"
after_test:
on_success:

View File

@@ -1,4 +1,4 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -10,54 +10,31 @@
#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;
#ifdef BOOST_STACKTRACE_DYN_LINK
# define BOOST_ST_API BOOST_SYMBOL_IMPORT
#else
# define BOOST_ST_API
#endif
#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_SYMNAME 0
# define BOOST_STACKTRACE_TEST_SHOULD_OUTPUT_READABLE_NAMES 0
#else
# define BOOST_STACKTRACE_SYMNAME 1
# define BOOST_STACKTRACE_TEST_SHOULD_OUTPUT_READABLE_NAMES 1
#endif
typedef std::pair<stacktrace, stacktrace> (*foo1_t)(int i);
BOOST_ST_API std::pair<stacktrace, stacktrace> foo2(int i, foo1_t foo1);
BOOST_ST_API stacktrace return_from_nested_namespaces();
BOOST_ST_API boost::stacktrace::stacktrace bar1();
BOOST_ST_API boost::stacktrace::stacktrace bar2();
BOOST_NOINLINE std::pair<stacktrace, stacktrace> foo1(int i) {
if (i) {
return foo2(i - 1, foo1);
}
std::pair<stacktrace, stacktrace> ret;
try {
throw std::logic_error("test");
} catch (const std::logic_error& /*e*/) {
ret.second = stacktrace();
return ret;
}
}
void test_deeply_nested_namespaces() {
std::stringstream ss;
ss << return_from_nested_namespaces();
std::cout << ss.str() << '\n';
#if BOOST_STACKTRACE_SYMNAME
#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
@@ -70,16 +47,37 @@ void test_deeply_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() {
std::pair<stacktrace, stacktrace> res = foo2(Depth, foo1);
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;
std::cout << "'" << ss1.str() << "'\n\n" << ss2.str() << std::endl;
if (print) {
std::cout << "'" << ss1.str() << "'\n\n" << ss2.str() << std::endl;
}
BOOST_TEST(!ss1.str().empty());
BOOST_TEST(!ss2.str().empty());
@@ -92,18 +90,16 @@ void test_nested() {
BOOST_TEST(ss1.str().find(" in ") != std::string::npos);
BOOST_TEST(ss2.str().find(" in ") != std::string::npos);
#if BOOST_STACKTRACE_SYMNAME
#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("foo2") != std::string::npos);
BOOST_TEST(ss2.str().find("foo2") != 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("foo1") != std::string::npos);
BOOST_TEST(ss2.str().find("foo1") != 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
//BOOST_TEST(false);
}
template <class Bt>
@@ -194,7 +190,7 @@ void test_iterators() {
void test_frame() {
stacktrace nst = return_from_nested_namespaces();
stacktrace st;
stacktrace st = make_some_stacktrace1();
const std::size_t min_size = (nst.size() < st.size() ? nst.size() : st.size());
BOOST_TEST(min_size > 2);
@@ -231,9 +227,9 @@ void test_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_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
@@ -263,6 +259,7 @@ void test_empty_basic_stacktrace() {
int main() {
test_deeply_nested_namespaces();
test_frames_string_data_validity();
test_nested<15>();
test_comparisons();
test_iterators();
@@ -270,14 +267,14 @@ int main() {
test_empty_basic_stacktrace<true>();
test_empty_basic_stacktrace<false>();
BOOST_TEST(&bar1 != &bar2);
boost::stacktrace::stacktrace b1 = bar1();
BOOST_TEST(&make_some_stacktrace1 != &make_some_stacktrace2);
boost::stacktrace::stacktrace b1 = make_some_stacktrace1();
BOOST_TEST(b1.size() == 4);
boost::stacktrace::stacktrace b2 = bar2();
boost::stacktrace::stacktrace b2 = make_some_stacktrace2();
BOOST_TEST(b2.size() == 4);
test_comparisons_base(bar1(), bar2());
test_comparisons_base(make_some_stacktrace1(), make_some_stacktrace2());
test_nested<300>();
test_nested<260>(false);
BOOST_TEST(boost::stacktrace::stacktrace(0, 1).size() == 1);
BOOST_TEST(boost::stacktrace::stacktrace(1, 1).size() == 1);

View File

@@ -0,0 +1,154 @@
// Copyright Antony Polukhin, 2023-2024.
//
// 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.hpp>
#include <iostream>
#include <thread>
#include <boost/core/lightweight_test.hpp>
namespace boost { namespace stacktrace { namespace impl {
void assert_no_pending_traces() noexcept;
}}}
using boost::stacktrace::stacktrace;
struct test_no_pending_on_finish {
~test_no_pending_on_finish() {
boost::stacktrace::impl::assert_no_pending_traces();
}
};
BOOST_NOINLINE BOOST_SYMBOL_VISIBLE void in_test_throw_1(const char* msg) {
std::string new_msg{msg};
throw std::runtime_error(new_msg);
}
BOOST_NOINLINE BOOST_SYMBOL_VISIBLE void in_test_throw_2(const char* msg) {
std::string new_msg{msg};
throw std::runtime_error(new_msg);
}
BOOST_NOINLINE BOOST_SYMBOL_VISIBLE void test_no_exception() {
auto trace = stacktrace::from_current_exception();
BOOST_TEST(!trace);
}
BOOST_NOINLINE BOOST_SYMBOL_VISIBLE void test_trace_from_exception() {
// const test_no_pending_on_finish guard{}; // something strange
try {
in_test_throw_1("testing basic");
} catch (const std::exception&) {
auto trace = stacktrace::from_current_exception();
BOOST_TEST(trace);
std::cout << "Tarce in test_trace_from_exception(): " << trace << '\n';
BOOST_TEST(to_string(trace).find("in_test_throw_1") != std::string::npos);
}
}
BOOST_NOINLINE BOOST_SYMBOL_VISIBLE void test_after_other_exception() {
try {
in_test_throw_1("test_other_exception_active");
} catch (const std::exception&) {
try {
in_test_throw_2("test_other_exception_active 2");
} catch (const std::exception&) {}
auto trace = stacktrace::from_current_exception();
BOOST_TEST(trace);
std::cout << "Tarce in test_after_other_exception(): " << trace;
BOOST_TEST(to_string(trace).find("in_test_throw_1") != std::string::npos);
BOOST_TEST(to_string(trace).find("in_test_throw_2") == std::string::npos);
}
}
BOOST_NOINLINE BOOST_SYMBOL_VISIBLE void test_nested() {
try {
in_test_throw_1("test_other_exception_active");
} catch (const std::exception&) {
try {
in_test_throw_2("test_other_exception_active 2");
} catch (const std::exception&) {
auto trace = stacktrace::from_current_exception();
BOOST_TEST(trace);
std::cout << "Tarce in test_nested(): " << trace << '\n';
BOOST_TEST(to_string(trace).find("in_test_throw_1") == std::string::npos);
BOOST_TEST(to_string(trace).find("in_test_throw_2") != std::string::npos);
}
}
}
BOOST_NOINLINE BOOST_SYMBOL_VISIBLE void test_rethrow_nested() {
std::exception_ptr ptr;
try {
in_test_throw_1("test_other_exception_active");
} catch (const std::exception&) {
try {
in_test_throw_2("test_other_exception_active 2");
} catch (const std::exception&) {
ptr = std::current_exception();
}
}
try {
std::rethrow_exception(ptr);
} catch (...) {
auto trace = stacktrace::from_current_exception();
BOOST_TEST(trace);
std::cout << "Tarce in test_rethrow_nested(): " << trace << '\n';
BOOST_TEST(to_string(trace).find("in_test_throw_1") == std::string::npos);
BOOST_TEST(to_string(trace).find("in_test_throw_2") != std::string::npos);
}
}
BOOST_NOINLINE BOOST_SYMBOL_VISIBLE void test_from_other_thread() {
// MinGW error: 'thread' is not a member of 'std'
#ifndef __MINGW32__
std::exception_ptr ptr;
std::thread t([&ptr]{
try {
in_test_throw_1("test_other_exception_active");
} catch (const std::exception&) {
try {
in_test_throw_2("test_other_exception_active 2");
} catch (const std::exception&) {
ptr = std::current_exception();
}
}
});
t.join();
try {
std::rethrow_exception(ptr);
} catch (...) {
auto trace = stacktrace::from_current_exception();
BOOST_TEST(trace);
std::cout << "Tarce in test_rethrow_nested(): " << trace << '\n';
BOOST_TEST(to_string(trace).find("in_test_throw_1") == std::string::npos);
BOOST_TEST(to_string(trace).find("in_test_throw_2") != std::string::npos);
}
#endif
}
int main() {
const test_no_pending_on_finish guard{};
BOOST_TEST(boost::stacktrace::this_thread::get_capture_stacktraces_at_throw());
test_no_exception();
test_trace_from_exception();
test_after_other_exception();
test_nested();
test_rethrow_nested();
test_from_other_thread();
return boost::report_errors();
}

View File

@@ -0,0 +1,34 @@
// Copyright Antony Polukhin, 2023-2024.
//
// 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.hpp>
#include <boost/core/lightweight_test.hpp>
using boost::stacktrace::stacktrace;
BOOST_NOINLINE BOOST_SYMBOL_VISIBLE void in_test_throw_1(const char* msg) {
std::string new_msg{msg};
throw std::runtime_error(new_msg);
}
BOOST_NOINLINE BOOST_SYMBOL_VISIBLE void test_no_trace_from_exception() {
try {
in_test_throw_1("testing basic");
} catch (const std::exception&) {
auto trace = stacktrace::from_current_exception();
BOOST_TEST(!trace);
}
}
int main() {
boost::stacktrace::this_thread::set_capture_stacktraces_at_throw(false);
BOOST_TEST(!boost::stacktrace::this_thread::get_capture_stacktraces_at_throw());
test_no_trace_from_exception();
return boost::report_errors();
}

View File

@@ -1,32 +1,15 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// 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>
#define BOOST_STACKTRACE_TEST_IMPL_LIB 1
#include "test_impl.hpp"
using namespace boost::stacktrace;
#ifdef BOOST_STACKTRACE_DYN_LINK
# define BOOST_ST_API BOOST_SYMBOL_EXPORT
#else
# define BOOST_ST_API
#endif
typedef std::pair<stacktrace, stacktrace> (*foo1_t)(int i);
BOOST_ST_API BOOST_NOINLINE std::pair<stacktrace, stacktrace> foo2(int i, foo1_t foo1) {
BOOST_ST_API BOOST_NOINLINE std::pair<stacktrace, stacktrace> function_from_library(int i, foo1_t foo1) {
if (i) {
return foo1(--i);
} else {
@@ -59,31 +42,31 @@ BOOST_ST_API BOOST_NOINLINE stacktrace return_from_nested_namespaces() {
return get_backtrace_from_nested_namespaces();
}
BOOST_ST_API BOOST_NOINLINE boost::stacktrace::stacktrace bar1_impl(int d = 0) {
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 bar1_impl(d + 1);
return make_some_stacktrace1_impl(d + 1);
}
return result;
}
BOOST_ST_API BOOST_NOINLINE boost::stacktrace::stacktrace bar2_impl(int d = 0) {
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 bar2_impl(d + 1);
return make_some_stacktrace2_impl(d + 1);
}
return result;
}
BOOST_ST_API BOOST_NOINLINE boost::stacktrace::stacktrace bar1() {
boost::stacktrace::stacktrace result = bar1_impl();
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 bar2() {
boost::stacktrace::stacktrace result = bar2_impl();
BOOST_ST_API BOOST_NOINLINE boost::stacktrace::stacktrace make_some_stacktrace2() {
boost::stacktrace::stacktrace result = make_some_stacktrace2_impl();
return result;
}

58
test/test_impl.hpp Normal file
View File

@@ -0,0 +1,58 @@
// Copyright Antony Polukhin, 2016-2024.
//
// 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;
}
}

View File

@@ -1,44 +1,21 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// 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;
#ifdef BOOST_STACKTRACE_DYN_LINK
# define BOOST_ST_API BOOST_SYMBOL_IMPORT
#else
# define BOOST_ST_API
#endif
typedef std::pair<stacktrace, stacktrace> (*foo1_t)(int i);
BOOST_ST_API std::pair<stacktrace, stacktrace> foo2(int i, foo1_t foo1);
BOOST_ST_API stacktrace return_from_nested_namespaces();
BOOST_NOINLINE std::pair<stacktrace, stacktrace> foo1(int i) {
if (i) {
return foo2(i - 1, foo1);
}
std::pair<stacktrace, stacktrace> ret;
try {
throw std::logic_error("test");
} catch (const std::logic_error& /*e*/) {
ret.second = stacktrace();
return ret;
}
}
void test_deeply_nested_namespaces() {
BOOST_TEST(return_from_nested_namespaces().size() == 0);
BOOST_TEST(return_from_nested_namespaces().empty());
@@ -46,7 +23,7 @@ void test_deeply_nested_namespaces() {
}
void test_nested() {
std::pair<stacktrace, stacktrace> res = foo2(15, foo1);
std::pair<stacktrace, stacktrace> res = function_from_library(15, function_from_main_translation_unit);
BOOST_TEST(!res.first);
BOOST_TEST(res.first.empty());

71
test/test_num_conv.cpp Normal file
View File

@@ -0,0 +1,71 @@
// Copyright Antony Polukhin, 2016-2024.
//
// 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();
}

15
test/test_trivial.cpp Normal file
View File

@@ -0,0 +1,15 @@
// Copyright Antony Polukhin, 2022-2024.
//
// 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)
// See https://github.com/boostorg/stacktrace/issues/116
#include <boost/stacktrace/stacktrace.hpp>
#include <iostream>
int main() {
std::cout << boost::stacktrace::stacktrace() << std::endl;
}

View File

@@ -1,45 +1,22 @@
// Copyright Antony Polukhin, 2016-2017.
// Copyright Antony Polukhin, 2016-2024.
//
// 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 <chrono>
#include <sstream>
#include <thread>
#include <boost/stacktrace.hpp>
#include <boost/thread.hpp>
#include <boost/optional.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/timer/timer.hpp>
#ifdef BOOST_STACKTRACE_DYN_LINK
# define BOOST_ST_API BOOST_SYMBOL_IMPORT
#else
# define BOOST_ST_API
#endif
using boost::stacktrace::stacktrace;
typedef std::pair<stacktrace, stacktrace> (*foo1_t)(int i);
BOOST_ST_API std::pair<stacktrace, stacktrace> foo2(int i, foo1_t foo1);
BOOST_ST_API stacktrace return_from_nested_namespaces();
BOOST_NOINLINE std::pair<stacktrace, stacktrace> foo1(int i) {
if (i) {
return foo2(i - 1, foo1);
}
std::pair<stacktrace, stacktrace> ret;
try {
throw std::logic_error("test");
} catch (const std::logic_error& /*e*/) {
ret.second = stacktrace();
return ret;
}
}
void main_test_loop() {
std::size_t loops = 100;
@@ -49,7 +26,7 @@ void main_test_loop() {
std::stringstream ss_ethalon;
while (--loops) {
std::pair<stacktrace, stacktrace> res = foo2(Depth, foo1);
std::pair<stacktrace, stacktrace> res = function_from_library(Depth, function_from_main_translation_unit);
if (ethalon) {
BOOST_TEST(res == *ethalon);
@@ -63,32 +40,21 @@ void main_test_loop() {
}
}
#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
const auto t = std::chrono::steady_clock::now();
boost::timer::auto_cpu_timer t;
boost::thread t1(main_test_loop);
boost::thread t2(main_test_loop);
boost::thread t3(main_test_loop);
std::thread t1(main_test_loop);
std::thread t2(main_test_loop);
std::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
const auto elapsed = t - std::chrono::steady_clock::now();
std::cout << "Elapsed: " << std::chrono::duration_cast<std::chrono::milliseconds>(
elapsed
). count() << "ms";
return boost::report_errors();
}

26
test/torture.cpp Normal file
View File

@@ -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;
}