JDK-6934356 : Vector.writeObject() synchronization risks serialization deadlock
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util
  • Affected Version: 7
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2010-03-12
  • Updated: 2011-04-06
  • Resolved: 2011-04-06
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7
7 b132Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Description
Synopsis:
=========
This bug report revisits topics previously discussed in 4741471 and 5085747.
A testcase and suggested code change have been provided by a Licensee.

JDK Versions:
=============

This problem exists since JDK 1.4.2, including JDK 7-b85.


Problem Description from Licensee:
==================================

java.util.Vector.writeObject() currently calls ObjectOutputStream.writeObject(Object)
for the (elementData) Object[] held by the Vector object whilst synchronized on
the Vector object.

If the Object[] in the Vector object holds a reference (directly or indirectly) to
that of another Vector object, which itself holds a (direct or indirect) reference
to the first Vector object in its Object[], then there is a possibility of deadlock
during serialization if two threads try to write out each Vector object simultaneously.

Given that the evaluation text in 4741471 implicitly acknowledges that the
synchronization in Hashtable and Vector risk deadlock, and 5085747 was
closed primarily because a testcase had not been provided (which we have
now done), both the sunbugs referred to confirm our assertion that this is
a bona fide bug.

The risk of deadlock may be avoided by:

1) Moving the synchronization from being on the whole writeObject()
   method to being a synchronized block within the method
2) Copying the elementData Object[] within the synchronized block
3) Using the ObjectOutputStream putFields mechanism to specify that
   the Object[] copy be output as the "elementData" field
4) Making the call to ObjectOutputStream.writeFields() outside (i.e.
   subsequent to) the synchronized block

As the fix is in Java code, it is naturally cross (OS) platform.
It is unconditionally fixed in our (Licensee's) current Java 6 code.
_Whilst fixing the functional problem does introduce some small overhead,
the suggested fix proposed I believe represents the most efficient way
of addressing the problem without side-effects._

The user cannot avoid the problem without introducing coarser grained
locking round the data structures, which would defeat the primary reason
for using Hashtable and Vector over HashMap and ArrayList - namely, their
implicit synchronization.

Therefore, given that the user has chosen to use Hashtable and Vector,
it seems to me correct to take the necessary steps to ensure that they
behave in a functionally correct manner.


Testcase:
=========

Testcase is attached to this bug report.


Suggested fix:
=============

      * is, serialize it).  This method is present merely for synchronization.
      * It just calls the default writeObject method.
      */
-    private synchronized void writeObject(java.io.ObjectOutputStream s)
+    private void writeObject(java.io.ObjectOutputStream s)
         throws java.io.IOException
     {
-	s.defaultWriteObject();
+	final java.io.ObjectOutputStream.PutField fields = s.putFields();
+	Object[] data = null;
+	synchronized (this) {
+	    fields.put("capacityIncrement", capacityIncrement);
+	    fields.put("elementCount", elementCount);
+	    final int dataLength = elementData.length;
+	    data = new Object[dataLength];
+	    System.arraycopy(elementData, 0, data, 0, dataLength);
+	}
+	fields.put("elementData", data);
+	s.writeFields();
     }
 }

Comments
PUBLIC COMMENTS Fix contributed by Neil Richards of IBM UK
2011-02-15

SUGGESTED FIX See webrev provided by Neil Richards of IBM: http://cr.openjdk.java.net/~mduigou/6934356.3/webrev/
2011-01-11

EVALUATION patch provided by IBM
2011-01-11