You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Pressing Cmd+N crashes with EXC_BAD_ACCESS (SIGSEGV) — pointer authentication failure in swift_retain called from TabManager.addWorkspace. This is a use-after-free of a Swift object that only manifests in Release (nightly) builds, not Debug (dev) builds.
This crash persists after both PR #2173 and PR #2178. The nightly build 2357244224201 was built from commit b93be12 (the #2178 merge commit itself).
PR #2178 sanitized the C struct (ghostty_surface_config_s) to avoid dangling Ghostty pointers. But this crash is in swift_retain — it's retaining a Swift object that was already freed. The offset +760 places this further into addWorkspace, past snapshot creation, likely in the tab array manipulation or workspace wiring phase.
Why Release-only
ARC optimizations in Release builds (-O/-Osize) eliminate intermediate retain/release pairs. An object that stays alive in Debug (due to extra retains) gets freed earlier in Release. The background git metadata probe on Thread 2 (com.cmux.initial-workspace-git-probe) running initialWorkspaceGitMetadataSnapshot concurrently may contribute a race condition:
Looking at TabManager.addWorkspace() (line 1201), offset +760 is past snapshot creation and likely in:
var updatedTabs = tabs (line 1243) — retaining the array copies retains each Workspace element. If a workspace was freed concurrently, the retain of that stale reference crashes.
tabs = updatedTabs (line 1249) — assigning back to @Published triggers Combine machinery that retains observers/subscribers.
makeWorkspaceForCreation(...) (line 1228) — creating the workspace involves wiring up configTemplate: inheritedConfig which, despite Fix Cmd+N crash from workspace creation config snapshots #2178's sanitization, might still reference state from a deallocated surface.
Suggested fix
The root cause across all three variants is that addWorkspace accesses shared mutable state (tabs, selectedWorkspace, terminal panel surfaces) that can be invalidated by concurrent operations during the brief window between snapshot capture and workspace insertion. Consider:
Audit all Swift object references in WorkspaceCreationSnapshot and the addWorkspace body for lifetime hazards under ARC optimization — explicit withExtendedLifetime on any workspace/panel accessed during creation.
Gate the background git probe to not run during workspace creation, or ensure it never touches workspace-level state on the main actor.
Reproduce in Release by building with swift build -c release or xcodebuild -configuration Release and rapidly pressing Cmd+N on launch.
Crash
Pressing Cmd+N crashes with
EXC_BAD_ACCESS (SIGSEGV)— pointer authentication failure inswift_retaincalled fromTabManager.addWorkspace. This is a use-after-free of a Swift object that only manifests in Release (nightly) builds, not Debug (dev) builds.This crash persists after both PR #2173 and PR #2178. The nightly build
2357244224201was built from commitb93be12(the #2178 merge commit itself).Related issues: #2157, #2169
Related PRs: #2173, #2178
Environment
0.62.2-nightly.2357244224201(b93be12)Stack trace
Exception
The PAC-stripped address
0x000051a102f4de88is "not in any region" — the object has been completely freed and its memory unmapped.Why this is a new variant
workspaceCreationSnapshot() + 1260workspaceCreationSnapshot()/newTabInsertIndexghostty_surface_config_spointersaddWorkspace() + 760swift_retainPAC failure)PR #2178 sanitized the C struct (
ghostty_surface_config_s) to avoid dangling Ghostty pointers. But this crash is inswift_retain— it's retaining a Swift object that was already freed. The offset+760places this further intoaddWorkspace, past snapshot creation, likely in the tab array manipulation or workspace wiring phase.Why Release-only
ARC optimizations in Release builds (
-O/-Osize) eliminate intermediate retain/release pairs. An object that stays alive in Debug (due to extra retains) gets freed earlier in Release. The background git metadata probe on Thread 2 (com.cmux.initial-workspace-git-probe) runninginitialWorkspaceGitMetadataSnapshotconcurrently may contribute a race condition:Likely candidates at addWorkspace + 760
Looking at
TabManager.addWorkspace()(line 1201), offset +760 is past snapshot creation and likely in:var updatedTabs = tabs(line 1243) — retaining the array copies retains eachWorkspaceelement. If a workspace was freed concurrently, the retain of that stale reference crashes.tabs = updatedTabs(line 1249) — assigning back to@Publishedtriggers Combine machinery that retains observers/subscribers.makeWorkspaceForCreation(...)(line 1228) — creating the workspace involves wiring upconfigTemplate: inheritedConfigwhich, despite Fix Cmd+N crash from workspace creation config snapshots #2178's sanitization, might still reference state from a deallocated surface.Suggested fix
The root cause across all three variants is that
addWorkspaceaccesses shared mutable state (tabs,selectedWorkspace, terminal panel surfaces) that can be invalidated by concurrent operations during the brief window between snapshot capture and workspace insertion. Consider:WorkspaceCreationSnapshotand theaddWorkspacebody for lifetime hazards under ARC optimization — explicitwithExtendedLifetimeon any workspace/panel accessed during creation.swift build -c releaseorxcodebuild -configuration Releaseand rapidly pressing Cmd+N on launch.