Skip to content

[release/0.25] fix: reset inherited signal dispositions for forked processes on macOS - #245

Merged
David Negstad (danegsta) merged 2 commits into
release/0.25from
backport/pr-244-to-release/0.25
Aug 20, 2026
Merged

[release/0.25] fix: reset inherited signal dispositions for forked processes on macOS#245
David Negstad (danegsta) merged 2 commits into
release/0.25from
backport/pr-244-to-release/0.25

Conversation

@danegsta

Copy link
Copy Markdown
Member

Backport of #244 to release/0.25

/cc David Negstad (@danegsta)

Customer Impact

Testing

Risk

Regression?

On macOS, processes started by 'dcp fork-process' inherited the Go
runtime's signal handler flags (SA_SIGINFO|SA_ONSTACK|SA_RESTART).
Other language runtimes do not expect to start with those flags set,
and NativeAOT .NET binaries crash with SIGSEGV the first time they
take a GC suspension via SIGUSR1.

Clearing the dispositions in 'fork-process' before starting the child
does not help, because the Go runtime restores its own dispositions in
the forked child before it reaches execve. The reset has to happen in
the process that calls exec, so 'fork-process' now routes the child
through a hidden 'fork-process-exec' command that clears the
dispositions and then execs the requested program. Since execve keeps
the process ID, the reported PID, session, standard streams, and exit
code all stay the same.

The reset is a no-op on other platforms, where children are started
directly as before.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: fcd61592-fa3e-49ab-8efc-d21136bb147d
Routing the child through the exec shim made every start look successful,
because the process being started became dcp itself, which always exists
and is executable. A program that could not be run was reported as started
and its PID was written to stdout, even though the process exited
immediately. Commands are given absolute paths, which skip the PATH lookup
that used to catch this before the child was started.

The shim now reports the outcome of the exec on an inherited descriptor:
a successful execve closes it, and a failure sends the errno first.
'fork-process' waits for that before reporting the PID, so a program that
cannot be executed is once again a start failure carrying the original
reason.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: fcd61592-fa3e-49ab-8efc-d21136bb147d
@danegsta
David Negstad (danegsta) enabled auto-merge (squash) August 20, 2026 00:25
@danegsta
David Negstad (danegsta) merged commit 8efd260 into release/0.25 Aug 20, 2026
12 of 14 checks passed
@danegsta
David Negstad (danegsta) deleted the backport/pr-244-to-release/0.25 branch August 20, 2026 01:00
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.

2 participants