Skip to content

fix(desktop): keep AppKit assertions in the accent-frame paint from aborting the app - #550

Merged
marcelxpfeifer merged 1 commit into
mainfrom
t3code/fix-accent-frame-crash
Aug 12, 2026
Merged

fix(desktop): keep AppKit assertions in the accent-frame paint from aborting the app#550
marcelxpfeifer merged 1 commit into
mainfrom
t3code/fix-accent-frame-crash

Conversation

@marcelxpfeifer

Copy link
Copy Markdown
Contributor

Fixes a SIGABRT crash reported on macOS 26.5.1 (v0.3.2): an AppKit assertion (NSAssertionHandler out of -[NSView dealloc]) fired while apply_accent_frame repainted a window, and the Objective-C exception unwound through the Rust frames into std::terminate, taking the whole app down.

Trigger. The crashed stack shows a live set_accent_frame IPC (WKWebView didPostMessage → handle_ipc_message → set_accent_frame → run_on_main_thread → apply_accent_frame) landing on a window whose view hierarchy is mid-teardown — the compose window closes at will, racing in-flight accent updates. In that state the paint's transient retain of the content view can be the release that runs -[NSView dealloc] on this stack, and AppKit's dealloc assertion throws.

Fix. Two layers, both scoped to the accent frame:

  • Run the whole AppKit paint (split out as paint_accent_frame) under objc2::exception::catch, so an AppKit assertion now costs one skipped, logged repaint instead of the process. Needs the objc2 exception feature (added in Cargo.toml — feature-only, no lockfile change); the crate builds with the default panic=unwind, which the catch requires.
  • Skip painting when the content view is already detached from its window (content.window() is nil), the mid-teardown state that made the final-release dealloc possible in the first place.

Also reattaches the "Draw the per-workspace identity frame" doc block to the paint function — it had been left fused onto window_corner_radius's doc when that helper was inserted between the comment and the function.

Verified locally: desktop TS bridge lint/typecheck/tests (37 passing, unaffected by the Rust-only change). The Rust side compiles only in Desktop CI here (no local toolchain), so the macos-14 cargo fmt --check + cargo test job is the compile gate.

…borting the app

A crash report (macOS 26.5.1, v0.3.2) showed the app dying with SIGABRT:
an AppKit assertion (NSAssertionHandler out of -[NSView dealloc]) fired
while apply_accent_frame repainted a window, and the Objective-C
exception unwound through the Rust frames into std::terminate. The
trigger is a set_accent_frame IPC landing on a window whose view
hierarchy is mid-teardown (the compose window closes at will), where the
paint's transient retain of the content view can be the release that
runs -[NSView dealloc] on this stack.

Two layers of defense, both scoped to the accent frame:

- Run the whole AppKit paint (split out as paint_accent_frame) under
  objc2::exception::catch, so an AppKit assertion now costs one skipped,
  logged repaint instead of the process. Needs the objc2 "exception"
  feature; the crate builds with the default panic=unwind, which the
  catch requires.
- Skip painting when the content view is already detached from its
  window (content.window() == nil), the mid-teardown state that made the
  final-release dealloc possible in the first place.

Also reattaches the "Draw the per-workspace identity frame" doc block to
the paint function — it had been left fused onto window_corner_radius's
doc when that helper was inserted between the comment and the function.
@marcelxpfeifer
marcelxpfeifer merged commit 67174ed into main Aug 12, 2026
19 checks passed
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.

1 participant