Bug 31171 - ClassCastException in org.apache.jasper.runtime.PageContextImpl.getException
Summary: ClassCastException in org.apache.jasper.runtime.PageContextImpl.getException
Status: RESOLVED FIXED
Alias: None
Product: Tomcat 5
Classification: Unclassified
Component: Jasper (show other bugs)
Version: 5.0.19
Hardware: All other
: P3 normal (vote)
Target Milestone: ---
Assignee: Tomcat Developers Mailing List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2004-09-10 16:53 UTC by Steve Revilak
Modified: 2004-11-16 19:05 UTC (History)
0 users



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Steve Revilak 2004-09-10 16:53:50 UTC
I am writing to report a case where calling PageContextImpl.getException()
can result in a ClassCastException.  This occurred in tomcat 5.0.19,
but examination of tomcat 5.0.28's source code, the problem could
occur there as well.

In my application, I have an jsp declared as an error page.  This
error page uses a tag to record some additional information.  The
first few lines of this tag are as follows:

    public void doTag() throws IOException, JspException
    {
	try {

	    PageContext context = (PageContext)getJspContext();
	    JspWriter out = context.getOut();
            HttpServletRequest request = (HttpServletRequest) context.getRequest();
            Throwable error = context.getException();
            // proceed to log the exception and some of the
            // surrounding contextual information

In one case, the `catch' associated with this try caught a
ClassCastException from PageContextImpl.getException():

  // line 608 in 5.0.19's PageContextImpl.java
  // line 560 in 5.0.28's PageContextImpl.java
  public Exception getException() { return (Exception)request.getAttribute(EXCEPTION); }


This would occur if the error was a result of a java.lang.Throwable.


What possible paths might lead up to this?

The _jspService() generated by JspC typically terminates with
something like the following:

    } catch (Throwable t) {
      if (!(t instanceof SkipPageException)){
        out = _jspx_out;
        if (out != null && out.getBufferSize() != 0)
          out.clearBuffer();
        if (pageContext != null) pageContext.handlePageException(t);
      }
    } finally {
      if (_jspxFactory != null) _jspxFactory.releasePageContext(pageContext);
    }

It's catching a Throwable.

PageContextImpl.handlePageException() (lines 730 - 745 in version
5.0.28) does this: 


   public void handlePageException(final Throwable t)
        throws IOException, ServletException
    {
        if (t == null)
            throw new NullPointerException("null Throwable");

        if (System.getSecurityManager() != null){
            try{
                AccessController.doPrivileged(new PrivilegedExceptionAction(){
                    public Object run() throws Exception{
                        doHandlePageException(t);
                        return null;
                    }
                });


It's dealing with throwables.

Continuing on to doHandlePageException(), (lines 763 - 786 in version
5.0.28):

    private void doHandlePageException(Throwable t)
        throws IOException, ServletException {

        if (errorPageURL != null && !errorPageURL.equals("")) {

            /*
             * Set request attributes.
             * Do not set the javax.servlet.error.exception attribute here
             * (instead, set in the generated servlet code for the error page)
             * in order to prevent the ErrorReportValve, which is invoked as
             * part of forwarding the request to the error page, from
             * throwing it if the response has not been committed (the response
             * will have been committed if the error page is a JSP page).
             */
            request.setAttribute("javax.servlet.jsp.jspException", t);
            request.setAttribute("javax.servlet.error.status_code",
                new Integer(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
            request.setAttribute("javax.servlet.error.request_uri",
            ((HttpServletRequest) request).getRequestURI());
            request.setAttribute("javax.servlet.error.servlet_name",
                     config.getServletName());
                try {
                    forward(errorPageURL);


It's also dealing with Throwables.


The following two (short) jsp files reproduce the problem consistently.


--------------- Page: foo.jsp -----------------------------------
<%@ page session="false"
         language="java" 
         errorPage="/myerror.jsp"
%>

<html><body>hello world</body></html>
<%
  if (1 + 1 == 2) {
    throw new Throwable("The cake fell in the mud");
  }
%>
------------------------------------------------------------------


------------------- Page: myerror.jsp ----------------------------
<!-- myerror.jsp -->
<%@ page session="false"
         language="java"
         isErrorPage="true"
         import="java.io.PrintWriter"
%>

An error occurred:

<pre>
<%
out.println(pageContext.getException().toString());

%>
</pre>
------------------------------------------------------------------


Perhaps getException() could take extra steps to ensure that the
object being returned is indeed an exception (and wrap it if it's
not).
Comment 1 Yoav Shapira 2004-09-15 18:14:29 UTC
Good, interesting catch.  It seems like something simple in the PageContext 
imlpementation, like

if(! (exception instanceof Exception)) {
  exception = new JspException(exception);
}

would be a good wrap.  It only wraps if needed, and the JspException 
constructor takes a Throwable root cause, so I think we'll be all set.  I'll 
wait to see what more experienced Jasper developers (Kin-Man?) think of this.
Comment 2 Steve Revilak 2004-09-19 02:04:05 UTC
Yoav Shapira's suggestion (2004-09-15 18:14) seems like a reasonable way to handle this.  If my 
opinion matters :)
Comment 3 Yoav Shapira 2004-09-20 18:09:33 UTC
Fixed for 5.0.29 and 5.5.3.