1 /*
2  * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /*
25  * Portions Copyright (c) 2010, 2011 IBM Corporation
26  */
27 
28 /*
29  * @test
30  * @bug 6934356
31  * @summary Serializing Vector objects which refer to each other should not be able to deadlock.
32  * @author Neil Richards <neil.richards@ngmr.net>, <neil_richards@uk.ibm.com>
33  */
34 
35 import java.io.ByteArrayOutputStream;
36 import java.io.IOException;
37 import java.io.ObjectOutputStream;
38 import java.io.PrintWriter;
39 import java.io.Serializable;
40 import java.io.StringWriter;
41 import java.util.ArrayList;
42 import java.util.List;
43 import java.util.Vector;
44 import java.util.concurrent.CyclicBarrier;
45 
46 public class SerializationDeadlock {
main(final String[] args)47     public static void main(final String[] args) throws Exception {
48         // Test for Vector serialization deadlock
49         final Vector<Object> v1 = new Vector<>();
50         final Vector<Object> v2 = new Vector<>();
51         final TestBarrier testStart = new TestBarrier(3);
52 
53         // Populate the vectors so that they refer to each other
54         v1.add(testStart);
55         v1.add(v2);
56         v2.add(testStart);
57         v2.add(v1);
58 
59         final CyclicBarrier testEnd = new CyclicBarrier(3);
60         final TestThread t1 = new TestThread(v1, testEnd);
61         final TestThread t2 = new TestThread(v2, testEnd);
62 
63         t1.start();
64         t2.start();
65 
66         // Wait for both test threads to have initiated serialization
67         // of the 'testStart' object (and hence of both 'v1' and 'v2')
68         testStart.await();
69 
70         // Wait for both test threads to successfully finish serialization
71         // of 'v1' and 'v2'.
72         System.out.println("Waiting for Vector serialization to complete ...");
73         System.out.println("(This test will hang if serialization deadlocks)");
74         testEnd.await();
75         System.out.println("Test PASSED: serialization completed successfully");
76 
77         TestThread.handleExceptions();
78     }
79 
80     static final class TestBarrier extends CyclicBarrier
81             implements Serializable {
TestBarrier(final int count)82         public TestBarrier(final int count) {
83             super(count);
84         }
85 
writeObject(final ObjectOutputStream oos)86         private void writeObject(final ObjectOutputStream oos)
87                 throws IOException {
88             oos.defaultWriteObject();
89             // Wait until all test threads have started serializing data
90             try {
91                 await();
92             } catch (final Exception e) {
93                 throw new IOException("Test ERROR: Unexpected exception caught", e);
94             }
95         }
96     }
97 
98     static final class TestThread extends Thread {
99         private static final List<Exception> exceptions = new ArrayList<>();
100 
101         private final Vector vector;
102         private final CyclicBarrier testEnd;
103 
TestThread(final Vector vector, final CyclicBarrier testEnd)104         public TestThread(final Vector vector, final CyclicBarrier testEnd) {
105             this.vector = vector;
106             this.testEnd = testEnd;
107             setDaemon(true);
108         }
109 
run()110         public void run() {
111             try {
112                 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
113                 final ObjectOutputStream oos = new ObjectOutputStream(baos);
114 
115                 oos.writeObject(vector);
116                 oos.close();
117             } catch (final IOException ioe) {
118                 addException(ioe);
119             } finally {
120                 try {
121                     testEnd.await();
122                 } catch (Exception e) {
123                     addException(e);
124                 }
125             }
126         }
127 
addException(final Exception exception)128         private static synchronized void addException(final Exception exception) {
129             exceptions.add(exception);
130         }
131 
handleExceptions()132         public static synchronized void handleExceptions() {
133             if (false == exceptions.isEmpty()) {
134                 throw new RuntimeException(getErrorText(exceptions));
135             }
136         }
137 
getErrorText(final List<Exception> exceptions)138         private static String getErrorText(final List<Exception> exceptions) {
139             final StringWriter sw = new StringWriter();
140             final PrintWriter pw = new PrintWriter(sw);
141 
142             pw.println("Test ERROR: Unexpected exceptions thrown on test threads:");
143             for (Exception exception : exceptions) {
144                 pw.print("\t");
145                 pw.println(exception);
146                 for (StackTraceElement element : exception.getStackTrace()) {
147                     pw.print("\t\tat ");
148                     pw.println(element);
149                 }
150             }
151 
152             pw.close();
153             return sw.toString();
154         }
155     }
156 }
157 
158