Name: nt126004 Date: 07/10/2002
FULL PRODUCT VERSION :
java version "1.4.1-beta"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1-beta-
b14)
Java HotSpot(TM) Client VM (build 1.4.1-beta-b14, mixed mode)
FULL OPERATING SYSTEM VERSION :
Windows 2000 CZ sp2 (Microsoft Windows
2000 [Verze 5.00.2195])
ADDITIONAL OPERATING SYSTEMS :
Linux
A DESCRIPTION OF THE PROBLEM :
OutputStream subclass returned by
java.nio.channels.Channels.newOutputStream() throws
IllegalArgumentException under certain circumstances on perfectly
legal request.
Problem stems from internally cahced instance of
ByteBuffer used to write byte[] into channel. When setting parameters of
ByteBuffer to match that of array fragment passed to be written to
channel, ByteBuffer's position is incorrectly set BEFORE it's limit.
This results in IllegalArgumentException when one part of array at the
beginning of array is written first, then another part of the same array
which starts after the fist part (+1) in the array. Cached ByteBuffer's
limit is set below start of the second fragment, at the end of the first
fragment, which relults in IllegalArgumentException when trying to
call ByteBuffer.position() with offset higher than current
limit.
Fix:
In the implementation of anonymous OutputStream
subclass in Channels.newOutputStream(), following two lines must be
swapped to make it work:
bb.position(off);
bb.limit(Math.min(off + len, bb.capacity()));
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Create any WritableByteChannel
2. Call
java.nio.channels.Channels.newOutputStream() on it to get
OutputStream instance (out)
3. let's say we have an_array =
byte[3]
4. call out.write(an_array,0,1)
5. call
out.write(an_array,2,1) -> IllegalArgumentException
See
attached code for a working example.
EXPECTED VERSUS ACTUAL BEHAVIOR :
Bytes should have been written into channel.
Instead,
IllegalArgumentException is thrown.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
/**
* Test case
to demonstrate bug in Channels.newOutputStream() in JDK 1.4.0/1.4.1beta.
* It will create
file testfile.txt in current directory and try to write chunks of byte array
* to it, using
OutputStream returned by Channels.newOutputStream() .
*
* @author Jan Hlavat?,
<###@###.###>
*/
public class NioBug {
public static void main(String[] args) {
try {
// create test byte buffer and fill it in with data:
byte[] testbuffer = new byte[3];
testbuffer[0]=0x31;
testbuffer[1]=0x32;
testbuffer[2]=0x33;
// create a Channel
FileOutputStream ofs = new FileOutputStream("testfile.txt");
FileChannel fch = ofs.getChannel();
// create an OutputStream from Channel
OutputStream out = Channels.newOutputStream(fch);
//------ important part: ------------------
// write part of array to the output stream, setting limit of cached ByteBuffer instance to 1
out.write(testbuffer,0,1);
try {
// write the same array into output stream again, this time starting beyond limit at offset 2
out.write(testbuffer,2,1);
System.out.println("It works OK");
} catch (IllegalArgumentException e) {
System.out.println("It failed");
// this line gets executed, because cached ByteBuffer's
// limit is 1 and position(2) will throw exception as it should.
}
//----- end of important part -------------
// close OutputStream
out.close();
// close channel
fch.close();
ofs.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
---------- END SOURCE ----------
CUSTOMER WORKAROUND :
Don't use Channels.newOutputStream(), make equivalent but working
replacement
(Review ID: 159141)
======================================================================