Skip to content

Commit 6380713

Browse files
committed
fix(macos/tile-snap): switch release to panic=unwind so catch_unwind catches NSEvent handler panics
In v7.0.26 the bundled app crashed (SIGABRT in `GlobalObserverHandler`) three times in field logs. Root cause: `panic = "abort"` in the release profile makes `std::panic::catch_unwind` in the Tile Snap NSEvent global monitor (tiling/macos.rs) inert — any panic in the ObjC block bypasses the catch and aborts the process. Fix: - Set `panic = "unwind"` for release so catch_unwind actually catches. - Defensive `state.displays.get(display_idx)` in handle_snap_event to avoid an out-of-bounds panic when displays change mid-drag. Bumps version to 7.0.29.
1 parent bf0ac83 commit 6380713

3 files changed

Lines changed: 20 additions & 5 deletions

File tree

src-tauri/Cargo.toml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,14 @@ windows = { version = "0.58", features = [
5757
ddc-winapi = "0.2"
5858
winapi = { version = "0.3", features = ["wingdi", "windef"] }
5959

60+
# `panic = "unwind"` is required so that `std::panic::catch_unwind` in the
61+
# macOS Tile Snap NSEvent global monitor (tiling/macos.rs) actually catches
62+
# panics. With `panic = "abort"`, a panic in that ObjC-block handler bypasses
63+
# `catch_unwind` and calls `abort()`, which has crashed the bundled app
64+
# multiple times in the field (SIGABRT in `GlobalObserverHandler`). Slightly
65+
# larger binary in exchange for not aborting on a recoverable handler bug.
6066
[profile.release]
61-
panic = "abort"
67+
panic = "unwind"
6268
codegen-units = 1
6369
lto = true
6470
opt-level = "s"

src-tauri/src/tiling/macos.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2742,23 +2742,32 @@ fn handle_snap_event(ctx: &SnapContext, event_type: u64, cursor: CGPoint) {
27422742

27432743
match zone {
27442744
Some((layout, display_idx)) => {
2745+
// Defensive bounds check: `detect_snap_zone_macos` already
2746+
// returns an index into `state.displays`, but `state.displays`
2747+
// may have been refreshed mid-drag (monitor hotplug). An
2748+
// out-of-bounds indexing here would panic inside the NSEvent
2749+
// ObjC block, which on a `panic = "abort"` build aborts the
2750+
// process. Skip rather than crash.
2751+
let display = match state.displays.get(display_idx) {
2752+
Some(d) => d.clone(),
2753+
None => return,
2754+
};
27452755
if state.current_layout != Some(layout) || state.current_display != display_idx
27462756
{
27472757
if let Some(dbg_state) = ctx.app.try_state::<crate::AppState>() {
2748-
let d = &state.displays[display_idx];
27492758
crate::config::write_debug_log(
27502759
&dbg_state,
27512760
&format!(
27522761
"tile_snap: zone detected — layout={:?}, display={} ({:.0},{:.0} {:.0}x{:.0}), cursor=({:.0},{:.0})",
2753-
layout, display_idx, d.x, d.y, d.width, d.height, cursor.x, cursor.y,
2762+
layout, display_idx, display.x, display.y, display.width, display.height, cursor.x, cursor.y,
27542763
),
27552764
);
27562765
}
27572766
state.current_layout = Some(layout);
27582767
state.current_display = display_idx;
27592768
let target = calculate_target_rect(
27602769
layout,
2761-
&state.displays[display_idx],
2770+
&display,
27622771
state.half_ratio,
27632772
state.third_ratio,
27642773
state.gap,

src-tauri/tauri.conf.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"$schema": "https://raw.githubusercontent.com/nicoverbruggen/tauri-v2-docs/refs/heads/main/schemas/config.schema.json",
33
"productName": "Display DJ",
4-
"version": "7.0.28",
4+
"version": "7.0.29",
55
"identifier": "com.synle.display-dj",
66
"build": {
77
"beforeDevCommand": "npm run dev",

0 commit comments

Comments
 (0)