Bug 46354 - LIMIT_BUFFER setting causes arraycopy errors
LIMIT_BUFFER setting causes arraycopy errors
Status: RESOLVED FIXED
Product: Tomcat 5
Classification: Unclassified
Component: Jasper
5.5.27
All Linux
: P2 major (vote)
: ---
Assigned To: Tomcat Developers Mailing List
:
Depends on:
Blocks:
  Show dependency tree
 
Reported: 2008-12-05 09:01 UTC by Ed Hill
Modified: 2009-05-25 02:38 UTC (History)
0 users



Attachments
webapp that reproduces the issue (828 bytes, application/zip)
2009-01-03 17:11 UTC, Konstantin Kolinko
Details
patch for BodyContentImpl class of tc6.0.x (2.15 KB, patch)
2009-01-03 18:33 UTC, Konstantin Kolinko
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Ed Hill 2008-12-05 09:01:51 UTC
Per the advice in this issue:

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

We just tried to apply the following setting to our Tomcat instances

-Dorg.apache.jasper.runtime.BodyContentImpl.LIMIT_BUFFER=true

A short time after applying this setting, we would start seeing the following stack traces on various random requests.

SEVERE: Servlet.service() for servlet jsp threw exception
java.lang.ArrayIndexOutOfBoundsException
        at java.lang.System.arraycopy(System.java)
        at java.lang.String.getChars(String.java:855)
        at org.apache.jasper.runtime.BodyContentImpl.write(BodyContentImpl.java:146)
        at org.apache.jasper.runtime.BodyContentImpl.write(BodyContentImpl.java:159)
        at org.apache.jsp.tag.web.arch.patterns.DetailInspector.list_tag._jspx_meth_c_005fif_005f3(list_tag.java:683)
        at org.apache.jsp.tag.web.arch.patterns.DetailInspector.list_tag._jspx_meth_c_005fforEach_005f0(list_tag.java:630)
        at org.apache.jsp.tag.web.arch.patterns.DetailInspector.list_tag.doTag(list_tag.java:302)
        at org.apache.jsp.WEB_002dINF.pages.registrar.academic.Student.inspect.pgmstudy_002dtab_jsp._jspx_meth_detail_005flist_005f0(pgmstudy_002dtab_jsp.java:224)
        at org.apache.jsp.WEB_002dINF.pages.registrar.academic.Student.inspect.pgmstudy_002dtab_jsp.access$0(pgmstudy_002dtab_jsp.java:214)
        at org.apache.jsp.WEB_002dINF.pages.registrar.academic.Student.inspect.pgmstudy_002dtab_jsp$pgmstudy_002dtab_jspHelper.invoke0(pgmstudy_002dtab_jsp.java:492)
        at org.apache.jsp.WEB_002dINF.pages.registrar.academic.Student.inspect.pgmstudy_002dtab_jsp$pgmstudy_002dtab_jspHelper.invoke(pgmstudy_002dtab_jsp.java:571)
        at org.apache.jsp.tag.web.arch.patterns.DetailInspector.inspector_tag.doTag(inspector_tag.java:163)
        at org.apache.jsp.WEB_002dINF.pages.registrar.academic.Student.inspect.pgmstudy_002dtab_jsp._jspService(pgmstudy_002dtab_jsp.java:151)
        at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:98)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
        at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:328)
        at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:315)
        at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:265)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
        ...

If we remove the setting, then things behave normally (albeit with the memory issues discussed in the linked issue).

We are running on top of java version 1.6.0.
Comment 1 Mark Thomas 2008-12-05 09:04:34 UTC
Upgrading to 5.5.27 may well fix this.
Comment 2 Ed Hill 2008-12-05 09:16:25 UTC
I will try, but nothing in the release notes jumped out at me...
Comment 3 Ed Hill 2008-12-08 09:06:04 UTC
I've upgraded to Tomcat-5.5.27 and Java 1.6.0_11 and I still am getting the exception (with a slightly different stack trace - just not showing the arraycopy)

