Join GitHub today
GitHub is home to over 36 million developers working together to host and review code, manage projects, and build software together.Sign up
Embedded cglib 3.2.5 not closing input streams that read class files [SPR-16267] #20814
cglib 3.2.5, which is currently the latest released cglib version and is the version that Spring embeds in spring-core, has a bug where it calls ClassLoader getResourceAsStream but never closes the stream. I've reported this cglib problem here: cglib/cglib#115
The bug is in cglib.proxy.BridgeMethodResolver's resolveAll method. Spring can arrive in that code when a Spring configuration class requires synthetic bridge methods as part of Java's type erasure for generics. For example, I'm attaching an example to this issue where I have an ApplicationListener class that listens for ContextRefreshedEvents using a generic, like this:
At web application startup, the presence of that class results in Spring invoking the problematic BridgeMethodResolver code via the path shown in this stack trace:
The serious consequence of this bug shows up when my web application is deployed to Tomcat 8.5 on Windows, Tomcat refuses to undeploy the web application -- I have to shut down the entire Tomcat server. This happens because Tomcat's classloader keeps a Windows file lock on jar files when someone has an open input stream on one of the classes in the jar file (such as when opened by classLoader.getResourceAsStream in cglib's BridgeMethodResolver). This is a substantial problem for users of my web application, since they cannot upgrade it without shutting down Tomcat, which often means that users get kicked out of all other web applications that Tomcat is hosting.
To reproduce the problem, unpack the attached spring-locked-file.zip, and run "mvn package" in the top-level directory (use Java 8). It creates two thing: a separate jar file (locked-jar-1.0-SNAPSHOT.jar, built in the "jar" subproject) that contains the ListenerSpringConfig class shown above, and a war file (built in the "war" subproject) that contains that jar file in its WEB-INF/lib. The "mvn package" will result in a war file named locked-file-1.0-SNAPSHOT.war in war/target. Deploy that war file in Tomcat 8.5 on Windows. Wait for the web application to finish deploying, then undeploy the web application. The application will not undeploy completely, and the deployed war directory will still contain WEB-INF/lib/locked-jar-1.0-SNAPSHOT after the undeployment attempt, because Tomcat still has the jar file open because of the never-closed InputStream, and Windows does not allow an open file to be deleted. I tried with both Tomcat 8.5.14 and the most-recent 8.5.23, and the problem occurs with both.
Affects: 4.3.9, 4.3.13
Backported to: 4.3.14