0

We have a C++20 library that compiles several Boost modules and statically links their object files into our shared library. One of those modules is Boost.Stacktrace. We compile this library, and a test application that uses it, on many platforms: macOS 14 Clang 16 ARM, macOS 15 Clang 17 ARM, and macOS 15 Clang 17 Intel; GCC 8, 9, 11, 13, and 14 across RHEL 8, RHEL9, Ubuntu 22.04, and Ubuntu 24.04; and Windows 10, 11, 2022, and 2025 with MSVC 2022. And then for all of these, we compile separate opt and debug (-g) libraries and test applications.

On the POSIX platforms (so excluding Windows for the duration of this question), we link to libbacktrace, and we build and link to boost.stacktrace.backtrace. On Ubuntu, this is using the GCC-provided libbacktrace. On RHEL and macOS, libbacktrace is not provided, so we compile libbacktrace from source and use that.

And on all of these POSIX platforms except one, it all works great. We get expected, helpful information for stacktraces without error. However, on macOS 15 (only) Clang 17 (only) Intel (only) opt (only), calling boost::stacktrace::frame::source_line() or source_file() or name() segfaults (EXC_BAD_ACCESS (SIGSEGV)), and it segfaults every single time consistently. This does not happen on ARM. It does not happen on Clang 16. It does not happen on macOS 15 Clang 17 Intel debug. Only macOS 15 Clang 17 Intel opt (which makes tracing down the source harder, but I think I have).

Here are the first two frames from the macOS Console crash report. The third frame is our code's call to source_line():

0 libdyld.dylib 0x7ff817a8ef96 _tlv_get_addr + 3 1 libNameOfMySharedLibrary.dylib 0x1096e44db boost::stacktrace::frame::source_line() const + 27 3 [our code] ... 

Even without the file names and line numbers I'd get on a debug build, this is decisive. _tlv_get_addr is a function specifically used for thread_local storage. This leaves only one possible call stack that can generate this specific condition (manually generated):

0 _tlv_get_addr in libdylib.dylib 1 thread_local in ??? 2 boost::stacktrace::detail::construct_state(...) at boost/stacktrace/detail/libbacktrace_impls.hpp:104 3 boost::stacktrace::frame::source_line() at boost/stacktrace/detail/libbacktrace_impls.hpp:229 4 [our code] ... 

Links to above sources:

Here is some more information from the crash report, little of which I understand:

Exception Type: EXC_BAD_ACCESS (SIGSEGV) Exception Codes: KERN_INVALID_ADDRESS at 0x00007ff914b8b9e0 Exception Codes: 0x0000000000000001, 0x00007ff914b8b9e0 Termination Reason: Namespace SIGNAL, Code 11 Segmentation fault: 11 Terminating Process: exc handler [11903] VM Region Info: 0x7ff914b8b9e0 is not in any region. Bytes after previous region: 1961314785 Bytes before following region: 16938528 REGION TYPE START - END [ VSIZE] PRT/MAX SHRMOD REGION DETAIL __LINKEDIT 7ff895bb3000-7ff89fd17000 [161.4M] r--/r-- SM=COW dyld shared cache combined __LINKEDIT ---> GAP OF 0x75e9c000 BYTES unused __TEXT 7ff915bb3000-7ff935a5b000 [510.7M] r-x/r-x SM=COW unused unknown system shared lib __TEXT 

So, all of that information dumped out there, I don't know who to report this problem to. Is this a:

  1. Boost bug (I don't think so)?
  2. macOS bug?
  3. Clang (LLVM) bug?
  4. Some third-party OSS C++ library bug?
  5. Something else entirely?
5
  • Looks like a problem with thread local storage and/or compiler/linker optimization. What optimization level do you compile/link at? And does it disappear when you lower optimization settings? If so it may be a compiler/linker bug for apple/x86 combo (just brainstorming to find a rootcause ;) ) Commented Sep 13 at 5:18
  • We're compiling with -g -O3 -fPIC (there are others, like many -Is and -Ds, but those are the only ones I feel could affect this). The only difference between that and the debug build is the -O3, which isn't present on the debug build. All other arguments are present on both. I'll try decreasing to -O2 and then -O1 and report back. Commented Sep 17 at 20:15
  • So, turns out it wasn't even about what our code was optimized with (which, in retrospect ... duh). It's about boost/libs/stacktrace/src/backtrace.cpp being compiled with -O3. I tried changing that to -O2 with no affect. However, changing it to -O1 fixed the segfault. We can still compile our code with -O3, but Boost's backtrace.cpp needs -O1. Commented Sep 18 at 14:26
  • with no *effect (edit window closed) Commented Sep 18 at 14:33
  • 1
    Might still be a compiler bug, that might be worth reporting. But seems you can at least continue for now. Commented Sep 18 at 15:37

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.