Skip to content

8377935: (process) jspawnhelper race can cause hangs in ProcessBuilder - fix for FORK mode#29725

Draft
tstuefe wants to merge 2 commits intoopenjdk:masterfrom
tstuefe:JDK-8377935-process-jspawnhelper-race-can-cause-hangs-in-ProcessBuilder-fix-for-FORK-mode
Draft

8377935: (process) jspawnhelper race can cause hangs in ProcessBuilder - fix for FORK mode#29725
tstuefe wants to merge 2 commits intoopenjdk:masterfrom
tstuefe:JDK-8377935-process-jspawnhelper-race-can-cause-hangs-in-ProcessBuilder-fix-for-FORK-mode

Conversation

@tstuefe
Copy link
Member

@tstuefe tstuefe commented Feb 14, 2026

A customer reported a process-hanging issue (intermittent hangs in ProcessBuilder.start).

*Note: Fixing it for FORK mode is trivial; fixing it for POSIX_SPAWN is very difficult. Therefore, I decided to patch the FORK mode immediately to get backports underway. This issue is a sub-issue of the real problem and addresses only the FORK mode fix. Fixing POSIX_SPAWN will happen in a separate RFE. *


Process A (a JVM) spawns, via ProcessBuilder.start, child process B. To do that, it will create a fail pipe to listen for error messages from the child. Child B:

  • closes read end of pipe
  • sets write end of pipe to O_CLOEXEC
  • execve() the target binary.

Parent A:

  • closes write end of pipe
  • waits on read end.

If child execve succeeds, it will automatically close the write end of the pipe in child B. The parent gets an EOF and knows the child succeeded in doing execve.

If child B execve fails, it sends an error message to the parent via the still-open write end of the pipe.

However, if between the parent creating a pipe and the parent closing the write end of the pipe, some native thread in the parent forks off via a native - not controlled by us - fork() call, that new child process C now also carries a copy of the write end of the pipe. The fail pipe will stay open as long as the second child process C did not end. That, in turn, causes the parent process to hang in forkAndExec() waiting for the fail pipe to go away.

For -Djdk.lang.Process.launchMechanism=FORK, we can provide a complete fix for Linux and xxxBSD (using pipe2), and at least make the error significantly less likely on MacOS and AIX (by using pipe() and setting their file descriptors to CLOEXEC right away).


Progress

  • Change must be properly reviewed (1 review required, with at least 1 Reviewer)
  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue

Issue

  • JDK-8377935: (process) jspawnhelper race can cause hangs in ProcessBuilder - fix for FORK mode (Sub-task - P3)

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/29725/head:pull/29725
$ git checkout pull/29725

Update a local copy of the PR:
$ git checkout pull/29725
$ git pull https://git.openjdk.org/jdk.git pull/29725/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 29725

View PR using the GUI difftool:
$ git pr show -t 29725

Using diff file

Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/29725.diff

@bridgekeeper
Copy link

bridgekeeper bot commented Feb 14, 2026

👋 Welcome back stuefe! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@openjdk
Copy link

openjdk bot commented Feb 14, 2026

❗ This change is not yet ready to be integrated.
See the Progress checklist in the description for automated requirements.

@openjdk openjdk bot changed the title JDK-8377935: (process) jspawnhelper race can cause hangs in ProcessBuilder - fix for FORK mode 8377935: (process) jspawnhelper race can cause hangs in ProcessBuilder - fix for FORK mode Feb 14, 2026
@openjdk openjdk bot added the core-libs core-libs-dev@openjdk.org label Feb 14, 2026
@openjdk
Copy link

openjdk bot commented Feb 14, 2026

@tstuefe The following label will be automatically applied to this pull request:

  • core-libs

When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing list. If you would like to change these labels, use the /label pull request command.

@lukellmann
Copy link

I think there is a hack to unset FD_CLOEXEC for a file descriptor in the process created by posix_spawn():

// process that calls posix_spawn():

int fd = /* from pipe2() */;
int fd2 = fcntl(fd, F_DUPFD_CLOEXEC, 0);

// both fd and fd2 now have FD_CLOEXEC set

posix_spawn_file_actions_t actions;
posix_spawn_file_actions_init(&actions);
posix_spawn_file_actions_adddup2(&actions, fd, fd2);

posix_spawn(/*...*/, &actions, /*...*/);

// process created by posix_spawn() can now use fd2 as FD_CLOEXEC was unset by the dup2 action

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core-libs core-libs-dev@openjdk.org

Development

Successfully merging this pull request may close these issues.

2 participants