Skip to content
This repository was archived by the owner on Aug 27, 2022. It is now read-only.
/ lanai Public archive

Commit 955aee3

Browse files
author
Vyom Tewari
committedJul 17, 2020
8237858: PlainSocketImpl.socketAccept() handles EINTR incorrectly
PlainSocketImpl.socketAccept() handles EINTR incorrectly Reviewed-by: alanb, dfuchs, martin
1 parent a8d6a05 commit 955aee3

File tree

8 files changed

+480
-24
lines changed

8 files changed

+480
-24
lines changed
 

‎make/common/TestFilesCompilation.gmk

+5-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,11 @@ define SetupTestFilesCompilationBody
6262
$1_OUTPUT_SUBDIR := lib
6363
$1_BASE_CFLAGS := $(CFLAGS_JDKLIB)
6464
$1_BASE_CXXFLAGS := $(CXXFLAGS_JDKLIB)
65-
$1_LDFLAGS := $(LDFLAGS_JDKLIB) $$(call SET_SHARED_LIBRARY_ORIGIN)
65+
ifeq ($(call isTargetOs, windows), false)
66+
$1_LDFLAGS := $(LDFLAGS_JDKLIB) $$(call SET_SHARED_LIBRARY_ORIGIN) -pthread
67+
else
68+
$1_LDFLAGS := $(LDFLAGS_JDKLIB) $$(call SET_SHARED_LIBRARY_ORIGIN)
69+
endif
6670
$1_COMPILATION_TYPE := LIBRARY
6771
else ifeq ($$($1_TYPE), PROGRAM)
6872
$1_PREFIX = exe

‎src/java.base/aix/native/libnet/aix_close.c

