Skip to content

StreamPollFeeder: declare done and exception as volatile - #387

Open
elharo wants to merge 5 commits into
masterfrom
fix/streampollfeeder-volatile
Open

StreamPollFeeder: declare done and exception as volatile#387
elharo wants to merge 5 commits into
masterfrom
fix/streampollfeeder-volatile

Conversation

@elharo

@elharo elharo commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

StreamPollFeeder.done and StreamPollFeeder.exception are accessed from multiple threads without volatile, violating the Java Memory Model.

done (line 40): read in run() outside any synchronized block (line 61), written in waitUntilDone() inside synchronized (lock) (line 107). When the feeder thread is continuously reading data (input.available() > 0), it never enters the synchronized block, so no happens‑before guarantees the write to done is ever seen. The thread loops forever and waitUntilDone()'s join() call hangs.

exception (line 38): written by the run() thread (lines 79, 92) and read from other threads via getException() (line 101). Without volatile, a thread calling getException() may see a stale null. StreamPumper already declares its equivalent field as volatileStreamPollFeeder should follow the same pattern.

Fixes #385
Fixes #386

@elharo
elharo requested a review from kwin July 1, 2026 13:11
@slachiewicz slachiewicz added the bug Something isn't working label Jul 2, 2026
@elharo
elharo requested review from Copilot and slachiewicz July 24, 2026 10:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a Java Memory Model visibility bug in StreamPollFeeder by ensuring cross-thread state (done, exception) is safely published, and adds a regression test that exercises the previously-hanging scenario with continuously-available input.

Changes:

  • Declare StreamPollFeeder.done as volatile to guarantee termination visibility when the feeder loop doesn’t enter the synchronized(lock) block.
  • Declare StreamPollFeeder.exception as volatile so concurrent readers don’t observe a stale null.
  • Add a JUnit regression test that simulates continuously available data and asserts waitUntilDone() completes within a timeout.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/main/java/org/apache/maven/shared/utils/cli/StreamPollFeeder.java Marks done and exception as volatile to fix cross-thread visibility and prevent hangs/stale reads.
src/test/java/org/apache/maven/shared/utils/cli/StreamPollFeederTest.java Adds a timeout-based regression test targeting the continuous-data hang scenario.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/test/java/org/apache/maven/shared/utils/cli/StreamPollFeederTest.java Outdated
elharo and others added 2 commits July 24, 2026 13:11
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

StreamPollFeeder.exception should be volatile StreamPollFeeder.done should be volatile (thread may hang)

3 participants