Skip to content

Fix terminateHandler() on macOS #563

Queued
edolstra wants to merge 3 commits into
mainfrom
fix-terminate
Queued

Fix terminateHandler() on macOS #563
edolstra wants to merge 3 commits into
mainfrom
fix-terminate

Conversation

@edolstra

@edolstra edolstra commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

Motivation

On macOS, calling std::set_terminate(nullptr) to restore the original terminate handler is ineffective, since std::terminate() calls the handler recorded in the exception. So we end up in an infinite recursion of terminateHandler() calls, which eventually overflows the stack, leading to an unhelpful crash report.

So instead, just call onTerminate() to print the stack trace and abort.

(On Linux / libstdc++, std::terminate() calls the global terminate handler so we don't have this issue.)

Also added some hackery to make the __cxa_throw interposer build with libc++ on Linux, and added an abort mode to nix __crash.

Context

Summary by CodeRabbit

  • New Features

    • Added an abort option to the crash-testing command, allowing users to simulate process termination explicitly.
  • Bug Fixes

    • Improved termination handling so unexpected failures consistently produce a crash report and log the active exception when available.
    • Improved crash diagnostics with clearer formatting in termination messages.
  • Tests

    • Expanded crash-reporting coverage to include the new abort scenario alongside existing crash types.

edolstra added 3 commits July 14, 2026 11:52
is-logic-error.hh relied on <cxxabi.h> declaring the Itanium ABI RTTI
classes (__cxxabiv1::__si_class_type_info and its __base_type member).
Only libstdc++'s <cxxabi.h> does that; libc++abi keeps them in its
private, uninstalled private_typeinfo.h, so building with
-stdlib=libc++ on Linux failed with

  error: no type named '__si_class_type_info' in namespace '__cxxabiv1'

Since the layout of these classes is fixed by the Itanium C++ ABI
(https://itanium-cxx-abi.github.io/cxx-abi/abi.html#rtti) and libc++abi
exports their vtables/type infos, declare the parts we need ourselves
when not using libstdc++ headers.

(macOS was unaffected only because the interposer is Linux-only in
meson.build.)

Assisted-by: Claude Fable 5 <noreply@anthropic.com>
On macOS, calling std::set_terminate(nullptr) to restore the original
terminate handler is ineffective, since std::terminate() calls the
handler recorded in the exception. So we end up in an infinite
recursion of terminateHandler() calls, which eventually overflows the
stack, leading to an unhelpful crash report.

So instead, just call onTerminate() to print the stack trace and
abort.

(On Linux / libstdc++, std::terminate() calls the global terminate
handler so we don't have this issue.)
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 34d2639f-bef7-4fba-83ed-91312fbb2d27

📥 Commits

Reviewing files that changed from the base of the PR and between 1128ff5 and 96cc170.

📒 Files selected for processing (6)
  • nix-meson-build-support/common/cxa-throw/is-logic-error.hh
  • src/libutil/include/nix/util/error.hh
  • src/nix/crash-handler.cc
  • src/nix/crash.cc
  • src/nix/main.cc
  • tests/functional/sentry.sh

📝 Walkthrough

Walkthrough

Crash termination handling now uses a shared onTerminate() path, adds portable logic-error termination support, exposes an abort crash scenario, and tests abort crash reporting through the Sentry functional test.

Changes

Crash termination handling

Layer / File(s) Summary
Portable logic-error termination hook
nix-meson-build-support/common/cxa-throw/is-logic-error.hh
Adds an overrideable CXA_THROW_ON_LOGIC_ERROR() hook defaulting to abort(), plus conditional Itanium ABI RTTI declarations.
Shared termination entry point
src/libutil/include/nix/util/error.hh, src/nix/crash-handler.cc, src/nix/main.cc
Declares and defines nix::onTerminate(), and routes terminateHandler() through it after recording Sentry exception tags.
Abort crash scenario
src/nix/crash.cc, tests/functional/sentry.sh
Adds the abort crash type and includes it in Sentry crash-dump coverage.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant terminateHandler
  participant onTerminate
  participant logFatal
  terminateHandler->>onTerminate: delegate termination
  onTerminate->>logFatal: log current exception and crash message
  onTerminate->>onTerminate: call abort
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: fixing terminateHandler() behavior on macOS.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-terminate

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

@edolstra edolstra added this pull request to the merge queue Jul 14, 2026
Any commits made after this event will not be merged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants