Skip to content

Commit 68cf13a

Browse files
committed
fix bug with pixel counts over INT_MAX/4
1 parent 69bdf62 commit 68cf13a

File tree

3 files changed

+23
-8
lines changed

3 files changed

+23
-8
lines changed

src/JPEGView/ImageLoadThread.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,14 +190,17 @@ static CJPEGImage* ConvertGDIPlusBitmapToJPEGImage(Gdiplus::Bitmap* pBitmap, int
190190

191191
Gdiplus::Rect bmRect(0, 0, pBitmap->GetWidth(), pBitmap->GetHeight());
192192
Gdiplus::BitmapData bmData;
193-
if (pBitmapToUse->LockBits(&bmRect, Gdiplus::ImageLockModeRead, PixelFormat32bppRGB, &bmData) == Gdiplus::Ok) {
193+
lastStatus = pBitmapToUse->LockBits(&bmRect, Gdiplus::ImageLockModeRead, PixelFormat32bppRGB, &bmData);
194+
if (lastStatus == Gdiplus::Ok) {
194195
assert(bmData.PixelFormat == PixelFormat32bppRGB);
195196
void* pDIB = CBasicProcessing::ConvertGdiplus32bppRGB(bmRect.Width, bmRect.Height, bmData.Stride, bmData.Scan0);
196197
if (pDIB != NULL) {
197198
pJPEGImage = new CJPEGImage(bmRect.Width, bmRect.Height, pDIB, pEXIFData, 4, nJPEGHash, eImageFormat,
198199
eImageFormat == IF_GIF && nFrameCount > 1, nFrameIndex, nFrameCount, nFrameTimeMs);
199200
}
200201
pBitmapToUse->UnlockBits(&bmData);
202+
} else if (lastStatus == Gdiplus::ValueOverflow) {
203+
isOutOfMemory = true;
201204
}
202205

203206
if (pBmGraphics != NULL && pBmTarget != NULL) {
@@ -695,7 +698,7 @@ void CImageLoadThread::ProcessReadPNGRequest(CRequest* request) {
695698
#ifndef WINXP
696699
// If UseEmbeddedColorProfiles is true and the image isn't animated, we should use GDI+ for better color management
697700
bool bUseGDIPlus = CSettingsProvider::This().ForceGDIPlus() || CSettingsProvider::This().UseEmbeddedColorProfiles();
698-
if (bUseCachedDecoder || !bUseGDIPlus || PngReader::IsAnimated(pBuffer, nFileSize))
701+
if (bUseCachedDecoder || !bUseGDIPlus || PngReader::MustUseLibpng(pBuffer, nFileSize))
699702
pPixelData = (uint8*)PngReader::ReadImage(nWidth, nHeight, nBPP, bHasAnimation, nFrameCount, nFrameTimeMs, pEXIFData, request->OutOfMemory, pBuffer, nFileSize);
700703
#endif
701704

src/JPEGView/PNGWrapper.cpp

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -379,16 +379,28 @@ void PngReader::DeleteCache() {
379379
DeleteCacheInternal(true);
380380
}
381381

382-
bool PngReader::IsAnimated(void* buffer, size_t sizebytes) {
383-
// Valid APNGs must have an acTL chunk before the first IDAT chunk, this lets us quickly determine if a PNG is animated
382+
bool PngReader::MustUseLibpng(const void* bufferIn, size_t sizebytes) {
383+
const char* buffer = (const char*)bufferIn;
384+
385+
// GDI+ fails if the uncompressed image size is over INT_MAX
386+
if (sizebytes < 24) {
387+
return false;
388+
}
389+
unsigned int width = _byteswap_ulong(*(unsigned int*)(buffer + 16));
390+
unsigned int height = _byteswap_ulong(*(unsigned int*)(buffer + 20));
391+
if (4.0 * width * height > INT_MAX) {
392+
return true;
393+
}
384394

395+
// GDI+ does not support APNG
396+
// Valid APNGs must have an acTL chunk before the first IDAT chunk, this lets us quickly determine if a PNG is animated
385397
size_t offset = 8; // skip PNG signature
386398
while (offset + 7 < sizebytes) {
387-
if (memcmp((char*)buffer + offset + 4, "acTL", 4) == 0)
399+
if (memcmp(buffer + offset + 4, "acTL", 4) == 0)
388400
return true;
389-
if (memcmp((char*)buffer + offset + 4, "IDAT", 4) == 0)
401+
if (memcmp(buffer + offset + 4, "IDAT", 4) == 0)
390402
return false;
391-
unsigned int chunksize = *(unsigned int*)((char*)buffer + offset);
403+
unsigned int chunksize = *(unsigned int*)(buffer + offset);
392404

393405
// PNG chunk sizes are big-endian and must be converted to little-endian
394406
chunksize = _byteswap_ulong(chunksize);

src/JPEGView/PNGWrapper.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class PngReader
2020
static void DeleteCache();
2121

2222
// Returns true if PNG is animated, false otherwise
23-
static bool IsAnimated(void* buffer, size_t sizebytes);
23+
static bool MustUseLibpng(const void* buffer, size_t sizebytes);
2424
#endif
2525
// Get EXIF Block
2626
static void* GetEXIFBlock(void* buffer, size_t sizebytes);

0 commit comments

Comments
 (0)