Return error code on avifinfo_tool failure Change-Id: Iadbef3dbd6ad3565d1c8b0c218238123e9df5f3c
diff --git a/tools/avifinfo_tool.cc b/tools/avifinfo_tool.cc index 4d4e4ae..4a086fe 100644 --- a/tools/avifinfo_tool.cc +++ b/tools/avifinfo_tool.cc
@@ -8,8 +8,9 @@ // PATENTS file, you can obtain it at www.aomedia.org/license/patent. #include <algorithm> +#include <cstdint> #include <cstring> -#include <filesystem> +#include <filesystem> // NOLINT #include <fstream> #include <iostream> #include <iterator> @@ -33,6 +34,7 @@ str += " --fast .......... Skip libavif decoding, only use libavifinfo\n"; str += " --min-size ...... Find minimum size to extract features per file\n"; str += " --validate ...... Check libavifinfo consistency on each file\n"; + str += " --no-bad-file ... Return an error code in case of invalid file\n"; return str; } @@ -148,7 +150,9 @@ } // Uses libavif then libavifinfo to extract the features of an AVIF file. -void DecodeAndParseFile(const std::string& path, const uint8_t* data, +// Returns false in case of libavifinfo parsing failure or behavior +// inconsistency compared to libavif. +bool DecodeAndParseFile(const std::string& path, const uint8_t* data, size_t data_size, Stats& stats) { const Result decode = DecodeAvif(data, data_size); const Result parse = ParseAvif(data, data_size); @@ -174,7 +178,9 @@ << " / parsing " << (parse.success ? "success" : "failure"); } std::cout << " for " << path << std::endl; + return false; } + return true; } // Returns the minimum number of bytes of AVIF 'data' for features to be @@ -191,11 +197,14 @@ } // Checks the consistency of libavifinfo over an AVIF file. -void ValidateFile(const std::string& path, const uint8_t* data, +// Returns false in case of error. +bool ValidateFile(const std::string& path, const uint8_t* data, size_t data_size) { if (LLVMFuzzerTestOneInput(data, data_size) != 0) { std::cout << "validation failed for " << path << std::endl; + return false; } + return true; } } // namespace @@ -207,6 +216,7 @@ bool only_parse = false; bool find_min_size = false; bool validate = false; + bool error_on_bad_file = false; for (int arg = 1; arg < argc; ++arg) { if (!std::strcmp(argv[arg], "-h")) { @@ -219,6 +229,8 @@ only_parse = true; } else if (!std::strcmp(argv[arg], "--validate")) { validate = true; + } else if (!std::strcmp(argv[arg], "--no-bad-file")) { + error_on_bad_file = true; } else { FindFiles(argv[arg], file_paths); } @@ -234,6 +246,7 @@ } Stats stats; + bool success = true; for (const std::string& file_path : file_paths) { std::vector<uint8_t> bytes(std::filesystem::file_size(prefix + file_path)); std::ifstream file(prefix + file_path, std::ios::binary); @@ -242,11 +255,12 @@ FindMinSizeOfFile(file_path, bytes.data(), bytes.size(), stats); } else if (only_parse) { ParseFile(file_path, bytes.data(), bytes.size(), stats); - } else { - DecodeAndParseFile(file_path, bytes.data(), bytes.size(), stats); + } else if (!DecodeAndParseFile(file_path, bytes.data(), bytes.size(), + stats)) { + success = false; } - if (validate) { - ValidateFile(file_path, bytes.data(), bytes.size()); + if (validate && !ValidateFile(file_path, bytes.data(), bytes.size())) { + success = false; } } @@ -266,5 +280,10 @@ << " bytes to extract features" << std::endl; } } - return 0; + + if (error_on_bad_file && (stats.num_files_invalid_at_parse > 0 || + stats.num_files_invalid_at_decode > 0)) { + success = false; + } + return success ? 0 : 1; }