Skip to content

Fix/native proc exec bugs#43

Merged
guillerodriguez merged 2 commits into
masterfrom
fix/native-proc-exec-bugs
Jul 11, 2026
Merged

Fix/native proc exec bugs#43
guillerodriguez merged 2 commits into
masterfrom
fix/native-proc-exec-bugs

Conversation

@guillerodriguez

Copy link
Copy Markdown
Contributor

No description provided.

When the child of cpproc_forkAndExec fails to chdir or exec, the
failure is never reported to the parent: the child simply calls
abort(). Running a non-existing binary appears to succeed, and
the failure is only observable as a SIGABRT exit code (-6) from
Process.waitFor(), instead of an IOException thrown from
Runtime.exec() or ProcessBuilder.start().

Fix this with an extra pipe (FD_CLOEXEC) between child and parent:
if chdir or exec fails, the child writes its errno to the pipe and
exits; on success the exec itself closes the pipe. The parent blocks
reading the pipe: EOF means success, otherwise it reaps the failed
child and returns the child's errno, which surfaces as an
IOException.

Also initialize the output fds so that the caller never sees stale
values in them if the spawn fails, or in the unused stderr entry
when redirection is requested.

Fixes #41 (BZ#111585)

Signed-off-by: Guillermo Rodríguez <grodriguez@ingelabs.com>
When cpproc_forkAndExec receives a non-NULL environment array (which
is always the case for ProcessBuilder), the PATH is not searched.
This happens because cpproc_forkAndExec internally uses execve when
a non-NULL environment is passed, and execvp otherwise.

What we'd want here is execvpe, but this is not POSIX; it is a GNU
extension introduced in glibc 2.11.

(Additionally, POSIX does not list execvp as async-signal-safe, so
it shouldn't be used after fork() in a multi-threaded process. For
a precedent, see [1].)

Fix this by implementing an execvpe replacement which emulates its
behaviour (pass environment if one is supplied, search parent's PATH,
fallback to running via /bin/sh if execv/execve fails with ENOEXEC).
Error handling follows execvp semantics: an empty command name fails
with ENOENT, broken PATH entries are skipped, and EACCES is sticky.

Both the null and non-null environment cases now go through the same
implementation, so both spawn paths behave identically.

[1] https://git.kernel.org/pub/scm/git/git.git/commit/?id=e3a434468f
    ("run-command: use the async-signal-safe execv instead of execvp")

Fixes #42 (BZ#111586)

Signed-off-by: Guillermo Rodríguez <grodriguez@ingelabs.com>
@guillerodriguez guillerodriguez requested a review from phvega July 8, 2026 17:14
@guillerodriguez guillerodriguez merged commit fc6a680 into master Jul 11, 2026
5 checks passed
@guillerodriguez guillerodriguez deleted the fix/native-proc-exec-bugs branch July 13, 2026 08:07
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