changeset 53808:8f9ce4460636

8256818: SSLSocket that is never bound or connected leaks socket resources Reviewed-by: xuelei
author clanger
date Tue, 22 Dec 2020 20:28:49 +0000
parents 8821ab2da718
children 0fdf7159d5c2
files src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java test/jdk/java/lang/ProcessBuilder/checkHandles/CheckHandles.java test/jdk/java/lang/ProcessBuilder/checkHandles/libCheckHandles.c test/jdk/native_util/libFileUtils.c test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketLeak.java test/lib/jdk/test/lib/util/FileUtils.java
diffstat 6 files changed, 154 insertions(+), 71 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java	Wed Dec 04 11:57:58 2019 +0100
+++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java	Tue Dec 22 20:28:49 2020 +0000
@@ -552,7 +552,7 @@
     // locks may be deadlocked.
     @Override
     public void close() throws IOException {
-        if (tlsIsClosed) {
+        if (isClosed()) {
             return;
         }
 
@@ -561,19 +561,16 @@
         }
 
         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
@@ -581,7 +578,19 @@
                 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;
+                }
+            }
         }
     }
 
--- a/test/jdk/java/lang/ProcessBuilder/checkHandles/CheckHandles.java	Wed Dec 04 11:57:58 2019 +0100
+++ b/test/jdk/java/lang/ProcessBuilder/checkHandles/CheckHandles.java	Tue Dec 22 20:28:49 2020 +0000
@@ -27,32 +27,30 @@
 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 @@
         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 @@
             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));
--- a/test/jdk/java/lang/ProcessBuilder/checkHandles/libCheckHandles.c	Wed Dec 04 11:57:58 2019 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2020, 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.
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef _WIN32
-
-#include "jni.h"
-#include "jni_util.h"
-#include <windows.h>
-
-JNIEXPORT jlong JNICALL Java_CheckHandles_getProcessHandleCount(JNIEnv *env)
-{
-    DWORD handleCount;
-    HANDLE handle = GetCurrentProcess();
-    if (GetProcessHandleCount(handle, &handleCount)) {
-        return (jlong)handleCount;
-    } else {
-        return -1L;
-    }
-}
-
-#endif  /*  _WIN32 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/native_util/libFileUtils.c	Tue Dec 22 20:28:49 2020 +0000
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2020, 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef _WIN32
+
+#include "jni.h"
+#include "jni_util.h"
+#include <windows.h>
+
+JNIEXPORT jlong JNICALL Java_jdk_test_lib_util_FileUtils_getWinProcessHandleCount(JNIEnv *env)
+{
+    DWORD handleCount;
+    HANDLE handle = GetCurrentProcess();
+    if (GetProcessHandleCount(handle, &handleCount)) {
+        return (jlong)handleCount;
+    } else {
+        return -1L;
+    }
+}
+
+#endif  /*  _WIN32 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketLeak.java	Tue Dec 22 20:28:49 2020 +0000
@@ -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.");
+        }
+    }
+}
--- a/test/lib/jdk/test/lib/util/FileUtils.java	Wed Dec 04 11:57:58 2019 +0100
+++ b/test/lib/jdk/test/lib/util/FileUtils.java	Tue Dec 22 20:28:49 2020 +0000
@@ -23,12 +23,11 @@
 
 package jdk.test.lib.util;
 
-import jdk.test.lib.Platform;
-
 import java.io.IOException;
 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;
@@ -38,14 +37,16 @@
 import java.nio.file.SimpleFileVisitor;
 import java.nio.file.attribute.BasicFileAttributes;
 import java.time.Instant;
-import java.time.Duration;
 import java.util.ArrayList;
-import java.util.ArrayDeque;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Optional;
 import java.util.concurrent.TimeUnit;
 
+import jdk.test.lib.Platform;
+
+import com.sun.management.UnixOperatingSystemMXBean;
+
 /**
  * Common library for various test file utility functions.
  */
@@ -53,6 +54,7 @@
     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.
@@ -273,4 +275,19 @@
             }
         });
     }
+
+    // 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();
 }