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