Std::stacktrace shows inlined fn, main doesn't

I have a code snippet that is compiled with a debug build:

#include <stacktrace>
#include <iostream>

void bar() {
    for (const auto &entry : std::stacktrace::current()) {
        std::cout << entry << '\n';
    }
}

void foo() {
    bar();
}

int main() {
    foo();
}

When compiled with a debug build, this code prints out the expected stack trace:

bar() at /app/example.cpp:5
foo() at /app/example.cpp:11
main at /app/example.cpp:15
     at :0
_start at :0

However, when compiled with optimizations enabled (-O2), the stack trace changes to:

bar() at /app/example.cpp:5
foo() at /app/example.cpp:11
     at :0
_start at :0

The assembly output of the optimized build is:

main:
  sub rsp, 8
  call bar()
  xor eax, eax
  add rsp, 8
  ret

See live example at Compiler Explorer

Questions

  1. How can bar() know that the stacktrace is foo() -> bar() if foo() is inlined, and completely skipped in the call chain?
  2. If bar() somehow knows its callers -even the inlined ones-, how come main disappeared from the stacktrace when enabling optimizations?
  3. What is the at :0 entry with no name? Is there a way to easily filter it out (without string manipulation)?

Answer

  1. When foo() is inlined, the call to bar() is directly inserted into the code of foo(). In this case, bar() can still access the stack trace because the compiler generates debug information that allows it to determine the call chain at runtime.

  2. When optimizations are enabled, the compiler may perform various transformations on the code, including inlining function calls. In the optimized code, the call to bar() is directly inserted into the main function, and the call to foo() is eliminated. As a result, main does not appear in the stack trace because there is no explicit call to foo() in the optimized code.

  3. The at :0 entry with no name represents a frame that could not be resolved to a specific function or location. This can occur when the compiler is unable to determine the source of a particular instruction or when certain optimizations are applied. Unfortunately, there is no built-in way to filter out this entry without some form of string manipulation or processing.