non-blocking channel Infinite loop in java.util.Scanner
Rémi Forax
forax at univ-mlv.fr
Tue Jun 5 03:00:36 PDT 2012
One of my student find a bug in the implementation of Scanner,
that allows you to use a non blocking channel as input of a Scanner.
The Scanner uses Channels.newReader() to create a Reader
from a channel which itself create a StreamDecoder.
In that case, StreamDecoder.impReader() goes into an infinite loop
because impReader() calls readBytes() that does nothing
if channel.read() returns zero.
The javadoc of Channels.newReader() clearly states that
it should throw a IllegalBlockingModeException but
there is no code that checks that.
I think a way to solve the problem is to insert a code
that check the blocking state in Channels.newWriter().
if (ch instanceof SelectableChannel) {
SelectableChannel sc = (SelectableChannel)ch;
if (!sc.isBlocking())
throw new IllegalBlockingModeException();
}
}
and to document the exception in the constructor of
Scanner that takes a channel.
If someone provide me a bug id, it will provide a patch :)
cheers,
Rémi
PS: The code below is a simple test to reproduce the infinite loop.
----------------------------------------------------
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Scanner;
public class Main {
public static void main(String[] args) throws IOException {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(2332));
new Thread(new Runnable() {
@Override
public void run() {
try {
SocketChannel channel = SocketChannel.open(new
InetSocketAddress("localhost", 2332));
do {
channel.write(ByteBuffer.wrap(new byte[] {'A'}));
Thread.sleep(1000);
} while(true);
} catch (IOException | InterruptedException e) {
throw new AssertionError(e);
}
}
}).start();
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
Scanner scanner = new Scanner(socketChannel);
while(scanner.hasNextLine()) {
System.out.println(scanner.nextLine());
}
}
}
More information about the nio-dev
mailing list