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

StackOverflowError when using URLStreamHandlerFactory in WebAppClassloader #1448

Closed
joakime opened this issue Apr 4, 2017 · 5 comments
Closed
Assignees
Labels
Bug For general bugs on Jetty side

Comments

@joakime
Copy link
Contributor

joakime commented Apr 4, 2017

If an environment has a URLStreamHandler installed, its possible for a StackOverflowError to occur when in the WebAppClassloader ...

Exception in thread "FelixStartLevel" java.lang.StackOverflowError
 	at org.apache.felix.framework.URLHandlers.createURLStreamHandler(URLHandlers.java:495)
 	at java.net.URL.getURLStreamHandler(URL.java:1142)
 	at java.net.URL.<init>(URL.java:599)
 	at java.net.URL.<init>(URL.java:490)
 	at java.net.URL.<init>(URL.java:439)
 	at org.eclipse.jetty.util.resource.Resource.newResource(Resource.java:166)
 	at org.eclipse.jetty.util.resource.Resource.newResource(Resource.java:149)
 	at org.eclipse.jetty.util.TypeUtil.getLoadedFrom(TypeUtil.java:726)
 	at org.eclipse.jetty.webapp.ClasspathPattern.match(ClasspathPattern.java:518)
 	at org.eclipse.jetty.webapp.WebAppContext.isServerClass(WebAppContext.java:811)
 	at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:563)
 	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
 	at org.apache.felix.framework.URLHandlers.createURLStreamHandler(URLHandlers.java:495)
 	at java.net.URL.getURLStreamHandler(URL.java:1142)
 	at java.net.URL.<init>(URL.java:599)
 	at java.net.URL.<init>(URL.java:490)
 	at java.net.URL.<init>(URL.java:439)
 	at org.eclipse.jetty.util.resource.Resource.newResource(Resource.java:166)
 	at org.eclipse.jetty.util.resource.Resource.newResource(Resource.java:149)
 	at org.eclipse.jetty.util.TypeUtil.getLoadedFrom(TypeUtil.java:726)
 	at org.eclipse.jetty.webapp.ClasspathPattern.match(ClasspathPattern.java:518)
 	at org.eclipse.jetty.webapp.WebAppContext.isServerClass(WebAppContext.java:811)
 	at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:563)
 	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
 	at org.apache.felix.framework.URLHandlers.createURLStreamHandler(URLHandlers.java:495)
 	at java.net.URL.getURLStreamHandler(URL.java:1142)
 	at java.net.URL.<init>(URL.java:599)
 	at java.net.URL.<init>(URL.java:490)
@joakime joakime added the Bug For general bugs on Jetty side label Apr 4, 2017
@joakime joakime self-assigned this Apr 4, 2017
@joakime joakime changed the title Minimize URL object creation in Classloader work Minimize new URL object creation in Classloader work Apr 4, 2017
@joakime joakime changed the title Minimize new URL object creation in Classloader work StackOverflowError when using URLStreamHandlerFactory in WebAppClassloader Apr 4, 2017
@joakime
Copy link
Contributor Author

joakime commented Apr 4, 2017

Been able to reproduce in a simple testcase.

@joakime
Copy link
Contributor Author

joakime commented Apr 20, 2017

There is still a StackOverflowError present, this time from the following code path ...

Exception in thread "FelixStartLevel" java.lang.StackOverflowError
 	at org.apache.felix.framework.URLHandlers.createURLStreamHandler(URLHandlers.java:495)
 	at java.net.URL.getURLStreamHandler(URL.java:1142)
 	at java.net.URL.<init>(URL.java:599)
 	at java.net.URL.<init>(URL.java:490)
 	at java.net.URL.<init>(URL.java:439)
 	at java.net.URI.toURL(URI.java:1089)
 	at org.eclipse.jetty.util.resource.Resource.newResource(Resource.java:87)
 	at org.eclipse.jetty.util.TypeUtil.getLoadedFrom(TypeUtil.java:724)
 	at org.eclipse.jetty.webapp.ClasspathPattern.match(ClasspathPattern.java:518)
 	at org.eclipse.jetty.webapp.WebAppContext.isServerClass(WebAppContext.java:816)
 	at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:563)
 	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
 	at org.apache.felix.framework.URLHandlers.createURLStreamHandler(URLHandlers.java:495)
 	at java.net.URL.getURLStreamHandler(URL.java:1142)
 	at java.net.URL.<init>(URL.java:599)
 	at java.net.URL.<init>(URL.java:490)
 	at java.net.URL.<init>(URL.java:439)
 	at java.net.URI.toURL(URI.java:1089)
 	at org.eclipse.jetty.util.resource.Resource.newResource(Resource.java:87)

@joakime joakime reopened this Apr 20, 2017
joakime added a commit that referenced this issue Apr 24, 2017
…om()

+ Replaced with URI TypeUtil.getLocationOfClass(Class clazz)
+ and File TypeUtil.getLocationOfClassAsFile(Class clazz)
+ This is done to eliminate extraneous "new URL" and "URI.toURL" calls
  that can trigger URL Stream Handler creation and initialization
  which is the cause of the StackOverflowError
@janbartel
Copy link
Contributor

@joakime great that this seems to work, however can you explain how it is working, when I still see references to URL in the new TypeUtil.getLocationOfClass method?

gregw pushed a commit that referenced this issue Apr 26, 2017
…om()

+ Replaced with URI TypeUtil.getLocationOfClass(Class clazz)
+ and File TypeUtil.getLocationOfClassAsFile(Class clazz)
+ This is done to eliminate extraneous "new URL" and "URI.toURL" calls
  that can trigger URL Stream Handler creation and initialization
  which is the cause of the StackOverflowError
gregw added a commit that referenced this issue Apr 26, 2017
Optimized excluded by name handling
@joakime
Copy link
Contributor Author

joakime commented Apr 26, 2017

@janbartel The key is new URL() (and anything that uses new URL(), such as URI.toURL() and Resource.newResource())

The lookup for URLStreamHandler occurs during new URL(), and only on the first time it encounters a new protocol (such as jar, file, http, bundle, etc).

Internally in the JVM has a static / singleton cache of protocol to URLStreamHandler.

The working theory that produced that commit is .. if by the time you call TypeUtil.getLocationOfClass(Class) that particular Class instance has already been loaded via the ClassLoader and whatever URLStreamhandler it needed to load has been initialized already.

@joakime
Copy link
Contributor Author

joakime commented Apr 26, 2017

@gregw tested the new jetty-9.4.x HEAD (with your merge) against felix-webapp.
Works great.
Closing issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug For general bugs on Jetty side
Projects
None yet
Development

No branches or pull requests

2 participants