Hello Sergey,

Thanks for reviewing the changes.

The maximum value of inputBands & bitDepth can be 4 & 16. Also in readHeader() 
we verify the values present in inputBands & bitDepth and if they are not in 
required bounds we throw IIOException. So (inputBands * bitDepth) will not 
cause overflow.

Also I noticed that we need to use  Math.multiplyExact() in skipPass() function 
too where we have same calculation.
So I have updated the code to reflect the same.

Please review the updated webrev:
http://cr.openjdk.java.net/~jdv/8191174/webrev.03/ 

Thanks,
Jay

-----Original Message-----
From: Sergey Bylokhov 
Sent: Saturday, January 13, 2018 9:00 AM
To: Jayathirth D V; 2d-dev
Subject: Re: [OpenJDK 2D-Dev] RFR JDK-8191174: PngReader throws 
IllegalArgumentException because ScanlineStride calculation logic is not proper

Hi, Jay.
Can you please confirm that it is not possible to get overflow in: 
"inputBands * bitDepth"?
1051 int bitsPerRow = Math.multiplyExact((inputBands * bitDepth), passWidth);

On 08/01/2018 02:04, Jayathirth D V wrote:
> As you have mentioned throwing "Pixel stride times width must be less than or 
> equal to the scanline stride" is not proper in this scenario as image 
> contains proper width as per PNG specification.
> Thanks for pointing to Math.multiplyExact() function and it is very 
> beneficial for solving this issue. While calculating bytesPerRow itself we 
> can use Math.multiplyExact() and throw "int overflow" ArithmeticException and 
> it will be wrapped into IIOException because of changes present in 
> https://bugs.openjdk.java.net/browse/JDK-8190332 .
> 
> By doing this we will not have multiple "Caused by" chain and we will be 
> throwing proper exception as per ImageIO specification.
> Please find updated webrev for review:
> http://cr.openjdk.java.net/~jdv/8191174/webrev.02/
> 
> Thanks,
> Jay
> 
> -----Original Message-----
> From: Sergey Bylokhov
> Sent: Saturday, January 06, 2018 2:45 PM
> To: Prahalad Kumar Narayanan; Jayathirth D V; 2d-dev
> Subject: Re: [OpenJDK 2D-Dev] RFR JDK-8191174: PngReader throws 
> IllegalArgumentException because ScanlineStride calculation logic is 
> not proper
> 
> Probably we can use Math.multiplyExact()? The current exception text wrapped 
> a few times "Pixel stride times width must be less than or equal to the 
> scanline stride" is not strictly correct because it is possible that the 
> image itself has correct data, but we cannot handle it because of overflow.
> 
> On 28/12/2017 22:49, Prahalad Kumar Narayanan wrote:
>> Hello Jay
>>
>> Good day to you.
>>
>> The code changes wrap the IllegalArgumentException in IIOException.
>> This approach is better & aligns with how OutOfMemoryError was wrapped to 
>> fix JDK-8190332.
>>
>> The only point that I 'm not sure is- whether we could wrap 
>> IllegalArgumentException twice before throwing to the user code.
>>
>> javax.imageio.IIOException: Error reading PNG image data
>>                   at 
>> java.desktop/com.sun.imageio.plugins.png.PNGImageReader.readImage
>>                   at 
>> java.desktop/com.sun.imageio.plugins.png.PNGImageReader.read
>>                   at java.desktop/javax.imageio.ImageIO.read
>>                   ...
>> Caused by: javax.imageio.IIOException: Caught exception during read:
>>                   at 
>> java.desktop/com.sun.imageio.plugins.png.PNGImageReader.decodePass
>>                   at 
>> java.desktop/com.sun.imageio.plugins.png.PNGImageReader.decodeImage
>>                   ...
>> Caused by: java.lang.IllegalArgumentException: Pixel stride times width must 
>> be less than or equal to the scanline stride
>>                   at 
>> java.desktop/java.awt.image.PixelInterleavedSampleModel.<init>
>>                   at 
>> java.desktop/java.awt.image.Raster.createInterleavedRaster
>>                   at
>> java.desktop/com.sun.imageio.plugins.png.PNGImageReader.createRaster
>>
>> Since there are multiple levels of same exception, programmer could have 
>> trouble getting the cause using getCause() method.
>> However, Invoking printStackTrace() on the outer most exception object gives 
>> complete call stack (as listed above).
>> So I think, this should be ok.
>>
>> I would like to know of others' opinion too.
>>
>> Thank you
>> Have a good day
>>
>> Prahalad N.
>>
>>
>> -----Original Message-----
>> From: Jayathirth D V
>> Sent: Thursday, December 28, 2017 3:43 PM
>> To: Prahalad Kumar Narayanan; 2d-dev
>> Subject: RE: [OpenJDK 2D-Dev] RFR JDK-8191174: PngReader throws 
>> IllegalArgumentException because ScanlineStride calculation logic is 
>> not proper
>>
>> Hi Prahalad,
>>
>> Thanks for your valuable inputs.
>>
>> Even though the fix resolves the issue for the particular test case we have 
>> it will not solve the buffer overflow problem as you have mentioned in 
>> highest limit case or many other cases where the computed value is very high.
>>
>> Also we cannot change datatype of bytesPerRow/eltsPerRow as they are used in 
>> many passed to many other Raster and Stream API's. The best approach to 
>> resolve this issue would be to wrap the Exception that we are getting while 
>> creating Raster/SampleModel into an IIOException as we have done in 
>> https://bugs.openjdk.java.net/browse/JDK-8190332 . By doing this we will 
>> abide by specification and also we will have complete stack of why we got 
>> the exception so that it can be debugged properly in future.
>>
>> Please find updated webrev for review:
>> http://cr.openjdk.java.net/~jdv/8191174/webrev.01/
>>
>> Thanks,
>> Jay
>>
>> -----Original Message-----
>> From: Prahalad Kumar Narayanan
>> Sent: Tuesday, December 19, 2017 3:08 PM
>> To: Jayathirth D V; 2d-dev
>> Subject: RE: [OpenJDK 2D-Dev] RFR JDK-8191174: PngReader throws 
>> IllegalArgumentException because ScanlineStride calculation logic is 
>> not proper
>>
>>
>> Hello Jay
>>
>> Good day to you.
>>
>> I don't think it's possible to fix this issue despite having intermediate " 
>> long " variable to hold intermediate bits per pixel.
>> Here is a simple math that considers the worst case scenario with max values:
>>
>> . As per the PNG specification, the maximum permissible width, number of 
>> bands, bit-depth are as follows-
>>         max_width : (2 ^ 31) - 1 = 2147483647
>>         max_input_bands = 4
>>         max_bit_depth = 16 (2 Bytes)
>>
>> . As per the logic proposed in the fix, the intermediate bits per row would 
>> fit into a "long" variable but bytes per pixel would not fit into "int" 
>> variable.
>>         // Fits into "long" data type
>>         max_bits_per_row = max_width * max_input_bands * max_bit_depth
>>                                                = 2147483647 x 4 x 16
>>                                                = 137438953408
>>
>>         // Does not fit into "int" data type
>>         max_bytes_per_row = max_bits_per_row + 7 / 8
>>                                                    = 17179869176
>>                                                    = (0x 3FFFFFFF8 - 
>> Goes beyond 4B boundary)
>>
>>         // Upon division by 2 for 16-bit images
>>         max_elts_per_row = max_bytes_per_row / 2
>>                                                = 8589934588
>>                                                = (0x 1FFFFFFFC - Goes 
>> beyond 4B boundary)
>>
>> . If we intend to store bytes per row (and eltsPerRow which is scanline 
>> stride) in a "long" variable, the same cannot be sent to Raster APIs because 
>> the APIs accept "int" type for scanline stride in arguments list.
>>     Going by the Raster APIs used in PNGImageReader, a proper fix would 
>> require changes to its APIs as well to handle such large scanline stride 
>> values.
>>
>> Thank you
>> Have a good day
>>
>> Prahalad N.
>>
>> ----- Original Message -----
>> From: Jayathirth D V
>> Sent: Thursday, December 14, 2017 1:48 PM
>> To: 2d-dev
>> Subject: [OpenJDK 2D-Dev] RFR JDK-8191174: PngReader throws 
>> IllegalArgumentException because ScanlineStride calculation logic is 
>> not proper
>>
>> Hello All,
>>
>> Please review the following fix in JDK :
>>
>> Bug : https://bugs.openjdk.java.net/browse/JDK-8191174
>> Webrev : http://cr.openjdk.java.net/~jdv/8191174/webrev.00/
>>
>> Issue : When we try to read PNG image with large width we throw undocumented 
>> IllegalArgumentException with message "Pixel stride times width must be less 
>> than or equal to the scanline stride".
>>
>> Exception in thread "main" java.lang.IllegalArgumentException: Pixel 
>> stride times width must be less than or equal to the scanline stride
>>                   at
>> java.desktop/java.awt.image.PixelInterleavedSampleModel.<init>(PixelI
>> n
>> terleavedSampleModel.java:101)
>>                   at
>> java.desktop/java.awt.image.Raster.createInterleavedRaster(Raster.jav
>> a
>> :642)
>>                   at
>> java.desktop/com.sun.imageio.plugins.png.PNGImageReader.createRaster(
>> P
>> NGImageReader.java:974)
>>                   at
>> java.desktop/com.sun.imageio.plugins.png.PNGImageReader.decodePass(PN
>> G
>> ImageReader.java:1099)
>>                   at
>> java.desktop/com.sun.imageio.plugins.png.PNGImageReader.decodeImage(P
>> N
>> GImageReader.java:1295)
>>                   at
>> java.desktop/com.sun.imageio.plugins.png.PNGImageReader.readImage(PNG
>> I
>> mageReader.java:1420)
>>                   at
>> java.desktop/com.sun.imageio.plugins.png.PNGImageReader.read(PNGImage
>> R
>> eader.java:1699)
>>                   at
>> java.desktop/javax.imageio.ImageIO.read(ImageIO.java:1468)
>>                   at
>> java.desktop/javax.imageio.ImageIO.read(ImageIO.java:1363)
>>                   at
>> PngReaderLargeWidthStrideTest.main(PngReaderLargeWidthStrideTest.java:
>> 50)
>>
>> Root cause : We use large width present in IHDR and calculate elements per 
>> row which is passed as scanlinestride for creating the required raster and 
>> its corresponding sample model.  When the call reaches creation of 
>> PixelInterleavedSampleModel it checks the condition of (pixelStride * w) > 
>> scanlineStride. Since in our case we pass this condition it throws 
>> IllegalArgumentException. We have invalid scanlineStride value because when 
>> we calculate elements per row/bytes per row value in PNGImageReader the 
>> integer variable buffer is overflowed and we maintain invalid value for 
>> bytesPerRow.
>>
>> Solution : We can maintain the intermediate bitsPerRow value in long 
>> datatype and calculate bytesPerRow using the long value and then typecast it 
>> to int bytesPerRow variable. By doing this we will maintain the required 
>> scanlineStride/eltsPerRow value properly. After this solution we will throw 
>> proper IIOException because of changes present in JDK-8190332 and not the 
>> undocumented IllegalArgumentException.
>>
>> Thanks,
>> Jay
>>
> 
> 
> --
> Best regards, Sergey.
> 


--
Best regards, Sergey.

Reply via email to