From 07380615b5effc8316f803e715548c563f3ebf34 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Wed, 11 Jun 2025 09:27:31 -0600 Subject: [PATCH] JSSE: skip calling freeSSL() inside SSLSocket.close() if InputStream or OutputStream are still active --- .../wolfssl/provider/jsse/WolfSSLSocket.java | 67 +++++++++++++++++-- 1 file changed, 62 insertions(+), 5 deletions(-) diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLSocket.java b/src/java/com/wolfssl/provider/jsse/WolfSSLSocket.java index 0bcb297..1f226d2 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLSocket.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLSocket.java @@ -1967,6 +1967,30 @@ public class WolfSSLSocket extends SSLSocket { return false; } + /** + * Internal private method to check if WolfSSLInputStream + * and WolfSSLOutputStream are closed. + * + * @return true if both streams are closed (or were not created/null), + * otherwise false if they were created and are still active. + */ + private boolean ioStreamsAreClosed() { + + if (this.inStream == null && this.outStream == null) { + return true; + } + + if (this.inStream != null && !this.inStream.isClosed()) { + return false; + } + + if (this.outStream != null && !this.outStream.isClosed()) { + return false; + } + + return true; + } + /** * Closes this SSLSocket. * @@ -2132,13 +2156,22 @@ public class WolfSSLSocket extends SSLSocket { /* Connection is closed, free native WOLFSSL session * to release native memory earlier than garbage - * collector might with finalize(), if we don't - * have any threads still waiting in poll/select. */ - if (this.ssl.getThreadsBlockedInPoll() == 0) { + * collector might with finalize(), Don't free if we + * have threads still waiting in poll/select or if + * our WolfSSLInputStream or WolfSSLOutputStream are + * still open. */ + if (this.ssl.getThreadsBlockedInPoll() == 0 && + ioStreamsAreClosed()) { WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, () -> "calling this.ssl.freeSSL()"); this.ssl.freeSSL(); this.ssl = null; + } else { + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + () -> "deferring freeing this.ssl, threads " + + "blocked in poll: " + + this.ssl.getThreadsBlockedInPoll() + + ", or streams not closed"); } /* Reset internal WolfSSLEngineHelper to null */ @@ -2517,7 +2550,7 @@ public class WolfSSLSocket extends SSLSocket { private WolfSSLSession ssl; private WolfSSLSocket socket; - private boolean isClosed = true; + private volatile boolean isClosed = true; /* Atomic boolean to indicate if this InputStream has started to * close. Protects against deadlock between two threads calling @@ -2530,6 +2563,18 @@ public class WolfSSLSocket extends SSLSocket { this.isClosed = false; } + /** + * Non standard method to check if this InputStream has been + * closed. This is used by WolfSSLSocket to check if the associated + * WolfSSLInputStream has been closed before calling freeSSL() + * internally. + * + * @return true if this InputStream has been closed, otherwise false + */ + public boolean isClosed() { + return this.isClosed; + } + /** * Close InputStream, but gives caller option to close underlying * Socket or not. @@ -2741,7 +2786,7 @@ public class WolfSSLSocket extends SSLSocket { private WolfSSLSession ssl; private WolfSSLSocket socket; - private boolean isClosed = true; + private volatile boolean isClosed = true; /* Atomic boolean to indicate if this InputStream has started to * close. Protects against deadlock between two threads calling @@ -2754,6 +2799,18 @@ public class WolfSSLSocket extends SSLSocket { this.isClosed = false; } + /** + * Non standard method to check if this OutputStream has been + * closed. This is used by WolfSSLSocket to check if the associated + * WolfSSLOutputStream has been closed before calling freeSSL() + * internally. + * + * @return true if this OutputStream has been closed, otherwise false + */ + public boolean isClosed() { + return this.isClosed; + } + /** * Close OutputStream, but gives caller option to close underlying * Socket or not.