+10-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved.
33
* Copyright (c) 2016, 2019, SAP SE and/or its affiliates. All rights reserved.
44
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
55
*
@@ -531,12 +531,16 @@ int NET_Timeout(JNIEnv *env, int s, long timeout, jlong nanoTimeStamp) {
531531
* has expired return 0 (indicating timeout expired).
532532
*/
533533
if (rv < 0 && errno == EINTR) {
534-
jlong newNanoTime = JVM_NanoTime(env, 0);
535-
nanoTimeout -= newNanoTime - prevNanoTime;
536-
if (nanoTimeout < NET_NSEC_PER_MSEC) {
537-
return 0;
534+
if (timeout > 0) {
535+
jlong newNanoTime = JVM_NanoTime(env, 0);
536+
nanoTimeout -= newNanoTime - prevNanoTime;
537+
if (nanoTimeout < NET_NSEC_PER_MSEC) {
538+
return 0;
539+
}
540+
prevNanoTime = newNanoTime;
541+
} else {
542+
continue; // timeout is -1, so loop again.
538543
}
539-
prevNanoTime = newNanoTime;
540544
} else {
541545
return rv;
542546
}

‎src/java.base/linux/native/libnet/linux_close.c

+10-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -437,12 +437,16 @@ int NET_Timeout(JNIEnv *env, int s, long timeout, jlong nanoTimeStamp) {
437437
* has expired return 0 (indicating timeout expired).
438438
*/
439439
if (rv < 0 && errno == EINTR) {
440-
jlong newNanoTime = JVM_NanoTime(env, 0);
441-
nanoTimeout -= newNanoTime - prevNanoTime;
442-
if (nanoTimeout < NET_NSEC_PER_MSEC) {
443-
return 0;
440+
if (timeout > 0) {
441+
jlong newNanoTime = JVM_NanoTime(env, 0);
442+
nanoTimeout -= newNanoTime - prevNanoTime;
443+
if (nanoTimeout < NET_NSEC_PER_MSEC) {
444+
return 0;
445+
}
446+
prevNanoTime = newNanoTime;
447+
} else {
448+
continue; // timeout is -1, so loop again.
444449
}
445-
prevNanoTime = newNanoTime;
446450
} else {
447451
return rv;
448452
}

‎src/java.base/macosx/native/libnet/bsd_close.c

+14-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -472,17 +472,20 @@ int NET_Timeout(JNIEnv *env, int s, long timeout, jlong nanoTimeStamp) {
472472
* has expired return 0 (indicating timeout expired).
473473
*/
474474
if (rv < 0 && errno == EINTR) {
475-
jlong newNanoTime = JVM_NanoTime(env, 0);
476-
nanoTimeout -= newNanoTime - prevNanoTime;
477-
if (nanoTimeout < NET_NSEC_PER_MSEC) {
478-
if (allocated != 0)
479-
free(fdsp);
480-
return 0;
475+
if (timeout > 0) {
476+
jlong newNanoTime = JVM_NanoTime(env, 0);
477+
nanoTimeout -= newNanoTime - prevNanoTime;
478+
if (nanoTimeout < NET_NSEC_PER_MSEC) {
479+
if (allocated != 0)
480+
free(fdsp);
481+
return 0;
482+
}
483+
prevNanoTime = newNanoTime;
484+
t.tv_sec = nanoTimeout / NET_NSEC_PER_SEC;
485+
t.tv_usec = (nanoTimeout % NET_NSEC_PER_SEC) / NET_NSEC_PER_USEC;
486+
} else {
487+
continue; // timeout is -1, so loop again.
481488
}
482-
prevNanoTime = newNanoTime;
483-
t.tv_sec = nanoTimeout / NET_NSEC_PER_SEC;
484-
t.tv_usec = (nanoTimeout % NET_NSEC_PER_SEC) / NET_NSEC_PER_USEC;
485-
486489
} else {
487490
if (allocated != 0)
488491
free(fdsp);
+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright (c) 2020, 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+
public class NativeThread {
25+
26+
public static final int SIGPIPE;
27+
28+
static {
29+
SIGPIPE = getSIGPIPE();
30+
}
31+
32+
public static native long getID();
33+
34+
public static native int signal(long threadId, int sig);
35+
36+
private static native int getSIGPIPE();
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
/*
2+
* Copyright (c) 2020, 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 8237858
27+
* @summary PlainSocketImpl.socketAccept() handles EINTR incorrectly
28+
* @requires (os.family != "windows")
29+
* @compile NativeThread.java
30+
* @run main/othervm/native -Djdk.net.usePlainSocketImpl=true SocketAcceptInterruptTest 0
31+
* @run main/othervm/native -Djdk.net.usePlainSocketImpl=true SocketAcceptInterruptTest 5000
32+
* @run main/othervm/native SocketAcceptInterruptTest 0
33+
* @run main/othervm/native SocketAcceptInterruptTest 5000
34+
*/
35+
import java.io.IOException;
36+
import java.io.InputStream;
37+
import java.io.OutputStream;
38+
import java.net.InetAddress;
39+
import java.net.ServerSocket;
40+
import java.net.*;
41+
import java.util.concurrent.Callable;
42+
import java.util.concurrent.ExecutorService;
43+
import java.util.concurrent.Executors;
44+
import java.util.concurrent.Future;
45+
46+
public class SocketAcceptInterruptTest {
47+
48+
public static void main(String[] args) throws Exception {
49+
System.loadLibrary("NativeThread");
50+
InetAddress loopback = InetAddress.getLoopbackAddress();
51+
ExecutorService executor = Executors.newFixedThreadPool(1);
52+
53+
try ( ServerSocket ss = new ServerSocket(0, 50, loopback);) {
54+
Server server = new Server(ss, Integer.parseInt(args[0]));
55+
Future<Result> future = executor.submit(server);
56+
long threadId = server.getID();
57+
58+
sendSignal(threadId, ss);
59+
sleep(100);
60+
// In failing case server socket will be closed, so we do need to check first
61+
if (!ss.isClosed()) {
62+
// After sending SIGPIPE, create client socket and connect to server
63+
try ( Socket s = new Socket(loopback, ss.getLocalPort()); InputStream in = s.getInputStream();) {
64+
in.read(); // reading one byte is enought for test.
65+
}
66+
}
67+
Result result = future.get();
68+
if (result.status == Result.FAIL) {
69+
throw result.exception;
70+
}
71+
} finally {
72+
executor.shutdown();
73+
}
74+
System.out.println("OK!");
75+
}
76+
77+
private static void sendSignal(long threadId, ServerSocket ss) {
78+
System.out.println("Sending SIGPIPE to ServerSocket thread.");
79+
int count = 0;
80+
while (!ss.isClosed() && count++ < 20) {
81+
sleep(10);
82+
if (NativeThread.signal(threadId, NativeThread.SIGPIPE) != 0) {
83+
throw new RuntimeException("Failed to interrupt the server thread.");
84+
}
85+
}
86+
}
87+
88+
private static void sleep(long time) {
89+
try {
90+
Thread.sleep(time);
91+
} catch (InterruptedException e) {
92+
// ignore the exception.
93+
}
94+
}
95+
96+
static class Server implements Callable<Result> {
97+
98+
private volatile long threadId;
99+
private final ServerSocket serverSocket;
100+
private final int timeout;
101+
102+
public Server(ServerSocket ss, int timeout) {
103+
serverSocket = ss;
104+
this.timeout = timeout;
105+
}
106+
107+
@Override
108+
public Result call() {
109+
try {
110+
threadId = NativeThread.getID();
111+
serverSocket.setSoTimeout(timeout);
112+
try ( Socket socket = serverSocket.accept();
113+
OutputStream outputStream = socket.getOutputStream();) {
114+
outputStream.write("Hello!".getBytes());
115+
return new Result(Result.SUCCESS, null);
116+
}
117+
} catch (IOException e) {
118+
close();
119+
return new Result(Result.FAIL, e);
120+
}
121+
}
122+
123+
long getID() {
124+
while (threadId == 0) {
125+
sleep(5);
126+
}
127+
return threadId;
128+
}
129+
130+
private void close() {
131+
if (!serverSocket.isClosed()) {
132+
try {
133+
serverSocket.close();
134+
} catch (IOException ex) {
135+
// ignore the exception
136+
}
137+
}
138+
}
139+
}
140+
141+
static class Result {
142+
143+
static final int SUCCESS = 0;
144+
static final int FAIL = 1;
145+
final int status;
146+
final Exception exception;
147+
148+
public Result(int status, Exception ex) {
149+
this.status = status;
150+
exception = ex;
151+
}
152+
}
153+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
/*
2+
* Copyright (c) 2020, 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 8237858
27+
* @summary PlainSocketImpl.socketAccept() handles EINTR incorrectly
28+
* @requires (os.family != "windows")
29+
* @compile NativeThread.java
30+
* @run main/othervm/native -Djdk.net.usePlainSocketImpl=true SocketReadInterruptTest 2000 3000
31+
* @run main/othervm/native SocketReadInterruptTest 2000 3000
32+
* @run main/othervm/native -Djdk.net.usePlainSocketImpl=true SocketReadInterruptTest 2000 0
33+
* @run main/othervm/native SocketReadInterruptTest 2000 0
34+
*/
35+
import java.io.IOException;
36+
import java.io.InputStream;
37+
import java.io.OutputStream;
38+
import java.net.InetAddress;
39+
import java.net.ServerSocket;
40+
41+
import java.net.*;
42+
import java.util.concurrent.Callable;
43+
import java.util.concurrent.ExecutorService;
44+
import java.util.concurrent.Executors;
45+
import java.util.concurrent.Future;
46+
47+
public class SocketReadInterruptTest {
48+
49+
public static void main(String[] args) throws Exception {
50+
System.loadLibrary("NativeThread");
51+
ExecutorService executor = Executors.newFixedThreadPool(2);
52+
InetAddress loopback = InetAddress.getLoopbackAddress();
53+
54+
try ( ServerSocket ss = new ServerSocket(0, 50, loopback);
55+
Socket s1 = new Socket(loopback, ss.getLocalPort());) {
56+
Server server = new Server(ss, Integer.parseInt(args[0]));
57+
Future<Result> f1 = executor.submit(server);
58+
59+
Client client = new Client(s1, Integer.parseInt(args[1]));
60+
Future<Result> f2 = executor.submit(client);
61+
long threadId = client.getID();
62+
63+
sleep(200);
64+
System.out.println("Sending SIGPIPE to client thread.");
65+
if (NativeThread.signal(threadId, NativeThread.SIGPIPE) != 0) {
66+
throw new RuntimeException("Failed to interrupt the thread.");
67+
}
68+
69+
Result r1 = f1.get();
70+
if (r1.status == Result.FAIL) {
71+
throw r1.exception;
72+
}
73+
74+
Result r2 = f2.get();
75+
if (r2.status == Result.FAIL) {
76+
throw r2.exception;
77+
}
78+
System.out.println("OK!");
79+
} finally {
80+
executor.shutdown();
81+
}
82+
}
83+
84+
private static void sleep(long time) {
85+
try {
86+
Thread.sleep(time);
87+
} catch (InterruptedException e) {
88+
Thread.currentThread().interrupt();
89+
}
90+
}
91+
92+
static class Client implements Callable<Result> {
93+
94+
private volatile long threadId;
95+
private final Socket client;
96+
private final int timeout;
97+
98+
public Client(Socket s, int timeout) {
99+
client = s;
100+
this.timeout = timeout;
101+
}
102+
103+
@Override
104+
public Result call() {
105+
threadId = NativeThread.getID();
106+
byte[] arr = new byte[64];
107+
try ( InputStream in = client.getInputStream();) {
108+
client.setSoTimeout(timeout);
109+
in.read(arr);
110+
return new Result(Result.SUCCESS, null);
111+
} catch (IOException ex) {
112+
close();
113+
return new Result(Result.FAIL, ex);
114+
}
115+
}
116+
117+
long getID() {
118+
while (threadId == 0) {
119+
sleep(5);
120+
}
121+
return threadId;
122+
}
123+
124+
void close() {
125+
if (!client.isClosed()) {
126+
try {
127+
client.close();
128+
} catch (IOException ex) {
129+
// ignore the exception.
130+
}
131+
}
132+
}
133+
}
134+
135+
static class Server implements Callable<Result> {
136+
137+
private final ServerSocket serverSocket;
138+
private final int timeout;
139+
140+
public Server(ServerSocket ss, int timeout) {
141+
serverSocket = ss;
142+
this.timeout = timeout;
143+
}
144+
145+
@Override
146+
public Result call() {
147+
try {
148+
try ( Socket client = serverSocket.accept(); OutputStream outputStream = client.getOutputStream();) {
149+
sleep(timeout);
150+
outputStream.write("This is just a test string.".getBytes());
151+
return new Result(Result.SUCCESS, null);
152+
}
153+
} catch (IOException e) {
154+
close();
155+
return new Result(Result.FAIL, e);
156+
}
157+
}
158+
159+
public void close() {
160+
if (!serverSocket.isClosed()) {
161+
try {
162+
serverSocket.close();
163+
} catch (IOException ex) {
164+
}
165+
}
166+
}
167+
}
168+
169+
static class Result {
170+
171+
static final int SUCCESS = 0;
172+
static final int FAIL = 1;
173+
final int status;
174+
final Exception exception;
175+
176+
public Result(int status, Exception ex) {
177+
this.status = status;
178+
exception = ex;
179+
}
180+
}
181+
}
+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright (c) 2020, 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+
#include<jni.h>
24+
#include<signal.h>
25+
#include<stdlib.h>
26+
#if defined(__linux__) || defined(_ALLBSD_SOURCE) || defined(_AIX)
27+
#include <pthread.h>
28+
#endif
29+
30+
/*
31+
* Class: NativeThread
32+
* Method: getID
33+
* Signature: ()J
34+
*/
35+
JNIEXPORT jlong JNICALL Java_NativeThread_getID(JNIEnv *env, jclass class)
36+
{
37+
#if defined(__linux__) || defined(_ALLBSD_SOURCE) || defined(_AIX)
38+
return (jlong)pthread_self();
39+
#else
40+
return 0;
41+
#endif
42+
}
43+
44+
/*
45+
* Class: NativeThread
46+
* Method: signal
47+
* Signature: (JI)I
48+
*/
49+
JNIEXPORT jint JNICALL Java_NativeThread_signal(JNIEnv *env, jclass class, jlong thread, jint sig)
50+
{
51+
#if defined(__linux__) || defined(_ALLBSD_SOURCE) || defined(_AIX)
52+
return pthread_kill((pthread_t)thread, sig);
53+
#else
54+
return 0;
55+
#endif
56+
}
57+
58+
/*
59+
* Class: NativeThread
60+
* Method: getSIGPIPE
61+
* Signature: ()I
62+
*/
63+
JNIEXPORT jint JNICALL Java_NativeThread_getSIGPIPE(JNIEnv *env, jclass class)
64+
{
65+
#if defined(__linux__) || defined(_ALLBSD_SOURCE) || defined(_AIX)
66+
return SIGPIPE;
67+
#else
68+
return 0;
69+
#endif
70+
}

0 commit comments

Comments
 (0)
This repository has been archived.