https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112649
Bug ID: 112649 Summary: [c++23] in presence of inline functions and debug-info stacktrace reports the deepest callee Product: gcc Version: 14.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: vincenzo.innocente at cern dot ch Target Milestone: --- Created attachment 56657 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=56657&action=edit a small demo demonstating the description. feature or defect? or missing feature in std::stacktrace... what I find disturbing is that the "symbol name" is different for the very same pc depending if it has been compiled with "-g" or not: in case of debug-info it is set to the deepest callee, w/o to the outermost caller. maybe it is a issue for the libstd committee? DEMO: just compile the attached demo program and compile it with c++ -std=c++23 stackTraceDemo.cpp -lstdc++exp -O2 -DINCLUDE='' -g and run it than without -g one can also try to run gdb to compare with the demo output. ``` gdb ./a.out b instrumentedFunc run where ``` Details: in libstdc++-v3/src/c++23/stacktrace.cc 123 bool 124 stacktrace_entry::_Info::_M_populate(native_handle_type pc) 125 { 126 auto cb = [](void* self, uintptr_t, const char* filename, int lineno, 127 const char* function) -> int 128 { 129 auto& info = *static_cast<_Info*>(self); 130 info._M_set_desc(function); 131 info._M_set_file(filename); 132 if (info._M_line) 133 *info._M_line = lineno; 134 return function != nullptr; 135 }; 136 const auto state = init(); 137 if (::__glibcxx_backtrace_pcinfo(state, pc, +cb, err_handler, this)) 138 return true; according to doc __glibcxx_backtrace_pcinfo * Given PC, a program counter in the current program, call the callback function with filename, line number, and function name information. This will normally call the callback function exactly once. However, if the PC happens to describe an inlined call, and the debugging information contains the necessary information, then this may call the callback function multiple times. This will make at least one call to either CALLBACK or ERROR_CALLBACK. This returns the first non-zero value returned by CALLBACK, or 0. */ >From my tests last sentence means that if the callback does not return 0 it may be called again. So in the current implementation it will be called just once even in presence of inline functions and therefore the stacktrace-entry will be set to the deepest callee. If one waits till last call (returning always "false") one will be able to set the entry to the outermost caller or even record the full call chain (as GDB does). This last option does not seem to fit std::backtrace interface. -------------- here is the output of the demo (I prefer to print the stacktrace reversed) # is from the stacktrace entry >> is from __glibcxx_backtrace_pcinfo returning always "false" [innocent@patatrack01 demos]$ c++ -std=c++23 stackTraceDemo.cpp -lstdc++exp -O2 -DINCLUDE=''; ./a.out #0 0xffffffffffffffff :0 #1 0x40164d _start :0 #2 0x7f4412f23d84 __libc_start_main :0 #3 0x40159a main :0 #4 0x401eeb func(int) :0 #5 0x401ab0 instrumentedFunc(int) :0 10 [innocent@patatrack01 demos]$ c++ -std=c++23 stackTraceDemo.cpp -lstdc++exp -O2 -DINCLUDE='' -g; ./a.out #0 0xffffffffffffffff :0 #1 0x40164d _start :0 #2 0x7ff80f90ed84 __libc_start_main :0 #3 0x40159a main /data/user/innocent/MallocProfiler/demos/stackTraceDemo.cpp:116 >> 1 main /data/user/innocent/MallocProfiler/demos/stackTraceDemo.cpp:116 #4 0x401eeb nestedFunc2(int) /data/user/innocent/MallocProfiler/demos/stackTraceDemo.cpp:101 >> 1 _Z11nestedFunc2i >> /data/user/innocent/MallocProfiler/demos/stackTraceDemo.cpp:101 >> 2 _Z10nestedFunci >> /data/user/innocent/MallocProfiler/demos/stackTraceDemo.cpp:106 >> 3 _Z4funci /data/user/innocent/MallocProfiler/demos/stackTraceDemo.cpp:112 #5 0x401ab0 instrumentedFunc(int) /data/user/innocent/MallocProfiler/demos/stackTraceDemo.cpp:91 >> 1 _Z16instrumentedFunci >> /data/user/innocent/MallocProfiler/demos/stackTraceDemo.cpp:91 10 [innocent@patatrack01 demos]$ gdb ./a.out GNU gdb (GDB) Red Hat Enterprise Linux 8.2-19.el8 ... Reading symbols from ./a.out...done. (gdb) b instrumentedFunc Breakpoint 1 at 0x401a90: file /afs/cern.ch/work/i/innocent/public/w5/include/c++/14.0.0/bits/new_allocator.h, line 88. (gdb) run Starting program: /data/user/innocent/MallocProfiler/demos/a.out Breakpoint 1, instrumentedFunc (c=4) at /afs/cern.ch/work/i/innocent/public/w5/include/c++/14.0.0/bits/new_allocator.h:88 88 __new_allocator() _GLIBCXX_USE_NOEXCEPT { } (gdb) where #0 instrumentedFunc (c=4) at /afs/cern.ch/work/i/innocent/public/w5/include/c++/14.0.0/bits/new_allocator.h:88 #1 0x0000000000401eec in nestedFunc2 (c=<optimized out>) at stackTraceDemo.cpp:112 #2 nestedFunc (c=<optimized out>) at stackTraceDemo.cpp:106 #3 func (c=<optimized out>) at stackTraceDemo.cpp:112 #4 0x000000000040159b in main (argc=<optimized out>) at stackTraceDemo.cpp:116 well the gdb stacktrace is also strange as it reports a pc off by one for nestedFunc2 (and the line number is wrong as it correspond to the call to nestedFunc in func... the one from __glibcxx_backtrace_pcinfo looks correct.