undefect. CWE-407 — 63 sites patched across 27 ecosystems

Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
This commit is contained in:
russell@unturf.com 2026-03-26 17:11:57 -04:00
commit 0a580b313d
70422 changed files with 17213626 additions and 0 deletions

View file

@ -0,0 +1,145 @@
/*
* Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* author Edward Wang
*
* @test
* @bug 6368984
* @key intermittent
* @summary Configuring unconnected Socket before passing to implAccept
* can cause fd leak.
* This test may fail intermittently if foreign processes will
* try to establish connection to the test server socket.
* @requires os.family != "windows"
* @requires vm.flagless
* @library /test/lib
* @build jdk.test.lib.Utils
* jdk.test.lib.Asserts
* jdk.test.lib.JDKToolFinder
* jdk.test.lib.JDKToolLauncher
* jdk.test.lib.Platform
* jdk.test.lib.process.*
* AcceptCauseFileDescriptorLeak
* @run main/othervm AcceptCauseFileDescriptorLeak root
*/
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;
import jdk.test.lib.JDKToolFinder;
import jdk.test.lib.process.OutputAnalyzer;
public class AcceptCauseFileDescriptorLeak {
private static final int REPS = 2048;
private static final int THRESHOLD = 1024;
public static void main(String[] args) throws Exception {
if (args.length != 0) {
OutputAnalyzer analyzer = execCmd("ulimit -n -H");
String output = analyzer.getOutput();
if (output == null || output.length() == 0) {
throw new RuntimeException("\"ulimit -n -H\" output nothing"
+ " and its exit code is " + analyzer.getExitValue());
} else {
output = output.trim();
// Set max open file descriptors to 1024
// if it is unlimited or greater than 1024,
// otherwise just do test directly
if ("unlimited".equals(output)
|| Integer.valueOf(output) > THRESHOLD) {
analyzer = execCmd("ulimit -n " + THRESHOLD + "; "
+ composeJavaTestStr());
System.out.println("Output: ["
+ analyzer.getOutput() + "]");
int rc = analyzer.getExitValue();
if (rc != 0) {
throw new RuntimeException(
"Unexpected exit code: " + rc);
}
return;
}
}
}
final ServerSocket ss = new ServerSocket() {
public Socket accept() throws IOException {
Socket s = new Socket() {
};
s.setSoTimeout(10000);
implAccept(s);
return s;
}
};
ss.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
Thread t = new Thread(new Runnable() {
public void run() {
int repsCompleted = 0;
try {
for (; repsCompleted < REPS; repsCompleted++) {
(new Socket(InetAddress.getLoopbackAddress(), ss.getLocalPort())).close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
System.out.println("Client iterations completed:" + repsCompleted);
}
}
});
t.start();
int repsCompleted = 0;
try {
for (; repsCompleted < REPS; repsCompleted++) {
ss.accept().close();
}
} finally {
System.out.println("Server iterations completed:" + repsCompleted);
ss.close();
}
t.join();
}
/**
* Execute command with shell
*
* @param command
* @return OutputAnalyzer
* @throws IOException
*/
static OutputAnalyzer execCmd(String command) throws IOException {
List<String> cmd = List.of("sh", "-c", command);
System.out.println("Executing: " + cmd);
ProcessBuilder pb = new ProcessBuilder(cmd);
return new OutputAnalyzer(pb.start());
}
static String composeJavaTestStr() {
return JDKToolFinder.getTestJDKTool("java") + " "
+ AcceptCauseFileDescriptorLeak.class.getName();
}
}

View file

@ -0,0 +1,158 @@
/*
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8067105
* @library /test/lib
* @summary Socket returned by ServerSocket.accept() is inherited by child process on Windows
* @author Chris Hegarty
*/
import java.io.*;
import java.net.*;
import java.nio.channels.ServerSocketChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import jdk.test.lib.net.IPSupport;
import jdk.test.lib.process.ProcessTools;
public class AcceptInheritHandle {
enum ServerSocketProducer {
JAVA_NET(() -> {
try {
return new ServerSocket();
} catch(IOException x) {
throw new UncheckedIOException(x);
}
}),
NIO_CHANNELS(() -> {
try {
return ServerSocketChannel.open().socket();
} catch (IOException x) {
throw new UncheckedIOException(x);
}
});
final Supplier<ServerSocket> supplier;
ServerSocketProducer(Supplier<ServerSocket> supplier) {
this.supplier = supplier;
}
Supplier<ServerSocket> supplier () { return supplier; }
}
static final String JAVA = System.getProperty("java.home")
+ File.separator + "bin" + File.separator + "java";
static final String CLASSPATH = System.getProperty("java.class.path");
public static void main(String[] args) throws Exception {
if (args.length == 1)
server(ServerSocketProducer.valueOf(args[0]));
else
mainEntry();
}
static void mainEntry() throws Exception {
testJavaNetServerSocket();
testNioServerSocketChannel();
}
static void testJavaNetServerSocket() throws Exception {
test(ServerSocketProducer.JAVA_NET);
if (IPSupport.hasIPv4()) {
test(ServerSocketProducer.JAVA_NET, "-Djava.net.preferIPv4Stack=true");
}
}
static void testNioServerSocketChannel() throws Exception {
test(ServerSocketProducer.NIO_CHANNELS);
}
static void test(ServerSocketProducer ssp, String... jvmArgs) throws Exception {
System.out.println("\nStarting test for " + ssp.name());
List<String> commands = new ArrayList<>();
Collections.addAll(commands, jvmArgs);
commands.add("AcceptInheritHandle");
commands.add(ssp.name());
System.out.println("Executing: "+ commands);
ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(commands);
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
Process serverProcess = pb.start();
DataInputStream dis = new DataInputStream(serverProcess.getInputStream());
int port = dis.readInt();
System.out.println("Server process listening on " + port + ", connecting...");
String address;
if (Arrays.stream(jvmArgs).anyMatch("-Djava.net.preferIPv4Stack=true"::equals)) {
address = "127.0.0.1";
} else {
InetAddress loopback = InetAddress.getLoopbackAddress();
address = loopback.getHostAddress();
}
Socket socket = new Socket(address, port);
String s = dis.readUTF();
System.out.println("Server process said " + s);
serverProcess.destroy();
serverProcess.waitFor(30, TimeUnit.SECONDS);
System.out.println("serverProcess exitCode:" + serverProcess.exitValue());
try {
socket.setSoTimeout(10 * 1000);
socket.getInputStream().read();
} catch (SocketTimeoutException x) {
// failed
throw new RuntimeException("Failed: should get reset, not " + x);
} catch (SocketException x) {
System.out.println("Expected:" + x);
}
}
static void server(ServerSocketProducer producer) throws Exception {
try (ServerSocket ss = producer.supplier().get()) {
InetAddress loopback = InetAddress.getLoopbackAddress();
ss.bind(new InetSocketAddress(loopback, 0));
int port = ss.getLocalPort();
DataOutputStream dos = new DataOutputStream(System.out);
dos.writeInt(port);
dos.flush();
ss.accept(); // do not close
Runtime.getRuntime().exec("sleep 20");
Thread.sleep(3 * 1000);
dos.writeUTF("kill me!");
dos.flush();
Thread.sleep(30 * 1000);
}
}
}

View file

@ -0,0 +1,75 @@
/*
* Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8035897
* @summary FD_SETSIZE should be set on macosx
* @requires os.family == "mac"
* @run main/othervm AnotherSelectFdsLimit 1023
* @run main/othervm AnotherSelectFdsLimit 1024
* @run main/othervm AnotherSelectFdsLimit 1025
* @run main/othervm AnotherSelectFdsLimit 1600
*/
import java.io.IOException;
import java.net.ServerSocket;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.List;
public class AnotherSelectFdsLimit {
static final int DEFAULT_FDS_TO_USE = 1600;
public static void main(String [] args) throws Exception {
int fdsToUse = DEFAULT_FDS_TO_USE;
if (args.length == 1)
fdsToUse = Integer.parseInt(args[0]);
System.out.println("Using " + fdsToUse + " fds.");
List<Thread> threads = new ArrayList<>();
for (int i=0; i<fdsToUse; i++)
threads.add(new WorkerThread());
for (Thread t : threads)
t.start();
for (Thread t : threads)
t.join();
}
static class WorkerThread extends Thread {
public void run() {
try (ServerSocket ss = new ServerSocket(0)) {
ss.setSoTimeout(2000);
ss.accept();
} catch (SocketTimeoutException x) {
// expected
} catch (IOException x) {
throw new java.io.UncheckedIOException(x);
}
}
}
}

View file

@ -0,0 +1,123 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.SocketException;
import java.net.StandardSocketOptions;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
import static org.junit.jupiter.api.Assertions.assertTrue;
/*
* @test
* @summary verifies that the APIs on java.net.ServerSocket throw expected exceptions
* when invoked on a closed ServerSocket
* @run junit ClosedServerSocketTest
*/
public class ClosedServerSocketTest {
private static final InetAddress loopback = InetAddress.getLoopbackAddress();
private static final InetSocketAddress loopbackEphemeral = new InetSocketAddress(loopback, 0);
/**
* Verifies that various operations that specify to throw an IOException on a
* closed ServerSocket, do indeed throw it.
*/
@Test
public void testIOExceptionThrown() throws Exception {
try (final ServerSocket ss = new ServerSocket()) {
// close and then invoke the operations on the ServerSocket
ss.close();
assertTrue(ss.isClosed(), "ServerSocket isn't closed");
assertThrows(IOException.class,
ss::accept,
"accept() when already closed didn't throw IOException");
assertThrows(IOException.class,
() -> ss.bind(loopbackEphemeral),
"bind() when already closed didn't throw IOException");
assertThrows(IOException.class,
() -> ss.bind(loopbackEphemeral, 10),
"bind(SocketAddress, int) when already closed didn't throw IOException");
assertThrows(IOException.class,
() -> ss.getOption(StandardSocketOptions.SO_RCVBUF),
"getOption() when already closed didn't throw IOException");
assertThrows(IOException.class,
ss::getSoTimeout,
"getSoTimeout() when already closed didn't throw IOException");
assertThrows(IOException.class,
() -> ss.setOption(StandardSocketOptions.SO_RCVBUF, 1024),
"setOption() when already closed didn't throw IOException");
}
}
/**
* Verifies that various operations that specify to throw a SocketOperation on a
* closed ServerSocket, do indeed throw it.
*/
@Test
public void testSocketExceptionThrown() throws Exception {
try (final ServerSocket ss = new ServerSocket()) {
// close and then invoke the operations on the ServerSocket
ss.close();
assertTrue(ss.isClosed(), "ServerSocket isn't closed");
assertThrowsExactly(SocketException.class,
ss::getReceiveBufferSize,
"getReceiveBufferSize() when already closed didn't throw SocketException");
assertThrowsExactly(SocketException.class,
ss::getReuseAddress,
"getReuseAddress() when already closed didn't throw SocketException");
assertThrowsExactly(SocketException.class,
() -> ss.setReceiveBufferSize(1024),
"setReceiveBufferSize() when already closed didn't throw SocketException");
assertThrowsExactly(SocketException.class,
() -> ss.setReuseAddress(false),
"setReuseAddress() when already closed didn't throw SocketException");
assertThrowsExactly(SocketException.class,
() -> ss.setSoTimeout(1000),
"setSoTimeout() when already closed didn't throw SocketException");
}
}
/**
* Verifies that various operations that aren't expected to throw an exception on a
* closed ServerSocket, complete normally.
*/
@Test
public void testNoExceptionThrown() throws Exception {
try (final ServerSocket ss = new ServerSocket()) {
// close and then invoke the operations on the ServerSocket
ss.close();
assertTrue(ss.isClosed(), "ServerSocket isn't closed");
ss.getInetAddress();
ss.getLocalPort();
ss.getLocalSocketAddress();
ss.isBound();
ss.supportedOptions();
}
}
}

View file

@ -0,0 +1,293 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8278326
* @modules java.base/java.net:+open
* @run junit ImplAccept
* @summary Test ServerSocket.implAccept with a Socket in different states.
*/
import java.io.FileDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketImpl;
import java.net.SocketOption;
import java.net.StandardSocketOptions;
import java.io.IOException;
import org.junit.*;
import static org.junit.jupiter.api.Assertions.*;
public class ImplAccept {
/**
* Test ServerSocket.implAccept with an unbound Socket.
*/
@Test
public void testUnbound() throws Exception {
try (Socket socket = new Socket()) {
// Socket.impl -> DelegatingSocketImpl
SocketImpl si = getSocketImpl(socket);
assertTrue(isDelegatingSocketImpl(si));
try (ServerSocket ss = serverSocketToAccept(socket);
Socket peer = new Socket(ss.getInetAddress(), ss.getLocalPort())) {
Socket s = ss.accept();
assertTrue(s == socket);
// Socket.impl should be replaced with a new PlatformSocketImpl
SocketImpl psi = getSocketImpl(socket);
assertTrue(isPlatformSocketImpl(psi));
// socket and peer should be connected to each other
pingPong(socket, peer);
}
}
}
/**
* Test ServerSocket.implAccept with a bound Socket. The usage is nonsensical
* but we can test that the accepted Socket is connected and the underlying
* socket from the original SocketImpl is closed.
*/
@Test
public void testBound() throws Exception {
try (Socket socket = new Socket()) {
// Socket.impl -> DelegatingSocketImpl -> PlatformSocketImpl
SocketImpl si = getSocketImpl(socket);
SocketImpl psi1 = getDelegate(si);
assertTrue(isPlatformSocketImpl(psi1));
// bind to local address
socket.bind(loopbackSocketAddress());
assertTrue(isSocketOpen(psi1));
try (ServerSocket ss = serverSocketToAccept(socket);
Socket peer = new Socket(ss.getInetAddress(), ss.getLocalPort())) {
Socket s = ss.accept();
assertTrue(s == socket);
// Socket.impl should be replaced with a new PlatformSocketImpl
SocketImpl psi2 = getSocketImpl(socket);
assertTrue(isPlatformSocketImpl(psi2));
// psi1 should be closed
assertFalse(isSocketOpen(psi1));
// socket and peer should be connected to each other
pingPong(socket, peer);
}
}
}
/**
* Test ServerSocket.implAccept with a connected Socket. The usage is nonsensical
* but we can test that the accepted Socket is connected and the underlying
* socket from the original SocketImpl is closed.
*/
@Test
public void testConnected() throws Exception {
Socket socket;
Socket peer1;
try (ServerSocket ss = new ServerSocket()) {
ss.bind(loopbackSocketAddress());
socket = new Socket(ss.getInetAddress(), ss.getLocalPort());
peer1 = ss.accept();
}
try {
// Socket.impl -> DelegatingSocketImpl -> PlatformSocketImpl
SocketImpl si = getSocketImpl(socket);
SocketImpl psi1 = getDelegate(si);
assertTrue(isPlatformSocketImpl(psi1));
try (ServerSocket ss = serverSocketToAccept(socket);
Socket peer2 = new Socket(ss.getInetAddress(), ss.getLocalPort())) {
Socket s = ss.accept();
assertTrue(s == socket);
// Socket.impl should be replaced with a new PlatformSocketImpl
SocketImpl psi2 = getSocketImpl(socket);
assertTrue(isPlatformSocketImpl(psi2));
// psi1 should be closed and peer1 should read EOF
assertFalse(isSocketOpen(psi1));
assertTrue(peer1.getInputStream().read() == -1);
// socket and peer2 should be connected to each other
pingPong(socket, peer2);
}
} finally {
socket.close();
peer1.close();
}
}
/**
* Test ServerSocket.implAccept with a closed Socket. The usage is nonsensical
* but we can test ServerSocket.accept throws and that it closes the connection
* to the peer.
*/
@Test
public void testClosed() throws Exception {
Socket socket = new Socket();
socket.close();
try (ServerSocket ss = serverSocketToAccept(socket);
Socket peer = new Socket(ss.getInetAddress(), ss.getLocalPort())) {
SocketImpl si = getSocketImpl(socket);
// accept should throw and peer should read EOF
assertThrows(IOException.class, ss::accept);
assertTrue(peer.getInputStream().read() == -1);
// the SocketImpl should have not changed
assertTrue(getSocketImpl(socket) == si);
}
}
/**
* Returns the socket's SocketImpl.
*/
private static SocketImpl getSocketImpl(Socket s) {
try {
Field f = Socket.class.getDeclaredField("impl");
f.setAccessible(true);
return (SocketImpl) f.get(s);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Returns the SocketImpl that the given SocketImpl delegates to.
*/
private static SocketImpl getDelegate(SocketImpl si) {
try {
Class<?> clazz = Class.forName("java.net.DelegatingSocketImpl");
Field f = clazz.getDeclaredField("delegate");
f.setAccessible(true);
return (SocketImpl) f.get(si);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Returns true if the SocketImpl is a DelegatingSocketImpl.
*/
private static boolean isDelegatingSocketImpl(SocketImpl si) {
try {
Class<?> clazz = Class.forName("java.net.DelegatingSocketImpl");
return clazz.isInstance(si);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Returns true if the SocketImpl is a PlatformSocketImpl.
*/
private static boolean isPlatformSocketImpl(SocketImpl si) {
try {
Class<?> clazz = Class.forName("sun.net.PlatformSocketImpl");
return clazz.isInstance(si);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Returns true if the SocketImpl has an open socket.
*/
private static boolean isSocketOpen(SocketImpl si) throws Exception {
assertTrue(isPlatformSocketImpl(si));
// check if SocketImpl.fd is set
Field f = SocketImpl.class.getDeclaredField("fd");
f.setAccessible(true);
FileDescriptor fd = (FileDescriptor) f.get(si);
if (fd == null) {
return false; // not created
}
// call getOption to get the value of the SO_REUSEADDR socket option
Method m = SocketImpl.class.getDeclaredMethod("getOption", SocketOption.class);
m.setAccessible(true);
try {
m.invoke(si, StandardSocketOptions.SO_REUSEADDR);
return true; // socket is open
} catch (InvocationTargetException e) {
if (e.getCause() instanceof IOException) {
return false; // assume socket is closed
}
throw e;
}
}
/**
* Test that two sockets are connected to each other.
*/
private static void pingPong(Socket s1, Socket s2) throws Exception {
s1.getOutputStream().write(11);
s2.getOutputStream().write(22);
assertTrue(s1.getInputStream().read() == 22);
assertTrue(s2.getInputStream().read() == 11);
}
/**
* Creates a ServerSocket that returns the given Socket from accept.
*/
private static ServerSocket serverSocketToAccept(Socket s) throws IOException {
ServerSocket ss = new ServerSocket() {
@Override
public Socket accept() throws IOException {
implAccept(s);
return s;
}
};
ss.bind(loopbackSocketAddress());
return ss;
}
/**
* Returns a new InetSocketAddress with the loopback interface and port 0.
*/
private static InetSocketAddress loopbackSocketAddress() {
InetAddress loopback = InetAddress.getLoopbackAddress();
return new InetSocketAddress(loopback, 0);
}
}

View file

@ -0,0 +1,81 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 8278339
* @summary Test that ServerSocket::isClosed returns true after async close
*/
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class IsClosedAfterAsyncClose {
private static final int ITERATIONS = 100;
public static void main(String[] args) throws Exception {
for (int i = 0; i < ITERATIONS; i++) {
System.out.printf("Test %d...%n", i);
// create listener bound to the loopback address
ServerSocket listener = new ServerSocket();
InetAddress loopback = InetAddress.getLoopbackAddress();
listener.bind(new InetSocketAddress(loopback, 0));
// task to close listener after a delay
Runnable closeListener = () -> {
try {
Thread.sleep(100);
listener.close();
} catch (Exception e) {
e.printStackTrace();
}
};
// main thread blocks in accept. When listener is closed then accept
// should wakeup with an IOException and isClosed should be true.
try (listener) {
Thread closer = new Thread(closeListener);
closer.start();
try {
while (true) {
Socket s = listener.accept();
// close spurious connection
s.close();
}
} catch (IOException ioe) {
if (!listener.isClosed()) {
throw new RuntimeException("isClosed returned false!!");
}
} finally {
closer.join();
}
}
}
}
}

View file

@ -0,0 +1,110 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.ServerSocketChannel;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
/*
* @test
* @bug 8330940
* @summary verify that java.net.ServerSocket and the server socket channels in java.nio.channels
* when configured with a backlog of >=200 on Windows, will allow for those many
* backlogged Socket connections
* @requires os.family == "windows"
* @run junit LargeBacklogTest
*/
class LargeBacklogTest {
@Test
void testServerSocket() throws Exception {
final int backlog = 242;
// Create a ServerSocket configured with the given backlog.
// The ServerSocket never accept()s a connection so each connect() attempt
// will be backlogged.
try (var server = new ServerSocket(0, backlog, InetAddress.getLoopbackAddress())) {
final int serverPort = server.getLocalPort();
testBackloggedConnects(backlog, serverPort);
}
}
@Test
void testServerSocketChannel() throws Exception {
final int backlog = 213;
// Create a ServerSocketChannel configured with the given backlog.
// The channel never accept()s a connection so each connect() attempt
// will be backlogged.
try (var serverChannel = ServerSocketChannel.open()) {
serverChannel.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), backlog);
final int serverPort = ((InetSocketAddress) serverChannel.getLocalAddress()).getPort();
testBackloggedConnects(backlog, serverPort);
}
}
@Test
void testAsynchronousServerSocketChannel() throws Exception {
final int backlog = 209;
// Create a AsynchronousServerSocketChannel configured with the given backlog.
// The channel never accept()s a connection so each connect() attempt
// will be backlogged.
try (var serverChannel = AsynchronousServerSocketChannel.open()) {
serverChannel.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), backlog);
final int serverPort = ((InetSocketAddress) serverChannel.getLocalAddress()).getPort();
testBackloggedConnects(backlog, serverPort);
}
}
private static void testBackloggedConnects(final int backlog, final int serverPort) {
int numSuccessfulConnects = 0;
System.err.println("attempting " + backlog + " connections to port " + serverPort);
// attempt the Socket connections
for (int i = 1; i <= backlog; i++) {
try (final Socket sock = new Socket(InetAddress.getLoopbackAddress(), serverPort)) {
numSuccessfulConnects++;
System.err.println("connection " + i + " established " + sock);
} catch (IOException ioe) {
System.err.println("connection attempt " + i + " failed: " + ioe);
// do not attempt any more connections
break;
}
}
System.err.println(numSuccessfulConnects + " connections successfully established");
// ideally we expect the number of successful connections to be equal to the backlog value.
// however in certain environments, it's possible that some other process attempts a
// connection to the server's port. so we allow for a small number of connection attempts
// to fail (due to exceeding the backlog)
final int minimumExpectedSuccessfulConns = backlog - 5;
if (numSuccessfulConnects < minimumExpectedSuccessfulConns) {
fail("expected at least " + minimumExpectedSuccessfulConns
+ " successful connections for a backlog of " + backlog + ", but only "
+ numSuccessfulConnects + " were successful");
}
}
}

View file

@ -0,0 +1,42 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 8223457
* @run main NullConstructor
* @summary java.net.ServerSocket protected constructor should throw NPE if impl null
*/
import java.net.ServerSocket;
import java.net.SocketImpl;
public class NullConstructor {
public static void main(String args[]) throws Exception {
try {
ServerSocket server = new ServerSocket((SocketImpl)null) {};
throw new RuntimeException("Test failed");
} catch (NullPointerException ee) {}
}
}

View file

@ -0,0 +1,98 @@
/*
* Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8021820
* @summary The total number of file descriptors is limited to
* 1024(FDSET_SIZE) on MacOSX (the size of fd array passed to select()
* call in java.net classes is limited to this value).
* @requires os.family == "mac"
* @run main/othervm SelectFdsLimit
* @author aleksej.efimov@oracle.com
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.SocketTimeoutException;
/*
* Test must be run in othervm mode to ensure that all files
* opened by openFiles() are closed propertly.
*/
public class SelectFdsLimit {
static final int FDTOOPEN = 1023;
static final String TESTFILE = "testfile";
static FileInputStream [] testFIS;
static void prepareTestEnv() throws IOException {
File fileToCreate = new File(TESTFILE);
if (!fileToCreate.exists())
if (!fileToCreate.createNewFile())
throw new RuntimeException("Can't create test file");
}
//If there will be some problem (i.e. ulimits on number of opened files will fail)
//then this method will fail with exception and test will be considered as
//failed. But allocated fds will be released because the test is executed by
//dedicated VM (@run main/othervm).
static void openFiles(int fn, File f) throws FileNotFoundException, IOException {
testFIS = new FileInputStream[FDTOOPEN];
for (;;) {
if (0 == fn)
break;
FileInputStream fis = new FileInputStream(f);
testFIS[--fn] = fis;
}
}
public static void main(String [] args) throws IOException, FileNotFoundException {
//Create test directory with test files
prepareTestEnv();
//Consume FD ids for this java process to overflow the 1024
openFiles(FDTOOPEN,new File(TESTFILE));
//Wait for incoming connection and make the select() used in java.net
//classes fail the limitation on FDSET_SIZE
ServerSocket socket = new ServerSocket(0);
//Set the minimal timeout, no one is
//going to connect to this server socket
socket.setSoTimeout(1);
// The accept() call will throw SocketException if the
// select() has failed due to limitation on fds size,
// indicating test failure. A SocketTimeoutException
// is expected, so it is caught and ignored, and the test
// passes.
try {
socket.accept();
} catch (SocketTimeoutException e) { }
}
}

View file

@ -0,0 +1,80 @@
/*
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6505016
* @summary Socket spec should clarify what getInetAddress/getPort/etc return after the Socket is closed
*/
import java.net.*;
import java.io.*;
public class TestAfterClose
{
static int failCount;
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(0, 0, null);
test(ss);
} catch (IOException ioe) {
ioe.printStackTrace();
}
if (failCount > 0)
throw new RuntimeException("Failed: failcount = " + failCount);
}
static void test(ServerSocket ss) throws IOException {
//Before Close
InetAddress ssInetAddress = ss.getInetAddress();
int ssLocalPort = ss.getLocalPort();
SocketAddress ssLocalSocketAddress = ss.getLocalSocketAddress();
//After Close
ss.close();
if (ssLocalPort != ss.getLocalPort()) {
System.out.println("ServerSocket.getLocalPort failed");
failCount++;
}
if (!ss.getInetAddress().equals(ssInetAddress)) {
System.out.println("ServerSocket.getInetAddress failed");
failCount++;
}
if (!ss.getLocalSocketAddress().equals(ssLocalSocketAddress)) {
System.out.println("ServerSocket.getLocalSocketAddress failed");
failCount++;
}
if (!ss.isBound()) {
System.out.println("ServerSocket.isBound failed");
failCount++;
}
}
}

View file

@ -0,0 +1,288 @@
/*
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @library /test/lib
* @modules java.management java.base/java.io:+open java.base/java.net:+open
* @run main/othervm/timeout=480 UnreferencedSockets
* @run main/othervm/timeout=480 -Djava.net.preferIPv4Stack=true UnreferencedSockets
* @summary Check that unreferenced sockets are closed
*/
import java.io.FileDescriptor;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketImpl;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayDeque;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import com.sun.management.UnixOperatingSystemMXBean;
import jdk.test.lib.net.IPSupport;
public class UnreferencedSockets {
/**
* The set of sockets we have to check up on.
*/
final static ArrayDeque<NamedWeak> pendingSockets = new ArrayDeque<>(100);
/**
* Queued sockets when they are unreferenced.
*/
final static ReferenceQueue<Object> pendingQueue = new ReferenceQueue<>();
// Server to echo a stream
static class Server implements Runnable {
ServerSocket ss;
Server(InetAddress address) throws IOException {
ss = new ServerSocket(0, 0, address);
pendingSockets.add(new NamedWeak(ss, pendingQueue, "serverSocket"));
extractRefs(ss, "serverSocket");
}
public int localPort() {
return ss.getLocalPort();
}
public void run() {
try {
Socket s = ss.accept();
pendingSockets.add(new NamedWeak(s, pendingQueue, "acceptedSocket"));
extractRefs(s, "acceptedSocket");
InputStream in = s.getInputStream();
int b = in.read();
OutputStream out = s.getOutputStream();
out.write(b);
// do NOT close but 'forget' the socket reference
out = null;
in = null;
s = null;
} catch (Exception ioe) {
ioe.printStackTrace();
} finally {
try {
ss.close();
ss = null;
} catch (IOException x) {
x.printStackTrace();
}
}
}
}
public static void main(String args[]) throws Exception {
IPSupport.throwSkippedExceptionIfNonOperational();
InetAddress lba = InetAddress.getLoopbackAddress();
// Create and close a ServerSocket to warm up the FD count for side effects.
try (ServerSocket s = new ServerSocket(0, 0, lba)) {
// no-op; close immediately
s.getLocalPort(); // no-op
}
long fdCount0 = getFdCount();
listProcFD();
// start a server
Server svr = new Server(lba);
Thread thr = new Thread(svr);
thr.start();
Socket s = new Socket(lba, svr.localPort());
pendingSockets.add(new NamedWeak(s, pendingQueue, "clientSocket"));
extractRefs(s, "clientSocket");
OutputStream out = s.getOutputStream();
out.write('x');
out.flush();
InputStream in = s.getInputStream();
int b = in.read(); // wait for it back
System.out.printf(" data sent and received%n");
// Do NOT close the Socket; forget it
Object ref;
int loops = 20;
while (!pendingSockets.isEmpty() && loops-- > 0) {
ref = pendingQueue.remove(1000L);
if (ref != null) {
pendingSockets.remove(ref);
System.out.printf(" ref queued: %s, remaining: %d%n", ref, pendingSockets.size());
} else {
s = null;
out = null;
in = null;
System.gc();
}
}
thr.join();
// List the open file descriptors
long fdCount = getFdCount();
System.out.printf("Initial fdCount: %d, final fdCount: %d%n", fdCount0, fdCount);
listProcFD();
if (loops == 0) {
throw new AssertionError("Not all references reclaimed");
}
}
// Get the count of open file descriptors, or -1 if not available
private static long getFdCount() {
OperatingSystemMXBean mxBean = ManagementFactory.getOperatingSystemMXBean();
return (mxBean instanceof UnixOperatingSystemMXBean)
? ((UnixOperatingSystemMXBean) mxBean).getOpenFileDescriptorCount()
: -1L;
}
// Reflect to find references in the socket implementation that will be gc'd
private static void extractRefs(Socket s, String name) {
try {
Field socketImplField = Socket.class.getDeclaredField("impl");
socketImplField.setAccessible(true);
Object socketImpl = socketImplField.get(s);
Field fileDescriptorField = SocketImpl.class.getDeclaredField("fd");
fileDescriptorField.setAccessible(true);
FileDescriptor fileDescriptor = (FileDescriptor) fileDescriptorField.get(socketImpl);
extractRefs(fileDescriptor, name);
} catch (NoSuchFieldException | IllegalAccessException ex) {
ex.printStackTrace();
throw new AssertionError("missing field", ex);
}
}
private static void extractRefs(FileDescriptor fileDescriptor, String name) {
Object cleanup = null;
int rawfd = -1;
try {
if (fileDescriptor != null) {
Field fd1Field = FileDescriptor.class.getDeclaredField("fd");
fd1Field.setAccessible(true);
rawfd = fd1Field.getInt(fileDescriptor);
Field cleanupfdField = FileDescriptor.class.getDeclaredField("cleanup");
cleanupfdField.setAccessible(true);
cleanup = cleanupfdField.get(fileDescriptor);
pendingSockets.add(new NamedWeak(fileDescriptor, pendingQueue,
name + "::fileDescriptor: " + rawfd));
pendingSockets.add(new NamedWeak(cleanup, pendingQueue, name + "::fdCleanup: " + rawfd));
}
} catch (NoSuchFieldException | IllegalAccessException ex) {
ex.printStackTrace();
throw new AssertionError("missing field", ex);
} finally {
System.out.print(String.format(" fd: %s, fd: %d, cleanup: %s%n",
fileDescriptor, rawfd, cleanup));
}
}
private static void extractRefs(ServerSocket s, String name) {
try {
Field socketImplField = ServerSocket.class.getDeclaredField("impl");
socketImplField.setAccessible(true);
Object socketImpl = socketImplField.get(s);
Field fileDescriptorField = SocketImpl.class.getDeclaredField("fd");
fileDescriptorField.setAccessible(true);
FileDescriptor fileDescriptor = (FileDescriptor) fileDescriptorField.get(socketImpl);
Field fdField = FileDescriptor.class.getDeclaredField("fd");
fdField.setAccessible(true);
int rawfd = fdField.getInt(fileDescriptor);
Field cleanupField = FileDescriptor.class.getDeclaredField("cleanup");
cleanupField.setAccessible(true);
Object cleanup = cleanupField.get(fileDescriptor);
System.out.print(String.format(" fd: %s, fd: %d, cleanup: %s, socket: %s%n",
fileDescriptor, rawfd, cleanup, s));
pendingSockets.add(new NamedWeak(fileDescriptor, pendingQueue,
name + "::fileDescriptor: " + rawfd));
pendingSockets.add(new NamedWeak(cleanup, pendingQueue, name + "::fdCleanup: " + rawfd));
} catch (NoSuchFieldException | IllegalAccessException ex) {
ex.printStackTrace();
throw new AssertionError("missing field", ex);
}
}
/**
* Method to list the open file descriptors (if supported by the 'lsof' command).
*/
static void listProcFD() {
List<String> lsofDirs = List.of("/usr/bin", "/usr/sbin");
Optional<Path> lsof = lsofDirs.stream()
.map(s -> Paths.get(s, "lsof"))
.filter(f -> Files.isExecutable(f))
.findFirst();
lsof.ifPresent(exe -> {
try {
System.out.printf("Open File Descriptors:%n");
long pid = ProcessHandle.current().pid();
ProcessBuilder pb = new ProcessBuilder(exe.toString(), "-p", Integer.toString((int) pid));
pb.inheritIO();
Process p = pb.start();
p.waitFor(10, TimeUnit.SECONDS);
} catch (IOException | InterruptedException ie) {
ie.printStackTrace();
}
});
}
// Simple class to identify which refs have been queued
static class NamedWeak extends WeakReference<Object> {
private final String name;
NamedWeak(Object o, ReferenceQueue<Object> queue, String name) {
super(o, queue);
this.name = name;
}
public String toString() {
return name + "; " + super.toString();
}
}
}