From 4b150be1e481b3adab08b4e3983b937f73d648a6 Mon Sep 17 00:00:00 2001 From: metsw24-max Date: Wed, 20 May 2026 00:20:29 +0530 Subject: [PATCH 1/2] Add avifCalloc() and harden allocation call sites --- include/avif/avif.h | 5 +++++ src/avif.c | 3 +-- src/codec_aom.c | 6 ++---- src/codec_avm.c | 6 ++---- src/codec_dav1d.c | 6 ++---- src/codec_libgav1.c | 6 ++---- src/codec_rav1e.c | 6 ++---- src/codec_svt.c | 12 ++++-------- src/gainmap.c | 3 +-- src/io.c | 6 ++---- src/mem.c | 20 ++++++++++++++++++++ 11 files changed, 43 insertions(+), 36 deletions(-) diff --git a/include/avif/avif.h b/include/avif/avif.h index 204827b403..be10d3db3a 100644 --- a/include/avif/avif.h +++ b/include/avif/avif.h @@ -156,6 +156,11 @@ AVIF_API unsigned int avifLibYUVVersion(void); // returns 0 if libavif wasn't co // Returns NULL on memory allocation failure. AVIF_API void * avifAlloc(size_t size); +// Allocates count * size bytes and zero-initializes them. Returns NULL on memory +// allocation failure, if either argument is 0, or if count * size overflows size_t. +// Using avifCalloc() instead of avifAlloc() + memset() ensures the multiplication +// is overflow-checked at a single, audited site. +AVIF_API void * avifCalloc(size_t count, size_t size); AVIF_API void avifFree(void * p); // --------------------------------------------------------------------------- diff --git a/src/avif.c b/src/avif.c index f44dc49e93..e4bbfa187f 100644 --- a/src/avif.c +++ b/src/avif.c @@ -234,9 +234,8 @@ static avifResult avifImageCopyProperties(avifImage * dstImage, const avifImage dstImage->numProperties = 0; if (srcImage->numProperties != 0) { - dstImage->properties = (avifImageItemProperty *)avifAlloc(srcImage->numProperties * sizeof(srcImage->properties[0])); + dstImage->properties = (avifImageItemProperty *)avifCalloc(srcImage->numProperties, sizeof(srcImage->properties[0])); AVIF_CHECKERR(dstImage->properties != NULL, AVIF_RESULT_OUT_OF_MEMORY); - memset(dstImage->properties, 0, srcImage->numProperties * sizeof(srcImage->properties[0])); dstImage->numProperties = srcImage->numProperties; for (size_t i = 0; i < srcImage->numProperties; ++i) { memcpy(dstImage->properties[i].boxtype, srcImage->properties[i].boxtype, sizeof(srcImage->properties[i].boxtype)); diff --git a/src/codec_aom.c b/src/codec_aom.c index bc6bd55d4b..beba54e8e1 100644 --- a/src/codec_aom.c +++ b/src/codec_aom.c @@ -1395,11 +1395,10 @@ const char * avifCodecVersionAOM(void) avifCodec * avifCodecCreateAOM(void) { - avifCodec * codec = (avifCodec *)avifAlloc(sizeof(avifCodec)); + avifCodec * codec = (avifCodec *)avifCalloc(1, sizeof(avifCodec)); if (codec == NULL) { return NULL; } - memset(codec, 0, sizeof(struct avifCodec)); #if defined(AVIF_CODEC_AOM_DECODE) codec->getNextImage = aomCodecGetNextImage; @@ -1411,12 +1410,11 @@ avifCodec * avifCodecCreateAOM(void) #endif codec->destroyInternal = aomCodecDestroyInternal; - codec->internal = (struct avifCodecInternal *)avifAlloc(sizeof(struct avifCodecInternal)); + codec->internal = (struct avifCodecInternal *)avifCalloc(1, sizeof(struct avifCodecInternal)); if (codec->internal == NULL) { avifFree(codec); return NULL; } - memset(codec->internal, 0, sizeof(struct avifCodecInternal)); return codec; } diff --git a/src/codec_avm.c b/src/codec_avm.c index 2328d6e457..6222f7fa6d 100644 --- a/src/codec_avm.c +++ b/src/codec_avm.c @@ -1043,11 +1043,10 @@ const char * avifCodecVersionAVM(void) avifCodec * avifCodecCreateAVM(void) { - avifCodec * codec = (avifCodec *)avifAlloc(sizeof(avifCodec)); + avifCodec * codec = (avifCodec *)avifCalloc(1, sizeof(avifCodec)); if (codec == NULL) { return NULL; } - memset(codec, 0, sizeof(struct avifCodec)); codec->getNextImage = avmCodecGetNextImage; @@ -1055,11 +1054,10 @@ avifCodec * avifCodecCreateAVM(void) codec->encodeFinish = avmCodecEncodeFinish; codec->destroyInternal = avmCodecDestroyInternal; - codec->internal = (struct avifCodecInternal *)avifAlloc(sizeof(struct avifCodecInternal)); + codec->internal = (struct avifCodecInternal *)avifCalloc(1, sizeof(struct avifCodecInternal)); if (codec->internal == NULL) { avifFree(codec); return NULL; } - memset(codec->internal, 0, sizeof(struct avifCodecInternal)); return codec; } diff --git a/src/codec_dav1d.c b/src/codec_dav1d.c index 3f83c351e5..2f1210afbe 100644 --- a/src/codec_dav1d.c +++ b/src/codec_dav1d.c @@ -232,19 +232,17 @@ const char * avifCodecVersionDav1d(void) avifCodec * avifCodecCreateDav1d(void) { - avifCodec * codec = (avifCodec *)avifAlloc(sizeof(avifCodec)); + avifCodec * codec = (avifCodec *)avifCalloc(1, sizeof(avifCodec)); if (codec == NULL) { return NULL; } - memset(codec, 0, sizeof(struct avifCodec)); codec->getNextImage = dav1dCodecGetNextImage; codec->destroyInternal = dav1dCodecDestroyInternal; - codec->internal = (struct avifCodecInternal *)avifAlloc(sizeof(struct avifCodecInternal)); + codec->internal = (struct avifCodecInternal *)avifCalloc(1, sizeof(struct avifCodecInternal)); if (codec->internal == NULL) { avifFree(codec); return NULL; } - memset(codec->internal, 0, sizeof(struct avifCodecInternal)); return codec; } diff --git a/src/codec_libgav1.c b/src/codec_libgav1.c index 7d07adf875..ec791ccac4 100644 --- a/src/codec_libgav1.c +++ b/src/codec_libgav1.c @@ -140,20 +140,18 @@ const char * avifCodecVersionGav1(void) avifCodec * avifCodecCreateGav1(void) { - avifCodec * codec = (avifCodec *)avifAlloc(sizeof(avifCodec)); + avifCodec * codec = (avifCodec *)avifCalloc(1, sizeof(avifCodec)); if (codec == NULL) { return NULL; } - memset(codec, 0, sizeof(struct avifCodec)); codec->getNextImage = gav1CodecGetNextImage; codec->destroyInternal = gav1CodecDestroyInternal; - codec->internal = (struct avifCodecInternal *)avifAlloc(sizeof(struct avifCodecInternal)); + codec->internal = (struct avifCodecInternal *)avifCalloc(1, sizeof(struct avifCodecInternal)); if (codec->internal == NULL) { avifFree(codec); return NULL; } - memset(codec->internal, 0, sizeof(struct avifCodecInternal)); Libgav1DecoderSettingsInitDefault(&codec->internal->gav1Settings); return codec; } diff --git a/src/codec_rav1e.c b/src/codec_rav1e.c index dc220ed13c..97c92be3a7 100644 --- a/src/codec_rav1e.c +++ b/src/codec_rav1e.c @@ -333,20 +333,18 @@ const char * avifCodecVersionRav1e(void) avifCodec * avifCodecCreateRav1e(void) { - avifCodec * codec = (avifCodec *)avifAlloc(sizeof(avifCodec)); + avifCodec * codec = (avifCodec *)avifCalloc(1, sizeof(avifCodec)); if (codec == NULL) { return NULL; } - memset(codec, 0, sizeof(struct avifCodec)); codec->encodeImage = rav1eCodecEncodeImage; codec->encodeFinish = rav1eCodecEncodeFinish; codec->destroyInternal = rav1eCodecDestroyInternal; - codec->internal = (struct avifCodecInternal *)avifAlloc(sizeof(struct avifCodecInternal)); + codec->internal = (struct avifCodecInternal *)avifCalloc(1, sizeof(struct avifCodecInternal)); if (codec->internal == NULL) { avifFree(codec); return NULL; } - memset(codec->internal, 0, sizeof(struct avifCodecInternal)); return codec; } diff --git a/src/codec_svt.c b/src/codec_svt.c index 2b887e85ef..6aee502e04 100644 --- a/src/codec_svt.c +++ b/src/codec_svt.c @@ -291,11 +291,10 @@ static avifResult svtCodecEncodeImage(avifCodec * codec, if (uvSize * 2 > UINT32_MAX - input_buffer->n_filled_len) { goto cleanup; } - uvPlanes = avifAlloc(uvSize); + uvPlanes = avifCalloc(1, uvSize); if (uvPlanes == NULL) { goto cleanup; } - memset(uvPlanes, 0, uvSize); input_picture_buffer->cb = uvPlanes; input_buffer->n_filled_len += (uint32_t)uvSize; input_picture_buffer->cr = uvPlanes; @@ -402,21 +401,19 @@ static void svtCodecDestroyInternal(avifCodec * codec) avifCodec * avifCodecCreateSvt(void) { - avifCodec * codec = (avifCodec *)avifAlloc(sizeof(avifCodec)); + avifCodec * codec = (avifCodec *)avifCalloc(1, sizeof(avifCodec)); if (codec == NULL) { return NULL; } - memset(codec, 0, sizeof(struct avifCodec)); codec->encodeImage = svtCodecEncodeImage; codec->encodeFinish = svtCodecEncodeFinish; codec->destroyInternal = svtCodecDestroyInternal; - codec->internal = (struct avifCodecInternal *)avifAlloc(sizeof(avifCodecInternal)); + codec->internal = (struct avifCodecInternal *)avifCalloc(1, sizeof(avifCodecInternal)); if (codec->internal == NULL) { avifFree(codec); return NULL; } - memset(codec->internal, 0, sizeof(struct avifCodecInternal)); return codec; } @@ -426,11 +423,10 @@ static avifBool allocate_svt_buffers(EbBufferHeaderType ** input_buf) if (!(*input_buf)) { return AVIF_FALSE; } - (*input_buf)->p_buffer = avifAlloc(sizeof(EbSvtIOFormat)); + (*input_buf)->p_buffer = avifCalloc(1, sizeof(EbSvtIOFormat)); if (!(*input_buf)->p_buffer) { return AVIF_FALSE; } - memset((*input_buf)->p_buffer, 0, sizeof(EbSvtIOFormat)); (*input_buf)->size = sizeof(EbBufferHeaderType); (*input_buf)->p_app_private = NULL; (*input_buf)->pic_type = EB_AV1_INVALID_PICTURE; diff --git a/src/gainmap.c b/src/gainmap.c index b35734f892..c5fe1bac74 100644 --- a/src/gainmap.c +++ b/src/gainmap.c @@ -393,11 +393,10 @@ avifResult avifFindMinMaxWithoutOutliers(const float * gainMapF, size_t numPixel const int maxNumBuckets = 10000; const int numBuckets = AVIF_MIN((int)ceilf((max - min) / bucketSize), maxNumBuckets); - int * histogram = avifAlloc(sizeof(int) * numBuckets); + int * histogram = avifCalloc((size_t)numBuckets, sizeof(int)); if (histogram == NULL) { return AVIF_RESULT_OUT_OF_MEMORY; } - memset(histogram, 0, sizeof(int) * numBuckets); for (size_t i = 0; i < numPixels; ++i) { ++(histogram[avifValueToBucketIdx(gainMapF[i], min, max, numBuckets)]); } diff --git a/src/io.c b/src/io.c index 08eb032a94..bd0ebda8b5 100644 --- a/src/io.c +++ b/src/io.c @@ -132,11 +132,10 @@ static void avifIOMemoryReaderDestroy(struct avifIO * io) avifIO * avifIOCreateMemoryReader(const uint8_t * data, size_t size) { - avifIOMemoryReader * reader = (avifIOMemoryReader *)avifAlloc(sizeof(avifIOMemoryReader)); + avifIOMemoryReader * reader = (avifIOMemoryReader *)avifCalloc(1, sizeof(avifIOMemoryReader)); if (reader == NULL) { return NULL; } - memset(reader, 0, sizeof(avifIOMemoryReader)); reader->io.destroy = avifIOMemoryReaderDestroy; reader->io.read = avifIOMemoryReaderRead; reader->io.sizeHint = size; @@ -230,12 +229,11 @@ avifIO * avifIOCreateFileReader(const char * filename) return NULL; } - avifIOFileReader * reader = (avifIOFileReader *)avifAlloc(sizeof(avifIOFileReader)); + avifIOFileReader * reader = (avifIOFileReader *)avifCalloc(1, sizeof(avifIOFileReader)); if (!reader) { fclose(f); return NULL; } - memset(reader, 0, sizeof(avifIOFileReader)); reader->f = f; reader->io.destroy = avifIOFileReaderDestroy; reader->io.read = avifIOFileReaderRead; diff --git a/src/mem.c b/src/mem.c index 5ccf5f3e0e..3499e9d219 100644 --- a/src/mem.c +++ b/src/mem.c @@ -4,7 +4,9 @@ #include "avif/avif.h" #include +#include #include +#include void * avifAlloc(size_t size) { @@ -12,6 +14,24 @@ void * avifAlloc(size_t size) return malloc(size); } +void * avifCalloc(size_t count, size_t size) +{ + // Match the contract documented in avif.h: reject zero or overflow rather than + // passing 0 to avifAlloc (which would trip its assert) or allowing the wrap. + if (count == 0 || size == 0) { + return NULL; + } + if (count > SIZE_MAX / size) { + return NULL; + } + const size_t bytes = count * size; + void * ptr = avifAlloc(bytes); + if (ptr != NULL) { + memset(ptr, 0, bytes); + } + return ptr; +} + void avifFree(void * p) { free(p); From ab518f13cd5ee9407398d8cb4dacf68d4cc4e748 Mon Sep 17 00:00:00 2001 From: metsw24-max Date: Wed, 20 May 2026 12:33:35 +0530 Subject: [PATCH 2/2] Move avifCalloc() to internal.h and use libc calloc() Addressed: - Move avifCalloc() declaration from the public avif.h to internal.h and drop AVIF_API; avifAlloc()/avifFree() were exported in the public interface unintentionally and the new helper is for internal use only. - Update the declaration comment to describe behavior (incl. the overflow case) rather than the rationale for the helper. - Simplify the body to a single call to libc calloc(), which already handles count*size overflow per C11. Drop the now-unused and includes. - codec_svt.c: pass uvSize as the element count, sizeof(uint8_t) as the element size, matching the count-then-size convention. - gainmap.c: drop the redundant (size_t) cast on numBuckets. --- include/avif/avif.h | 5 ----- include/avif/internal.h | 4 ++++ src/codec_svt.c | 2 +- src/gainmap.c | 2 +- src/mem.c | 19 ++----------------- 5 files changed, 8 insertions(+), 24 deletions(-) diff --git a/include/avif/avif.h b/include/avif/avif.h index be10d3db3a..204827b403 100644 --- a/include/avif/avif.h +++ b/include/avif/avif.h @@ -156,11 +156,6 @@ AVIF_API unsigned int avifLibYUVVersion(void); // returns 0 if libavif wasn't co // Returns NULL on memory allocation failure. AVIF_API void * avifAlloc(size_t size); -// Allocates count * size bytes and zero-initializes them. Returns NULL on memory -// allocation failure, if either argument is 0, or if count * size overflows size_t. -// Using avifCalloc() instead of avifAlloc() + memset() ensures the multiplication -// is overflow-checked at a single, audited site. -AVIF_API void * avifCalloc(size_t count, size_t size); AVIF_API void avifFree(void * p); // --------------------------------------------------------------------------- diff --git a/include/avif/internal.h b/include/avif/internal.h index 4982eac121..293c84ef10 100644 --- a/include/avif/internal.h +++ b/include/avif/internal.h @@ -14,6 +14,10 @@ extern "C" { #error "Your target is linking against avif and avif_internal: only one should be chosen" #endif +// Allocates count * size bytes and zero-initializes them. Returns NULL on memory +// allocation failure, including the case when count * size overflows size_t. +void * avifCalloc(size_t count, size_t size); + // Yes, clamp macros are nasty. Do not use them. #define AVIF_CLAMP(x, low, high) (((x) < (low)) ? (low) : (((high) < (x)) ? (high) : (x))) #define AVIF_MIN(a, b) (((a) < (b)) ? (a) : (b)) diff --git a/src/codec_svt.c b/src/codec_svt.c index 6aee502e04..a76fb5bd53 100644 --- a/src/codec_svt.c +++ b/src/codec_svt.c @@ -291,7 +291,7 @@ static avifResult svtCodecEncodeImage(avifCodec * codec, if (uvSize * 2 > UINT32_MAX - input_buffer->n_filled_len) { goto cleanup; } - uvPlanes = avifCalloc(1, uvSize); + uvPlanes = avifCalloc(uvSize, sizeof(uint8_t)); if (uvPlanes == NULL) { goto cleanup; } diff --git a/src/gainmap.c b/src/gainmap.c index c5fe1bac74..d87f96a8ba 100644 --- a/src/gainmap.c +++ b/src/gainmap.c @@ -393,7 +393,7 @@ avifResult avifFindMinMaxWithoutOutliers(const float * gainMapF, size_t numPixel const int maxNumBuckets = 10000; const int numBuckets = AVIF_MIN((int)ceilf((max - min) / bucketSize), maxNumBuckets); - int * histogram = avifCalloc((size_t)numBuckets, sizeof(int)); + int * histogram = avifCalloc(numBuckets, sizeof(int)); if (histogram == NULL) { return AVIF_RESULT_OUT_OF_MEMORY; } diff --git a/src/mem.c b/src/mem.c index 3499e9d219..07ab027f62 100644 --- a/src/mem.c +++ b/src/mem.c @@ -1,12 +1,10 @@ // Copyright 2019 Joe Drago. All rights reserved. // SPDX-License-Identifier: BSD-2-Clause -#include "avif/avif.h" +#include "avif/internal.h" #include -#include #include -#include void * avifAlloc(size_t size) { @@ -16,20 +14,7 @@ void * avifAlloc(size_t size) void * avifCalloc(size_t count, size_t size) { - // Match the contract documented in avif.h: reject zero or overflow rather than - // passing 0 to avifAlloc (which would trip its assert) or allowing the wrap. - if (count == 0 || size == 0) { - return NULL; - } - if (count > SIZE_MAX / size) { - return NULL; - } - const size_t bytes = count * size; - void * ptr = avifAlloc(bytes); - if (ptr != NULL) { - memset(ptr, 0, bytes); - } - return ptr; + return calloc(count, size); } void avifFree(void * p)