Skip to content

macos: Reset exception ports for shell-spawned processes#44193

Merged
Veykril merged 1 commit intozed-industries:mainfrom
RemiKalbe:fix/reset-exception-ports-for-shell-processes
Dec 8, 2025
Merged

macos: Reset exception ports for shell-spawned processes#44193
Veykril merged 1 commit intozed-industries:mainfrom
RemiKalbe:fix/reset-exception-ports-for-shell-processes

Conversation

@RemiKalbe
Copy link
Contributor

Summary

Follow-up to #40716. This applies the same reset_exception_ports() fix to set_pre_exec_to_start_new_session(), which is used by shell environment capture, terminal spawning, and DAP transport.

Root Cause

After more debugging, I finally figured out what was causing the issue on my machine. Here's what was happening:

  1. Zed spawns a login shell (zsh) to capture environment variables
  2. A pipe is created: reader in Zed, writer mapped to fd 0 in zsh
  3. zsh sources .zshrc → loads oh-my-zsh → runs poetry plugin
  4. Poetry plugin runs poetry completions zsh &| in background
  5. Poetry inherits fd 0 (the pipe's write end) from zsh
  6. zsh finishes zed --printenv and exits
  7. Poetry still holds fd 0 open
  8. Zed's reader.read_to_end() blocks waiting for all writers to close
  9. Poetry hangs (likely due to inherited crash handler exception ports interfering with its normal operation)
  10. Pipe stays open → Zed stuck → no more processes spawn (including LSPs)

I confirmed this by killing the hanging poetry process, which immediately unblocked Zed and allowed LSPs to start. However, this workaround was needed every time I started Zed.

While poetry was the culprit in my case, this can affect any shell configuration that spawns background processes during initialization (oh-my-zsh plugins, direnv, asdf, nvm, etc.).

Fixes #36754

Test plan

  • Build with ZED_GENERATE_MINIDUMPS=true to force crash handler initialization
  • Verify crash handler logs appear ("spawning crash handler process", "crash handler registered")
  • Confirm LSPs start correctly with shell plugins that spawn background processes

Release Notes:

  • Fixed an issue on macOS where LSPs could fail to start when shell plugins spawn background processes during environment capture.

@cla-bot cla-bot bot added the cla-signed The user has signed the Contributor License Agreement label Dec 5, 2025
The original fix in zed-industries#40716 only applied to processes spawned via
`new_smol_command()`, but shell environment capture uses a different
code path: `new_std_command()` → `set_pre_exec_to_start_new_session()`
→ convert to smol::process::Command.

This caused an issue where:
1. Zed spawns a login shell to capture environment variables
2. The shell sources user config (e.g., .zshrc with oh-my-zsh plugins)
3. Plugins may spawn background processes (e.g., `poetry completions zsh &|`)
4. These processes inherit the crash handler's exception ports
5. The inherited exception ports can cause the processes to hang
6. The hanging process keeps the pipe to Zed open
7. Zed's `read_to_end()` blocks waiting for the pipe to close
8. This prevents Zed from spawning any more processes (including LSPs)

Fix by also calling `reset_exception_ports()` in
`set_pre_exec_to_start_new_session()`, which is used by shell
environment capture, terminal spawning, and DAP transport.

Fixes zed-industries#36754
@RemiKalbe RemiKalbe force-pushed the fix/reset-exception-ports-for-shell-processes branch from a2e1637 to b40c1b2 Compare December 5, 2025 03:55
Copy link
Member

@Veykril Veykril left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@Veykril Veykril merged commit 5bfc0ba into zed-industries:main Dec 8, 2025
23 checks passed
CherryWorm pushed a commit to CherryWorm/zed that referenced this pull request Dec 16, 2025
…ies#44193)

## Summary

Follow-up to zed-industries#40716. This applies the same `reset_exception_ports()` fix
to `set_pre_exec_to_start_new_session()`, which is used by shell
environment capture, terminal spawning, and DAP transport.

### Root Cause

After more debugging, I finally figured out what was causing the issue
on my machine. Here's what was happening:

1. Zed spawns a login shell (zsh) to capture environment variables
2. A pipe is created: reader in Zed, writer mapped to fd 0 in zsh
3. zsh sources `.zshrc` → loads oh-my-zsh → runs poetry plugin
4. Poetry plugin runs `poetry completions zsh &|` in background
5. Poetry inherits fd 0 (the pipe's write end) from zsh
6. zsh finishes `zed --printenv` and exits
7. Poetry still holds fd 0 open
8. Zed's `reader.read_to_end()` blocks waiting for all writers to close
9. Poetry hangs (likely due to inherited crash handler exception ports
interfering with its normal operation)
10. Pipe stays open → Zed stuck → no more processes spawn (including
LSPs)

I confirmed this by killing the hanging `poetry` process, which
immediately unblocked Zed and allowed LSPs to start. However, this
workaround was needed every time I started Zed.

While poetry was the culprit in my case, this can affect any shell
configuration that spawns background processes during initialization
(oh-my-zsh plugins, direnv, asdf, nvm, etc.).

Fixes zed-industries#36754

## Test plan

- [x] Build with `ZED_GENERATE_MINIDUMPS=true` to force crash handler
initialization
- [x] Verify crash handler logs appear ("spawning crash handler
process", "crash handler registered")
- [x] Confirm LSPs start correctly with shell plugins that spawn
background processes

Release Notes:

- Fixed an issue on macOS where LSPs could fail to start when shell
plugins spawn background processes during environment capture.
someone13574 pushed a commit to someone13574/zed that referenced this pull request Dec 16, 2025
…ies#44193)

## Summary

Follow-up to zed-industries#40716. This applies the same `reset_exception_ports()` fix
to `set_pre_exec_to_start_new_session()`, which is used by shell
environment capture, terminal spawning, and DAP transport.

### Root Cause

After more debugging, I finally figured out what was causing the issue
on my machine. Here's what was happening:

1. Zed spawns a login shell (zsh) to capture environment variables
2. A pipe is created: reader in Zed, writer mapped to fd 0 in zsh
3. zsh sources `.zshrc` → loads oh-my-zsh → runs poetry plugin
4. Poetry plugin runs `poetry completions zsh &|` in background
5. Poetry inherits fd 0 (the pipe's write end) from zsh
6. zsh finishes `zed --printenv` and exits
7. Poetry still holds fd 0 open
8. Zed's `reader.read_to_end()` blocks waiting for all writers to close
9. Poetry hangs (likely due to inherited crash handler exception ports
interfering with its normal operation)
10. Pipe stays open → Zed stuck → no more processes spawn (including
LSPs)

I confirmed this by killing the hanging `poetry` process, which
immediately unblocked Zed and allowed LSPs to start. However, this
workaround was needed every time I started Zed.

While poetry was the culprit in my case, this can affect any shell
configuration that spawns background processes during initialization
(oh-my-zsh plugins, direnv, asdf, nvm, etc.).

Fixes zed-industries#36754

## Test plan

- [x] Build with `ZED_GENERATE_MINIDUMPS=true` to force crash handler
initialization
- [x] Verify crash handler logs appear ("spawning crash handler
process", "crash handler registered")
- [x] Confirm LSPs start correctly with shell plugins that spawn
background processes

Release Notes:

- Fixed an issue on macOS where LSPs could fail to start when shell
plugins spawn background processes during environment capture.
smitbarmase added a commit that referenced this pull request Feb 10, 2026
Follow-up to #47420 and #44193.

#47420 fixed child-exit status handling via upstream alacritty change
(alacritty/alacritty#8825). However,
stable/preview/nightly builds still reproduced hangs that dev builds did
not.

The root cause matches #44193: spawned children inherit crash-handler
Mach exception ports and hang. We already reset exception ports in
`util::command::new_smol_command` and
`util::set_pre_exec_to_start_new_session`, but PTY child spawning in
`alacritty_terminal` was not covered.

This PR updates `alacritty_terminal` to include PTY `pre_exec`
exception-port reset:

zed-industries/alacritty@9d9640d

Upstream:
- alacritty/alacritty#8835

Release Notes:

- Fixed terminal tasks hanging on macOS when a spawned process is killed
by a signal.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed The user has signed the Contributor License Agreement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LSPs no longer working (macOS 26 Tahoe)

2 participants