https://gcc.gnu.org/g:08b2c542e4d0c223f50e46692bccf0c2ebbe3454

commit r16-4457-g08b2c542e4d0c223f50e46692bccf0c2ebbe3454
Author: Jonathan Wakely <[email protected]>
Date:   Wed Oct 15 20:10:34 2025 +0100

    libstdc++: Improve ostream output for std::stacktrace
    
    With this change stacktrace entries always output the frame address, and
    source file information no longer results in " at :0", e.g.
    
      16#  myfunc(int) at /tmp/bt.cc:48 [0x4008b7]
      17#  main at /tmp/bt.cc:61 [0x40091a]
      18#  __libc_start_call_main [0x7efc3d6d3574]
      19#  __libc_start_main@GLIBC_2.2.5 [0x7efc3d6d3627]
      20#  _start [0x400684]
    
    This replaces the previous output:
    
      16# myfunc(int) at /tmp/bt.cc:48
      17# main at /tmp/bt.cc:61
      18# __libc_start_call_main at :0
      19# __libc_start_main@GLIBC_2.2.5 at :0
      20# _start at :0
    
    A change that is not visible in the examples above is that for a
    non-empty stacktrace_entry, we now print "<unknown>" for the function
    name if description() returns an empty string.  For an empty (e.g.
    default constructed) stacktrace_entry the entire string representation
    is now "<unknown>" instead of an empty string.
    
    Instead of printing "<unknown>" for the function name, we could set that
    string in the stacktrace_entry::_Info object, so that description()
    returns "<unknown>" and then operator<< wouldn't need to handle an empty
    description() string. However, returning an empty string from that
    function seems simpler for users to detect, rather than having to parse
    "<unknown>".
    
    We could also choose a different string for an empty stacktrace_entry,
    maybe "<none>" or "<invalid>", but "<unknown>" seems good.
    
    libstdc++-v3/ChangeLog:
    
            * include/std/stacktrace
            (operator<<(ostream&, const stacktrace_entry&)): Improve output
            when description() or source_file() returns an empty string,
            or the stacktrace_entry is invalid. Append frame address to
            output.
            (operator<<(ostream&, const basic_stacktrace<A>&)): Use the
            size_type of the correct specialization.
    
    Reviewed-by: Tomasz KamiƄski <[email protected]>
    Reviewed-by: Nathan Myers <[email protected]>

Diff:
---
 libstdc++-v3/include/std/stacktrace | 28 ++++++++++++++++++++++++----
 1 file changed, 24 insertions(+), 4 deletions(-)

diff --git a/libstdc++-v3/include/std/stacktrace 
b/libstdc++-v3/include/std/stacktrace
index b9e260e19f89..587a163e9766 100644
--- a/libstdc++-v3/include/std/stacktrace
+++ b/libstdc++-v3/include/std/stacktrace
@@ -683,13 +683,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   inline ostream&
   operator<<(ostream& __os, const stacktrace_entry& __f)
   {
+    if (!__f) [[unlikely]]
+      return __os << "<unknown>";
+
     string __desc, __file;
     int __line;
-    if (__f._M_get_info(&__desc, &__file, &__line))
+    if (__f._M_get_info(&__desc, &__file, &__line)) [[likely]]
       {
-       __os.width(4);
-       __os << __desc << " at " << __file << ':' << __line;
+       __os << ' ';
+       if (__desc.empty()) [[unlikely]]
+         __os << "<unknown>";
+       else
+         __os << __desc;
+       if (!__file.empty()) [[likely]]
+         __os << " at " << __file << ':' << __line;
       }
+
+    struct _Flag_guard // Set and restore hex format
+    {
+      _Flag_guard(ios& __s) : _M_ios(__s) { }
+      ~_Flag_guard() { _M_ios.setf(_M_f); }
+
+      ios& _M_ios;
+      ios::fmtflags _M_f = _M_ios.setf(ios::hex, ios::basefield);
+    };
+    _Flag_guard __g(__os);
+    __os << " [0x" << __f.native_handle() << ']';
     return __os;
   }
 
@@ -697,7 +716,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     inline ostream&
     operator<<(ostream& __os, const basic_stacktrace<_Allocator>& __st)
     {
-      for (stacktrace::size_type __i = 0; __i < __st.size(); ++__i)
+      using size_type = typename basic_stacktrace<_Allocator>::size_type;
+      for (size_type __i = 0, __size = __st.size(); __i < __size; ++__i)
        {
          __os.width(4);
          __os << __i << "# " << __st[__i] << '\n';

Reply via email to