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

PngReader throws OutOfMemoryError for very small malformed PNGs

    XMLWordPrintable

Details

    Description

      FULL PRODUCT VERSION :
      openjdk version "9.0.1"
      OpenJDK Runtime Environment (build 9.0.1+11)
      OpenJDK 64-Bit Server VM (build 9.0.1+11, mixed mode)

      ADDITIONAL OS VERSION INFORMATION :
      Linux 4.4.0-97-generic Ubuntu SMP x86_64 GNU/Linux

      EXTRA RELEVANT SYSTEM CONFIGURATION :
      Although this issue describes an OutOfMemoryError, it is independent of the amount of physical memory available on the machine or the heap size configured for the JVM.

      A DESCRIPTION OF THE PROBLEM :
      The ImageReader com.sun.imageio.plugins.png.PNGImageReader throws a java.lang.OutOfMemoryError when attempting to decode malformed image files whose IHDR sections specify dimensions such that WIDTH x HEIGHT is less than Integer.MAX_VALUE but larger than the VM's maximum array size limit (which, on Linux 64-bit, is Integer.MAX_VALUE-2).

      Not only is this absent in the API spec for either ImageReader.read() or ImageIO.read(), but throwing an Error instead of an Exception can lead to applications crashing unexpectedly even if the system/VM has ample free memory and the size of the input PNG file is bounded.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Construct a PNG with an IHDR section that specifies width as Integer.MAX_VALUE-1 (= 0x0x7ffffffe) and height as 1 pixel. The image need not actually be this large -- the example provided below is in fact only 209 bytes but has such a header (therefore, the image itself is malformed). Then attempt to decode this image using ImageIO via ImageIO.read() or ImageReader.read().

      A self-contained example is provided below. Simply compile and run the main class PngReaderOutOfMemoryIssue.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      For the test case provided below, the expected behavior is a java.io.IOException (typically an instance of javax.imageio.IIOException) since the image itself is malformed. The data does not actually contain Integer.MAX_VALUE-1 pixels.
      ACTUAL -
      A java.lang.OutOfMemoryError is thrown.

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      Exception in thread "main" java.lang.OutOfMemoryError: Requested array size exceeds VM limit
      at java.desktop/java.awt.image.DataBufferByte.<init>(DataBufferByte.java:92)
      at java.desktop/java.awt.image.ComponentSampleModel.createDataBuffer(ComponentSampleModel.java:439)
      at java.desktop/java.awt.image.Raster.createWritableRaster(Raster.java:1005)
      at java.desktop/javax.imageio.ImageTypeSpecifier.createBufferedImage(ImageTypeSpecifier.java:1074)
      at java.desktop/javax.imageio.ImageReader.getDestination(ImageReader.java:2877)
      at java.desktop/com.sun.imageio.plugins.png.PNGImageReader.readImage(PNGImageReader.java:1324)
      at java.desktop/com.sun.imageio.plugins.png.PNGImageReader.read(PNGImageReader.java:1627)
      at java.desktop/javax.imageio.ImageIO.read(ImageIO.java:1468)
      at java.desktop/javax.imageio.ImageIO.read(ImageIO.java:1363)
      at PngReaderOutOfMemoryIssue.main(PngReaderOutOfMemoryIssue.java:20)


      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import java.io.ByteArrayInputStream;
      import java.io.InputStream;
      import java.util.Base64;
      import javax.imageio.ImageIO;

      public class PngReaderOutOfMemoryIssue {

      // PNG image test case (encoded as base64 to avoid attaching files)
      private static String inputImageBase64 = "iVBORw0KGgoAAAANSUhEUn////4" +
      "AAAABCAMAAABEpIrGAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAA" +
      "AAA9QTFRFZszM////AAAAM5lmmf/MPkyvFQAAAGFJREFUeNrckzEOwCAMA5OY/7+5NBQ" +
      "J1DphYaA3sPgkCwtEE0TVAm7BCkfMBaHgp4JvFwjPulSoITAabwHwk1a0PBB6TSBM+bc" +
      "w5ERIlkQiTEPuqTj2ydWbUWzl8yZcAgwA0mYDNbDXy5oAAAo=";

      public static void main(String[] args) throws java.io.IOException {
      // Convert test case into input stream
      byte[] inputBytes = Base64.getDecoder().decode(inputImageBase64);
      InputStream in = new ByteArrayInputStream(inputBytes);

      // Attempt to read PNG
      ImageIO.read(in); // Throws java.lang.OutOfMemoryError!
      }
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      A workaround is to use ImageReader.getWidth() and ImageReader.getHeight() to first check the dimensions of the image, and only invoke read() if the dimensions are below a safe bound.

      Attachments

        Issue Links

          Activity

            People

              jdv Jayathirth D V
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: