You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by bu...@apache.org on 2021/09/06 07:53:40 UTC

[Bug 65553] New: Orphaned thread by JNDIRealm / clearReferencesThreads reports memory leak

https://bz.apache.org/bugzilla/show_bug.cgi?id=65553

            Bug ID: 65553
           Summary: Orphaned thread by JNDIRealm / clearReferencesThreads
                    reports memory leak
           Product: Tomcat 9
           Version: 9.0.52
          Hardware: PC
            Status: NEW
          Severity: minor
          Priority: P2
         Component: Catalina
          Assignee: dev@tomcat.apache.org
          Reporter: Thomas.Hoffmann@speed4trade.com
  Target Milestone: -----

Created attachment 38020
  --> https://bz.apache.org/bugzilla/attachment.cgi?id=38020&action=edit
Stacktrace on creation of orphaned thread

Hello,

we are using the org.apache.catalina.realm.JNDIRealm for authentication of
users against our windows AD.
When undeploying the application, we see the following  warning in our logs:

WARNING [Catalina-utility-1]  org.apache.catalina.loader.Webapp
ClassLoaderBase.clearReferencesThreads The  web application [ROOT] appears to
have started a thread named [Thread-106] but  has failed to stop it. This is
very likely to create a memory leak. Stack trace  of thread:
 java.base@11.0.3/java.net.SocketInputStream.socketRead0(Native  Method)

java.base@11.0.3/java.net.SocketInputStream.socketRead(SocketInputStream.java:115)
 java.base@11.0.3/java.net.SocketInputStream.read(SocketInputStream.java:168)
 java.base@11.0.3/java.net.SocketInputStream.read(SocketInputStream.java:140)

java.base@11.0.3/sun.security.ssl.SSLSocketInputRecord.read(SSLSocketInputRecord.java:448)

java.base@11.0.3/sun.security.ssl.SSLSocketInputRecord.bytesInCompletePacket(SSLSocketInputRecord.java:68)

java.base@11.0.3/sun.security.ssl.SSLSocketImpl.readApplicationRecord(SSLSocketImpl.java:1104)

java.base@11.0.3/sun.security.ssl.SSLSocketImpl$AppInputStream.read(SSLSocketImpl.java:823)

java.base@11.0.3/java.io.BufferedInputStream.fill(BufferedInputStream.java:252)

java.base@11.0.3/java.io.BufferedInputStream.read1(BufferedInputStream.java:292)

java.base@11.0.3/java.io.BufferedInputStream.read(BufferedInputStream.java:351)
 java.naming@11.0.3/com.sun.jndi.ldap.Connection.run(Connection.java:832)
 java.base@11.0.3/java.lang.Thread.run(Thread.java:834)

The warning is not always shown but quite often.

Summary of the analysis of the problem: 
On tomcat startup, the worker-thread is running under the  tomcat classloader.
But when a reconnect happens, the thread is running with  the classloader of
the web application and gets thus reported.

The details:
Digging into the problem via remote debugging showed the  reason how this
happens:
During startup, Tomcat is initializing the JNDIRealm. The  open-method of
JNDIRealm is switching the classloader between bootstrap-CL and  tomcat-lib-CL,
depending on the attribute "useContextClassLoader".
Afterwards the context-Object is created  (createDirContext). Within this
LdapCtx, an LdapClient is used to communicate  with the AD-Server.
This LdapClient uses a com.sun.jndi.ldap.Connection for  TCP communication.
This connection opens the reported Worker-Thread.
This can be seen at
https://github.com/AdoptOpenJDK/openjdk-jdk11/blob/master/src/java.naming/share/classes/com/sun/jndi/ldap/Connection.java
 around line 243 --> worker = Obj.helper.createThread(this);

So far, so good.

Somehow, the com.sun.jndi.ldap.Connection is sometimes  closed and the thread
dies. At least, the thread is not visible any more. Maybe because of a timeout
on the AD-server side or something else happened.
If a new user accesses the site, the JNDIRealm is  authenticating the user.
This triggers the following chain (path is shortened): 
JNDIRealm.getUserBySearch --> LdapCtx.dosearch --> LdapCtx.ensureOpen  -->
LdapCtx.connect --> LdapClient.getInstance -->  Connection.<init>

A detailed stack is attached as an image.

This call chain creates a new com.sun.jndi.ldap.Connection and  thus a new
thread. But this time, the thread is connected to the classloader of  the
web-application.
On undeployment, the thread is thus reported to be orphaned.

It was tested with Tomcat 9.0.52, Windows 10, OpenJDK  11.0.12_7.

As the authentication is conducted within tomcat, before  the application is
triggered, thus the application can't handle that error.

The flag "useContextClassLoader" is not taken into account during
authentication.
During this process a re-connect can occur and create the thread with the wrong
classloader.

Thanks in advance,
Thomas

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 65553] Orphaned thread by JNDIRealm / clearReferencesThreads reports memory leak

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=65553

Mark Thomas <ma...@apache.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 OS|                            |All

--- Comment #1 from Mark Thomas <ma...@apache.org> ---
One view is that the JRE should not be doing this - or at least doing it in a
way that doesn't run the risk of memory leaks in a Java EE / Jakarta EE
environment. We have raised JRE bugs for issues like this in the past and they
have been fixed.

