On Thu, Oct 16, 2025 at 1:53 PM Tomasz Kaminski <[email protected]> wrote:
> > > On Thu, Oct 16, 2025 at 1:24 PM Jonathan Wakely <[email protected]> > wrote: > >> With this change locations that don't have a source file look like this: >> >> 18# __libc_start_call_main at [0x7fd6568f6574] >> 19# __libc_start_main@GLIBC_2.2.5 at [0x7fd6568f6627] >> 20# _start at [0x4006a4] >> >> Instead of: >> >> 18# __libc_start_call_main at :0 >> 19# __libc_start_main@GLIBC_2.2.5 at :0 >> 20# _start at :0 >> >> For a non-empty stacktrace_entry, if the function name returned by >> description() is an empty string we now print "<unknown>" for the >> function name. 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 OK for now. >> >> 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. >> (operator<<(ostream&, const basic_stacktrace<A>&)): Use >> size_type of the correct specialization. >> --- >> >> v2: Restore fmtflags as pointed out by Nathan. Adjust control flow in >> operator<< as suggested by Tomasz. >> >> Tested x86_64-linux. >> >> libstdc++-v3/include/std/stacktrace | 29 +++++++++++++++++++++++++---- >> 1 file changed, 25 insertions(+), 4 deletions(-) >> >> diff --git a/libstdc++-v3/include/std/stacktrace >> b/libstdc++-v3/include/std/stacktrace >> index b9e260e19f89..28ffda76328f 100644 >> --- a/libstdc++-v3/include/std/stacktrace >> +++ b/libstdc++-v3/include/std/stacktrace >> @@ -685,11 +685,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION >> { >> 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; >> + if (__desc.empty()) [[unlikely]] >> + __os << "<unknown>"; >> + else >> + __os << __desc; >> + __os << string_view(" at "); >> + if (!__file.empty()) [[likely]] >> + return __os << __file << ':' << __line; >> + // else fall through and write native_handle() as the location. >> } >> + >> + if (__f) [[likely]] >> + { >> + struct _Flag_guard >> + { >> + ios_base& _M_ios; >> + ios_base::fmtflags _M_f; >> + ~_Flag_guard() { _M_ios.setf(_M_f); } >> + }; >> + _Flag_guard _ = { __os, __os.setf(ios::hex, ios::basefield) }; >> + __os << "[0x" << __f.native_handle() << ']'; >> + } >> + else >> + __os << "<unknown>"; >> return __os; >> > I know that I ask for another change ag, but if (!__f) we will not ever > get info for it, so I would prefer: > if (!__f) [[unlikelly] > return __os << "<unknown>"; > > string __desc, __file; > int __line; > if (__f._M_get_info(&__desc, &__file, &__line)) [[likely]] > { > // unchanged > } > > struct _Flag_guard > { > ios_base& _M_ios; > ios_base::fmtflags _M_f; > ~_Flag_guard() { _M_ios.setf(_M_f); } > }; > _Flag_guard _ = { __os, __os.setf(ios::hex, ios::basefield) }; > __os << "[0x" << __f.native_handle() << ']'; > return __os; > > This way it is clear, that we never produce <unknown> at <unknown> > With flow changed as above LGTM. > > >> } >> >> @@ -697,7 +717,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'; >> -- >> 2.51.0 >> >>
