ADDITIONAL SYSTEM INFORMATION :
openjdk version "25-ea" 2025-09-16
OpenJDK Runtime Environment (build 25-ea+30-3419)
OpenJDK 64-Bit Server VM (build 25-ea+30-3419, mixed mode, sharing)
A DESCRIPTION OF THE PROBLEM :
The documentation of `InputStream::available` states that:
```
* @return an estimate of the number of bytes that can be read (or
* skipped over) from this input stream without blocking or
* {@code 0} when it reaches the end of the input stream.
```
However, in some rare cases `sun.nio.ch.ChannelInputStream` may return -1 if the channel is FileChannelImpl:
```
/**
* Returns an estimate of the number of remaining bytes that can be read
* from this channel without blocking.
*/
public int available() throws IOException {
ensureOpen();
synchronized (positionLock) {
int a = -1;
int ti = -1;
try {
beginBlocking();
ti = threads.add();
if (!isOpen())
return -1; // <---
a = nd.available(fd);
} finally {
threads.remove(ti);
endBlocking(a > -1);
}
return a;
}
}
```
Probably appeared afterJDK-8233451.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached program.
Replace path to a test file, if needed.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The program keeps running.
ACTUAL -
`Violation` is printed in the terminal.
---------- BEGIN SOURCE ----------
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.ConcurrentLinkedQueue;
public class ChannelInputStreamTest {
public static void main(String[] args) throws IOException {
System.out.println(Runtime.version());
var close = new ConcurrentLinkedQueue<InputStream>();
Thread.ofPlatform().start(() -> {
do {
InputStream in;
if ((in = close.poll()) != null)
try {
in.close();
} catch (IOException ignored) {
}
} while (true);
});
var path = Path.of("F:\\file.txt");
Files.createDirectories(path.getParent());
try {
Files.createFile(path);
} catch (FileAlreadyExistsException ignored) {
}
Thread.ofPlatform().start(() -> {
do {
InputStream in;
try {
in = Files.newInputStream(path);
} catch (IOException ignored) {
continue;
}
close.offer(in);
int available;
try {
available = in.available();
} catch (Throwable t) {
continue;
}
if (available < 0) {
System.err.println("Violation");
Runtime.getRuntime().halt(1);
}
} while (true);
});
}
}
---------- END SOURCE ----------
openjdk version "25-ea" 2025-09-16
OpenJDK Runtime Environment (build 25-ea+30-3419)
OpenJDK 64-Bit Server VM (build 25-ea+30-3419, mixed mode, sharing)
A DESCRIPTION OF THE PROBLEM :
The documentation of `InputStream::available` states that:
```
* @return an estimate of the number of bytes that can be read (or
* skipped over) from this input stream without blocking or
* {@code 0} when it reaches the end of the input stream.
```
However, in some rare cases `sun.nio.ch.ChannelInputStream` may return -1 if the channel is FileChannelImpl:
```
/**
* Returns an estimate of the number of remaining bytes that can be read
* from this channel without blocking.
*/
public int available() throws IOException {
ensureOpen();
synchronized (positionLock) {
int a = -1;
int ti = -1;
try {
beginBlocking();
ti = threads.add();
if (!isOpen())
return -1; // <---
a = nd.available(fd);
} finally {
threads.remove(ti);
endBlocking(a > -1);
}
return a;
}
}
```
Probably appeared after
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached program.
Replace path to a test file, if needed.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The program keeps running.
ACTUAL -
`Violation` is printed in the terminal.
---------- BEGIN SOURCE ----------
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.ConcurrentLinkedQueue;
public class ChannelInputStreamTest {
public static void main(String[] args) throws IOException {
System.out.println(Runtime.version());
var close = new ConcurrentLinkedQueue<InputStream>();
Thread.ofPlatform().start(() -> {
do {
InputStream in;
if ((in = close.poll()) != null)
try {
in.close();
} catch (IOException ignored) {
}
} while (true);
});
var path = Path.of("F:\\file.txt");
Files.createDirectories(path.getParent());
try {
Files.createFile(path);
} catch (FileAlreadyExistsException ignored) {
}
Thread.ofPlatform().start(() -> {
do {
InputStream in;
try {
in = Files.newInputStream(path);
} catch (IOException ignored) {
continue;
}
close.offer(in);
int available;
try {
available = in.available();
} catch (Throwable t) {
continue;
}
if (available < 0) {
System.err.println("Violation");
Runtime.getRuntime().halt(1);
}
} while (true);
});
}
}
---------- END SOURCE ----------
- caused by
-
JDK-8233451 (fs) Files.newInputStream() cannot be used with character special files
-
- Resolved
-