Add avifCalloc() and harden allocation call sites

Introduce avifCalloc() as a centralized overflow-checked,
zero-initializing allocation helper and convert existing open-coded
allocation patterns to use it.

This change replaces repeated patterns of:

    p = avifAlloc(...);
    memset(p, 0, ...);
    
with a single reusable helper that performs allocation arithmetic
validation and zero-initialization in one place.
diff --git a/include/avif/internal.h b/include/avif/internal.h
index cdaa654..e109496 100644
--- a/include/avif/internal.h
+++ b/include/avif/internal.h
@@ -81,6 +81,13 @@
 #define AVIF_CONTENT_TYPE_XMP "application/rdf+xml"
 
 // ---------------------------------------------------------------------------
+// Memory management
+
+// 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);
+
+// ---------------------------------------------------------------------------
 // Utils
 
 float avifRoundf(float v);
diff --git a/src/avif.c b/src/avif.c
index f44dc49..e4bbfa1 100644
--- a/src/avif.c
+++ b/src/avif.c
@@ -234,9 +234,8 @@
     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 bc6bd55..beba54e 100644
--- a/src/codec_aom.c
+++ b/src/codec_aom.c
@@ -1395,11 +1395,10 @@
 
 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 @@
 #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 2328d6e..6222f7f 100644
--- a/src/codec_avm.c
+++ b/src/codec_avm.c
@@ -1043,11 +1043,10 @@
 
 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 @@
     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 3f83c35..2f1210a 100644
--- a/src/codec_dav1d.c
+++ b/src/codec_dav1d.c
@@ -232,19 +232,17 @@
 
 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 7d07adf..ec791cc 100644
--- a/src/codec_libgav1.c
+++ b/src/codec_libgav1.c
@@ -140,20 +140,18 @@
 
 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 dc220ed..97c92be 100644
--- a/src/codec_rav1e.c
+++ b/src/codec_rav1e.c
@@ -333,20 +333,18 @@
 
 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 2b887e8..a76fb5b 100644
--- a/src/codec_svt.c
+++ b/src/codec_svt.c
@@ -291,11 +291,10 @@
         if (uvSize * 2 > UINT32_MAX - input_buffer->n_filled_len) {
             goto cleanup;
         }
-        uvPlanes = avifAlloc(uvSize);
+        uvPlanes = avifCalloc(uvSize, sizeof(uint8_t));
         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 @@
 
 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 @@
     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 b35734f..d87f96a 100644
--- a/src/gainmap.c
+++ b/src/gainmap.c
@@ -393,11 +393,10 @@
 
     const int maxNumBuckets = 10000;
     const int numBuckets = AVIF_MIN((int)ceilf((max - min) / bucketSize), maxNumBuckets);
-    int * histogram = avifAlloc(sizeof(int) * numBuckets);
+    int * histogram = avifCalloc(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 08eb032..bd0ebda 100644
--- a/src/io.c
+++ b/src/io.c
@@ -132,11 +132,10 @@
 
 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 @@
         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 54d9495..46f9fb5 100644
--- a/src/mem.c
+++ b/src/mem.c
@@ -1,7 +1,7 @@
 // Copyright 2019 Joe Drago. All rights reserved.
 // SPDX-License-Identifier: BSD-2-Clause
 
-#include "avif/avif.h"
+#include "avif/internal.h"
 
 #include <stdlib.h>
 
@@ -17,6 +17,11 @@
     return malloc(size);
 }
 
+void * avifCalloc(size_t count, size_t size)
+{
+    return calloc(count, size);
+}
+
 void avifFree(void * p)
 {
     free(p);