Skip to content

[java] Track PipedInputStream and PipedOutputStream as resources - #2290

Merged
dulmarod merged 1 commit into
meta:mainfrom
tanvir-ux:fix/pulse-piped-streams
Oct 30, 2026
Merged

dulmarod merged 1 commit into
meta:mainfrom
tanvir-ux:fix/pulse-piped-streams

Conversation

@tanvir-ux

Copy link
Copy Markdown
Contributor

Summary

PipedInputStream and PipedOutputStream are Closeable, but their constructors were not modeled, so Pulse never tracked them as resources. A pipe end that is only closed on the normal path was not reported when a read or write throws. The existing tests FN_pipedInputStreamNotClosedAfterReadBad and FN_pipedOutputStreamNotClosedAfterWriteBad in ResourceLeaks.java show this.

  • Model the <init> of both classes with Resource.allocate ~exn_class_name:"java.io.IOException", since the constructors that connect to the other end of the pipe may throw IOException (same pattern as Socket/ServerSocket).
  • read, write, flush and close already go through the existing InputStream, OutputStream and Closeable models, so nothing else is needed.

Tests

  • FN_pipedInputStreamNotClosedAfterReadBad and FN_pipedOutputStreamNotClosedAfterWriteBad are renamed without the FN_ prefix and are now reported.
  • pipedInputStreamClosedOk and pipedOutputStreamClosedOk closed the stream in finally without a null check. With the constructor able to throw, Pulse correctly flags that as a null dereference, so I added if (... != null) before close(), as the FileInputStream tests already do. They stay clean.

Test plan

  • Before (main @ 333eda4): neither piped-stream test is reported
  • After: PULSE_RESOURCE_LEAK for both, allocated by the PipedInputStream() / PipedOutputStream() constructors; the Ok cases stay clean
  • make direct_java_pulse_test: the only issues.exp changes are those 2 lines. (Locally I still get the unrelated lambda-name differences in InvokeDynamic/TransitiveAccess that also show up on main with my javac; not committed.)
  • ocamlformat 0.29.0 reports no changes for PulseModelsJava.ml

PipedInputStream and PipedOutputStream are Closeable, but their
constructors were not modeled, so Pulse never tracked them. A pipe end
that is only closed on the normal path was therefore not reported when
a read or write throws (FN_pipedInputStreamNotClosedAfterReadBad and
FN_pipedOutputStreamNotClosedAfterWriteBad).

Model their constructors as resource allocations that may throw
IOException, as connecting to the other end of the pipe can. Reads,
writes and close already go through the InputStream, OutputStream and
Closeable models.
@meta-cla meta-cla Bot added the CLA Signed label Oct 30, 2026
@dulmarod
dulmarod merged commit a8f5b17 into meta:main Oct 30, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants