Compare commits

...

3 Commits

Author SHA1 Message Date
Yannis Guyon
080044c7f2 Replace [[fallthrough]] with WEBP_FALLTHROUGH
C and C++ version values based on
https://en.cppreference.com/w/c/23.html and
https://en.cppreference.com/w/cpp/preprocessor/replace.

Change-Id: I1059fa9e17f25f05d452f8dd003ca7d421742bf7
2026-04-09 09:54:52 +00:00
James Zern
c95ed44524 mux,anim: ensure all images are in ANMF chunks
In an animated file, all image chunks must be contained in ANMF chunks.
This fixes an assertion failure:

```
src/mux/muxedit.c:448 in WebPMuxError
  GetAdjustedCanvasSize(const WebPMux *const, int *const, int *const):
  wpi->header != NULL
```

The demux library already has this check.

Bug: 498966755
Change-Id: I1f04088a60326b47d26d7690277192118ed8374f
2026-04-07 13:15:27 -07:00
Vincent Rabaud
6a9eb44282 Fix potential overflow in FramesAreSimilar
Bug: 496807858

Change-Id: Idc9af6f86a171322dd09e197dafbef59d5e4aa53
2026-04-07 09:42:44 +02:00
6 changed files with 40 additions and 17 deletions

View File

@@ -70,8 +70,10 @@ static int FramesAreSimilar(const uint8_t* const rgba1,
for (j = 0; j < height; ++j) {
for (i = 0; i < width; ++i) {
const int stride = width * 4;
const size_t offset = j * stride + i;
if (!PixelsAreSimilar(rgba1[offset], rgba2[offset], max_allowed_diff)) {
size_t offset_row, offset;
if (!CheckMultiplicationOverflow(j, stride, &offset_row) ||
!CheckAdditionOverflow(offset_row, i, &offset) ||
!PixelsAreSimilar(rgba1[offset], rgba2[offset], max_allowed_diff)) {
return 0;
}
}

View File

@@ -102,10 +102,8 @@ int CheckMultiplicationOverflow(uint32_t val1, uint32_t val2, size_t* product) {
return 0;
}
#if defined(WEBP_HAVE_GIF)
WEBP_NODISCARD
static int CheckAdditionOverflow(size_t val1, uint32_t val2, size_t* addition) {
int CheckAdditionOverflow(size_t val1, uint32_t val2, size_t* addition) {
const uint64_t size = (uint64_t)val1 + val2;
if (CheckSizeForOverflow(size)) {
*addition = (size_t)size;
@@ -114,6 +112,8 @@ static int CheckAdditionOverflow(size_t val1, uint32_t val2, size_t* addition) {
return 0;
}
#if defined(WEBP_HAVE_GIF)
// For the GIF functions below, the width, height, x_offset, y_offset fit on 16
// bits (but can fill the 16 bits) as per the GIF specification.
// Multiplications that can overflow are cast to 64 bits.

View File

@@ -73,6 +73,9 @@ void GetAnimatedImageVersions(int* const decoder_version,
// Check whether val1 * val2 fits in a size_t. Returns 1 on success.
int CheckMultiplicationOverflow(uint32_t val1, uint32_t val2, size_t* product);
// Check whether val1 + val2 fits in a size_t. Returns 1 on success.
int CheckAdditionOverflow(size_t val1, uint32_t val2, size_t* addition);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@@ -493,12 +493,18 @@ static int ParseFrameArgs(const char* args, WebPMuxFrameInfo* const info) {
&plus_minus, &blend_method, &unused);
switch (num_args) {
case 1:
info->x_offset = info->y_offset = 0; // fall through
info->x_offset = info->y_offset = 0;
WEBP_FALLTHROUGH;
// fall through
case 3:
dispose_method = 0; // fall through
dispose_method = 0;
WEBP_FALLTHROUGH;
// fall through
case 4:
plus_minus = '+';
blend_method = 'b'; // fall through
blend_method = 'b';
WEBP_FALLTHROUGH;
// fall through
case 6:
break;
case 2:

View File

@@ -500,6 +500,14 @@ WebPMuxError MuxValidate(const WebPMux* const mux) {
err = ValidateChunk(mux, IDX_XMP, XMP_FLAG, flags, 1, &num_xmp);
if (err != WEBP_MUX_OK) return err;
// Verify either VP8X chunk is present OR there is only one elem in
// mux->images.
err = ValidateChunk(mux, IDX_VP8X, NO_FLAG, flags, 1, &num_vp8x);
if (err != WEBP_MUX_OK) return err;
err = ValidateChunk(mux, IDX_VP8, NO_FLAG, flags, -1, &num_images);
if (err != WEBP_MUX_OK) return err;
if (num_vp8x == 0 && num_images != 1) return WEBP_MUX_INVALID_ARGUMENT;
// Animation: ANIMATION_FLAG, ANIM chunk and ANMF chunk(s) are consistent.
// At most one ANIM chunk.
err = ValidateChunk(mux, IDX_ANIM, NO_FLAG, flags, 1, &num_anim);
@@ -509,7 +517,10 @@ WebPMuxError MuxValidate(const WebPMux* const mux) {
{
const int has_animation = !!(flags & ANIMATION_FLAG);
if (has_animation && (num_anim == 0 || num_frames == 0)) {
// An ANIM chunk must be present when has_animation is true, and all images
// must be contained in ANMF chunks.
if (has_animation &&
(num_anim == 0 || num_frames == 0 || num_frames != num_images)) {
return WEBP_MUX_INVALID_ARGUMENT;
}
if (!has_animation && (num_anim == 1 || num_frames > 0)) {
@@ -531,14 +542,6 @@ WebPMuxError MuxValidate(const WebPMux* const mux) {
}
}
// Verify either VP8X chunk is present OR there is only one elem in
// mux->images.
err = ValidateChunk(mux, IDX_VP8X, NO_FLAG, flags, 1, &num_vp8x);
if (err != WEBP_MUX_OK) return err;
err = ValidateChunk(mux, IDX_VP8, NO_FLAG, flags, -1, &num_images);
if (err != WEBP_MUX_OK) return err;
if (num_vp8x == 0 && num_images != 1) return WEBP_MUX_INVALID_ARGUMENT;
// ALPHA_FLAG & alpha chunk(s) are consistent.
// Note: ALPHA_FLAG can be set when there is actually no Alpha data present.
if (MuxHasAlpha(mux->images)) {

View File

@@ -71,6 +71,15 @@ typedef long long int int64_t;
#endif /* defined(_WIN32) && defined(WEBP_DLL) */
#endif /* WEBP_EXTERN */
#ifndef WEBP_FALLTHROUGH
#if (defined(__cplusplus) && __cplusplus >= 201703L) || \
(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L)
#define WEBP_FALLTHROUGH [[fallthrough]]
#else
#define WEBP_FALLTHROUGH
#endif
#endif /* WEBP_FALLTHROUGH */
// Macro to check ABI compatibility (same major revision number)
#define WEBP_ABI_IS_INCOMPATIBLE(a, b) (((a) >> 8) != ((b) >> 8))