1 /*
2  * Copyright (c) 2012, 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  * @test
26  * @bug 8003833
27  * @summary Spurious NPE from Socket.getIn/OutputStream
28  */
29 
30 import java.io.IOException;
31 import java.lang.reflect.Constructor;
32 import java.net.ServerSocket;
33 import java.net.Socket;
34 import java.util.concurrent.Phaser;
35 
36 // Racey test, will not always fail, but if it does then there is a problem.
37 
38 public class Streams {
39     static final int NUM_THREADS = 100;
40     static volatile boolean failed;
41     static final Phaser startingGate = new Phaser(NUM_THREADS + 1);
42 
main(String[] args)43     public static void main(String[] args) throws Exception {
44 
45         try (ServerSocket ss = new ServerSocket(0)) {
46             runTest(OutputStreamGetter.class, ss);
47             runTest(InputStreamGetter.class, ss);
48         }
49 
50         if (failed)
51             throw new RuntimeException("Failed, check output");
52     }
53 
runTest(Class<? extends StreamGetter> klass, ServerSocket ss)54     static void runTest(Class<? extends StreamGetter> klass, ServerSocket ss)
55         throws Exception
56     {
57         final int port = ss.getLocalPort();
58         Socket[] sockets = new Socket[NUM_THREADS];
59         for (int i=0; i<NUM_THREADS; i++) {
60             sockets[i] = new Socket("localhost", port);
61             try (Socket socket = ss.accept()) {}
62         }
63 
64         Constructor<? extends StreamGetter> ctr = klass.getConstructor(Socket.class);
65 
66         Thread[] threads = new Thread[NUM_THREADS];
67         for (int i=0; i<NUM_THREADS; i++)
68             threads[i] = ctr.newInstance(sockets[i]);
69         for (int i=0; i<NUM_THREADS; i++)
70             threads[i].start();
71 
72         startingGate.arriveAndAwaitAdvance();
73         for (int i=0; i<NUM_THREADS; i++)
74             sockets[i].close();
75 
76         for (int i=0; i<NUM_THREADS; i++)
77             threads[i].join();
78     }
79 
80     static abstract class StreamGetter extends Thread {
81         final Socket socket;
StreamGetter(Socket s)82         StreamGetter(Socket s) { socket = s; }
83 
84         @Override
run()85         public void run() {
86             try {
87                 startingGate.arriveAndAwaitAdvance();
88                 getStream();
89             } catch (IOException x) {
90                 // OK, socket may be closed
91             } catch (NullPointerException x) {
92                 x.printStackTrace();
93                 failed = true;
94             }
95         }
96 
getStream()97         abstract void getStream() throws IOException;
98     }
99 
100     static class InputStreamGetter extends StreamGetter {
InputStreamGetter(Socket s)101         public InputStreamGetter(Socket s) { super(s); }
getStream()102         void getStream() throws IOException {
103             socket.getInputStream();
104         }
105     }
106 
107     static class OutputStreamGetter extends StreamGetter {
OutputStreamGetter(Socket s)108         public OutputStreamGetter(Socket s) { super(s); }
getStream()109         void getStream() throws IOException {
110             socket.getOutputStream();
111         }
112     }
113 }
114