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

java.util.Base64.Decoder stream adds unexpected null bytes at the end

    XMLWordPrintable

    Details

    • Subcomponent:
    • Resolved In Build:
      b07
    • CPU:
      generic
    • OS:
      generic

      Description

      ADDITIONAL SYSTEM INFORMATION :
      Reproduced on OSX using OpenJDK versions 1.8.0_202, 10.0.2, 11.0.2
      Also reproduced on Scientific Linux 7.6 version OpenJDK 1.8.0_201

      A DESCRIPTION OF THE PROBLEM :
      When reading Base64 encoded input of certain lengths with certain buffer sizes,
      from a wrapped InputStream ( Base64.getDecoder().wrap(InputStream) ),
      2 additional null bytes are added at the end of the input.

      This appears to only affect certain input and buffer size combinations, but was encountered in the wild using a buffer size of 4096. Seems like an unhandled edge case.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      See the source code below.

      javac Base64DecodeProblem.java
      java Base64DecodeProblem

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The decoded bytes read from the wrapped stream should match the originally encoded bytes ("12345678"), when a byte buffer of length 7 is used to read decoded output.
      ACTUAL -
      Two additional null bytes appear after the originally encoded bytes ("12345678\0\0"), when a byte buffer of length 7 is used to read decoded output.


      ---------- BEGIN SOURCE ----------
      import java.io.ByteArrayInputStream;
      import java.io.ByteArrayOutputStream;
      import java.io.InputStream;
      import java.io.OutputStream;
      import java.nio.charset.StandardCharsets;
      import java.util.Base64;


      /**
       * Class to reproduce java.util.Base64 Decoder wrapped stream issue.
       *
       * @author jmfee@usgs.gov
       */
      public class Base64DecodeProblem {

          // length 8 is first case where issue appears (buffer size 7)
          public static final String RAW = "12345678";
          // length 26 is first case where 2 buffer sizes are affected (5, 25)
          // public static final String RAW = "12345678901234567890123456";

          public static void main(final String[] args) throws Exception {
              byte[] raw = RAW.getBytes(StandardCharsets.UTF_8);
              System.err.println("input string = \"" + escaped(RAW) + "\"");
              System.err.println("length = " + raw.length);

              // encode to base64
              byte[] encoded = Base64.getEncoder().encode(raw);
              System.err.println("encoded = \"" + new String(encoded) + "\"");

              // decode using different buffer sizes [1, 8192]
              for (int bufferSize = 1; bufferSize < 8192; bufferSize++) {
                  try (
                      InputStream in = Base64.getDecoder().wrap(
                              new ByteArrayInputStream(encoded));
                      ByteArrayOutputStream baos = new ByteArrayOutputStream();
                  ) {
                      byte[] buffer = new byte[bufferSize];
                      int read;
                      while ((read = in.read(buffer, 0, bufferSize)) != -1) {
                          baos.write(buffer, 0, read);
                      }
                      // compare result, output info if lengths do not match
                      byte[] decoded = baos.toByteArray();
                      if (decoded.length != raw.length) {
                          System.err.println("Buffer size = " + bufferSize);
                          System.err.println("\tdecoded length = " + decoded.length);
                          System.err.println("\tdecoded = \"" +
                                  escaped(new String(decoded)) + "\"");
                      }
                  }
              }
          }

          public static String escaped(final String str) {
              String escaped = str;
              escaped = escaped.replace("\n", "\\n");
              escaped = escaped.replace("\r", "\\r");
              escaped = escaped.replace("\0", "\\0");
              return escaped;
          }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Buffer size of 1 byte never seems to be affected.

      FREQUENCY : always


        Attachments

          Activity

            People

            Assignee:
            lancea Lance Andersen
            Reporter:
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Dates

              Created:
              Updated:
              Resolved: