diff --git a/src/gainmap.c b/src/gainmap.c index d7acc700a5..f6f24c434b 100644 --- a/src/gainmap.c +++ b/src/gainmap.c @@ -420,6 +420,11 @@ avifResult avifGainMapValidateMetadata(const avifGainMap * gainMap, avifDiagnost avifDiagnosticsPrintf(diag, "Per-channel denominator is 0 in gain map metadata"); return AVIF_RESULT_INVALID_ARGUMENT; } + if ((int64_t)gainMap->gainMapMax[i].n * gainMap->gainMapMin[i].d < + (int64_t)gainMap->gainMapMin[i].n * gainMap->gainMapMax[i].d) { + avifDiagnosticsPrintf(diag, "Per-channel max is less than per-channel min in gain map metadata"); + return AVIF_RESULT_INVALID_ARGUMENT; + } if (gainMap->gainMapGamma[i].n == 0) { avifDiagnosticsPrintf(diag, "Per-channel gamma is 0 in gain map metadata"); return AVIF_RESULT_INVALID_ARGUMENT; diff --git a/tests/gtest/avif_fuzztest_enc_dec.cc b/tests/gtest/avif_fuzztest_enc_dec.cc index 80dd79b834..7ffee3dcbe 100644 --- a/tests/gtest/avif_fuzztest_enc_dec.cc +++ b/tests/gtest/avif_fuzztest_enc_dec.cc @@ -49,12 +49,12 @@ void EncodeDecodeValid(ImagePtr image, EncoderPtr encoder, DecoderPtr decoder) { const avifResult encoder_result = avifEncoderWrite(encoder.get(), image.get(), &encoded_data); ASSERT_EQ(encoder_result, AVIF_RESULT_OK) - << avifResultToString(encoder_result); + << avifResultToString(encoder_result) << " " << encoder->diag.error; const avifResult decoder_result = avifDecoderReadMemory( decoder.get(), decoded_image.get(), encoded_data.data, encoded_data.size); ASSERT_EQ(decoder_result, AVIF_RESULT_OK) - << avifResultToString(decoder_result); + << avifResultToString(decoder_result) << " " << decoder->diag.error; EXPECT_EQ(decoded_image->width, image->width); EXPECT_EQ(decoded_image->height, image->height); diff --git a/tests/gtest/avif_fuzztest_helpers.cc b/tests/gtest/avif_fuzztest_helpers.cc index cf5633c61c..cfb0f7b902 100644 --- a/tests/gtest/avif_fuzztest_helpers.cc +++ b/tests/gtest/avif_fuzztest_helpers.cc @@ -163,11 +163,10 @@ DecoderPtr AddGainMapOptionsToDecoder( } ImagePtr AddGainMapToImage( - ImagePtr image, ImagePtr gain_map, int32_t gain_map_min_n0, - int32_t gain_map_min_n1, int32_t gain_map_min_n2, uint32_t gain_map_min_d0, - uint32_t gain_map_min_d1, uint32_t gain_map_min_d2, int32_t gain_map_max_n0, - int32_t gain_map_max_n1, int32_t gain_map_max_n2, uint32_t gain_map_max_d0, - uint32_t gain_map_max_d1, uint32_t gain_map_max_d2, + ImagePtr image, ImagePtr gain_map, + const std::pair& gain_map_min_max0, + const std::pair& gain_map_min_max1, + const std::pair& gain_map_min_max2, uint32_t gain_map_gamma_n0, uint32_t gain_map_gamma_n1, uint32_t gain_map_gamma_n2, uint32_t gain_map_gamma_d0, uint32_t gain_map_gamma_d1, uint32_t gain_map_gamma_d2, @@ -182,13 +181,13 @@ ImagePtr AddGainMapToImage( image->gainMap = avifGainMapCreate(); image->gainMap->image = gain_map.release(); - image->gainMap->gainMapMin[0] = {gain_map_min_n0, gain_map_min_d0}; - image->gainMap->gainMapMin[1] = {gain_map_min_n1, gain_map_min_d1}; - image->gainMap->gainMapMin[2] = {gain_map_min_n2, gain_map_min_d2}; + image->gainMap->gainMapMin[0] = gain_map_min_max0.first; + image->gainMap->gainMapMin[1] = gain_map_min_max1.first; + image->gainMap->gainMapMin[2] = gain_map_min_max2.first; - image->gainMap->gainMapMax[0] = {gain_map_max_n0, gain_map_max_d0}; - image->gainMap->gainMapMax[1] = {gain_map_max_n1, gain_map_max_d1}; - image->gainMap->gainMapMax[2] = {gain_map_max_n2, gain_map_max_d2}; + image->gainMap->gainMapMax[0] = gain_map_min_max0.second; + image->gainMap->gainMapMax[1] = gain_map_min_max1.second; + image->gainMap->gainMapMax[2] = gain_map_min_max2.second; image->gainMap->gainMapGamma[0] = {gain_map_gamma_n0, gain_map_gamma_d0}; image->gainMap->gainMapGamma[1] = {gain_map_gamma_n1, gain_map_gamma_d1}; diff --git a/tests/gtest/avif_fuzztest_helpers.h b/tests/gtest/avif_fuzztest_helpers.h index 2f11f8cdd1..c3d57916c1 100644 --- a/tests/gtest/avif_fuzztest_helpers.h +++ b/tests/gtest/avif_fuzztest_helpers.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "avif/avif.h" @@ -167,13 +168,31 @@ inline auto ArbitraryAvifAnim() { return fuzztest::OneOf(ArbitraryAvifAnim8b(), ArbitraryAvifAnim16b()); } -// TODO: Try StructOf(StructOf())? +// Generates two signed fractions where the first one is smaller than the second +// one. +inline auto ArbitraryMinMaxSignedFraction() { + return fuzztest::FlatMap( + [](int32_t max_n, uint32_t max_d) { + return fuzztest::Map( + [max_n, max_d](int32_t min_n) { + // For simplicity, use the same denominator for both fractions. + // This does not cover all possible fractions but makes it easy + // to gurantee that the fraction is smaller. + return std::pair( + {min_n, max_d}, {max_n, max_d}); + }, + fuzztest::InRange(std::numeric_limits::min(), + max_n)); + }, + fuzztest::Arbitrary(), + fuzztest::InRange(1, std::numeric_limits::max())); +} + ImagePtr AddGainMapToImage( - ImagePtr image, ImagePtr gain_map, int32_t gain_map_min_n0, - int32_t gain_map_min_n1, int32_t gain_map_min_n2, uint32_t gain_map_min_d0, - uint32_t gain_map_min_d1, uint32_t gain_map_min_d2, int32_t gain_map_max_n0, - int32_t gain_map_max_n1, int32_t gain_map_max_n2, uint32_t gain_map_max_d0, - uint32_t gain_map_max_d1, uint32_t gain_map_max_d2, + ImagePtr image, ImagePtr gain_map, + const std::pair& gain_map_min_max0, + const std::pair& gain_map_min_max1, + const std::pair& gain_map_min_max2, uint32_t gain_map_gamma_n0, uint32_t gain_map_gamma_n1, uint32_t gain_map_gamma_n2, uint32_t gain_map_gamma_d0, uint32_t gain_map_gamma_d1, uint32_t gain_map_gamma_d2, @@ -189,16 +208,8 @@ ImagePtr AddGainMapToImage( inline auto ArbitraryAvifImageWithGainMap() { return fuzztest::Map( AddGainMapToImage, ArbitraryAvifImage(), ArbitraryAvifImage(), - fuzztest::Arbitrary(), fuzztest::Arbitrary(), - fuzztest::Arbitrary(), - fuzztest::InRange(1, std::numeric_limits::max()), - fuzztest::InRange(1, std::numeric_limits::max()), - fuzztest::InRange(1, std::numeric_limits::max()), - fuzztest::Arbitrary(), fuzztest::Arbitrary(), - fuzztest::Arbitrary(), - fuzztest::InRange(1, std::numeric_limits::max()), - fuzztest::InRange(1, std::numeric_limits::max()), - fuzztest::InRange(1, std::numeric_limits::max()), + ArbitraryMinMaxSignedFraction(), ArbitraryMinMaxSignedFraction(), + ArbitraryMinMaxSignedFraction(), fuzztest::InRange(1, std::numeric_limits::max()), fuzztest::InRange(1, std::numeric_limits::max()), fuzztest::InRange(1, std::numeric_limits::max()),