Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8015099

Classloading boundary crossing in Java 7

    Details

    • Type: Bug
    • Status: Closed
    • Priority: P3
    • Resolution: Fixed
    • Affects Version/s: 7
    • Fix Version/s: 9
    • Component/s: xml
    • Labels:

      Description

      FULL PRODUCT VERSION :
      Since Java 1.7.0_01. Problem is worse starting in at least Java 7u13.

      ADDITIONAL OS VERSION INFORMATION :
      OSes reproduced on include multiple versions of Windows and OS X.

      EXTRA RELEVANT SYSTEM CONFIGURATION :
      reproduced using both Tomcat (any version) and Jetty (v8.1.9). Therefore this does not appear to be servlet container specific and the hypothesis is that this is really a classloading problem in java itself. i.e. this could probably be duplicated in a standalone application that has more than one classloader.

      A DESCRIPTION OF THE PROBLEM :
      we have two web applications. One uses the AntiSAMY XSS prevention software from OWASP.org. This software, unfortunately, is dependent on a the Apache Xerces parser (NOT the derivation that is in Java itself.). I have posted a separate bug with the AntiSAMY developers to remove this dependency.

      The first web app loads the Apache Xerces parser via a call to XMLReaderFactory.createXMLReader(); and gets the Apach Xerces version (the Apache Xerces library is included in this particular webapps lib directory).

      The second web app does NOT use AntiSAMY and does not have the Apache Xerces parser library in its webapp lib directory. But it does also need *some* XML parser so it too calls XMLReaderFactory.createXMLReader(); to get a parser, expecting to get the parser supplied by Java itself.

      The problem is that, beginning with Java 7, the second web app createXMLReader call is failing because it looks specifically for the Apache Xerces parser the first webapp already loaded and can't find it (of course). ClassNotFoundException.



      REGRESSION. Last worked in version 6u31

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      deploy the servlets provided below. Include the Apache Xerces library in only the first web app lib dir. (xercesImpl.jar and xml-apis.jar). I don't think the version is important, just use a relative recent version.

      Execute the first web app's doGet() method.

      Now execute the second web app's doGet() method.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      each webapp finds an XML parser, prints out the classpath for that parser in the browser window.
      ACTUAL -
      the second webapp does not find the default XML parser (com.sun.org.apache.xerces.internal.parsers.SAXParser) and instead tries to load org.apache.xerces.parsers.SAXParser because the first webapp already loaded it.

      A ClassNotFoundException is thrown and the stack trace appears in the browser window.

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      java.lang.ClassNotFoundException: org.apache.xerces.parsers.SAXParser
      org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1701)
      org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1546)
      org.xml.sax.helpers.NewInstance.newInstance(NewInstance.java:73)
      org.xml.sax.helpers.XMLReaderFactory.loadClass(XMLReaderFactory.java:227)
      org.xml.sax.helpers.XMLReaderFactory.createXMLReader(XMLReaderFactory.java:190)
      ServletTwo.doGet(ServletTwo.java:28)
      javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
      javax.servlet.http.HttpServlet.service(HttpServlet.java:722)

      REPRODUCIBILITY :
      This bug can be reproduced often.

      ---------- BEGIN SOURCE ----------
      import org.xml.sax.SAXException;
      import org.xml.sax.XMLReader;
      import org.xml.sax.helpers.XMLReaderFactory;

      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.io.IOException;
      import java.io.OutputStream;

      public class ServletOne extends HttpServlet {

          public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException
          {

              StringBuilder sb = new StringBuilder( " ServletOne XMLReader class: " );

              try {

                  XMLReader reader = XMLReaderFactory.createXMLReader();
                  sb.append(reader.getClass().getName());

              } catch (SAXException e) {

                 throw new RuntimeException(e);

              }

              OutputStream os = response.getOutputStream();

              os.write(sb.toString().getBytes());

          }

      }



      ---------------------------------------------------------------------------------------------------




      import org.xml.sax.SAXException;
      import org.xml.sax.XMLReader;
      import org.xml.sax.helpers.XMLReaderFactory;

      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.io.IOException;
      import java.io.OutputStream;

      public class ServletTwo extends HttpServlet {

          public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException
          {

              // At one point, the line below would fix the problem on all platforms. Since Java 7u11, it only fixes it on some.
              //System.setProperty( " org.xml.sax.driver " , " com.sun.org.apache.xerces.internal.parsers.SAXParser " );

              StringBuilder sb = new StringBuilder( " ServletTwo XMLReader class: " );

              try {

                  // the java classloading bug exhibits here class not found exception for parser
                  // note: at this point we can pass in the classpath as a String to createXMLReader and that works.
                  XMLReader reader = XMLReaderFactory.createXMLReader();

                  sb.append(reader.getClass().getName());

              } catch (SAXException e) {

                  throw new RuntimeException(e);

              }

              OutputStream os = response.getOutputStream();

              os.write(sb.toString().getBytes());

          }

      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      With Java 1.7.0_01 up to Java 7u11, we were able to work around the problem by specifying the following line in the second web app.

      System.setProperty( " org.xml.sax.driver " , " com.sun.org.apache.xerces.internal.parsers.SAXParser " );

      Beginning with Java 7u13 (tested with u15 too), the above workaround no longer works on SOME environments, notably certain Windows OSes, but the problem isn't reliably duplicated.

      The new workaround is to explicit state the classpath for the parser in createXMLReader(). e.g. XMLReaderFactory.createXMLReader( " com.sun.org.apache.xerces.internal.parsers.SAXParser " );


      We can also workaround the problem by including the Apache Xerces libraries in the second web apps lib dir.

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                joehw Joe Wang
                Reporter:
                webbuggrp Webbug Group
              • Votes:
                0 Vote for this issue
                Watchers:
                3 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: