Bug 49667 - JdbcLeakPrevention class can register unregistered JCBC Driver
Summary: JdbcLeakPrevention class can register unregistered JCBC Driver
Alias: None
Product: Tomcat 6
Classification: Unclassified
Component: Catalina (show other bugs)
Version: 6.0.29
Hardware: Sun Solaris
: P2 normal (vote)
Target Milestone: default
Assignee: Tomcat Developers Mailing List
Depends on:
Reported: 2010-07-29 09:31 UTC by Arjen Knibbe
Modified: 2010-10-03 13:36 UTC (History)
0 users

Demo for bug 49667 (720.08 KB, application/zip)
2010-08-25 07:37 UTC, Arjen Knibbe
Demo for bug 49667 - Application B (719.92 KB, application/zip)
2010-08-25 07:39 UTC, Arjen Knibbe

Note You need to log in before you can comment on or make changes to this bug.
Description Arjen Knibbe 2010-07-29 09:31:33 UTC
Suppose there is an web application A that uses a database and registers a Driver with the java.sql.DriverManager, and a web application B that doesn't use a database but has a jar file in its WEB-INF/lib directory that contains the same Driver. Suppose you undeploy web application B.
Running the org.apache.catalina.loader.JdbcLeakPrevention class will actually register the Driver and leave it loaded! The cause is the way the DriverManager checks whether a ClassLoader has permission to load the Driver. It does that by calling Class.forName with the ClassLoader, which will load the class if the class has not been loaded by that ClassLoader. Loading a Driver class triggers the Driver to register itself. 

Steps to reproduce
Create two web applications: one which registeres a Driver with the java.sql.Drivermanager and one that uses no database. Put the jar containing the Driver class in the WEB-INF/lib directory of both applications. Deploy both in Tomcat. Then undeploy the latter one.
Inspect catalina.out, verify that there are no messages about a JDBC Driver being forcibly unregistered.
Create a memory dump using jmap and inspect the dump using jhat.

Actual results
The WebappClassLoader for the latter application is still present. Its "rootset references" page shows two reference chains from class java.sql.DriverManager:
Static reference from java.sql.DriverManager.readDrivers (from class java.sql.DriverManager) :
--> java.util.Vector@0xeb6eb3f0 (24 bytes) (field elementData:)
--> [Ljava.lang.Object;@0xeb6eb408 (20 bytes) (Element 2 of [Ljava.lang.Object;@0xeb6eb408:)
--> java.sql.DriverInfo@0xeb6eb420 (20 bytes) (field driverClass:)
--> class oracle.jdbc.driver.OracleDriver (84 bytes) (??:)
--> org.apache.catalina.loader.WebappClassLoader@0xeb5a84a0 (157 bytes) 

and a similar one from java.sql.DriverManager.writeDrivers.

Expected results
The WebappClassLoader is not present in memory anymore.

Build date & platform
Downloaded Core tar.gz from http://tomcat.apache.org/download-70.cgi
Comment 1 Arjen Knibbe 2010-07-29 10:08:42 UTC
Before making a memory dump, you must wait an hour.
Comment 2 Mark Thomas 2010-08-24 16:51:04 UTC
I don't see this error with the latest 7.0.x code. Please test with 7.0.2 and if you still see the issue please provide sample web applications and the exact steps to reproduce from a clean 7.0.2 install.
Comment 3 Arjen Knibbe 2010-08-25 07:37:16 UTC
Created attachment 25935 [details]
Demo for bug 49667

This tar/zip contains a minimal implementation of the A application as mentioned in the bug Overview. Application B will follow. Both applications contain the MySQL JdbC jar file. A pplication A loads the Driver on startup, B doesn' t.

Starting with a clean Tomcat (no entries in webapps), the bug can be reproduces as follows:
* copy A.war into webapps, wait until catalina.out shows application A deployed.
* copy B.war into webapps, wait until catalina.out shows application B deployed.
* Remove B.war from webapps, wait until catalina.out shows context /B undeployed. Verify that no warning is issued about a Driver being forcilbly unloaded.
* Optionally, wait an hour.
* Trigger a memory dump using jmap, inspect the dump using jhat.
* in the All Classes excluding plathform screen, verify that class com.snt.connect.demo.B.servlet.Servlet is still there.
* Click on the class, then click on its class loader.
* Click on Other Queries/Exclude weak refs, verify that class java.sql.DriverManager is in the System class references, and that class com.mysql.jdbc.Driver is in that reference chain.
Comment 4 Arjen Knibbe 2010-08-25 07:39:02 UTC
Created attachment 25936 [details]
Demo for bug 49667 - Application B

And here is application B. It had to be uploaded separately, since Bugzilla accepts only 1000Kb as attachment :-(
Comment 5 Arjen Knibbe 2010-10-01 05:19:17 UTC
I added attachments and a description how to repoduce the bugs as requested by Mark Thomas (comment 2). See comments 3 and 4. Tested with Tomcat 7.0.2 and jdk 6.0.21 on a Solaris machine.
Comment 6 Mark Thomas 2010-10-01 06:47:44 UTC
Thanks for the sample apps. I can now reproduce this. Looking at a fix now...
Comment 7 Mark Thomas 2010-10-01 07:13:26 UTC
Fixed in trunk and will be included in 7.0.3 onwards.

Proposed for 6.0.x
Comment 8 Arjen Knibbe 2010-10-01 07:16:52 UTC
That was a quick fix Thomas! Thanks a lot.
Comment 9 Mark Thomas 2010-10-03 13:36:57 UTC
Fixed in 6.0.x and will be included in 6.0.30 onwards.