Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8313657 : com.sun.jndi.ldap.Connection.cleanup does not close connections on SocketTimeoutErrors #15143

Closed
wants to merge 8 commits into from

Conversation

weibxiao
Copy link
Contributor

@weibxiao weibxiao commented Aug 3, 2023

com.sun.jndi.ldap.Connection::leanup does not close the underlying socket if the is an IOException generation when the output stream was flushing the buffer.

Please refer to the bug https://bugs.openjdk.org/browse/JDK-8313657.


Progress

  • Change must be properly reviewed (1 review required, with at least 1 Reviewer)
  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue

Issue

  • JDK-8313657: com.sun.jndi.ldap.Connection.cleanup does not close connections on SocketTimeoutErrors (Bug - P3)

Reviewers

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/15143/head:pull/15143
$ git checkout pull/15143

Update a local copy of the PR:
$ git checkout pull/15143
$ git pull https://git.openjdk.org/jdk.git pull/15143/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 15143

View PR using the GUI difftool:
$ git pr show -t 15143

Using diff file

Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/15143.diff

Webrev

Link to Webrev Comment

@bridgekeeper
Copy link

bridgekeeper bot commented Aug 3, 2023

👋 Welcome back weibxiao! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@openjdk
Copy link

openjdk bot commented Aug 3, 2023

@weibxiao The following label will be automatically applied to this pull request:

  • core-libs

When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing list. If you would like to change these labels, use the /label pull request command.

