From the terminal, if I run a program (or Cursor runs a terminal command while testing code changes) that seg-faults, I end up with Zombie processes and I’m unable to kill them. It’s like the signal handlers for the child process that died are not being properly handled by the parent processes.
Looking the which processes are still running, I often the failed command + a cursor wrapper of some kind.
Steps to Reproduce
From Cursor Terminal
Run a program that seg-faults from the terminal. The terminal just hangs.
To compare:
2. Run the same program from a standard shell and it’ll segfault with an error.
Hey, thanks for the detailed report. Good repro steps and process info.
This looks like a gap in how the integrated terminal handles child process signals on macOS, specifically around SIGCHLD reaping when a grandchild segfaults inside the pty session.
A couple of quick questions to help us narrow it down:
Which shell are you using in Cursor’s terminal, zsh, bash, or something else?
What kind of program is segfaulting, C/C++ or something else? If you can share a minimal repro, even a trivial C program that does *(int*)0 = 0;, that’d help.
As a workaround for now, you can kill zombie processes from an external terminal with kill -9 <parent_pid> (the shell PID, not the zombie itself). That should clean up the zombie without restarting Cursor.
I’ve flagged this with the team. No ETA yet, but your report helps us prioritize it.
I have Cursor configured with zsh as my terminal shell.
Demo
Save this to a file
#include <stdio.h>
int main() { int *ptr = NULL; // pointer that points to nothing *ptr = 42; // ❌ writing to NULL -> segfault printf("This will never print\n"); return 0; }
Build the file:
cc segfault.c -o segfault
Run this inside the Cursor terminal: ./segfault
Reaping Process Workaround
I’ve tried the workaround to kill the parent process id…
On the workaround: the zombie moving under PID 1 after you kill -9 the parent shell is expected on macOS. A zombie process is already “dead” meaning its code has finished, but the process table entry stays until the parent calls wait(). When you kill the parent, the zombie gets reparented to init PID 1, and it will stay in the table until init reaps it, or until you restart Cursor.
The most reliable workaround right now is to close and reopen Cursor. Not ideal, but it reliably clears all zombies.
The root cause is most likely how node-pty handles SIGCHLD from grandchild processes in a pty session on macOS. No specific timeline yet, but a report with a repro this good definitely helps with prioritization.