Skip to content

Commit d76e6ea

Browse files
Andrei PanginPaul Hohensee
Andrei Pangin
authored and
Paul Hohensee
committed
8237858: PlainSocketImpl.socketAccept() handles EINTR incorrectly
PlainSocketImpl.socketAccept() handles EINTR incorrectly Reviewed-by: phh Backport-of: 955aee3
1 parent b77c161 commit d76e6ea

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+
}

0 commit comments

Comments
 (0)