Author: rjung Date: Thu May 6 19:17:49 2010 New Revision: 941868 URL: http://svn.apache.org/viewvc?rev=941868&view=rev Log: BZ48903: Fix deadlock in webapp class loader. Backport of r927565 and r927877 from trunk. Already applied to TC 5.5 as r935947.
Modified: tomcat/tc6.0.x/trunk/STATUS.txt tomcat/tc6.0.x/trunk/java/org/apache/catalina/loader/ResourceEntry.java tomcat/tc6.0.x/trunk/java/org/apache/catalina/loader/WebappClassLoader.java tomcat/tc6.0.x/trunk/java/org/apache/jasper/servlet/JasperLoader.java tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml Modified: tomcat/tc6.0.x/trunk/STATUS.txt URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/STATUS.txt?rev=941868&r1=941867&r2=941868&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/STATUS.txt (original) +++ tomcat/tc6.0.x/trunk/STATUS.txt Thu May 6 19:17:49 2010 @@ -142,28 +142,6 @@ PATCHES PROPOSED TO BACKPORT: kkolinko: We have to mention the new parameter in jasper-howto.html#Configuration -* Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=48903 - and https://issues.apache.org/bugzilla/show_bug.cgi?id=48694#c8 - Fix deadlock /sync issues in WebappClassLoader. Revert to using - synchronized(this) as analysis and experience shows anything else will just - cause problems - The patch looks huge but it just removes the sync block and sync's the method - http://svn.apache.org/viewvc?rev=927565&view=rev - svn diff -x -w -r927564:927565 http://svn.apache.org/repos/asf/tomcat/trunk - +1: markt, kkolinko, rjung - -1: - - Additional patch: - Mark ResourceEntry.loadedClass as volatile. - http://svn.apache.org/viewvc?rev=927877&view=rev - +1: kkolinko, markt, rjung - -1: - - Note: (kkolinko): Applied to 5.5.x in r935947. The above patches address - BZ 44041, BZ 48903, BZ 48694. Those three issues are to be marked as RESOLVED, - when these patches are applied. - - * Correct SSL session timeout attribute name http://people.apache.org/~markt/patches/2010-04-07-SslSessionTimeout.patch +1: markt Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/loader/ResourceEntry.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/loader/ResourceEntry.java?rev=941868&r1=941867&r2=941868&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/catalina/loader/ResourceEntry.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/loader/ResourceEntry.java Thu May 6 19:17:49 2010 @@ -47,7 +47,7 @@ public class ResourceEntry { /** * Loaded class. */ - public Class loadedClass = null; + public volatile Class loadedClass = null; /** Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/loader/WebappClassLoader.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/loader/WebappClassLoader.java?rev=941868&r1=941867&r2=941868&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/catalina/loader/WebappClassLoader.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/loader/WebappClassLoader.java Thu May 6 19:17:49 2010 @@ -1432,102 +1432,121 @@ public class WebappClassLoader * * @exception ClassNotFoundException if the class was not found */ - public Class loadClass(String name, boolean resolve) + public synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException { - synchronized (name.intern()) { - if (log.isDebugEnabled()) - log.debug("loadClass(" + name + ", " + resolve + ")"); - Class clazz = null; - - // Log access to stopped classloader - if (!started) { - try { - throw new IllegalStateException(); - } catch (IllegalStateException e) { - log.info(sm.getString("webappClassLoader.stopped", name), e); - } + if (log.isDebugEnabled()) + log.debug("loadClass(" + name + ", " + resolve + ")"); + Class clazz = null; + + // Log access to stopped classloader + if (!started) { + try { + throw new IllegalStateException(); + } catch (IllegalStateException e) { + log.info(sm.getString("webappClassLoader.stopped", name), e); } - - // (0) Check our previously loaded local class cache - clazz = findLoadedClass0(name); + } + + // (0) Check our previously loaded local class cache + clazz = findLoadedClass0(name); + if (clazz != null) { + if (log.isDebugEnabled()) + log.debug(" Returning class from cache"); + if (resolve) + resolveClass(clazz); + return (clazz); + } + + // (0.1) Check our previously loaded class cache + clazz = findLoadedClass(name); + if (clazz != null) { + if (log.isDebugEnabled()) + log.debug(" Returning class from cache"); + if (resolve) + resolveClass(clazz); + return (clazz); + } + + // (0.2) Try loading the class with the system class loader, to prevent + // the webapp from overriding J2SE classes + try { + clazz = system.loadClass(name); if (clazz != null) { - if (log.isDebugEnabled()) - log.debug(" Returning class from cache"); if (resolve) resolveClass(clazz); return (clazz); } - - // (0.1) Check our previously loaded class cache - clazz = findLoadedClass(name); - if (clazz != null) { - if (log.isDebugEnabled()) - log.debug(" Returning class from cache"); - if (resolve) - resolveClass(clazz); - return (clazz); + } catch (ClassNotFoundException e) { + // Ignore + } + + // (0.5) Permission to access this class when using a SecurityManager + if (securityManager != null) { + int i = name.lastIndexOf('.'); + if (i >= 0) { + try { + securityManager.checkPackageAccess(name.substring(0,i)); + } catch (SecurityException se) { + String error = "Security Violation, attempt to use " + + "Restricted Class: " + name; + log.info(error, se); + throw new ClassNotFoundException(error, se); + } } - - // (0.2) Try loading the class with the system class loader, to prevent - // the webapp from overriding J2SE classes + } + + boolean delegateLoad = delegate || filter(name); + + // (1) Delegate to our parent if requested + if (delegateLoad) { + if (log.isDebugEnabled()) + log.debug(" Delegating to parent classloader1 " + parent); + ClassLoader loader = parent; + if (loader == null) + loader = system; try { - clazz = system.loadClass(name); + clazz = loader.loadClass(name); if (clazz != null) { + if (log.isDebugEnabled()) + log.debug(" Loading class from parent"); if (resolve) resolveClass(clazz); return (clazz); } } catch (ClassNotFoundException e) { - // Ignore - } - - // (0.5) Permission to access this class when using a SecurityManager - if (securityManager != null) { - int i = name.lastIndexOf('.'); - if (i >= 0) { - try { - securityManager.checkPackageAccess(name.substring(0,i)); - } catch (SecurityException se) { - String error = "Security Violation, attempt to use " + - "Restricted Class: " + name; - log.info(error, se); - throw new ClassNotFoundException(error, se); - } - } + ; } - - boolean delegateLoad = delegate || filter(name); - - // (1) Delegate to our parent if requested - if (delegateLoad) { + } + + // (2) Search local repositories + if (log.isDebugEnabled()) + log.debug(" Searching local repositories"); + try { + clazz = findClass(name); + if (clazz != null) { if (log.isDebugEnabled()) - log.debug(" Delegating to parent classloader1 " + parent); - ClassLoader loader = parent; - if (loader == null) - loader = system; - try { - clazz = loader.loadClass(name); - if (clazz != null) { - if (log.isDebugEnabled()) - log.debug(" Loading class from parent"); - if (resolve) - resolveClass(clazz); - return (clazz); - } - } catch (ClassNotFoundException e) { - ; - } + log.debug(" Loading class from local repository"); + if (resolve) + resolveClass(clazz); + return (clazz); } - - // (2) Search local repositories + } catch (ClassNotFoundException e) { + ; + } + + // (3) Delegate to parent unconditionally + if (!delegateLoad) { if (log.isDebugEnabled()) - log.debug(" Searching local repositories"); + log.debug(" Delegating to parent classloader at end: " + parent); + ClassLoader loader = parent; + if (loader == null) + loader = system; try { - clazz = findClass(name); + clazz = loader.loadClass(name); if (clazz != null) { if (log.isDebugEnabled()) - log.debug(" Loading class from local repository"); + log.debug(" Loading class from parent"); if (resolve) resolveClass(clazz); return (clazz); @@ -1535,30 +1554,10 @@ public class WebappClassLoader } catch (ClassNotFoundException e) { ; } - - // (3) Delegate to parent unconditionally - if (!delegateLoad) { - if (log.isDebugEnabled()) - log.debug(" Delegating to parent classloader at end: " + parent); - ClassLoader loader = parent; - if (loader == null) - loader = system; - try { - clazz = loader.loadClass(name); - if (clazz != null) { - if (log.isDebugEnabled()) - log.debug(" Loading class from parent"); - if (resolve) - resolveClass(clazz); - return (clazz); - } - } catch (ClassNotFoundException e) { - ; - } - } - - throw new ClassNotFoundException(name); } + + throw new ClassNotFoundException(name); + } @@ -2544,7 +2543,7 @@ public class WebappClassLoader if (clazz != null) return clazz; - synchronized (name.intern()) { + synchronized (this) { clazz = entry.loadedClass; if (clazz != null) return clazz; Modified: tomcat/tc6.0.x/trunk/java/org/apache/jasper/servlet/JasperLoader.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/jasper/servlet/JasperLoader.java?rev=941868&r1=941867&r2=941868&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/jasper/servlet/JasperLoader.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/jasper/servlet/JasperLoader.java Thu May 6 19:17:49 2010 @@ -91,7 +91,7 @@ public class JasperLoader extends URLCla * * @exception ClassNotFoundException if the class was not found */ - public Class loadClass(final String name, boolean resolve) + public synchronized Class loadClass(final String name, boolean resolve) throws ClassNotFoundException { Class clazz = null; @@ -169,4 +169,4 @@ public class JasperLoader extends URLCla public final PermissionCollection getPermissions(CodeSource codeSource) { return permissionCollection; } -} \ No newline at end of file +} Modified: tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml?rev=941868&r1=941867&r2=941868&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml (original) +++ tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml Thu May 6 19:17:49 2010 @@ -47,6 +47,9 @@ address via the HTTP WWW-Authenticate header when using BASIC or DIGEST authentication. (markt) </fix> + <fix> + <bug>48903</bug>: Fix deadlock in webapp class loader. (rjung) + </fix> <add> Include context name when reporting memory leaks to aid root cause identification. (markt) --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org