jeremy-rifkin/cpptrace

Stack is empty with `-fno-exceptions` on m2 macbook

Ghost-LZW opened this issue · 8 comments

We can build this library without the -no-exceptions flag and then link it with a no-exceptions library. However, I found that without exception support, the stack will be empty. Here is an simple example.

cmake_minimum_required(VERSION 3.24...3.26)

project(test)
set(CMAKE_CXX_STANDARD 20)

include(FetchContent)
FetchContent_Declare(
  cpptrace
  GIT_REPOSITORY https://github.com/jeremy-rifkin/cpptrace.git
  GIT_TAG        v0.7.0 # <HASH or TAG>
)
FetchContent_MakeAvailable(cpptrace)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")

add_executable(my_target test.cc)

target_link_libraries(my_target cpptrace::cpptrace)

# Create a .dSYM file on macOS
if(APPLE)
  add_custom_command(
    TARGET my_target
    POST_BUILD
    COMMAND dsymutil $<TARGET_FILE:my_target>
  )
endif()
#include "cpptrace/cpptrace.hpp"

void test() {
  cpptrace::generate_trace().print();
}

int main() {
  test();
}

/*
Stack trace (most recent call first):
<empty trace>
*/

I test it on Apple M2 Pro macbook.

I found it can work on linux.

Stack trace (most recent call first):
#0 0x00000000004036fe in test() at cmake_test/test.cc:7:27
#1 0x0000000000403722 in main at cmake_test/test.cc:11:7
#2 0x00007f4f0f87909a in __libc_start_main at /libc-start.c:308:16
#3 0x0000000000403629 at /cmake_test/build/my_target

Thank you for opening this and providing suchc a clear minimal reproducible example. I will look into this tomorrow.

Alright, I have reproduced the behavior you describe. I think what's happening here is that _Unwind_Backtrace relies on unwinding tables on arm and these aren't generated under -fno-exceptions. I've seen this before in #134. A workaround is to use execinfo's unwinding, -DCPPTRACE_UNWIND_WITH_EXECINFO=On, which doesn't rely on these. I expect libunwind would also work, however, I haven't tested that.

I'll look into how to and whether to provide a better library default here to prevent issues in the future.

libunwind indeed work, I test it with this patch #162

# cmake -S . -B build_libunwind -DCMAKE_BUILD_TYPE=Debug -DCPPTRACE_UNWIND_WITH_LIBUNWIND=ON
Stack trace (most recent call first):
#0 0x00000001022f31bb in test() at /cmake_test/test.cc:7:3 #1 0x00000001022f31e3 in main at /cmake_test/test.cc:11:3 #2 0x000000018da390df at /usr/lib/dyld

I found that I might not have built it correctly, which means the output is wrong. The stack is generated but does not properly resolve symbols, similar to jeremy-rifkin's result.

Thanks so much for taking the time to figure that out! I gave your patch a try with the repro setup using PATCH_COMMAND and it built using libunwind however unfortunately I still got an empty trace. If it worked for you and not for me I'd like to understand why. It might be a configuration issue on my end.

Sorry for the synchronization issue. When I use GCC on macOS, the stack is generated correctly (even with unwind). However, with Apple Clang or Clang, the stack remains empty.

Thanks for clarifying, interesting that it doesn't work on clang

Tested a number of configurations:

  • Gcc default: Works normally
  • Gcc libunwind: Works normally (though it's not properly resolving symbols, I'll have to look into that)
  • Apple clang default: Does not work normally
  • Apple clang execinfo: Works
  • Apple clang libunwind: Doesn't work
  • Clang default: Does not work normally
  • Clang execinfo: Works
  • Clang libunwind: Doesn't work

I didn't test -stdlib=libstdc++ behavior. I will proceed with setting execinfo as the default for clang on apple.