Skip to content

TIKA-4721: Fix TOCTOU race in SharedServerManager port assignment#2791

Merged
nddipiazza merged 2 commits intomainfrom
TIKA-4721-fix-locale-sensitive-tests
Apr 28, 2026
Merged

TIKA-4721: Fix TOCTOU race in SharedServerManager port assignment#2791
nddipiazza merged 2 commits intomainfrom
TIKA-4721-fix-locale-sensitive-tests

Conversation

@nddipiazza
Copy link
Copy Markdown
Contributor

Summary

Fixes the intermittent testGracefulShutdown failure in the main jdk17 windows build (multi-locale) CI job (tr_TR.UTF-8 / de_DE.UTF-8).

The failure was not locale-related despite appearing only in that job. The root cause was a TOCTOU (time-of-check-time-of-use) race in SharedServerManager.startServer():

  1. A ServerSocket was opened to find a free port → then closed
  2. The child process was started and told to bind to that same port
  3. Between step 1 and step 2, another process (or the OS in TIME_WAIT state, which is far more common on slow Windows runners) could grab the port

When this happened, the child process failed to bind, never printed READY:{port}, and the parse on the next iteration returned a non-success result.

Changes

SharedServerManager

  • Remove the TOCTOU port probe (open/close ServerSocket just to learn a port)
  • Pass TIKA_PIPES_PORT=0 to the child process
  • waitForServerReady() now returns the actual port read from the READY:{port} signal and sets serverPort accordingly

PipesServer

  • In runSharedMode(), print READY:{serverSocket.getLocalPort()} instead of READY:{port} so the actual ephemeral port assigned by the OS is reported

Review Focus Areas

  • SharedServerManager.startServer() — TOCTOU removal
  • SharedServerManager.waitForServerReady() — now returns int (actual port)
  • PipesServer.runSharedMode()getLocalPort() instead of port

Critical Files

  • tika-pipes/tika-pipes-core/src/main/java/org/apache/tika/pipes/core/SharedServerManager.java
  • tika-pipes/tika-pipes-core/src/main/java/org/apache/tika/pipes/core/server/PipesServer.java

Testing Instructions

cd tika-pipes/tika-pipes-integration-tests
mvn test -Dtest=SharedServerModeTest#testGracefulShutdown

The existing CI job main jdk17 windows build (multi-locale) should stop failing intermittently once this merges.

Review Checklist

  • No functional behavior change — shared server still starts on a free port, clients connect to the same port
  • Removes a latent race condition that was causing intermittent CI failures
  • No new dependencies or test infrastructure changes needed

Potential Concerns

The READY:{port} stdout protocol is internal — only SharedServerManager reads it. No external consumers are affected by this change.

Closes TIKA-4721

Pass TIKA_PIPES_PORT=0 so the server binds to any available ephemeral
port. PipesServer now reports the actual bound port in its READY:{port}
stdout signal, which SharedServerManager reads and uses directly.

This eliminates the classic probe-close-rebind race where a probed free
port could be grabbed by another process (especially on slow Windows CI
with TIME_WAIT delays) between the probe ServerSocket being closed and
the child process binding to that port.

Root cause of intermittent testGracefulShutdown failures on the Windows
multi-locale CI job (tr_TR.UTF-8 / de_DE.UTF-8 runs).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@nddipiazza nddipiazza requested a review from Copilot April 27, 2026 15:19
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@tballison tballison self-requested a review April 28, 2026 14:59
@tballison
Copy link
Copy Markdown
Contributor

LGTM. May want to add a reasonability check on the port > 0 && < 65535? Otherwise, great catch!

Throw IOException if the server reports a port outside [1, 65535]
to catch any malformed or out-of-range values early.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@nddipiazza nddipiazza merged commit 4e0340b into main Apr 28, 2026
5 checks passed
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.

3 participants