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

Deserialization fails for cyclic object graphs, superclassing, and HashSet

      FULL PRODUCT VERSION :
      java version "9.0.4"
      Java(TM) SE Runtime Environment (build 9.0.4+11)
      Java HotSpot(TM) 64-Bit Server VM (build 9.0.4+11, mixed mode)

      ADDITIONAL OS VERSION INFORMATION :
      Linux prod-wgba-005.oslo-no0030.xxx.xxx 3.10.0-693.21.1.el7.x86_64 #1 SMP Wed Mar 7 19:03:37 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

      Microsoft Windows [Version 6.1.76.01]

      EXTRA RELEVANT SYSTEM CONFIGURATION :
      Seems to be independent of operating system.


      A DESCRIPTION OF THE PROBLEM :
      Seems to be similar to the 1.4.2 bug described here
      https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6208166#

      1) Create an object graph (for example object tree) with cyclic dependencies:
      - Node class with an Long field and a hashCode() method depending on this field.
      - A parent reference.
      - A set of children (represented by a HashSet) and a parent reference.
      2)
      - Create some Node instances and chain them together so that they represent a tree (with cyclic dependencies).
      3)
      - Serialize and de-serialize the object graph from 2)

      This works with JDK8 but fails with JDK9.



      REGRESSION. Last worked in version 8u172

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Run the attached code with JDK9.


      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      No output.

      ACTUAL -
      Exception in thread "main" java.lang.RuntimeException: java.lang.NullPointerException
      at wg.crewmanager.scrapbook.ReproduceHashSetSerializationBug.deSerialize(ReproduceHashSetSerializationBug.java:127)
      at wg.crewmanager.scrapbook.ReproduceHashSetSerializationBug.test(ReproduceHashSetSerializationBug.java:89)
      at wg.crewmanager.scrapbook.ReproduceHashSetSerializationBug.main(ReproduceHashSetSerializationBug.java:73)
      Caused by: java.lang.NullPointerException
      at wg.crewmanager.scrapbook.ReproduceHashSetSerializationBug$Superclass.hashCode(ReproduceHashSetSerializationBug.java:38)
      at java.base/java.util.HashMap.hash(HashMap.java:339)
      at java.base/java.util.HashMap.put(HashMap.java:612)
      at java.base/java.util.HashSet.readObject(HashSet.java:342)
      at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.base/java.lang.reflect.Method.invoke(Method.java:564)
      at java.base/java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1160)
      at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2207)
      at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2078)
      at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1585)
      at java.base/java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2346)
      at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2240)
      at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2078)
      at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1585)
      at java.base/java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2346)
      at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2240)
      at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2078)
      at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1585)
      at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:422)
      at java.base/java.util.ArrayList.readObject(ArrayList.java:825)
      at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.base/java.lang.reflect.Method.invoke(Method.java:564)
      at java.base/java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1160)
      at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2207)
      at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2078)
      at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1585)
      at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:422)
      at wg.crewmanager.scrapbook.ReproduceHashSetSerializationBug.deSerialize(ReproduceHashSetSerializationBug.java:123)
      ... 2 more


      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      package wg.crewmanager.scrapbook;

      import java.io.ByteArrayInputStream;
      import java.io.ByteArrayOutputStream;
      import java.io.ObjectInputStream;
      import java.io.ObjectOutputStream;
      import java.io.Serializable;
      import java.util.ArrayList;
      import java.util.HashSet;
      import java.util.List;
      import java.util.Random;
      import java.util.Set;

      /**
       * Test serialization of {@link HashSet}.
       *
       */
      public class ReproduceHashSetSerializationBug
      {

         private static final Random RANDOM = new Random();

         public static class Superclass implements Serializable
         {

            private final Long id;

            public Superclass()
            {
               this.id = RANDOM.nextLong();
            }

            public int hashCode()
            {
               return this.id.hashCode();
            }

            /*
            private void readObject(java.io.ObjectInputStream in)
               throws IOException, ClassNotFoundException
            {
               in.defaultReadObject();
            }
            */

         }


         public static class Node extends Superclass implements Serializable
         {

            private final String name;
            private final Node parent;
            private final Set<Node> children = new HashSet<>();

            public Node(String name, Node parent)
            {
               this.name = name;
               this.parent = parent;
               if (parent != null)
               {
                  parent.children.add(this);
               }
            }

         }

         public static void main(String[] args)
         {
            new ReproduceHashSetSerializationBug().test();
         }

         @SuppressWarnings("unchecked")
         private void test()
         {

            Node a = new Node("a", null);
            Node b = new Node("b", a);

            List<Node> elements = new ArrayList<>();
            elements.add(b);
            elements.add(a);

            byte[] bytes = serialize((Serializable) elements);

            List<Node> deserialized = (List<Node>) deSerialize(bytes);
         }

         /**
          * Serializes the given object into a byte array.
          *
          * @param serializable not null
          * @return a byte array, not null
          */
         private static byte[] serialize(Serializable serializable)
         {
            try
            {
               ByteArrayOutputStream out = new ByteArrayOutputStream();
               ObjectOutputStream objectOutputStream = new ObjectOutputStream(out);
               objectOutputStream.writeObject(serializable);
               return out.toByteArray();
            }
            catch (Exception e)
            {
               throw new RuntimeException(e);
            }
         }

         /**
          * De-serializes the given byte array into an object.
          *
          * @param bytes the byte array to de-serializes, not null
          * @return the de-serialized object
          */
         private static Serializable deSerialize(byte[] bytes)
         {
            try
            {
               return (Serializable) new ObjectInputStream(new ByteArrayInputStream(bytes)).readObject();
            }
            catch (Exception e)
            {
               throw new RuntimeException(e);
            }
         }

      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Explicit readObject in super class (remove comments and run again).

      Not sure why this makes it work.




          Loading...
          Uploaded image for project: 'JDK'
          1. JDK
          2. JDK-8201131

          Deserialization fails for cyclic object graphs, superclassing, and HashSet

              FULL PRODUCT VERSION :
              java version "9.0.4"
              Java(TM) SE Runtime Environment (build 9.0.4+11)
              Java HotSpot(TM) 64-Bit Server VM (build 9.0.4+11, mixed mode)

              ADDITIONAL OS VERSION INFORMATION :
              Linux prod-wgba-005.oslo-no0030.xxx.xxx 3.10.0-693.21.1.el7.x86_64 #1 SMP Wed Mar 7 19:03:37 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

              Microsoft Windows [Version 6.1.76.01]

              EXTRA RELEVANT SYSTEM CONFIGURATION :
              Seems to be independent of operating system.


              A DESCRIPTION OF THE PROBLEM :
              Seems to be similar to the 1.4.2 bug described here
              https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6208166#

              1) Create an object graph (for example object tree) with cyclic dependencies:
              - Node class with an Long field and a hashCode() method depending on this field.
              - A parent reference.
              - A set of children (represented by a HashSet) and a parent reference.
              2)
              - Create some Node instances and chain them together so that they represent a tree (with cyclic dependencies).
              3)
              - Serialize and de-serialize the object graph from 2)

              This works with JDK8 but fails with JDK9.



              REGRESSION. Last worked in version 8u172

              STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
              Run the attached code with JDK9.


              EXPECTED VERSUS ACTUAL BEHAVIOR :
              EXPECTED -
              No output.

              ACTUAL -
              Exception in thread "main" java.lang.RuntimeException: java.lang.NullPointerException
              at wg.crewmanager.scrapbook.ReproduceHashSetSerializationBug.deSerialize(ReproduceHashSetSerializationBug.java:127)
              at wg.crewmanager.scrapbook.ReproduceHashSetSerializationBug.test(ReproduceHashSetSerializationBug.java:89)
              at wg.crewmanager.scrapbook.ReproduceHashSetSerializationBug.main(ReproduceHashSetSerializationBug.java:73)
              Caused by: java.lang.NullPointerException
              at wg.crewmanager.scrapbook.ReproduceHashSetSerializationBug$Superclass.hashCode(ReproduceHashSetSerializationBug.java:38)
              at java.base/java.util.HashMap.hash(HashMap.java:339)
              at java.base/java.util.HashMap.put(HashMap.java:612)
              at java.base/java.util.HashSet.readObject(HashSet.java:342)
              at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
              at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
              at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
              at java.base/java.lang.reflect.Method.invoke(Method.java:564)
              at java.base/java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1160)
              at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2207)
              at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2078)
              at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1585)
              at java.base/java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2346)
              at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2240)
              at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2078)
              at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1585)
              at java.base/java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2346)
              at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2240)
              at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2078)
              at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1585)
              at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:422)
              at java.base/java.util.ArrayList.readObject(ArrayList.java:825)
              at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
              at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
              at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
              at java.base/java.lang.reflect.Method.invoke(Method.java:564)
              at java.base/java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1160)
              at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2207)
              at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2078)
              at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1585)
              at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:422)
              at wg.crewmanager.scrapbook.ReproduceHashSetSerializationBug.deSerialize(ReproduceHashSetSerializationBug.java:123)
              ... 2 more


              REPRODUCIBILITY :
              This bug can be reproduced always.

              ---------- BEGIN SOURCE ----------
              package wg.crewmanager.scrapbook;

              import java.io.ByteArrayInputStream;
              import java.io.ByteArrayOutputStream;
              import java.io.ObjectInputStream;
              import java.io.ObjectOutputStream;
              import java.io.Serializable;
              import java.util.ArrayList;
              import java.util.HashSet;
              import java.util.List;
              import java.util.Random;
              import java.util.Set;

              /**
               * Test serialization of {@link HashSet}.
               *
               */
              public class ReproduceHashSetSerializationBug
              {

                 private static final Random RANDOM = new Random();

                 public static class Superclass implements Serializable
                 {

                    private final Long id;

                    public Superclass()
                    {
                       this.id = RANDOM.nextLong();
                    }

                    public int hashCode()
                    {
                       return this.id.hashCode();
                    }

                    /*
                    private void readObject(java.io.ObjectInputStream in)
                       throws IOException, ClassNotFoundException
                    {
                       in.defaultReadObject();
                    }
                    */

                 }


                 public static class Node extends Superclass implements Serializable
                 {

                    private final String name;
                    private final Node parent;
                    private final Set<Node> children = new HashSet<>();

                    public Node(String name, Node parent)
                    {
                       this.name = name;
                       this.parent = parent;
                       if (parent != null)
                       {
                          parent.children.add(this);
                       }
                    }

                 }

                 public static void main(String[] args)
                 {
                    new ReproduceHashSetSerializationBug().test();
                 }

                 @SuppressWarnings("unchecked")
                 private void test()
                 {

                    Node a = new Node("a", null);
                    Node b = new Node("b", a);

                    List<Node> elements = new ArrayList<>();
                    elements.add(b);
                    elements.add(a);

                    byte[] bytes = serialize((Serializable) elements);

                    List<Node> deserialized = (List<Node>) deSerialize(bytes);
                 }

                 /**
                  * Serializes the given object into a byte array.
                  *
                  * @param serializable not null
                  * @return a byte array, not null
                  */
                 private static byte[] serialize(Serializable serializable)
                 {
                    try
                    {
                       ByteArrayOutputStream out = new ByteArrayOutputStream();
                       ObjectOutputStream objectOutputStream = new ObjectOutputStream(out);
                       objectOutputStream.writeObject(serializable);
                       return out.toByteArray();
                    }
                    catch (Exception e)
                    {
                       throw new RuntimeException(e);
                    }
                 }

                 /**
                  * De-serializes the given byte array into an object.
                  *
                  * @param bytes the byte array to de-serializes, not null
                  * @return the de-serialized object
                  */
                 private static Serializable deSerialize(byte[] bytes)
                 {
                    try
                    {
                       return (Serializable) new ObjectInputStream(new ByteArrayInputStream(bytes)).readObject();
                    }
                    catch (Exception e)
                    {
                       throw new RuntimeException(e);
                    }
                 }

              }

              ---------- END SOURCE ----------

              CUSTOMER SUBMITTED WORKAROUND :
              Explicit readObject in super class (remove comments and run again).

              Not sure why this makes it work.




                    smarks Stuart Marks
                    webbuggrp Webbug Group
                    Votes:
                    0 Vote for this issue
                    Watchers:
                    3 Start watching this issue

                      Created:
                      Updated:

                        smarks Stuart Marks
                        webbuggrp Webbug Group
                        Votes:
                        0 Vote for this issue
                        Watchers:
                        3 Start watching this issue

                          Created:
                          Updated: