From 08b201859da10f07521507183cceb0e625b1a171 Mon Sep 17 00:00:00 2001
From: Antony Polukhin The design is based on the Boost.Stacktrace library, a popular library that does not depend on any non-standard library components. Note about signal safety: this proposal does not attempt to provide a signal-safe solution for capturing and decoding stacktraces.
- Such functionality currently is not implementable on some of the popular platforms. However, the paper attempts to provide extendable solution, that may be made sygnal safe some day.A Proposal to add stack trace library
@@ -65,12 +65,45 @@ II. Impact on the Standard
III. Design Decisions
Note on performance: during Boost.Stacktrace development phase many users requested a fast way to store stack trace, without decoding the function names. This functionality is preserved in the paper.
+namespace std { + + class stack_frame; + + template<typename Allocator> + class basic_stacktrace; + + // free functions + + // This is the alias to use unless you'd like to provide a specific allocator to basic_stacktrace. + using stacktrace = basic_stacktrace<allocator<stack_frame>>; + + // Outputs stacktrace in a human readable format to output stream. + template<typename CharT, typename TraitsT, typename Allocator> + basic_ostream< CharT, TraitsT > & operator<<(basic_ostream<CharT, TraitsT>& os, const basic_stacktrace<Allocator>& bt); + + // Outputs stacktrace in a human readable format to string. + template<typename Allocator> + string to_string(const basic_stacktrace<Allocator>& f); + + // Outputs frame in a human readable format to string. + string to_string(const stack_frame& f); + + // Outputs frame in a human readable format to output stream. + template<typename CharT, typename TraitsT> + basic_ostream< CharT, TraitsT >& operator<<(basic_ostream<CharT, TraitsT>& os, const stack_frame& f); +} ++ + +
The stack_frame class stores a pointer to function and allows querying information about that function.
namespace std { class stack_frame { @@ -82,24 +115,56 @@+ + +Header <stacktrace>
constexpr stack_frame(const stack_frame&) noexcept = default; constexpr stack_frame& operator=(const stack_frame&) = default; - explicit stack_frame(native_frame_ptr_t f) noexcept; + constexpr explicit stack_frame(native_frame_ptr_t f) noexcept; template<typename T> explicit stack_frame(T* address) noexcept; constexpr native_frame_ptr_t address() const noexcept; - constexpr bool empty() const noexcept; + constexpr explicit operator bool() const noexcept; - strong_ordering operator <=>(const stack_frame& rhs) = default; + constexpr strong_ordering operator <=>(const stack_frame& rhs) = default; - // functions that do decoding + // functions that querying information about stored address string name() const; string source_file() const; size_t source_line() const; private: - native_frame_ptr_t data; // exposiotion only + native_frame_ptr_t data; // exposition only }; +} +
stack_frame
constructorsstack_frame() noexcept;+
source_file()
and source_line()
will return empty string. Calls to source_line()
will return 0.explicit stack_frame(native_frame_ptr_t addr) noexcept; +template<typename T> explicit stack_frame(T * addr) noexcept;+
stack_frame
member functionsstd::string name() const;+
constexpr native_frame_ptr_t address() const noexcept;+
std::string source_file() const;+
std::string source_line() const;+
explicit operator bool() const noexcept;+
The basic_stacktrace template class stores current call sequence on construction and provides functions for querying information about the call sequence.
++namespace std { template<typename Allocator> class basic_stacktrace { public: @@ -109,7 +174,7 @@- -Header <stacktrace>
using const_iterator = implementation-defined; using allocaotr_type = Allocator; - // functions that capture current call sequence without decoding it + // functions that capture current call sequence basic_stacktrace() noexcept; explicit basic_stacktrace(const allocator_type& a) noexcept; basic_stacktrace(size_type skip, size_type max_depth, const allocator_type& a = allocator_type()) noexcept; @@ -136,64 +201,19 @@Header <stacktrace>
vector<value_type> stack_frames; // exposition only }; - // This is the alias to use unless you'd like to provide a specific allocator to basic_stacktrace. - using stacktrace = basic_stacktrace<allocator<stack_frame>>; - - // Outputs stacktrace in a human readable format to output stream; unsafe to use in async handlers. - template<typename CharT, typename TraitsT, typename Allocator> - basic_ostream< CharT, TraitsT > & operator<<(basic_ostream<CharT, TraitsT>& os, const basic_stacktrace<Allocator>& bt); - - // Outputs frame in a human readable format to string; unsafe to use in async handlers. - string to_string(const stack_frame& f); - - // Outputs frame in a human readable format to output stream; unsafe to use in async handlers. - template<typename CharT, typename TraitsT> - basic_ostream< CharT, TraitsT >& operator<<(basic_ostream<CharT, TraitsT>& os, const stack_frame& f); }
stack_frame
constructorsstack_frame() noexcept;-
source_file()
and source_line()
will return empty string. Calls to source_line()
will return 0.explicit stack_frame(native_frame_ptr_t addr) noexcept; -template<typename T> explicit stack_frame(T * addr) noexcept;-
stack_frame
member functionsstd::string name() const;-
constexpr native_frame_ptr_t address() const noexcept;-
std::string source_file() const;-
std::string source_line() const;-
constexpr bool empty() const;-
basic_stacktrace
constructorsbasic_stacktrace() noexcept; explicit basic_stacktrace(const allocator_type & a) noexcept;-
(bool)*this
is false
basic_stacktrace(size_type skip, size_type max_depth, const allocator_type& a = allocator_type()) noexcept;-
(bool)*this
is false
basic_stacktrace
member functionsframe_no
- zero-based index of frame to return. 0 is the function index where stacktrace was constructed and index close to this->size() contains function main().explicit operator bool() const noexcept;-