blob: 8f69f9f4be49662d2031fd59874b07c0c74ccef1 [file] [log] [blame]
// Copyright 2023 Google LLC
// SPDX-License-Identifier: BSD-2-Clause
// Decodes an arbitrary sequence of bytes.
#include <algorithm>
#include <cstdint>
#include <limits>
#include "avif/avif.h"
#include "avif_fuzztest_helpers.h"
#include "aviftest_helpers.h"
#include "fuzztest/fuzztest.h"
#include "gtest/gtest.h"
using ::fuzztest::Arbitrary;
namespace avif {
namespace testutil {
namespace {
//------------------------------------------------------------------------------
void Parse(const std::string& arbitrary_bytes, bool is_persistent,
DecoderPtr decoder) {
ASSERT_FALSE(GetSeedDataDirs().empty()); // Make sure seeds are available.
const uint8_t* data =
reinterpret_cast<const uint8_t*>(arbitrary_bytes.data());
avifIO* const io = avifIOCreateMemoryReader(data, arbitrary_bytes.size());
if (io == nullptr) return;
io->persistent = is_persistent;
avifDecoderSetIO(decoder.get(), io);
// No need to worry about decoding taking too much time or memory because
// this test only exercises parsing.
decoder->imageSizeLimit = AVIF_DEFAULT_IMAGE_SIZE_LIMIT;
decoder->imageDimensionLimit = std::numeric_limits<uint32_t>::max();
decoder->imageCountLimit = 0;
// AVIF_RESULT_INTERNAL_ERROR means a broken invariant and should not happen.
ASSERT_NE(avifDecoderParse(decoder.get()), AVIF_RESULT_INTERNAL_ERROR);
}
FUZZ_TEST(ParseAvifTest, Parse)
.WithDomains(ArbitraryImageWithSeeds({AVIF_APP_FILE_FORMAT_AVIF}),
/*is_persistent=*/Arbitrary<bool>(),
ArbitraryAvifDecoderPossiblyNoContent());
//------------------------------------------------------------------------------
void Decode(const std::string& arbitrary_bytes, bool is_persistent,
DecoderPtr decoder) {
ASSERT_FALSE(GetSeedDataDirs().empty()); // Make sure seeds are available.
const uint8_t* data =
reinterpret_cast<const uint8_t*>(arbitrary_bytes.data());
avifIO* const io = avifIOCreateMemoryReader(data, arbitrary_bytes.size());
if (io == nullptr) return;
// The Chrome's avifIO object is not persistent.
io->persistent = is_persistent;
avifDecoderSetIO(decoder.get(), io);
avifResult result = avifDecoderParse(decoder.get());
// AVIF_RESULT_INTERNAL_ERROR means a broken invariant and should not happen.
ASSERT_NE(result, AVIF_RESULT_INTERNAL_ERROR);
if (result != AVIF_RESULT_OK) return;
for (size_t i = 0; i < decoder->image->numProperties; ++i) {
const avifRWData& box_payload = decoder->image->properties[i].boxPayload;
// Each custom property should be found as is in the input bitstream.
EXPECT_NE(std::search(data, data + arbitrary_bytes.size(), box_payload.data,
box_payload.data + box_payload.size),
data + arbitrary_bytes.size());
}
while ((result = avifDecoderNextImage(decoder.get())) == AVIF_RESULT_OK) {
EXPECT_GT(decoder->image->width, 0u);
EXPECT_GT(decoder->image->height, 0u);
}
ASSERT_NE(result, AVIF_RESULT_INTERNAL_ERROR);
// Loop once.
result = avifDecoderReset(decoder.get());
ASSERT_NE(result, AVIF_RESULT_INTERNAL_ERROR);
if (result != AVIF_RESULT_OK) return;
while ((result = avifDecoderNextImage(decoder.get())) == AVIF_RESULT_OK) {
}
ASSERT_NE(result, AVIF_RESULT_INTERNAL_ERROR);
}
FUZZ_TEST(DecodeAvifTest, Decode)
.WithDomains(ArbitraryImageWithSeeds({AVIF_APP_FILE_FORMAT_AVIF}),
/*is_persistent=*/Arbitrary<bool>(),
ArbitraryAvifDecoderPossiblyNoContent());
//------------------------------------------------------------------------------
} // namespace
} // namespace testutil
} // namespace avif