8256818: SSLSocket that is never bound or connected leaks socket resources

Reviewed-by: xuelei
This commit is contained in:
Christoph Langer 2020-12-02 19:23:26 +00:00
parent 692b273ec5
commit 93b6ab56ae
5 changed files with 114 additions and 32 deletions

View File

@ -553,7 +553,7 @@ public final class SSLSocketImpl
// locks may be deadlocked.
@Override
public void close() throws IOException {
if (tlsIsClosed) {
if (isClosed()) {
return;
}
@ -562,19 +562,16 @@ public final class SSLSocketImpl
}
try {
// shutdown output bound, which may have been closed previously.
if (!isOutputShutdown()) {
duplexCloseOutput();
}
if (isConnected()) {
// shutdown output bound, which may have been closed previously.
if (!isOutputShutdown()) {
duplexCloseOutput();
}
// shutdown input bound, which may have been closed previously.
if (!isInputShutdown()) {
duplexCloseInput();
}
if (!isClosed()) {
// close the connection directly
closeSocket(false);
// shutdown input bound, which may have been closed previously.
if (!isInputShutdown()) {
duplexCloseInput();
}
}
} catch (IOException ioe) {
// ignore the exception
@ -582,7 +579,19 @@ public final class SSLSocketImpl
SSLLogger.warning("SSLSocket duplex close failed", ioe);
}
} finally {
tlsIsClosed = true;
if (!isClosed()) {
// close the connection directly
try {
closeSocket(false);
} catch (IOException ioe) {
// ignore the exception
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
SSLLogger.warning("SSLSocket close failed", ioe);
}
} finally {
tlsIsClosed = true;
}
}
}
}

View File

@ -27,32 +27,30 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.ProcessHandle;
import jdk.test.lib.util.FileUtils;
/*
* @test
* @bug 8239893
* @summary Verify that handles for processes that terminate do not accumulate
* @requires ((os.family == "windows") & (vm.compMode != "Xcomp"))
* @library /test/lib
* @run main/othervm/native -Xint CheckHandles
*/
public class CheckHandles {
// Return the current process handle count
private static native long getProcessHandleCount();
public static void main(String[] args) throws Exception {
System.loadLibrary("CheckHandles");
System.out.println("mypid: " + ProcessHandle.current().pid());
// Warmup the process launch mechanism and vm to stabilize the number of handles in use
int MAX_WARMUP = 20;
long prevCount = getProcessHandleCount();
long prevCount = FileUtils.getProcessHandleCount();
for (int i = 0; i < MAX_WARMUP; i++) {
oneProcess();
System.gc(); // an opportunity to close unreferenced handles
sleep(10);
long count = getProcessHandleCount();
long count = FileUtils.getProcessHandleCount();
if (count < 0)
throw new AssertionError("getProcessHandleCount failed");
System.out.println("warmup handle delta: " + (count - prevCount));
@ -61,7 +59,7 @@ public class CheckHandles {
System.out.println("Warmup done");
System.out.println();
prevCount = getProcessHandleCount();
prevCount = FileUtils.getProcessHandleCount();
long startHandles = prevCount;
long maxHandles = startHandles;
int MAX_SPAWN = 50;
@ -70,7 +68,7 @@ public class CheckHandles {
System.gc(); // an opportunity to close unreferenced handles
sleep(10);
long count = getProcessHandleCount();
long count = FileUtils.getProcessHandleCount();
if (count < 0)
throw new AssertionError("getProcessHandleCount failed");
System.out.println("handle delta: " + (count - prevCount));

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2020 SAP SE. 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 javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;
import jdk.test.lib.util.FileUtils;
/*
* @test
* @bug 8256818
* @summary Test that creating and closing SSL Sockets without bind/connect
* will not leave leaking socket file descriptors
* @library /test/lib
* @run main/othervm SSLSocketLeak
*/
public class SSLSocketLeak {
private static final int NUM_TEST_SOCK = 500;
public static void main(String[] args) throws IOException {
long fds_start = FileUtils.getProcessHandleCount();
System.out.println("FDs at the beginning: " + fds_start);
SocketFactory f = SSLSocketFactory.getDefault();
for (int i = 0; i < NUM_TEST_SOCK; i++) {
f.createSocket().close();
}
long fds_end = FileUtils.getProcessHandleCount();
System.out.println("FDs in the end: " + fds_end);
if ((fds_end - fds_start) > (NUM_TEST_SOCK / 10)) {
throw new RuntimeException("Too many open file descriptors. Looks leaky.");
}
}
}

View File

@ -23,34 +23,34 @@
package jdk.test.lib.util;
import jdk.test.lib.Platform;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.UncheckedIOException;
import java.lang.ProcessBuilder.Redirect;
import java.lang.management.ManagementFactory;
import java.nio.file.DirectoryNotEmptyException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.Instant;
import java.time.Duration;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.TimeUnit;
import jdk.test.lib.Platform;
import com.sun.management.UnixOperatingSystemMXBean;
/**
* Common library for various test file utility functions.
@ -59,6 +59,7 @@ public final class FileUtils {
private static final boolean IS_WINDOWS = Platform.isWindows();
private static final int RETRY_DELETE_MILLIS = IS_WINDOWS ? 500 : 0;
private static final int MAX_RETRY_DELETE_TIMES = IS_WINDOWS ? 15 : 0;
private static volatile boolean nativeLibLoaded;
/**
* Deletes a file, retrying if necessary.
@ -363,6 +364,21 @@ public final class FileUtils {
});
}
// Return the current process handle count
public static long getProcessHandleCount() {
if (IS_WINDOWS) {
if (!nativeLibLoaded) {
System.loadLibrary("FileUtils");
nativeLibLoaded = true;
}
return getWinProcessHandleCount();
} else {
return ((UnixOperatingSystemMXBean)ManagementFactory.getOperatingSystemMXBean()).getOpenFileDescriptorCount();
}
}
private static native long getWinProcessHandleCount();
// Possible command locations and arguments
static String[][] lsCommands = new String[][] {
{"/usr/bin/lsof", "-p"},

View File

@ -29,7 +29,7 @@
#include "jni.h"
#include <windows.h>
JNIEXPORT jlong JNICALL Java_CheckHandles_getProcessHandleCount(JNIEnv *env)
JNIEXPORT jlong JNICALL Java_jdk_test_lib_util_FileUtils_getWinProcessHandleCount(JNIEnv *env)
{
DWORD handleCount;
HANDLE handle = GetCurrentProcess();