TurboJPEG: Properly handle gigapixel images

Prevent several integer overflow issues and subsequent segfaults that
occurred when attempting to compress or decompress gigapixel images with
the TurboJPEG API:

- Modify tjBufSize(), tjBufSizeYUV2(), and tjPlaneSizeYUV() to avoid
  integer overflow when computing the return values and to return an
  error if such an overflow is unavoidable.
- Modify tjunittest to validate the above.
- Modify tjCompress2(), tjEncodeYUVPlanes(), tjDecompress2(), and
  tjDecodeYUVPlanes() to avoid integer overflow when computing the row
  pointers in the 64-bit TurboJPEG C API.
- Modify TJBench (both C and Java versions) to avoid overflowing the
  size argument to malloc()/new and to fail gracefully if such an
  overflow is unavoidable.

In general, this allows gigapixel images to be accommodated by the
64-bit TurboJPEG C API when using automatic JPEG buffer (re)allocation.
Such images cannot currently be accommodated without automatic JPEG
buffer (re)allocation, due to the fact that tjAlloc() accepts a 32-bit
integer argument (oops.)  Such images cannot be accommodated in the
TurboJPEG Java API due to the fact that Java always uses a signed 32-bit
integer as an array index.

Fixes #361
This commit is contained in:
DRC
2019-07-11 15:30:04 -05:00
parent f37b7c1f96
commit 2a9e3bd743
5 changed files with 110 additions and 34 deletions

View File

@@ -121,6 +121,8 @@ final class TJBench {
int rindex = TJ.getRedOffset(pixelFormat);
int gindex = TJ.getGreenOffset(pixelFormat);
int bindex = TJ.getBlueOffset(pixelFormat);
if ((long)w[0] * (long)h[0] * (long)ps > (long)Integer.MAX_VALUE)
throw new Exception("Image is too large");
byte[] dstBuf = new byte[w[0] * h[0] * ps];
int pixels = w[0] * h[0], dstPtr = 0, rgbPtr = 0;
@@ -175,8 +177,11 @@ final class TJBench {
tjd = new TJDecompressor();
if (dstBuf == null)
if (dstBuf == null) {
if ((long)pitch * (long)scaledh > (long)Integer.MAX_VALUE)
throw new Exception("Image is too large");
dstBuf = new byte[pitch * scaledh];
}
/* Set the destination buffer to gray so we know whether the decompressor
attempted to write to it */
@@ -331,6 +336,8 @@ final class TJBench {
String pfStr = PIXFORMATSTR[pf];
YUVImage yuvImage = null;
if ((long)pitch * (long)h > (long)Integer.MAX_VALUE)
throw new Exception("Image is too large");
tmpBuf = new byte[pitch * h];
if (quiet == 0)
@@ -491,6 +498,8 @@ final class TJBench {
int tw, th, ttilew, ttileh, tntilesw, tntilesh, tsubsamp;
FileInputStream fis = new FileInputStream(fileName);
if (fis.getChannel().size() > (long)Integer.MAX_VALUE)
throw new Exception("Image is too large");
int srcSize = (int)fis.getChannel().size();
srcBuf = new byte[srcSize];
fis.read(srcBuf, 0, srcSize);