-
Bug
-
Resolution: Fixed
-
P4
-
1.3.1
-
beta
-
x86
-
windows_2000
Name: bsC130419 Date: 06/28/2001
java version "1.3.1"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.1-b24)
Java HotSpot(TM) Client VM (build 1.3.1-b24, mixed mode)
This bug scenario occurs in jdk1.3.1 but not jdk1.1.7b, jdk1.2, or jdk1.4beta
When an Externalizable object is deserialized by ObjectInputStream.readObject() and the object's readExternal() method generates an EOFException, ObjectInputStream does not generate an EOFException to its caller but instead hangs. The following test program illustrates the bug.
I haven't examined this extensively but I think I can point to the general cause. When ObjectInputStream catches the EOFException for an Externalizable object, it calls skipToEndOfBlockData() as part of a finally clause. This method calls skip(count) until the count goes to zero. In the bug case, count is nonzero even though EOF has been reached. Nothing in skip() allows the count to go to zero in these circumstances.
In fact these lines from ObjectInputStream.read(byte[] b, int off, int len) make matters even worse:
if (len > nread) // read remaining data from stream
nread += in.read(b, off + nread, len - nread);
count -= nread;
return nread;
in.read() returns -1 if EOF occurs, but the next line blindly decrements the count by the return value and so in the error case in fact increments the count.
====== Junk.java ======
import java.io.*;
// A really simple Externalizable class
public class Junk implements Externalizable
{
int i;
public Junk()
{
i = 0;
}
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException {
try {
i = in.readInt();
}
catch (EOFException e) {
System.out.println("readExternal caught EOFException and is rethrowing");
throw e;
}
}
public void writeExternal(ObjectOutput out)
throws IOException {
out.writeInt(i);
}
}
===== test.java =====
import java.io.*;
public class test
{
public static void main(String[] args)
throws Exception
{
Junk obj = new Junk();
// The buffer size must be large enough to contain the
// ClassDescriptor, but too
// small to contain the entire object.
//28 works for this example.
int BUFFER_SIZE = 28;
// Create an EOF in an ObjectInputStream by:
// 1. Serializing the object to file
// 2. Reading only part of the serialized object into a byte array
// 3. Constructing an InputObjectStream on the byte array
try
{
FileOutputStream outfile
= new FileOutputStream("c:\\testFile" );
ObjectOutputStream oos = new ObjectOutputStream(outfile);
oos.writeObject(obj);
oos.flush();
oos.close();
}
catch(IOException e)
{
System.out.println("Exception writing object: " + e);
return;
}
byte[] buf = new byte[BUFFER_SIZE];
try {
FileInputStream f = new FileInputStream("c:\\testFile");
f.read(buf);
ByteArrayInputStream infile = new ByteArrayInputStream(buf);
ObjectInputStream ois = new ObjectInputStream(infile);
System.out.println("Reading object ...");
obj = (Junk) ois.readObject();
System.out.println("Done reading object");
ois.close();
}
catch (Exception e) {
System.out.println("Exception reading object: " + e);
return;
}
System.out.println("Successfully read the object");
}
}
(Review ID: 127581)
======================================================================