Dec 8, 2008 10:57:20 AM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet StripesDispatcher threw exception
java.lang.ArrayIndexOutOfBoundsException
        at java.lang.String.getChars(String.java:855)
        at org.apache.jasper.runtime.BodyContentImpl.write(BodyContentImpl.java:146)
        at org.apache.jasper.runtime.BodyContentImpl.write(BodyContentImpl.java:159)
        at org.apache.jsp.tag.web.labelAndValue_tag._jspx_meth_c_005fif_005f1(labelAndValue_tag.java:1069)
        at org.apache.jsp.tag.web.labelAndValue_tag._jspx_meth_c_005fif_005f0(labelAndValue_tag.java:1039)
        at org.apache.jsp.tag.web.labelAndValue_tag.doTag(labelAndValue_tag.java:304)
        at org.apache.jsp.WEB_002dINF.pages.admissions.prospects.Prospect.inspect.person_002dtab_jsp._jspx_meth_tags_005flabelAndValue_005f0(person_002dtab_jsp.java:608)
        at org.apache.jsp.WEB_002dINF.pages.admissions.prospects.Prospect.inspect.person_002dtab_jsp._jspService(person_002dtab_jsp.java:199)
        at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:98)
Comment 4 Konstantin Kolinko 2009-01-03 16:14:26 UTC
This is caused by bug in implementation of o.a.jasper.runtime.BodyContentImpl#setWriter(Writer)
in current tc6.0.x and tc5.5.x code (and thus in TC 6.0.18, TC 5.5.27).

That method is called by PageContextImpl#pushBody(Writer) and is the one that prepares the bodycontent instance for reuse.

The current code, with comments omitted, is the following:

558:    void setWriter(Writer writer) {
559:        this.writer = writer;
560:        closed = false;
561:        if (writer != null) {
571:            if (bufferSize != 0) {
572:                bufferSizeSave = bufferSize;
573:                bufferSize = 0;
574:            }
575:        } else {
576:            bufferSize = bufferSizeSave;
577:            clearBody();
578:        }
579:    }

The unconditional assignment on line 576 is wrong.

Consider the following sequence of events:
1. setWriter(null)
   bufferSize = bufferSizeSave  is assigned 0 // <- this is wrong (1)
2. write more than 512 bytes of data
   bufferSize becomes > 512

3. setWriter(writer)
   bufferSizeSave = bufferSize  is assigned value that is > 512

4. setWriter(null)
   bufferSize = bufferSizeSave  is > 512
   BodyContentImpl#clear() is called and shrinks the buffer to its default size of 512, bufferSize becomes 512
5. write several bytes of data

6. setWriter(null)
   bufferSize = bufferSizeSave  is > 512  // <- this is wrong (2)
7. write more than 512 bytes of data

At this point the ArrayIndexOutOfBoundsException should occur, because bufferSize is > 512, but the buffer is only 512 bytes.
Comment 5 Konstantin Kolinko 2009-01-03 17:11:01 UTC
Created attachment 23076 [details]
webapp that reproduces the issue

To reproduce the issue:

1. deploy the war file
2. append the following line to conf/catalina.properties :
org.apache.jasper.runtime.BodyContentImpl.LIMIT_BUFFER=true
3. launch the server and access http://localhost:8080/bug46354/
4. Error 500 report is observed with stacktrace of 
java.lang.ArrayIndexOutOfBoundsException exception

Without step 2. the page works and displays some text.

Reproducible in TC 5.5.27 and in current tc6.0.x
Comment 6 Konstantin Kolinko 2009-01-03 18:33:11 UTC
Created attachment 23077 [details]
patch for BodyContentImpl class of tc6.0.x

I think that the straightforward way to fix this is to remove the private bufferSizeSave field and the trick from the #setWriter() method and to overwrite the #getBufferSize() method.

The bufferSize field is just declared in JspWriter and is not used for calculations neither there nor in BodyContent class, nor the JSP 2.1 spec requires any calculations from them (all methods except the #getBufferSize() getter are abstract). All the calculations are implemented in BodyContentImpl.

Thus the attached patch. It fixes the issue.
Comment 7 Mark Thomas 2009-04-09 08:14:22 UTC
Many thanks for the test case and patch, as well as your efforts in tracking this one down.

The patch has been applied to trunk and proposed for 6.0.x and 5.5.x
Comment 8 Mark Thomas 2009-04-28 06:32:43 UTC
This has been fixed in 6.0.x and will be included in 6.0.20 onwards. Thanks again for the patch.
Comment 9 Mark Thomas 2009-05-25 02:38:56 UTC
This has been fixed in 5.5.x and will be included in 5.5.28 onwards