@openjdk openjdk bot added the core-libs core-libs-dev@openjdk.org label Aug 3, 2023
sock.close();
unpauseReader();
if (debug) {
if (sock.isClosed()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is it possible for sock.close() to succeed but isClosed to return false?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is an unreachable code and got removed.

@weibxiao weibxiao changed the title 8313657 : com.sun.jndi.ldap.Connection.cleanup does not close connect… 8313657 : com.sun.jndi.ldap.Connection.cleanup does not close connections on SocketTimeoutErrors Aug 3, 2023
@openjdk openjdk bot added the rfr Pull request is ready for review label Aug 4, 2023
@mlbridge
Copy link

mlbridge bot commented Aug 4, 2023

Webrevs

@msheppar
Copy link

msheppar commented Aug 4, 2023

why not restructure the finally block a little ... refactor extract methods
flushOutputStream,
closeConnectionSocket
... should the outputStream be closed in this finally block, also?

            } finally {
                flushOutputStream(outStream);
                closeConnectionSocket(sock);
                try {
                    unpauseReader();
                } catch (IOException ie) {
                    if (debug)
                        System.err.println("Connection.cleanup: problem with unpuaseReader " + ie);
                }

...

private void flushOutputStream (OutputStream outputStream) {
    try {
        outStream.flush();
        outStream.close();
    } catch (IOException ioEx) {
        if (debug)
            System.err.println("Connection.flushOutputStream: OutputStream flush or close problem " + ioEx);
    }
}

private void closeConnectionSocket (Socket sock) {
    //bug 8313657, socket not closed util GC running
    try {
        sock.close();
    } catch (IOException ioEx) {
        if (debug)
            System.err.println("ConnectioncloseConnectioSocket: problem closing socket: " + ioEx);
    }
}                  

import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.net.SocketFactory;
import java.io.*;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we please use a set of class imports instead of package import here:

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

* @library /test/lib
*/

public class SocketCloseTest {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we change the test location from test/javax/naming/InitialContext to an LDAP-implementation specific folder - test/jdk/com/sun/jndi/ldap

48, 12, 2, 1, 1, 97, 7, 10, 1, 0, 4, 0, 4, 0
};
private static final int SEARCH_SIZE = 87;
private static final byte[] SEARCH_RESPONSE = new byte[]{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SEARCH_RESPONSE, SEARCH_SIZE and BIND_SIZE are not used in the test. If they're not needed they can be removed.

Hashtable<String, Object> props = new Hashtable<>();

props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
props.put(Context.PROVIDER_URL, "ldap://localhost:1389/o=example");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For future test maintainers - can we please clarify that the hostname and port do not matter here because the provided custom socket factory doesn't establish a connection to the specified provider URL

@@ -650,6 +650,19 @@ void cleanup(Control[] reqCtls, boolean notifyParent) {
} catch (IOException ie) {
if (debug)
System.err.println("Connection: problem closing socket: " + ie);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about combining the debug statement here with the one below and just print the socket isClosed state, something like

if (debug) {
    System.err.println("Connection: problem cleaning-up the connection: " + ie);
    System.err.println("Socket isClosed: " + sock.isClosed());
}

The text was changed here since the exception can also be thrown by unpauseReader

}
} catch (IOException ioe) {
if (debug)
System.err.println("Connection::cleanup problem: " + ioe);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe change the message here to highlight the fact that it's the 2nd attemp to clean-up the connection

@weibxiao
Copy link
Contributor Author

weibxiao commented Aug 4, 2023

  1. Extracted the methods for finally black of Connection::cleanUP
  2. Move the test class to LDAP test folder and updated the test comments.
  3. Removed the redundant code and update the import statement.

@@ -684,6 +682,43 @@ void cleanup(Control[] reqCtls, boolean notifyParent) {
}
}

// flush and close output stream
private void flushCloseOutputStream() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'flushAndCloseOutputStream' will be more meaningful name.

}

// close socket
private void closeConnectionSocket() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'closeSocketConnection' will be more meaningful.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the suggested name was to convey the closing of the Connection's socket, not a socket connection per se.

@msheppar
Copy link

msheppar commented Aug 7, 2023

I ran the test multiple times in mach5 and it executes fine. However, while examining the log output I noticed the "The socket was not closed. " output. This is a little confusing. While looking at the test and exploring the origins of this outout, we see that the test is essentially an othervm execution. As such, I restructured the test to othervm and it executes with some informative output and eliminates the discombobulating output.

I have left a comment in the JBS bug item with some further details and changes for othervm. This gives some imformative output as the test executes.

The origins of the output is the main try block executing in the agentvm and the throwing of a ClassNotFoundException.

If you don't wish to do otherrvm and to avoid the "The socket was not closed. " output, and if wish to retain the same structure, then consider adding a run command to the test with an arg, and then a conditional on the core test logic e.g.

  • @run main SocketCloseTest launcher

and in the main method

public static void main(String[] args) throws Exception {
    Hashtable<String, Object> props = new Hashtable<>();

if (args.length == 0) { // only executed in the launched JVM
props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
props.put(Context.PROVIDER_URL, "ldap://localhost:1389/o=example");
props.put("java.naming.ldap.factory.socket", CustomSocketFactory.class.getName());
try {
final DirContext ctx = new InitialDirContext(props);
} catch (Exception e) {
if (CustomSocketFactory.customSocket.closeMethodCalledCount() > 0) {
System.out.println(SOCKET_CLOSED_MSG);
} else {
System.out.println(SOCKET_NOT_CLOSED_MSG);
}
}
}

    OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm("SocketCloseTest_II");
    outputAnalyzer.stdoutShouldContain(SOCKET_CLOSED_MSG);
    outputAnalyzer.stdoutShouldNotContain(SOCKET_NOT_CLOSED_MSG);
    outputAnalyzer.stdoutShouldContain(BAD_FLUSH);
}

props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
props.put(Context.PROVIDER_URL, "ldap://localhost:1389/o=example");
props.put("java.naming.ldap.factory.socket", CustomSocketFactory.class.getName());
try {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will execute twice: once in the agentvm main and also, as desired, in the test JVM main.
The agentvm main sees a ClassNotFoundException being thrown and then the output of "The socket was not closed. " in the log c.f. other comments and bug comments for further details to avoid execution in agentvm or use of othervm test mode execution

@weibxiao
Copy link
Contributor Author

weibxiao commented Aug 9, 2023

  1. Update the name of the methods
  2. Update the test file.

public static class LdapInputStream extends InputStream {
private LdapOutputStream los;
private ByteArrayInputStream bos;
int pos = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

variable 'pos' is not used can be removed.

@Override
public int read() throws IOException {
bos = new ByteArrayInputStream(BIND_RESPONSE);
int next = bos.read();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can be simplified as follows return bos.read();

}

public static class CustomSocketFactory extends SocketFactory {
public static CustomSocket customSocket = new CustomSocket();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can make 'customSocket' to private.

@weibxiao
Copy link
Contributor Author

weibxiao commented Aug 9, 2023

  1. Cannot make CustomSocket be private. The test failed. I believe JDK is using the reflection to load the class.
  2. The rest of the changes are based on the comments.

Copy link
Contributor

@vyommani vyommani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Latest code looks OK to me.

}

private static class LdapInputStream extends InputStream {
private LdapOutputStream los;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The LdapOutputStream reference is not used by LdapInputStream, therefore the los field can be removed:

private static class LdapInputStream extends InputStream {
-        private LdapOutputStream los;
         private ByteArrayInputStream bos;
 
-        public LdapInputStream(LdapOutputStream los) {
-            this.los = los;
+        public LdapInputStream() {
         }
 
         @Override
@@ -144,7 +142,7 @@ public class SocketCloseTest {
     private static class CustomSocket extends Socket {
         private int closeMethodCalled = 0;
         private LdapOutputStream output = new LdapOutputStream();
-        private LdapInputStream input = new LdapInputStream(output);
+        private LdapInputStream input = new LdapInputStream();
 
         public void connect(SocketAddress address, int timeout) {
         }

@weibxiao
Copy link
Contributor Author

Updated LdapInputStream.java and remove the unused variable.

Copy link

@msheppar msheppar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for incorporating the feedback
LGTM

@openjdk
Copy link

openjdk bot commented Aug 14, 2023

@weibxiao This change now passes all automated pre-integration checks.

ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details.

After integration, the commit message for the final commit will be:

8313657: com.sun.jndi.ldap.Connection.cleanup does not close connections on SocketTimeoutErrors

Reviewed-by: vtewari, msheppar, aefimov

You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed.

At the time when this comment was updated there had been 107 new commits pushed to the master branch:

  • 4b2703a: 8313678: SymbolTable can leak Symbols during cleanup
  • f41c267: 8314045: ArithmeticException in GaloisCounterMode
  • 911d1db: 8314078: HotSpotConstantPool.lookupField() asserts due to field changes in ConstantPool.cpp
  • 6574dd7: 8314025: Remove JUnit-based test in java/lang/invoke from problem list
  • 207bd00: 8313756: [BACKOUT] 8308682: Enhance AES performance
  • 823f5b9: 8308850: Change JVM options with small ranges that get -Wconversion warnings to 32 bits
  • 5bfb82e: 8314119: G1: Fix -Wconversion warnings in G1CardSetInlinePtr::card_pos_for
  • 06aa3c5: 8314118: Update JMH devkit to 1.37
  • 4164693: 8313372: [JVMCI] Export vmIntrinsics::is_intrinsic_available results to JVMCI compilers.
  • 049b55f: 8314019: Add gc logging to jdk/jfr/event/gc/detailed/TestZAllocationStallEvent.java
  • ... and 97 more: https://git.openjdk.org/jdk/compare/ab1c212ac1097ae6e1122ef1aba47ca51eca11f2...master

As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details.

As you do not have Committer status in this project an existing Committer must agree to sponsor your change. Possible candidates are the reviewers of this PR (@vyommani, @msheppar, @AlekseiEfimov) but any other Committer may sponsor as well.

➡️ To flag this PR as ready for integration with the above commit message, type /integrate in a new comment. (Afterwards, your sponsor types /sponsor in a new comment to perform the integration).

@openjdk openjdk bot added the ready Pull request is ready to be integrated label Aug 14, 2023
@weibxiao
Copy link
Contributor Author

/integrate

@openjdk openjdk bot added the sponsor Pull request is ready to be sponsored label Aug 14, 2023
@openjdk
Copy link

openjdk bot commented Aug 14, 2023

@weibxiao
Your change (at version b7d0c25) is now ready to be sponsored by a Committer.

@AlekseiEfimov
Copy link
Member

/sponsor

@openjdk
Copy link

openjdk bot commented Aug 14, 2023

Going to push as commit e56d3bc.
Since your change was applied there have been 107 commits pushed to the master branch:

  • 4b2703a: 8313678: SymbolTable can leak Symbols during cleanup
  • f41c267: 8314045: ArithmeticException in GaloisCounterMode
  • 911d1db: 8314078: HotSpotConstantPool.lookupField() asserts due to field changes in ConstantPool.cpp
  • 6574dd7: 8314025: Remove JUnit-based test in java/lang/invoke from problem list
  • 207bd00: 8313756: [BACKOUT] 8308682: Enhance AES performance
  • 823f5b9: 8308850: Change JVM options with small ranges that get -Wconversion warnings to 32 bits
  • 5bfb82e: 8314119: G1: Fix -Wconversion warnings in G1CardSetInlinePtr::card_pos_for
  • 06aa3c5: 8314118: Update JMH devkit to 1.37
  • 4164693: 8313372: [JVMCI] Export vmIntrinsics::is_intrinsic_available results to JVMCI compilers.
  • 049b55f: 8314019: Add gc logging to jdk/jfr/event/gc/detailed/TestZAllocationStallEvent.java
  • ... and 97 more: https://git.openjdk.org/jdk/compare/ab1c212ac1097ae6e1122ef1aba47ca51eca11f2...master

Your commit was automatically rebased without conflicts.

@openjdk openjdk bot added the integrated Pull request has been integrated label Aug 14, 2023
@openjdk openjdk bot closed this Aug 14, 2023
@openjdk openjdk bot removed ready Pull request is ready to be integrated rfr Pull request is ready for review sponsor Pull request is ready to be sponsored labels Aug 14, 2023
@openjdk
Copy link

openjdk bot commented Aug 14, 2023

@AlekseiEfimov @weibxiao Pushed as commit e56d3bc.

💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core-libs core-libs-dev@openjdk.org integrated Pull request has been integrated
Development

Successfully merging this pull request may close these issues.

5 participants