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

An infinite loop occurs in FastByteArrayOutputStream.java.

Details

    • Bug
    • Status: Closed
    • Minor
    • Resolution: Fixed
    • 2.3.16.3
    • 2.3.20
    • Core Actions
    • 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;
      }
      

      Attachments

        1. WW4383Test.java
          1 kB
          Nigel Gay

        Activity

          lukaszlenart Lukasz Lenart added a comment - - edited

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

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

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

          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.
          lukaszlenart Lukasz Lenart added a comment -

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

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

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

          lukaszlenart Lukasz Lenart added a comment - Tested on 1.6.0_51 and 1.8.0-b132 - no problem as well
          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.

          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.
          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;
          }
          
          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; }
          lukaszlenart Lukasz Lenart added a comment -

          Patch applied, thanks!

          lukaszlenart Lukasz Lenart added a comment - Patch applied, thanks!

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

          WW-4383 Clears output to avoid infinitive loops

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

          People

            lukaszlenart Lukasz Lenart
            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