Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4385429

exception chaining facility: serialization of some Exception classes broken

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P2 P2
    • 1.4.0
    • 1.4.0
    • core-libs
    • None
    • beta
    • sparc
    • solaris_2.5
    • Verified

      With the addition of the exception chaining facility, some Exception types
      that supported legacy exception chaining were retrofitted to work with
      the new facility. Some of these exceptions will no longer deserialize.
      In particular, ClassNotFoundException can no longer be serialized and
      deserialized in 1.4 without throwing an IllegalStateException.

      The problem is the readObject method of ClassNotFoundException (and
      other exceptions such as UndeclaredThrowable exception). When a CNFE
      is created, its cause field (in Throwable) will be set to either
      null or some value other than the CNFE itself (i.e., it will have
      an initialized value). When the CNFE is deserialized, the cause field
      will have an initialized value. The readObject method obtains the
      value of the cause by calling getCause. The code assumes that if
      getCause returns null, that the cause field has not been initialized.
      However, if the cause field was initialized (in serializing/deserializing
      between 1.4 implementations it will be initialized), the field may
      be initialized to null. The readObject method next will attempt to
      initialize the cause (which has already been initialized) by calling
      initCause which will throw IllegalStateException because it assumes
      the caller is attempting to overwrite the already initialized value.

      There is no way to distinguish (via getCause) whether the cause is
      validly initialized to null or whether the cause has not yet been
      initialized.

      Here is a program that serializes and deserializes a CNFE and
      throws an IllegalStateException when run with our recent nightly builds:

      import java.io.*;

      public class Bug {

          public static void main(String[] args) {

      try {

      ByteArrayOutputStream bout = new ByteArrayOutputStream();
      ObjectOutputStream out = new ObjectOutputStream(bout);
      out.writeObject(new ClassNotFoundException("test"));
      out.flush();

      ByteArrayInputStream bin =
      new ByteArrayInputStream(bout.toByteArray());
      ObjectInputStream in = new ObjectInputStream(bin);
      Exception cnfe = (ClassNotFoundException) in.readObject();
      System.err.println("test passed");

      } catch (Exception e) {

      System.err.println("test failed: " + e.getMessage());
      e.printStackTrace();
      }
          }
      }

      It produces the following output:

      test failed: Can't overwrite cause
      java.lang.IllegalStateException: Can't overwrite cause
      at java.lang.Throwable.initCause(Throwable.java:305)
      at java.lang.ClassNotFoundException.readObject(ClassNotFoundException.java:115)
      at java.lang.reflect.Method.invoke(Native Method)
      at java.io.ObjectInputStream.invokeObjectReader(ObjectInputStream.java:2213)
      at java.io.ObjectInputStream.inputObject(ObjectInputStream.java:1410)
      at java.io.ObjectInputStream.readObject(ObjectInputStream.java:386)
      at java.io.ObjectInputStream.readObject(ObjectInputStream.java:236)
      at Bug.main(Bug.java:17)


            jjb Josh Bloch
            awollratsunw Ann Wollrath (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: