-
Bug
-
Resolution: Fixed
-
P3
-
7
-
mantis
-
b132
-
generic
-
generic
-
Verified
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();
}
}
=========
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();
}
}
- relates to
-
JDK-4741471 extraneous synchronization in collection serialization
-
- Closed
-
-
JDK-6927486 Hashtable.writeObject() synchronization risks serialization deadlock
-
- Closed
-
-
JDK-5085747 Java level deadlock in java.util.Vector.writeObject
-
- Closed
-