Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:52:31

0001 // Copyright Antony Polukhin, 2016-2023.
0002 //
0003 // Distributed under the Boost Software License, Version 1.0. (See
0004 // accompanying file LICENSE_1_0.txt or copy at
0005 // http://www.boost.org/LICENSE_1_0.txt)
0006 
0007 #ifndef BOOST_STACKTRACE_STACKTRACE_HPP
0008 #define BOOST_STACKTRACE_STACKTRACE_HPP
0009 
0010 #include <boost/config.hpp>
0011 #ifdef BOOST_HAS_PRAGMA_ONCE
0012 #   pragma once
0013 #endif
0014 
0015 #include <boost/core/no_exceptions_support.hpp>
0016 #include <boost/container_hash/hash_fwd.hpp>
0017 
0018 #include <iosfwd>
0019 #include <string>
0020 #include <vector>
0021 
0022 #ifndef BOOST_NO_CXX11_HDR_TYPE_TRAITS
0023 #   include <type_traits>
0024 #endif
0025 
0026 #include <boost/stacktrace/stacktrace_fwd.hpp>
0027 #include <boost/stacktrace/safe_dump_to.hpp>
0028 #include <boost/stacktrace/detail/frame_decl.hpp>
0029 #include <boost/stacktrace/frame.hpp>
0030 
0031 #ifdef BOOST_INTEL
0032 #   pragma warning(push)
0033 #   pragma warning(disable:2196) // warning #2196: routine is both "inline" and "noinline"
0034 #endif
0035 
0036 namespace boost { namespace stacktrace {
0037 
0038 /// Class that on construction copies minimal information about call stack into its internals and provides access to that information.
0039 /// @tparam Allocator Allocator to use during stack capture.
0040 template <class Allocator>
0041 class basic_stacktrace {
0042     std::vector<boost::stacktrace::frame, Allocator> impl_;
0043     typedef boost::stacktrace::detail::native_frame_ptr_t native_frame_ptr_t;
0044 
0045     /// @cond
0046     void fill(native_frame_ptr_t* begin, std::size_t size) {
0047         if (!size) {
0048             return;
0049         }
0050 
0051         impl_.reserve(static_cast<std::size_t>(size));
0052         for (std::size_t i = 0; i < size; ++i) {
0053             if (!begin[i]) {
0054                 return;
0055             }
0056             impl_.push_back(
0057                 frame(begin[i])
0058             );
0059         }
0060     }
0061 
0062     static std::size_t frames_count_from_buffer_size(std::size_t buffer_size) noexcept {
0063         const std::size_t ret = (buffer_size > sizeof(native_frame_ptr_t) ? buffer_size / sizeof(native_frame_ptr_t) : 0);
0064         return (ret > 1024 ? 1024 : ret); // Dealing with suspiciously big sizes
0065     }
0066 
0067     BOOST_NOINLINE void init(std::size_t frames_to_skip, std::size_t max_depth) {
0068         BOOST_CONSTEXPR_OR_CONST std::size_t buffer_size = 128;
0069         if (!max_depth) {
0070             return;
0071         }
0072 
0073         BOOST_TRY {
0074             {   // Fast path without additional allocations
0075                 native_frame_ptr_t buffer[buffer_size];
0076                 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);
0077                 if (buffer_size > frames_count || frames_count == max_depth) {
0078                     fill(buffer, frames_count);
0079                     return;
0080                 }
0081             }
0082 
0083             // Failed to fit in `buffer_size`. Allocating memory:
0084 #ifdef BOOST_NO_CXX11_ALLOCATOR
0085             typedef typename Allocator::template rebind<native_frame_ptr_t>::other allocator_void_t;
0086 #else
0087             typedef typename std::allocator_traits<Allocator>::template rebind_alloc<native_frame_ptr_t> allocator_void_t;
0088 #endif
0089             std::vector<native_frame_ptr_t, allocator_void_t> buf(buffer_size * 2, 0, impl_.get_allocator());
0090             do {
0091                 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);
0092                 if (buf.size() > frames_count || frames_count == max_depth) {
0093                     fill(&buf[0], frames_count);
0094                     return;
0095                 }
0096 
0097                 buf.resize(buf.size() * 2);
0098             } while (buf.size() < buf.max_size()); // close to `true`, but suppresses `C4127: conditional expression is constant`.
0099         } BOOST_CATCH (...) {
0100             // ignore exception
0101         }
0102         BOOST_CATCH_END
0103     }
0104     /// @endcond
0105 
0106 public:
0107     typedef typename std::vector<boost::stacktrace::frame, Allocator>::value_type             value_type;
0108     typedef typename std::vector<boost::stacktrace::frame, Allocator>::allocator_type         allocator_type;
0109     typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_pointer          pointer;
0110     typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_pointer          const_pointer;
0111     typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reference        reference;
0112     typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reference        const_reference;
0113     typedef typename std::vector<boost::stacktrace::frame, Allocator>::size_type              size_type;
0114     typedef typename std::vector<boost::stacktrace::frame, Allocator>::difference_type        difference_type;
0115     typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_iterator         iterator;
0116     typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_iterator         const_iterator;
0117     typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reverse_iterator reverse_iterator;
0118     typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reverse_iterator const_reverse_iterator;
0119 
0120     /// @brief Stores the current function call sequence inside *this without any decoding or any other heavy platform specific operations.
0121     ///
0122     /// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
0123     ///
0124     /// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
0125     BOOST_FORCEINLINE basic_stacktrace() noexcept
0126         : impl_()
0127     {
0128         init(0 , static_cast<std::size_t>(-1));
0129     }
0130 
0131     /// @brief Stores the current function call sequence inside *this without any decoding or any other heavy platform specific operations.
0132     ///
0133     /// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
0134     ///
0135     /// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
0136     ///
0137     /// @param a Allocator that would be passed to underlying storage.
0138     BOOST_FORCEINLINE explicit basic_stacktrace(const allocator_type& a) noexcept
0139         : impl_(a)
0140     {
0141         init(0 , static_cast<std::size_t>(-1));
0142     }
0143 
0144     /// @brief Stores [skip, skip + max_depth) of the current function call sequence inside *this without any decoding or any other heavy platform specific operations.
0145     ///
0146     /// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
0147     ///
0148     /// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
0149     ///
0150     /// @param skip How many top calls to skip and do not store in *this.
0151     ///
0152     /// @param max_depth Max call sequence depth to collect.
0153     ///
0154     /// @param a Allocator that would be passed to underlying storage.
0155     ///
0156     /// @throws Nothing. Note that default construction of allocator may throw, however it is
0157     /// performed outside the constructor and exception in `allocator_type()` would not result in calling `std::terminate`.
0158     BOOST_FORCEINLINE basic_stacktrace(std::size_t skip, std::size_t max_depth, const allocator_type& a = allocator_type()) noexcept
0159         : impl_(a)
0160     {
0161         init(skip , max_depth);
0162     }
0163 
0164     /// @b Complexity: O(st.size())
0165     ///
0166     /// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
0167     basic_stacktrace(const basic_stacktrace& st)
0168         : impl_(st.impl_)
0169     {}
0170 
0171     /// @b Complexity: O(st.size())
0172     ///
0173     /// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
0174     basic_stacktrace& operator=(const basic_stacktrace& st) {
0175         impl_ = st.impl_;
0176         return *this;
0177     }
0178 
0179 #ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
0180     /// @b Complexity: O(1)
0181     ///
0182     /// @b Async-Handler-Safety: Safe if Allocator::deallocate is async signal safe.
0183     ~basic_stacktrace() noexcept = default;
0184 #endif
0185 
0186 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
0187     /// @b Complexity: O(1)
0188     ///
0189     /// @b Async-Handler-Safety: Safe if Allocator construction and copying are async signal safe.
0190     basic_stacktrace(basic_stacktrace&& st) noexcept
0191         : impl_(std::move(st.impl_))
0192     {}
0193 
0194     /// @b Complexity: O(st.size())
0195     ///
0196     /// @b Async-Handler-Safety: Safe if Allocator construction and copying are async signal safe.
0197     basic_stacktrace& operator=(basic_stacktrace&& st)
0198 #ifndef BOOST_NO_CXX11_HDR_TYPE_TRAITS
0199         noexcept(( std::is_nothrow_move_assignable< std::vector<boost::stacktrace::frame, Allocator> >::value ))
0200 #else
0201         noexcept
0202 #endif
0203     {
0204         impl_ = std::move(st.impl_);
0205         return *this;
0206     }
0207 #endif
0208 
0209     /// @returns Number of function names stored inside the class.
0210     ///
0211     /// @b Complexity: O(1)
0212     ///
0213     /// @b Async-Handler-Safety: Safe.
0214     size_type size() const noexcept {
0215         return impl_.size();
0216     }
0217 
0218     /// @param frame_no Zero based index of frame to return. 0
0219     /// is the function index where stacktrace was constructed and
0220     /// index close to this->size() contains function `main()`.
0221     /// @returns frame that references the actual frame info, stored inside *this.
0222     ///
0223     /// @b Complexity: O(1).
0224     ///
0225     /// @b Async-Handler-Safety: Safe.
0226     const_reference operator[](std::size_t frame_no) const noexcept {
0227         return impl_[frame_no];
0228     }
0229 
0230     /// @b Complexity: O(1)
0231     ///
0232     /// @b Async-Handler-Safety: Safe.
0233     const_iterator begin() const noexcept { return impl_.begin(); }
0234     /// @b Complexity: O(1)
0235     ///
0236     /// @b Async-Handler-Safety: Safe.
0237     const_iterator cbegin() const noexcept { return impl_.begin(); }
0238     /// @b Complexity: O(1)
0239     ///
0240     /// @b Async-Handler-Safety: Safe.
0241     const_iterator end() const noexcept { return impl_.end(); }
0242     /// @b Complexity: O(1)
0243     ///
0244     /// @b Async-Handler-Safety: Safe.
0245     const_iterator cend() const noexcept { return impl_.end(); }
0246 
0247     /// @b Complexity: O(1)
0248     ///
0249     /// @b Async-Handler-Safety: Safe.
0250     const_reverse_iterator rbegin() const noexcept { return impl_.rbegin(); }
0251     /// @b Complexity: O(1)
0252     ///
0253     /// @b Async-Handler-Safety: Safe.
0254     const_reverse_iterator crbegin() const noexcept { return impl_.rbegin(); }
0255     /// @b Complexity: O(1)
0256     ///
0257     /// @b Async-Handler-Safety: Safe.
0258     const_reverse_iterator rend() const noexcept { return impl_.rend(); }
0259     /// @b Complexity: O(1)
0260     ///
0261     /// @b Async-Handler-Safety: Safe.
0262     const_reverse_iterator crend() const noexcept { return impl_.rend(); }
0263 
0264 
0265     /// @brief Allows to check that stack trace capturing was successful.
0266     /// @returns `true` if `this->size() != 0`
0267     ///
0268     /// @b Complexity: O(1)
0269     ///
0270     /// @b Async-Handler-Safety: Safe.
0271     constexpr explicit operator bool () const noexcept { return !empty(); }
0272 
0273     /// @brief Allows to check that stack trace failed.
0274     /// @returns `true` if `this->size() == 0`
0275     ///
0276     /// @b Complexity: O(1)
0277     ///
0278     /// @b Async-Handler-Safety: Safe.
0279     bool empty() const noexcept { return !size(); }
0280 
0281     const std::vector<boost::stacktrace::frame, Allocator>& as_vector() const noexcept {
0282         return impl_;
0283     }
0284 
0285     /// Constructs stacktrace from basic_istreamable that references the dumped stacktrace. Terminating zero frame is discarded.
0286     ///
0287     /// @b Complexity: O(N)
0288     template <class Char, class Trait>
0289     static basic_stacktrace from_dump(std::basic_istream<Char, Trait>& in, const allocator_type& a = allocator_type()) {
0290         typedef typename std::basic_istream<Char, Trait>::pos_type pos_type;
0291         basic_stacktrace ret(0, 0, a);
0292 
0293         // reserving space
0294         const pos_type pos = in.tellg();
0295         in.seekg(0, in.end);
0296         const std::size_t frames_count = frames_count_from_buffer_size(static_cast<std::size_t>(in.tellg()));
0297         in.seekg(pos);
0298         
0299         if (!frames_count) {
0300             return ret;
0301         }
0302 
0303         native_frame_ptr_t ptr = 0;
0304         ret.impl_.reserve(frames_count);
0305         while (in.read(reinterpret_cast<Char*>(&ptr), sizeof(ptr))) {
0306             if (!ptr) {
0307                 break;
0308             }
0309 
0310             ret.impl_.push_back(frame(ptr));
0311         }
0312 
0313         return ret;
0314     }
0315 
0316     /// Constructs stacktrace from raw memory dump. Terminating zero frame is discarded.
0317     ///
0318     /// @param begin Beginning of the memory where the stacktrace was saved using the boost::stacktrace::safe_dump_to
0319     ///
0320     /// @param buffer_size_in_bytes Size of the memory. Usually the same value that was passed to the boost::stacktrace::safe_dump_to
0321     ///
0322     /// @b Complexity: O(size) in worst case
0323     static basic_stacktrace from_dump(const void* begin, std::size_t buffer_size_in_bytes, const allocator_type& a = allocator_type()) {
0324         basic_stacktrace ret(0, 0, a);
0325         const native_frame_ptr_t* first = static_cast<const native_frame_ptr_t*>(begin);
0326         const std::size_t frames_count = frames_count_from_buffer_size(buffer_size_in_bytes);
0327         if (!frames_count) {
0328             return ret;
0329         }
0330 
0331         const native_frame_ptr_t* const last = first + frames_count;
0332         ret.impl_.reserve(frames_count);
0333         for (; first != last; ++first) {
0334             if (!*first) {
0335                 break;
0336             }
0337 
0338             ret.impl_.push_back(frame(*first));
0339         }
0340 
0341         return ret;
0342     }
0343 };
0344 
0345 /// @brief Compares stacktraces for less, order is platform dependent.
0346 ///
0347 /// @b Complexity: Amortized O(1); worst case O(size())
0348 ///
0349 /// @b Async-Handler-Safety: Safe.
0350 template <class Allocator1, class Allocator2>
0351 bool operator< (const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
0352     return lhs.size() < rhs.size() || (lhs.size() == rhs.size() && lhs.as_vector() < rhs.as_vector());
0353 }
0354 
0355 /// @brief Compares stacktraces for equality.
0356 ///
0357 /// @b Complexity: Amortized O(1); worst case O(size())
0358 ///
0359 /// @b Async-Handler-Safety: Safe.
0360 template <class Allocator1, class Allocator2>
0361 bool operator==(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
0362     return lhs.as_vector() == rhs.as_vector();
0363 }
0364 
0365 
0366 /// Comparison operators that provide platform dependant ordering and have amortized O(1) complexity; O(size()) worst case complexity; are Async-Handler-Safe.
0367 template <class Allocator1, class Allocator2>
0368 bool operator> (const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
0369     return rhs < lhs;
0370 }
0371 
0372 template <class Allocator1, class Allocator2>
0373 bool operator<=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
0374     return !(lhs > rhs);
0375 }
0376 
0377 template <class Allocator1, class Allocator2>
0378 bool operator>=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
0379     return !(lhs < rhs);
0380 }
0381 
0382 template <class Allocator1, class Allocator2>
0383 bool operator!=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept {
0384     return !(lhs == rhs);
0385 }
0386 
0387 /// Fast hashing support, O(st.size()) complexity; Async-Handler-Safe.
0388 template <class Allocator>
0389 std::size_t hash_value(const basic_stacktrace<Allocator>& st) noexcept {
0390     return boost::hash_range(st.as_vector().begin(), st.as_vector().end());
0391 }
0392 
0393 /// Returns std::string with the stacktrace in a human readable format; unsafe to use in async handlers.
0394 template <class Allocator>
0395 std::string to_string(const basic_stacktrace<Allocator>& bt) {
0396     if (!bt) {
0397         return std::string();
0398     }
0399 
0400     return boost::stacktrace::detail::to_string(&bt.as_vector()[0], bt.size());
0401 }
0402 
0403 /// Outputs stacktrace in a human readable format to the output stream `os`; unsafe to use in async handlers.
0404 template <class CharT, class TraitsT, class Allocator>
0405 std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT>& os, const basic_stacktrace<Allocator>& bt) {
0406     return os << boost::stacktrace::to_string(bt);
0407 }
0408 
0409 /// This is the typedef to use unless you'd like to provide a specific allocator to boost::stacktrace::basic_stacktrace.
0410 typedef basic_stacktrace<> stacktrace;
0411 
0412 }} // namespace boost::stacktrace
0413 
0414 #ifdef BOOST_INTEL
0415 #   pragma warning(pop)
0416 #endif
0417 
0418 #endif // BOOST_STACKTRACE_STACKTRACE_HPP