From 740763cc99de19521175723644c107a4744388aa Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Wed, 22 Jul 2026 10:37:01 +0000 Subject: [PATCH] Reallocate MJPEG databuf when scanline count changes MJpegDecoder reuses its per-component scanline buffers across calls to LoadFrame. The databuf_ buffer for each component is sized as scanlines_size * databuf_stride, but it was only reallocated when the stride changed (databuf_strides_[i] != databuf_stride). A subsequent frame with the same component width (hence the same stride) but a larger scanlines_size -- for example a different vertical sampling factor -- would reuse the previously allocated, now undersized, buffer. jpeglib then writes scanlines_size rows into it during decoding, overflowing the heap allocation. Track whether scanlines_size changed and reallocate databuf_ in that case as well, so the buffer always matches the size used to compute databuf_size. R=fbarchard@google.com Change-Id: Ie8bf7b7da9eb5e12bd59e578c704988b93d5816c --- source/mjpeg_decoder.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/source/mjpeg_decoder.cc b/source/mjpeg_decoder.cc index 559e3e3a7..5afe7a768 100644 --- a/source/mjpeg_decoder.cc +++ b/source/mjpeg_decoder.cc @@ -125,7 +125,11 @@ LIBYUV_BOOL MJpegDecoder::LoadFrame(const uint8_t* src, size_t src_len) { AllocOutputBuffers(GetNumComponents()); for (int i = 0; i < num_outbufs_; ++i) { int scanlines_size = GetComponentScanlinesPerImcuRow(i); - if (scanlines_sizes_[i] != scanlines_size) { + // The number of scanlines can change between frames (e.g. a different + // vertical sampling factor). The databuf below is sized from it, so track + // whether it changed to know when the databuf must be reallocated too. + int scanlines_size_changed = scanlines_sizes_[i] != scanlines_size; + if (scanlines_size_changed) { if (scanlines_[i]) { delete[] scanlines_[i]; } @@ -145,7 +149,7 @@ LIBYUV_BOOL MJpegDecoder::LoadFrame(const uint8_t* src, size_t src_len) { // DCTSIZE) is at most slightly larger than UINT16_MAX. // - Sampling factor is stored in 4 bits, so scanlines_size is < 16. int databuf_size = scanlines_size * databuf_stride; - if (databuf_strides_[i] != databuf_stride) { + if (databuf_strides_[i] != databuf_stride || scanlines_size_changed) { if (databuf_[i]) { delete[] databuf_[i]; }