Repository: ggml-org/llama.cpp
Pull request: fix: Provide macos-specific backtrace printing to avoid terminal death

## Description

In my development environment on MacOS, any time I hit a failing `GGML_ASSERT`, my entire `Terminal.app` crashes (all windows, all processes, not just the ones involving the failing binary). I traced this down to the attempt to use `lldb` to print out a backtrace [here](https://github.com/ggml-org/llama.cpp/blob/master/ggml/src/ggml.c#L181).

The simplest fix is simply setting `GGML_NO_BACKTRACE` in the environment, but this is unset by default and needs to be discovered. It also needs to either be set in a global `.bash_profile` or set on every terminal.

This PR adds an `__APPLE__`-specific code path that uses the native `backtrace()` function and avoids attempting to attach to the parent from the forked `lldb` process.

## Testing

To repro this, add a failing `GGML_ASSERT` somewhere, for example:

```diff
diff --git a/tests/test-log.cpp b/tests/test-log.cpp
index 306f28c61..b21e60cd6 100644
--- a/tests/test-log.cpp
+++ b/tests/test-log.cpp
@@ -6,6 +6,8 @@
 int main() {
     const int n_thread = 8;
 
+    GGML_ASSERT(false);
+
     std::thread threads[n_thread];
     for (int i = 0; i < n_thread; i++) {
         threads[i] = std::thread([i]() {
```

Once built, run it and hit the assert:

```sh
./bin/test-log
```

## Sources

(Found with the help of Claude Code)

- https://developer.apple.com/forums/thread/658582
- https://www.wefearchange.org/2018/11/forkmacos.rst
- https://developer.apple.com/forums/thread/747499
- https://github.com/llvm/llvm-project/issues/53254

Changed files:
filename: ggml/src/ggml.c
patch: @@ -124,6 +124,13 @@ static void ggml_print_backtrace_symbols(void) {
     int nptrs = backtrace(trace, sizeof(trace)/sizeof(trace[0]));
     backtrace_symbols_fd(trace, nptrs, STDERR_FILENO);
 }
+#elif defined(__APPLE__)
+#include <execinfo.h>
+static void ggml_print_backtrace_symbols(void) {
+    void * trace[100];
+    int nptrs = backtrace(trace, sizeof(trace)/sizeof(trace[0]));
+    backtrace_symbols_fd(trace, nptrs, STDERR_FILENO);
+}
 #else
 static void ggml_print_backtrace_symbols(void) {
     // platform not supported
@@ -135,6 +142,20 @@ void ggml_print_backtrace(void) {
     if (GGML_NO_BACKTRACE) {
         return;
     }
+#if defined(__APPLE__)
+    // On macOS, fork+debugger attachment is problematic due to:
+    // 1. libdispatch "poisons" forked child processes
+    // 2. lldb has issues attaching to parent from forked child
+    // Use simple backtrace() instead to avoid Terminal.app crashes
+    const char * GGML_BACKTRACE_LLDB = getenv("GGML_BACKTRACE_LLDB");
+    if (!GGML_BACKTRACE_LLDB) {
+        fprintf(stderr, "WARNING: Using native backtrace. Set GGML_BACKTRACE_LLDB for more info.\n");
+        fprintf(stderr, "WARNING: GGML_BACKTRACE_LLDB may cause native MacOS Terminal.app to crash.\n");
+        fprintf(stderr, "See: https://github.com/ggml-org/llama.cpp/pull/17869\n");
+        ggml_print_backtrace_symbols();
+        return;
+    }
+#endif
 #if defined(__linux__)
     FILE * f = fopen("/proc/self/status", "r");
     size_t size = 0;