The counter view is that this thread is not a one-off and is not short-lived
(the typical cases for JRE bugs that have been fixed) and Tomcat has already
acknowledged - with the useContextClassLoader flag - that it needs to be taking
action to ensure that any threads are created with the expected class loader.

If the consensus is that Tomcat needs to handle this then we'd need to ensure
that every version of authenticate() also set the class loader if required.
We'd probably want to refactor the existing handling to make sure we don't try
setting the class loader twice.

I am currently leaning towards handling this in Tomcat rather than raising a
JRE bug.

Thoughts?

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 65553] Orphaned thread by JNDIRealm / clearReferencesThreads reports memory leak

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=65553

--- Comment #2 from Michael Osipov <mi...@apache.org> ---
I see the same in my application, though not with the JNDIRealm:

2021-08-31T20:25:13.679 INFORMATION [https-openssl-apr-8443-exec-67]
org.apache.catalina.core.ApplicationContext.log HTMLManager: stop: Stopping web
application '/smartld##001'
2021-08-31T20:25:13.712 INFORMATION [https-openssl-apr-8443-exec-67]
org.apache.catalina.core.ApplicationContext.log
org.tuckey.web.filters.urlrewrite.UrlRewriteFilter INFO: destroy called

> 2021-09-01T15:55:23.726 WARNUNG [deblndw028v.ad001.siemens.net-startStop-3] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [ket##001] appears to have started a thread named [Thread-9] but has
>  java.lang.Object.wait(Native Method)
>  java.lang.Object.wait(Object.java:502)
>  com.sun.jndi.ldap.Connection.pauseReader(Connection.java:840)
>  com.sun.jndi.ldap.Connection.run(Connection.java:983)
>  java.lang.Thread.run(Thread.java:748)

which comes right after a stop in the manager app or a container shutdown:
> 2021-09-01T15:55:19.615 INFORMATION [main] org.apache.catalina.core.StandardServer.await A valid shutdown command was received via the shutdown port. Stopping the Server instance.
> 2021-09-01T15:55:19.616 INFORMATION [main] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["https-openssl-apr-8443"]
> 2021-09-01T15:55:19.635 INFORMATION [main] org.apache.catalina.core.StandardService.stopInternal Stopping service [Catalina]
> 2021-09-01T15:55:19.638 INFORMATION [deblndw028v.ad001.siemens.net-startStop-3] org.apache.catalina.core.ApplicationContext.log Destroying Spring FrameworkServlet 'dispatch'
> 2021-09-01T15:55:23.530 INFORMATION [deblndw028v.ad001.siemens.net-startStop-3] org.apache.catalina.core.ApplicationContext.log Closing Spring root WebApplicationContext


I think a solution within the JDK should be pursued first.

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 65553] Orphaned thread by JNDIRealm / clearReferencesThreads reports memory leak

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=65553

Mark Thomas <ma...@apache.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|---                         |FIXED

--- Comment #6 from Mark Thomas <ma...@apache.org> ---
Work-around added in:
- 10.1.x for 10.1.0-M6 onwards
- 10.0.x for 10.0.12 onwards
- 9.0.x for 9.0.54 onwards
- 8.5.x for 8.5.72 onwards

It will need to stay in place for these versions. Once there a fix in the JRE
and Tomcat's minimum JRE version is known to include the fix, then we can
remove the work-around.

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 65553] Orphaned thread by JNDIRealm / clearReferencesThreads reports memory leak

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=65553

--- Comment #5 from Mark Thomas <ma...@apache.org> ---
OpenJDK bug created

https://bugs.openjdk.java.net/browse/JDK-8273874

We will still need to address this in Tomcat to cover the time until we can
guarantee that the version of the JRE that Tomcat is running on has the
appropriate fix.

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 65553] Orphaned thread by JNDIRealm / clearReferencesThreads reports memory leak

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=65553

--- Comment #3 from Thomas Hoffmann <Th...@speed4trade.com> ---
Hello Michael,
if the leak is reported without using JNDIRealm, it might be
that your application creates an LDAP-Query or InitialDirContext without
closing it?
Maybe you can use a breakpoint in "com.sun.jndi.ldap.Connection" to see which
code is causing the thread to start.
I opened the bug because Tomcat is causing the thread to start, out of the
scope of the web-application. It can also happen that a web application causes
this leak report but then the application might be able to handle it.

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 65553] Orphaned thread by JNDIRealm / clearReferencesThreads reports memory leak

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=65553

--- Comment #4 from Michael Osipov <mi...@apache.org> ---
(In reply to Thomas Hoffmann from comment #3)
> Hello Michael,
> if the leak is reported without using JNDIRealm, it might be
> that your application creates an LDAP-Query or InitialDirContext without
> closing it?
> Maybe you can use a breakpoint in "com.sun.jndi.ldap.Connection" to see
> which code is causing the thread to start.
> I opened the bug because Tomcat is causing the thread to start, out of the
> scope of the web-application. It can also happen that a web application
> causes this leak report but then the application might be able to handle it.

One of the reasons is https://github.com/spring-projects/spring-ldap/issues/489

I have reviewed other spots, but always close/release connections as well as
naming enumerations. One reaons could be that I create test connection in
startInternal and that could be subject to not the webapp classloader.
I guess I have missed something.

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org