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 package test.java.util.Vector;
36 
37 import java.io.ByteArrayOutputStream;
38 import java.io.IOException;
39 import java.io.ObjectOutputStream;
40 import java.io.PrintWriter;
41 import java.io.Serializable;
42 import java.io.StringWriter;
43 import java.util.ArrayList;
44 import java.util.List;
45 import java.util.Vector;
46 import java.util.concurrent.CyclicBarrier;
47 
48 public class SerializationDeadlock {
main(final String[] args)49     public static void main(final String[] args) throws Exception {
50         // Test for Vector serialization deadlock
51         final Vector<Object> v1 = new Vector<>();
52         final Vector<Object> v2 = new Vector<>();
53         final TestBarrier testStart = new TestBarrier(3);
54 
55         // Populate the vectors so that they refer to each other
56         v1.add(testStart);
57         v1.add(v2);
58         v2.add(testStart);
59         v2.add(v1);
60 
61         final CyclicBarrier testEnd = new CyclicBarrier(3);
62         final TestThread t1 = new TestThread(v1, testEnd);
63         final TestThread t2 = new TestThread(v2, testEnd);
64 
65         t1.start();
66         t2.start();
67 
68         // Wait for both test threads to have initiated serialization
69         // of the 'testStart' object (and hence of both 'v1' and 'v2')
70         testStart.await();
71 
72         // Wait for both test threads to successfully finish serialization
73         // of 'v1' and 'v2'.
74         System.out.println("Waiting for Vector serialization to complete ...");
75         System.out.println("(This test will hang if serialization deadlocks)");
76         testEnd.await();
77         System.out.println("Test PASSED: serialization completed successfully");
78 
79         TestThread.handleExceptions();
80     }
81 
82     static final class TestBarrier extends CyclicBarrier
83             implements Serializable {
TestBarrier(final int count)84         public TestBarrier(final int count) {
85             super(count);
86         }
87 
writeObject(final ObjectOutputStream oos)88         private void writeObject(final ObjectOutputStream oos)
89                 throws IOException {
90             oos.defaultWriteObject();
91             // Wait until all test threads have started serializing data
92             try {
93                 await();
94             } catch (final Exception e) {
95                 throw new IOException("Test ERROR: Unexpected exception caught", e);
96             }
97         }
98     }
99 
100     static final class TestThread extends Thread {
101         private static final List<Exception> exceptions = new ArrayList<>();
102 
103         private final Vector vector;
104         private final CyclicBarrier testEnd;
105 
TestThread(final Vector vector, final CyclicBarrier testEnd)106         public TestThread(final Vector vector, final CyclicBarrier testEnd) {
107             this.vector = vector;
108             this.testEnd = testEnd;
109             setDaemon(true);
110         }
111 
run()112         public void run() {
113             try {
114                 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
115                 final ObjectOutputStream oos = new ObjectOutputStream(baos);
116 
117                 oos.writeObject(vector);
118                 oos.close();
119             } catch (final IOException ioe) {
120                 addException(ioe);
121             } finally {
122                 try {
123                     testEnd.await();
124                 } catch (Exception e) {
125                     addException(e);
126                 }
127             }
128         }
129 
addException(final Exception exception)130         private static synchronized void addException(final Exception exception) {
131             exceptions.add(exception);
132         }
133 
handleExceptions()134         public static synchronized void handleExceptions() {
135             if (false == exceptions.isEmpty()) {
136                 throw new RuntimeException(getErrorText(exceptions));
137             }
138         }
139 
getErrorText(final List<Exception> exceptions)140         private static String getErrorText(final List<Exception> exceptions) {
141             final StringWriter sw = new StringWriter();
142             final PrintWriter pw = new PrintWriter(sw);
143 
144             pw.println("Test ERROR: Unexpected exceptions thrown on test threads:");
145             for (Exception exception : exceptions) {
146                 pw.print("\t");
147                 pw.println(exception);
148                 for (StackTraceElement element : exception.getStackTrace()) {
149                     pw.print("\t\tat ");
150                     pw.println(element);
151                 }
152             }
153 
154             pw.close();
155             return sw.toString();
156         }
157     }
158 }
159 
160