avifRGBImageAllocatePixels() returns avifResult
To catch out-of-memory issues.
Change printf(ERROR) into fprintf(stderr,ERROR) in avifyuv.c.
Use RGBImageFreePixels() in RGBImageAllocatePixels().
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2786bd8..f760dd0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,7 @@
those pointers.
* Check the return value of avifEncoderSetCodecSpecificOption().
* The maxThreads member was added to the avifRGBImage struct.
+* Check the return value of avifRGBImageAllocatePixels().
### Added
* Add STATIC library target avif_internal to allow tests to access functions
@@ -60,6 +61,8 @@
* avifEncoderSetCodecSpecificOption() now returns avifResult instead of void to
report memory allocation failures.
* At decoding, avifIOStats now returns the same values as at encoding.
+* avifRGBImageAllocatePixels() now returns avifResult instead of void to report
+ memory allocation failures.
## [0.11.1] - 2022-10-19
diff --git a/apps/shared/avifjpeg.c b/apps/shared/avifjpeg.c
index 57f271f..87ff123 100644
--- a/apps/shared/avifjpeg.c
+++ b/apps/shared/avifjpeg.c
@@ -366,7 +366,10 @@
rgb.format = AVIF_RGB_FORMAT_RGB;
rgb.chromaDownsampling = chromaDownsampling;
rgb.depth = 8;
- avifRGBImageAllocatePixels(&rgb);
+ if (avifRGBImageAllocatePixels(&rgb) != AVIF_RESULT_OK) {
+ fprintf(stderr, "Conversion to YUV failed: %s (out of memory)\n", inputFilename);
+ goto cleanup;
+ }
int row = 0;
while (cinfo.output_scanline < cinfo.output_height) {
@@ -557,7 +560,10 @@
rgb.format = AVIF_RGB_FORMAT_RGB;
rgb.chromaUpsampling = chromaUpsampling;
rgb.depth = 8;
- avifRGBImageAllocatePixels(&rgb);
+ if (avifRGBImageAllocatePixels(&rgb) != AVIF_RESULT_OK) {
+ fprintf(stderr, "Conversion to RGB failed: %s (out of memory)\n", outputFilename);
+ goto cleanup;
+ }
if (avifImageYUVToRGB(avif, &rgb) != AVIF_RESULT_OK) {
fprintf(stderr, "Conversion to RGB failed: %s\n", outputFilename);
goto cleanup;
diff --git a/apps/shared/avifpng.c b/apps/shared/avifpng.c
index a91a121..4bbe8d6 100644
--- a/apps/shared/avifpng.c
+++ b/apps/shared/avifpng.c
@@ -339,7 +339,10 @@
avifRGBImageSetDefaults(&rgb, avif);
rgb.chromaDownsampling = chromaDownsampling;
rgb.depth = imgBitDepth;
- avifRGBImageAllocatePixels(&rgb);
+ if (avifRGBImageAllocatePixels(&rgb) != AVIF_RESULT_OK) {
+ fprintf(stderr, "Conversion to YUV failed: %s (out of memory)\n", inputFilename);
+ goto cleanup;
+ }
rowPointers = (png_bytep *)malloc(sizeof(png_bytep) * rgb.height);
for (uint32_t y = 0; y < rgb.height; ++y) {
rowPointers[y] = &rgb.pixels[y * rgb.rowBytes];
@@ -416,7 +419,10 @@
colorType = PNG_COLOR_TYPE_RGB;
rgb.format = AVIF_RGB_FORMAT_RGB;
}
- avifRGBImageAllocatePixels(&rgb);
+ if (avifRGBImageAllocatePixels(&rgb) != AVIF_RESULT_OK) {
+ fprintf(stderr, "Conversion to RGB failed: %s (out of memory)\n", outputFilename);
+ goto cleanup;
+ }
if (avifImageYUVToRGB(avif, &rgb) != AVIF_RESULT_OK) {
fprintf(stderr, "Conversion to RGB failed: %s\n", outputFilename);
goto cleanup;
diff --git a/examples/avif_example_decode_file.c b/examples/avif_example_decode_file.c
index f3fafb9..c25822a 100644
--- a/examples/avif_example_decode_file.c
+++ b/examples/avif_example_decode_file.c
@@ -58,10 +58,15 @@
// Alternative: set rgb.pixels and rgb.rowBytes yourself, which should match your chosen rgb.format
// Be sure to use uint16_t* instead of uint8_t* for rgb.pixels/rgb.rowBytes if (rgb.depth > 8)
- avifRGBImageAllocatePixels(&rgb);
+ result = avifRGBImageAllocatePixels(&rgb);
+ if (result != AVIF_RESULT_OK) {
+ fprintf(stderr, "Allocation of RGB samples failed: %s (%s)\n", inputFilename, avifResultToString(result));
+ goto cleanup;
+ }
- if (avifImageYUVToRGB(decoder->image, &rgb) != AVIF_RESULT_OK) {
- fprintf(stderr, "Conversion from YUV failed: %s\n", inputFilename);
+ result = avifImageYUVToRGB(decoder->image, &rgb);
+ if (result != AVIF_RESULT_OK) {
+ fprintf(stderr, "Conversion from YUV failed: %s (%s)\n", inputFilename, avifResultToString(result));
goto cleanup;
}
diff --git a/examples/avif_example_decode_memory.c b/examples/avif_example_decode_memory.c
index 2cf4a0b..1a5fbec 100644
--- a/examples/avif_example_decode_memory.c
+++ b/examples/avif_example_decode_memory.c
@@ -80,10 +80,15 @@
// Alternative: set rgb.pixels and rgb.rowBytes yourself, which should match your chosen rgb.format
// Be sure to use uint16_t* instead of uint8_t* for rgb.pixels/rgb.rowBytes if (rgb.depth > 8)
- avifRGBImageAllocatePixels(&rgb);
+ result = avifRGBImageAllocatePixels(&rgb);
+ if (result != AVIF_RESULT_OK) {
+ fprintf(stderr, "Allocation of RGB samples failed: %s (%s)\n", inputFilename, avifResultToString(result));
+ goto cleanup;
+ }
- if (avifImageYUVToRGB(decoder->image, &rgb) != AVIF_RESULT_OK) {
- fprintf(stderr, "Conversion from YUV failed: %s\n", inputFilename);
+ result = avifImageYUVToRGB(decoder->image, &rgb);
+ if (result != AVIF_RESULT_OK) {
+ fprintf(stderr, "Conversion from YUV failed: %s (%s)\n", inputFilename, avifResultToString(result));
goto cleanup;
}
diff --git a/examples/avif_example_encode.c b/examples/avif_example_encode.c
index 31b00d1..ec508db 100644
--- a/examples/avif_example_encode.c
+++ b/examples/avif_example_encode.c
@@ -66,7 +66,11 @@
// Alternative: set rgb.pixels and rgb.rowBytes yourself, which should match your chosen rgb.format
// Be sure to use uint16_t* instead of uint8_t* for rgb.pixels/rgb.rowBytes if (rgb.depth > 8)
- avifRGBImageAllocatePixels(&rgb);
+ avifResult allocationResult = avifRGBImageAllocatePixels(&rgb);
+ if (allocationResult != AVIF_RESULT_OK) {
+ fprintf(stderr, "Allocation of RGB samples failed: %s\n", avifResultToString(allocationResult));
+ goto cleanup;
+ }
// Fill your RGB(A) data here
memset(rgb.pixels, 255, rgb.rowBytes * image->height);
diff --git a/include/avif/avif.h b/include/avif/avif.h
index 8eb629a..79f0158 100644
--- a/include/avif/avif.h
+++ b/include/avif/avif.h
@@ -680,7 +680,7 @@
AVIF_API uint32_t avifRGBImagePixelSize(const avifRGBImage * rgb);
// Convenience functions. If you supply your own pixels/rowBytes, you do not need to use these.
-AVIF_API void avifRGBImageAllocatePixels(avifRGBImage * rgb);
+AVIF_API avifResult avifRGBImageAllocatePixels(avifRGBImage * rgb);
AVIF_API void avifRGBImageFreePixels(avifRGBImage * rgb);
// The main conversion functions
diff --git a/src/avif.c b/src/avif.c
index e74aba7..b29505b 100644
--- a/src/avif.c
+++ b/src/avif.c
@@ -579,14 +579,14 @@
rgb->maxThreads = 1;
}
-void avifRGBImageAllocatePixels(avifRGBImage * rgb)
+avifResult avifRGBImageAllocatePixels(avifRGBImage * rgb)
{
- if (rgb->pixels) {
- avifFree(rgb->pixels);
- }
-
- rgb->rowBytes = rgb->width * avifRGBImagePixelSize(rgb);
- rgb->pixels = avifAlloc((size_t)rgb->rowBytes * rgb->height);
+ avifRGBImageFreePixels(rgb);
+ const uint32_t rowBytes = rgb->width * avifRGBImagePixelSize(rgb);
+ rgb->pixels = avifAlloc((size_t)rowBytes * rgb->height);
+ AVIF_CHECKERR(rgb->pixels, AVIF_RESULT_OUT_OF_MEMORY);
+ rgb->rowBytes = rowBytes;
+ return AVIF_RESULT_OK;
}
void avifRGBImageFreePixels(avifRGBImage * rgb)
diff --git a/tests/avifyuv.c b/tests/avifyuv.c
index 5576767..c9b38d2 100644
--- a/tests/avifyuv.c
+++ b/tests/avifyuv.c
@@ -151,7 +151,7 @@
avifImage * image = avifImageCreate(dim, dim, yuvDepth, AVIF_PIXEL_FORMAT_YUV444);
if (!image) {
- printf("ERROR: Out of memory\n");
+ fprintf(stderr, "ERROR: Out of memory\n");
return 1;
}
image->colorPrimaries = cicp->cp;
@@ -168,13 +168,23 @@
avifRGBImageSetDefaults(&srcRGB, image);
srcRGB.format = AVIF_RGB_FORMAT_RGB;
srcRGB.depth = rgbDepth;
- avifRGBImageAllocatePixels(&srcRGB);
avifRGBImage dstRGB;
avifRGBImageSetDefaults(&dstRGB, image);
dstRGB.format = AVIF_RGB_FORMAT_RGB;
dstRGB.depth = rgbDepth;
- avifRGBImageAllocatePixels(&dstRGB);
+
+ if ((avifRGBImageAllocatePixels(&srcRGB) != AVIF_RESULT_OK)) {
+ avifImageDestroy(image);
+ fprintf(stderr, "ERROR: Out of memory\n");
+ return 1;
+ }
+ if ((avifRGBImageAllocatePixels(&dstRGB) != AVIF_RESULT_OK)) {
+ avifRGBImageFreePixels(&srcRGB);
+ avifImageDestroy(image);
+ fprintf(stderr, "ERROR: Out of memory\n");
+ return 1;
+ }
uint64_t driftPixelCounts[MAX_DRIFT];
for (int i = 0; i < MAX_DRIFT; ++i) {
@@ -259,7 +269,10 @@
maxDrift = drift;
}
} else {
- printf("ERROR: Encountered a drift greater than or equal to MAX_DRIFT(%d): %d\n", MAX_DRIFT, drift);
+ fprintf(stderr,
+ "ERROR: Encountered a drift greater than or equal to MAX_DRIFT(%d): %d\n",
+ MAX_DRIFT,
+ drift);
return 1;
}
}
@@ -307,7 +320,7 @@
avifImage * image = avifImageCreate(originalWidth, originalHeight, 8, AVIF_PIXEL_FORMAT_YUV444);
if (!image) {
- printf("ERROR: Out of memory\n");
+ fprintf(stderr, "ERROR: Out of memory\n");
return 1;
}
@@ -317,7 +330,11 @@
avifRGBImage srcRGB;
avifRGBImageSetDefaults(&srcRGB, image);
srcRGB.depth = yuvDepth;
- avifRGBImageAllocatePixels(&srcRGB);
+ if (avifRGBImageAllocatePixels(&srcRGB) != AVIF_RESULT_OK) {
+ avifImageDestroy(image);
+ fprintf(stderr, "ERROR: Out of memory\n");
+ return 1;
+ }
if (yuvDepth > 8) {
float maxChannelF = (float)((1 << yuvDepth) - 1);
for (uint32_t j = 0; j < srcRGB.height; ++j) {
@@ -362,7 +379,12 @@
avifRGBImageSetDefaults(&intermediateRGB, image);
intermediateRGB.depth = rgbDepth;
intermediateRGB.format = rgbFormat;
- avifRGBImageAllocatePixels(&intermediateRGB);
+ if (avifRGBImageAllocatePixels(&intermediateRGB) != AVIF_RESULT_OK) {
+ avifRGBImageFreePixels(&srcRGB);
+ avifImageDestroy(image);
+ fprintf(stderr, "ERROR: Out of memory\n");
+ return 1;
+ }
avifImageYUVToRGB(image, &intermediateRGB);
avifImageFreePlanes(image, AVIF_PLANES_ALL);
@@ -371,7 +393,13 @@
avifRGBImage dstRGB;
avifRGBImageSetDefaults(&dstRGB, image);
dstRGB.depth = yuvDepth;
- avifRGBImageAllocatePixels(&dstRGB);
+ if (avifRGBImageAllocatePixels(&dstRGB) != AVIF_RESULT_OK) {
+ avifRGBImageFreePixels(&intermediateRGB);
+ avifRGBImageFreePixels(&srcRGB);
+ avifImageDestroy(image);
+ fprintf(stderr, "ERROR: Out of memory\n");
+ return 1;
+ }
avifImageYUVToRGB(image, &dstRGB);
avifBool moveOn = AVIF_FALSE;
@@ -463,7 +491,10 @@
for (int i = 0; i < MAX_DRIFT; ++i) {
driftPixelCounts[i] = 0;
}
- avifRGBImageAllocatePixels(&rgb);
+ if (avifRGBImageAllocatePixels(&rgb) != AVIF_RESULT_OK) {
+ fprintf(stderr, "ERROR: Out of memory\n");
+ return 1;
+ }
for (uint32_t a = 0; a < size; ++a) {
// meaningful premultiplied RGB value can't exceed A value, so stop at R = A
@@ -492,12 +523,13 @@
uint8_t * pixel = &rgb.pixels[r * sizeof(uint8_t) * 4];
int drift = abs((int)pixel[0] - (int)r);
if (drift >= MAX_DRIFT) {
- printf("ERROR: Premultiply round-trip difference greater than or equal to MAX_DRIFT(%d): RGB depth: %d, src: %d, dst: %d, alpha: %d.\n",
- MAX_DRIFT,
- rgbDepth,
- pixel[0],
- r,
- a);
+ fprintf(stderr,
+ "ERROR: Premultiply round-trip difference greater than or equal to MAX_DRIFT(%d): RGB depth: %d, src: %d, dst: %d, alpha: %d.\n",
+ MAX_DRIFT,
+ rgbDepth,
+ pixel[0],
+ r,
+ a);
return 1;
}
if (maxDrift < drift) {
@@ -508,12 +540,13 @@
uint16_t * pixel = (uint16_t *)&rgb.pixels[r * sizeof(uint16_t) * 4];
int drift = abs((int)pixel[0] - (int)r);
if (drift >= MAX_DRIFT) {
- printf("ERROR: Premultiply round-trip difference greater than or equal to MAX_DRIFT(%d): RGB depth: %d, src: %d, dst: %d, alpha: %d.\n",
- MAX_DRIFT,
- rgbDepth,
- pixel[0],
- r,
- a);
+ fprintf(stderr,
+ "ERROR: Premultiply round-trip difference greater than or equal to MAX_DRIFT(%d): RGB depth: %d, src: %d, dst: %d, alpha: %d.\n",
+ MAX_DRIFT,
+ rgbDepth,
+ pixel[0],
+ r,
+ a);
return 1;
}
if (maxDrift < drift) {
diff --git a/tests/gtest/aviftest_helpers.cc b/tests/gtest/aviftest_helpers.cc
index 283a681..12eed18 100644
--- a/tests/gtest/aviftest_helpers.cc
+++ b/tests/gtest/aviftest_helpers.cc
@@ -6,6 +6,7 @@
#include <algorithm>
#include <cassert>
#include <cstdint>
+#include <cstdlib>
#include <string>
#include "avif/avif.h"
@@ -21,7 +22,9 @@
avifRGBImageSetDefaults(this, yuv);
depth = rgbDepth;
format = rgbFormat;
- avifRGBImageAllocatePixels(this);
+ if (avifRGBImageAllocatePixels(this) != AVIF_RESULT_OK) {
+ std::abort();
+ }
}
AvifRwData::AvifRwData(AvifRwData&& other) : avifRWData{other} {
diff --git a/tests/oss-fuzz/avif_decode_fuzzer.cc b/tests/oss-fuzz/avif_decode_fuzzer.cc
index 74c65e7..117aae5 100644
--- a/tests/oss-fuzz/avif_decode_fuzzer.cc
+++ b/tests/oss-fuzz/avif_decode_fuzzer.cc
@@ -50,7 +50,9 @@
rgb.depth = rgbDepths[rgbDepthsIndex];
rgb.chromaUpsampling = upsamplings[upsamplingsIndex];
rgb.avoidLibYUV = AVIF_TRUE;
- avifRGBImageAllocatePixels(&rgb);
+ if (avifRGBImageAllocatePixels(&rgb) != AVIF_RESULT_OK) {
+ continue;
+ }
avifResult rgbResult = avifImageYUVToRGB(decoder->image, &rgb);
// Since avifImageRGBToYUV() ignores rgb.chromaUpsampling, we only need
// to test avifImageRGBToYUV() with a single upsamplingsIndex.
@@ -61,9 +63,10 @@
decoder->image->height,
yuvDepths[yuvDepthsIndex],
decoder->image->yuvFormat);
- avifResult yuvResult = avifImageRGBToYUV(tempImage, &rgb);
- if (yuvResult != AVIF_RESULT_OK) {
+ if (!tempImage) {
+ continue;
}
+ (void)avifImageRGBToYUV(tempImage, &rgb);
avifImageDestroy(tempImage);
}
}