Bug: StackOverflowError on some unusual filenames

Splash Forums PrettyFaces Users Bug: StackOverflowError on some unusual filenames

This topic contains 9 replies, has 2 voices, and was last updated by  Christian Kaltepoth 4 years, 5 months ago.

Viewing 10 posts - 1 through 10 (of 10 total)
  • Author
    Posts
  • #19198

    adequmoda
    Participant

    Hello, occasionally I use Emacs to edit project files, it writes temporary files like #Test.java# (hash character on each end), and sometimes these temporary files end up in the deployment archive.

    PrettyFaces has a StackOverflowError while scanning classes.

    Somehow it thinks #Test.java# is a directory that needs to be recursed. I checked the file, it’s a plain text copy of the original .java file.

    09:57:01,151 TRACE [com.ocpsoft.pretty.faces.config.annotation.WebClassesFinder] (MSC service thread 1-2) Processing directory: jndi:/default-host/ICRWebTool/WEB-INF/classes/net/concentric/icrwebtool/util/
    09:57:01,153 TRACE [com.ocpsoft.pretty.faces.config.annotation.ByteCodeAnnotationFilter] (MSC service thread 1-2) No reference to PrettyFaces annotations found!
    09:57:01,154 TRACE [com.ocpsoft.pretty.faces.config.annotation.WebClassesFinder] (MSC service thread 1-2) Processing directory: jndi:/default-host/ICRWebTool/WEB-INF/classes/net/concentric/icrwebtool/util/#CacheControlFilter.java#
    ... several hundred of the previous logging message ...
    09:57:06,097 TRACE [com.ocpsoft.pretty.faces.config.annotation.WebClassesFinder] (MSC service thread 1-2) Processing directory: jndi:/default-host/ICRWebTool/WEB-INF/classes/net/concentric/icrwebtool/util/#CacheControlFilter.java#
    09:57:06,099 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/ICRWebTool]] (MSC service thread 1-2) Exception starting filter Pretty Filter: java.lang.StackOverflowError
    at sun.util.calendar.ZoneInfo.getOffsets(ZoneInfo.java:261) [rt.jar:1.7.0_09]
    at sun.util.calendar.ZoneInfo.getOffsets(ZoneInfo.java:248) [rt.jar:1.7.0_09]
    at java.util.GregorianCalendar.computeFields(GregorianCalendar.java:2276) [rt.jar:1.7.0_09]
    at java.util.GregorianCalendar.computeFields(GregorianCalendar.java:2248) [rt.jar:1.7.0_09]
    at java.util.Calendar.setTimeInMillis(Calendar.java:1140) [rt.jar:1.7.0_09]
    at java.util.Calendar.setTime(Calendar.java:1106) [rt.jar:1.7.0_09]
    at java.text.SimpleDateFormat.format(SimpleDateFormat.java:955) [rt.jar:1.7.0_09]
    at java.text.SimpleDateFormat.format(SimpleDateFormat.java:948) [rt.jar:1.7.0_09]
    at java.text.DateFormat.format(DateFormat.java:336) [rt.jar:1.7.0_09]
    at org.jboss.logmanager.formatters.Formatters$5.renderRaw(Formatters.java:245) [jboss-logmanager-1.2.2.GA.jar:1.2.2.GA]
    at org.jboss.logmanager.formatters.Formatters$JustifyingFormatStep.render(Formatters.java:148) [jboss-logmanager-1.2.2.GA.jar:1.2.2.GA]
    at org.jboss.logmanager.formatters.MultistepFormatter.format(MultistepFormatter.java:86) [jboss-logmanager-1.2.2.GA.jar:1.2.2.GA]
    at org.jboss.logmanager.ExtFormatter.format(ExtFormatter.java:35) [jboss-logmanager-1.2.2.GA.jar:1.2.2.GA]
    at org.jboss.logmanager.handlers.WriterHandler.doPublish(WriterHandler.java:49) [jboss-logmanager-1.2.2.GA.jar:1.2.2.GA]
    at org.jboss.logmanager.ExtHandler.publish(ExtHandler.java:64) [jboss-logmanager-1.2.2.GA.jar:1.2.2.GA]
    at org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:283) [jboss-logmanager-1.2.2.GA.jar:1.2.2.GA]
    at org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:291) [jboss-logmanager-1.2.2.GA.jar:1.2.2.GA]
    at org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:291) [jboss-logmanager-1.2.2.GA.jar:1.2.2.GA]
    at org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:291) [jboss-logmanager-1.2.2.GA.jar:1.2.2.GA]
    at org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:291) [jboss-logmanager-1.2.2.GA.jar:1.2.2.GA]
    at org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:291) [jboss-logmanager-1.2.2.GA.jar:1.2.2.GA]
    at org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:291) [jboss-logmanager-1.2.2.GA.jar:1.2.2.GA]
    at org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:291) [jboss-logmanager-1.2.2.GA.jar:1.2.2.GA]
    at org.jboss.logmanager.Logger.logRaw(Logger.java:649) [jboss-logmanager-1.2.2.GA.jar:1.2.2.GA]
    at org.jboss.logmanager.Logger.log(Logger.java:600) [jboss-logmanager-1.2.2.GA.jar:1.2.2.GA]
    at org.jboss.logmanager.Logger.log(Logger.java:612) [jboss-logmanager-1.2.2.GA.jar:1.2.2.GA]
    at org.jboss.logmanager.log4j.BridgeLogger.log(BridgeLogger.java:173)
    at com.ocpsoft.shade.org.apache.commons.logging.impl.Log4JLogger.trace(Log4JLogger.java:152) [prettyfaces-jsf2-3.3.3.jar:]
    at com.ocpsoft.pretty.faces.config.annotation.WebClassesFinder.processDirectory(WebClassesFinder.java:107) [prettyfaces-jsf2-3.3.3.jar:]
    at com.ocpsoft.pretty.faces.config.annotation.WebClassesFinder.processDirectory(WebClassesFinder.java:195) [prettyfaces-jsf2-3.3.3.jar:]
    at com.ocpsoft.pretty.faces.config.annotation.WebClassesFinder.processDirectory(WebClassesFinder.java:195) [prettyfaces-jsf2-3.3.3.jar:]
    at com.ocpsoft.pretty.faces.config.annotation.WebClassesFinder.processDirectory(WebClassesFinder.java:195) [prettyfaces-jsf2-3.3.3.jar:]
    ...several hundred of the previous stack frame ...

    #23328

    adequmoda
    Participant

    I stepped thru with a debugger and identified the problem a little better.

    Silly thing about file operations via the URL interface – the ‘#’ character is the “reference” part of a URL.

    PrettyFaces WebClassesFinder#processDirectory calls ServletContext#getResource(“/WEB-INF/classes/net/concentric/icrwebtool/util/#CacheControlFilter.java#”) which returns a URL consisting of Path “/default-host/ICRWebTool/WEB-INF/classes/net/concentric/icrwebtool/util/” and Ref “CacheControlFilter.java#”. Because the path has a trailing slash PrettyFaces treats the URL as another directory to recurse. Perhaps you have mistaken the contract of ServletContext#getResourcePaths (Set of Strings where trailing slash means directory) with ServletContext#getResource (URL, silly stuff about Scheme, Path, Ref, Query – no ‘trailing slash means directory’ contract).

    Looks like the code doesn’t need to operate on URL at all, can just use the String returned by ServletContext#getResourcePaths.

    #23329

    adequmoda
    Participant

    Attached is a diff that fixes the filename/URL-ref bug.

    #23330

    adequmoda
    Participant

    Huh. This WordPress thing is being weird, “denied extension”? Trying again with a gzip’d copy.

    #23331

    adequmoda
    Participant

    Paste of the diff, hopefully you can see what I mean about avoiding URL and use the String from ServletContext#getResourcePaths so you get the trailing-slash contract.

    --- com/ocpsoft/pretty/faces/config/annotation/WebClassesFinder.java.orig	2012-03-05 19:00:56.000000000 -0800
    +++ com/ocpsoft/pretty/faces/config/annotation/WebClassesFinder.java 2012-12-20 10:49:34.969867014 -0800
    @@ -111,23 +111,20 @@
    String relativeDirectoryName = getPathRelativeToClassesFolder(directoryUrl.getPath(), classesFolderPath);
    // call getResourcePaths to get directory entries
    - Set<?> paths = servletContext.getResourcePaths(CLASSES_FOLDER+relativeDirectoryName);
    + Set<String> paths = servletContext.getResourcePaths(CLASSES_FOLDER+relativeDirectoryName);
    if (paths != null) {
    // loop over all entries of the directory
    - for (Object relativePath : paths)
    + for (String relativePath : paths)
    {
    - // get full URL for this entry
    - URL entryUrl = servletContext.getResource(relativePath.toString());
    -
    // if this URL ends with .class it is a Java class
    - if (entryUrl.getPath().endsWith(".class"))
    + if (relativePath.endsWith(".class"))
    {
    // the name of the entry relative to the '/WEB-INF/classes/' folder
    - String entryRelativeName = getPathRelativeToClassesFolder(entryUrl.getPath(), classesFolderPath);
    + String entryRelativeName = getPathRelativeToClassesFolder(relativePath, classesFolderPath);
    // build class name from relative name
    String className = getClassName(entryRelativeName);
    @@ -152,13 +149,16 @@
    */
    try
    {
    + // get full URL for this entry
    + URL entryUrl = servletContext.getResource(relativePath);
    +
    classFileStream = entryUrl.openStream();
    }
    catch (IOException e)
    {
    if (log.isDebugEnabled())
    {
    - log.debug("Cound not obtain InputStream for class file: " + entryUrl.toString(), e);
    + log.debug("Cound not obtain InputStream for class file: " + relativePath, e);
    }
    }
    @@ -188,8 +188,10 @@
    }
    // if this URL ends with a slash, its a directory
    - if (entryUrl.getPath().endsWith("/"))
    + if (relativePath.endsWith("/"))
    {
    + // get full URL for this entry
    + URL entryUrl = servletContext.getResource(relativePath);
    // walk down the directory
    processDirectory(classesFolderUrl, entryUrl, handler);

    #23332

    Hey Gerald,

    thanks a lot for digging into this issue and providing the patch. I wasn’t aware that # characters may lead to problems when I wrote the code back than. :)

    I think I will find some time in the next days to have a deeper look at this issue. I’m not really sure but it may be that there was a reason why I used the URL class instead of the String representation in these places. Maybe it was related to scanning thought JAR files in the lib folder. But I’ll check that. :)

    Thanks a lot.

    Christian

    #23333

    Hey Gerald,

    I thought about this a bit more in the lat days. IMHO this is actually a bug in the container. If a path contains any number of # characters, the complete name should nevertheless be stored in the “path” component of the URL. It looks like you are using JBoss AS. Which exact version of it?

    Of cause this incorrect behavior of the container shouldn’t lead to a StackOverflowError. But IMHO this could be very easy be replacing entryUrl.getPath() with entryUrl.toString(). But I’ll have a look at this.

    Christian

    #23334

    I was able to reproduce this issue with JBoss AS 7.1.1. And I committed a workaround for this issue:

    https://github.com/ocpsoft/prettyfaces/commit/75c46faf7acd208401abf7c578fc21e57896a316

    These files shouldn’t be a problem any more. If you like, you could give the snapshots a try. But you may need to build them manually. I think the snapshots aren’t automatically deployed at the moment.

    Thanks a lot for reporting this. :)

    #23335

    Some more background info on this one. I’m currently creating a small sample app to reproduce this issue.

    It seems like doing this will always fail:

    URL url = servletContext.getResource("/file#1.txt");
    url.openStream();

    Calling openStream() always throws a FileNotFoundException because it tries to open /file instead of /file#1.txt. This happens on AS7 and also on Tomcat. But I think this is because AS7 uses some Tomcat classes internally.

    Interesting issue. :)

    #23336

    Some more news: Only Tomcat 7.0.20 – 7.0.27 are affected. 7.0.28 and newer works fine.

    The issue is tracked here:

    http://issues.apache.org/bugzilla/show_bug.cgi?id=53257

    Christian

Viewing 10 posts - 1 through 10 (of 10 total)

You must be logged in to reply to this topic.

Comments are closed.