Uploaded image for project: 'Struts 2'
  1. Struts 2
  2. WW-4383

An infinite loop occurs in FastByteArrayOutputStream.java.

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Minor
    • Resolution: Fixed
    • Affects Version/s: 2.3.16.3
    • Fix Version/s: 2.3.20
    • Component/s: Core Actions
    • Labels:
      None

      Description

      An infinite loop occurs in FastByteArrayOutputStream.java.
      The conditions which an infinite loop generates are as follows.

      • The character code of input data is UTF-8.
      • The length of input data is longer than 16 KB.
      • There is a character of a surrogate pair after 16 KB of input data.
      • Example of input data:
        The input data to reproduce repeats 3 bytes of character 5462 times, and the character of a surrogate pair appears behind that.
      • Added to 2014/8/22

      An infinite loop occurs with an include tag.
      The example data as follows.

      <s:include value="infinite.jsp" />
      

      — Content of infinite.jsp —

      <%@ page language="java" contentType="text/html; charset=UTF-8"
          pageEncoding="UTF-8"%>
      <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
      <html>
      <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      <title>Insert title here</title>
      </head>
      <body>
      あああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああい𠮟
      </body>
      </html>
      

      — end of infinite.jsp —

      • Cause
        Is clean of the out buffer necessary for decodeAndWritw method after the output in an out buffer?
        
      private static CoderResult decodeAndWrite(Writer writer, ByteBuffer in, CharBuffer out, CharsetDecoder decoder, boolean endOfInput) throws IOException {
          CoderResult result = decoder.decode(in, out, endOfInput);
          // To begin of decoded data
          out.flip();
          // Output
          writer.write(out.toString());
          return result;
      }
      

        Activity

        Hide
        lukaszlenart Lukasz Lenart added a comment - - edited

        Is it something that can happen during processing Http request or what?

        Show
        lukaszlenart Lukasz Lenart added a comment - - edited Is it something that can happen during processing Http request or what?
        Hide
        SuzukiYoshifumi Suzuki Yoshifumi added a comment -

        An infinite loop occurs with an include tag. The example of the data which an infinite loop generates was added to the detailed column.

        Show
        SuzukiYoshifumi Suzuki Yoshifumi added a comment - An infinite loop occurs with an include tag. The example of the data which an infinite loop generates was added to the detailed column.
        Hide
        lukaszlenart Lukasz Lenart added a comment -

        JDK version? I have tested on 1.7.0_45 and no issue

        Show
        lukaszlenart Lukasz Lenart added a comment - JDK version? I have tested on 1.7.0_45 and no issue
        Hide
        lukaszlenart Lukasz Lenart added a comment -

        Tested on 1.6.0_51 and 1.8.0-b132 - no problem as well

        Show
        lukaszlenart Lukasz Lenart added a comment - Tested on 1.6.0_51 and 1.8.0-b132 - no problem as well
        Hide
        nigel.gay Nigel Gay added a comment -

        We've ran into this now too, sometimes our <s:include> tags get stuck in this loop and max the CPU on our web app out to 100%. The problem as noted above is that "out.flip();" line - this reduces the capacity of the output buffer to equal the number of chars that were decoded. So if you can manufacture an example where:

        • The first 8,192 byte input buffer decodes to lets say 3,000 chars. So processing this reduces the capacity of the output buffer down to 3,000 chars.
        • The second 8,192 byte input buffer decodes to 3,001 chars. So it'll process the first 3,000, then returns with OVERFLOW because the remaining char won't fit in the output buffer.
        • It then loops around again processing the remaining input buffer, and decodes this to the single 3,001st char. At this point it decodes only 1 char, so reduces the size of the output buffer to 1 char. So even if it doesn't get stuck in an infinite loop, this is still very bad because its then looping around decoding only 1 char at a time.
        • The key part in the original poster's test data is that final char, details of which are here - http://www.fileformat.info/info/unicode/char/20b9f/index.htm. Note it says Character.charCount() = 2, so this single UTF-8 entity decodes into 2 Java characters. Since 2 characters cannot fit into an output buffer that's been reduced to 1 character, it gets stuck in an infinite loop.

        I'll attach a runnable example, tested with JDK 1.7.0_67, and both struts2-core.jar 2.3.8 and latest 2.3.16.3.

        Show
        nigel.gay Nigel Gay added a comment - We've ran into this now too, sometimes our <s:include> tags get stuck in this loop and max the CPU on our web app out to 100%. The problem as noted above is that "out.flip();" line - this reduces the capacity of the output buffer to equal the number of chars that were decoded. So if you can manufacture an example where: The first 8,192 byte input buffer decodes to lets say 3,000 chars. So processing this reduces the capacity of the output buffer down to 3,000 chars. The second 8,192 byte input buffer decodes to 3,001 chars. So it'll process the first 3,000, then returns with OVERFLOW because the remaining char won't fit in the output buffer. It then loops around again processing the remaining input buffer, and decodes this to the single 3,001st char. At this point it decodes only 1 char, so reduces the size of the output buffer to 1 char. So even if it doesn't get stuck in an infinite loop, this is still very bad because its then looping around decoding only 1 char at a time. The key part in the original poster's test data is that final char, details of which are here - http://www.fileformat.info/info/unicode/char/20b9f/index.htm . Note it says Character.charCount() = 2, so this single UTF-8 entity decodes into 2 Java characters. Since 2 characters cannot fit into an output buffer that's been reduced to 1 character, it gets stuck in an infinite loop. I'll attach a runnable example, tested with JDK 1.7.0_67, and both struts2-core.jar 2.3.8 and latest 2.3.16.3.
        Hide
        nigel.gay Nigel Gay added a comment -

        Fix is to add an "out.clear();", like so:

        private static CoderResult decodeAndWrite(Writer writer, ByteBuffer in, CharBuffer out, CharsetDecoder decoder, boolean endOfInput) throws IOException {
            CoderResult result = decoder.decode(in, out, endOfInput);
            // To begin of decoded data
            out.flip();
            // Output
            writer.write(out.toString());
            out.clear(); // <----------
            return result;
        }
        
        Show
        nigel.gay Nigel Gay added a comment - Fix is to add an "out.clear();", like so: private static CoderResult decodeAndWrite(Writer writer, ByteBuffer in, CharBuffer out, CharsetDecoder decoder, boolean endOfInput) throws IOException { CoderResult result = decoder.decode(in, out, endOfInput); // To begin of decoded data out.flip(); // Output writer.write(out.toString()); out.clear(); // <---------- return result; }
        Hide
        lukaszlenart Lukasz Lenart added a comment -

        Patch applied, thanks!

        Show
        lukaszlenart Lukasz Lenart added a comment - Patch applied, thanks!
        Hide
        jira-bot ASF subversion and git services added a comment -

        Commit f49b084fbe6b97313ad5f56f448e2fab70371692 in struts's branch refs/heads/develop from Lukasz Lenart
        [ https://git-wip-us.apache.org/repos/asf?p=struts.git;h=f49b084 ]

        WW-4383 Clears output to avoid infinitive loops

        Show
        jira-bot ASF subversion and git services added a comment - Commit f49b084fbe6b97313ad5f56f448e2fab70371692 in struts's branch refs/heads/develop from Lukasz Lenart [ https://git-wip-us.apache.org/repos/asf?p=struts.git;h=f49b084 ] WW-4383 Clears output to avoid infinitive loops

          People

          • Assignee:
            lukaszlenart Lukasz Lenart
            Reporter:
            SuzukiYoshifumi Suzuki Yoshifumi
          • Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Time Tracking

              Estimated:
              Original Estimate - 672h
              672h
              Remaining:
              Remaining Estimate - 672h
              672h
              Logged:
              Time Spent - Not Specified
              Not Specified

                Development