Fix: crash saving large WebP images

WebP images can be at most 16383x16383,
however saving sizes which overflowed an integer would crash.

- Early exit with an error when the image is too large.
- Replace integer offsets with size_t.

Back ported from: 37148d67116471d75fb335e0a4a0914b74b1f5ac

Pull Request: https://projects.blender.org/blender/blender/pulls/137442
This commit is contained in:
Campbell Barton
2025-04-14 10:10:56 +02:00
committed by Thomas Dinges
parent 66e8f1af57
commit 7ce866e3c0
+12 -6
View File
@@ -63,7 +63,7 @@ ImBuf *imb_loadwebp(const uchar *mem, size_t size, int flags, char colorspace[IM
ibuf->ftype = IMB_FTYPE_WEBP;
imb_addrectImBuf(ibuf);
/* Flip the image during decoding to match Blender. */
uchar *last_row = ibuf->byte_buffer.data + 4 * (ibuf->y - 1) * ibuf->x;
uchar *last_row = ibuf->byte_buffer.data + (4 * size_t(ibuf->y - 1) * size_t(ibuf->x));
if (WebPDecodeRGBAInto(mem, size, last_row, size_t(ibuf->x) * ibuf->y * 4, -4 * ibuf->x) ==
nullptr)
{
@@ -137,7 +137,7 @@ ImBuf *imb_load_filepath_thumbnail_webp(const char *filepath,
config.output.colorspace = MODE_RGBA;
config.output.u.RGBA.rgba = ibuf->byte_buffer.data;
config.output.u.RGBA.stride = 4 * ibuf->x;
config.output.u.RGBA.size = size_t(config.output.u.RGBA.stride * ibuf->y);
config.output.u.RGBA.size = size_t(config.output.u.RGBA.stride) * size_t(ibuf->y);
if (WebPDecode(data, data_size, &config) != VP8_STATUS_OK) {
fprintf(stderr, "WebP: Failed to decode image\n");
@@ -159,23 +159,29 @@ ImBuf *imb_load_filepath_thumbnail_webp(const char *filepath,
bool imb_savewebp(ImBuf *ibuf, const char *filepath, int /*flags*/)
{
const uint limit = 16383;
if (ibuf->x > limit || ibuf->y > limit) {
fprintf(stderr, "WebP: image x/y exceeds %u\n", limit);
return false;
}
const int bytesperpixel = (ibuf->planes + 7) >> 3;
uchar *encoded_data, *last_row;
size_t encoded_data_size;
if (bytesperpixel == 3) {
/* We must convert the ImBuf RGBA buffer to RGB as WebP expects a RGB buffer. */
const size_t num_pixels = ibuf->x * ibuf->y;
const size_t num_pixels = size_t(ibuf->x) * size_t(ibuf->y);
const uint8_t *rgba_rect = ibuf->byte_buffer.data;
uint8_t *rgb_rect = static_cast<uint8_t *>(
MEM_mallocN(sizeof(uint8_t) * num_pixels * 3, "webp rgb_rect"));
for (int i = 0; i < num_pixels; i++) {
for (size_t i = 0; i < num_pixels; i++) {
rgb_rect[i * 3 + 0] = rgba_rect[i * 4 + 0];
rgb_rect[i * 3 + 1] = rgba_rect[i * 4 + 1];
rgb_rect[i * 3 + 2] = rgba_rect[i * 4 + 2];
}
last_row = (uchar *)(rgb_rect + (ibuf->y - 1) * ibuf->x * 3);
last_row = (uchar *)(rgb_rect + (size_t(ibuf->y - 1) * size_t(ibuf->x) * 3));
if (ibuf->foptions.quality == 100.0f) {
encoded_data_size = WebPEncodeLosslessRGB(
@@ -188,7 +194,7 @@ bool imb_savewebp(ImBuf *ibuf, const char *filepath, int /*flags*/)
MEM_freeN(rgb_rect);
}
else if (bytesperpixel == 4) {
last_row = ibuf->byte_buffer.data + 4 * (ibuf->y - 1) * ibuf->x;
last_row = ibuf->byte_buffer.data + 4 * size_t(ibuf->y - 1) * size_t(ibuf->x);
if (ibuf->foptions.quality == 100.0f) {
encoded_data_size = WebPEncodeLosslessRGBA(