Name: rmT116609 Date: 08/28/2002
FULL PRODUCT VERSION :
java version "1.4.1-rc"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1-rc-b19)
Java HotSpot(TM) Client VM (build 1.4.1-rc-b19, mixed mode)
FULL OPERATING SYSTEM VERSION : Windows NT Version 4.0 SP 6a
A DESCRIPTION OF THE PROBLEM :
When using a nested ReadableByteChannel and InputStream
combination, FileChannel.transferFrom() doesn't work
correctly. Apparently, a byte buffer used in the transfer
is somehow accessed twice, resulting in a
BufferOverflowException.
The example uses a piped channel but the same problem
occurs e.g. with a SocketChannel / ServerSocketChannel
where the object is being read from a socket and another
program or thread is writing to the corresponding server
socket. Thus it might suggest that the problem is related
to FileChannel.transferFrom(), and/or the private inner
class Channels.ReadableByteChannelImpl.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Compile the provided source code (TransferBug.java)
2. Run it, i.e. java TransferBug
3. Observe the output
EXPECTED VERSUS ACTUAL BEHAVIOR :
Expected: nothing is output, the program runs succesfully
Actual: the program fails with an exception
ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "main" java.nio.BufferOverflowException
at java.nio.DirectByteBuffer.put(DirectByteBuffer.java:298)
at java.nio.channels.Channels$ReadableByteChannelImpl.read
(Channels.java:204)
at sun.nio.ch.FileChannelImpl.transferFromArbitraryChannel
(FileChannelImpl.java:536)
at sun.nio.ch.FileChannelImpl.transferFrom(FileChannelImpl.java:574)
at TransferBug$MyObject.readObject(TransferBug.java:57)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke
(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke
(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at java.io.ObjectStreamClass.invokeReadObject
(ObjectStreamClass.java:824)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1746)
at java.io.ObjectInputStream.readOrdinaryObject
(ObjectInputStream.java:1646)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1274)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:324)
at TransferBug.main(TransferBug.java:98)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.io.Serializable;
import java.io.File;
import java.io.RandomAccessFile;
import java.io.BufferedOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.IOException;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.Pipe;
public class TransferBug
{
private static class MyObject
implements Serializable
{
public MyObject()
throws IOException
{
init();
}
private void init()
throws IOException
{
this.file = new File(++MyObject.fileNumber + ".dat");
this.randomAccessFile = new RandomAccessFile(this.file, "rw");
this.fileChannel = this.randomAccessFile.getChannel();
}
public void setSize(long size)
throws IOException
{
this.randomAccessFile.setLength(size);
}
private void writeObject(ObjectOutputStream out)
throws IOException
{
long size = this.fileChannel.size();
out.writeLong(size);
this.fileChannel.transferTo(0, size, Channels.newChannel(out));
out.defaultWriteObject();
}
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException
{
init();
long size = in.readLong();
setSize(size);
this.fileChannel.transferFrom(Channels.newChannel(in), 0, size);
in.defaultReadObject();
}
private static volatile int fileNumber = 0;
private transient File file;
private transient RandomAccessFile randomAccessFile;
private transient FileChannel fileChannel;
}
public static void main(String[] args)
throws IOException, ClassNotFoundException
{
Pipe pipe = Pipe.open();
Pipe.SourceChannel sourceChannel = pipe.source();
final Pipe.SinkChannel sinkChannel = pipe.sink();
Thread writerThread = new Thread()
{
public void run()
{
try
{
ObjectOutputStream out = new ObjectOutputStream(new
BufferedOutputStream(Channels.newOutputStream(sinkChannel)));
MyObject myObject = new MyObject();
myObject.setSize(10000);
out.writeObject(myObject);
out.flush();
}
catch (IOException ioe)
{
throw new RuntimeException(ioe);
}
}
};
writerThread.start();
ObjectInputStream in = new ObjectInputStream(Channels.newInputStream
(sourceChannel));
MyObject myObject = (MyObject) in.readObject();
}
}
---------- END SOURCE ----------
(Review ID: 163696)
======================================================================