// Copyright 2018-2024 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //////////////////////////////////////////////////////////////////////////////// #ifndef WEBP_TESTS_FUZZER_FUZZ_UTILS_H_ #define WEBP_TESTS_FUZZER_FUZZ_UTILS_H_ #include #include #include #include #include #include #include #include #include "./img_alpha.h" #include "./img_grid.h" #include "./img_peak.h" #include "src/dsp/cpu.h" #include "src/webp/encode.h" #include "fuzztest/fuzztest.h" namespace fuzz_utils { //------------------------------------------------------------------------------ // Arbitrary limits to prevent OOM, timeout, or slow execution. // The decoded image size, and for animations additionally the canvas size. // Enabling some sanitizers slow down runtime significantly. // Use a very low threshold in this case to avoid timeouts. #if defined(__SANITIZE_ADDRESS__) // GCC static const size_t kFuzzPxLimit = 1024 * 1024 / 10; #elif !defined(__has_feature) // Clang static const size_t kFuzzPxLimit = 1024 * 1024; #elif __has_feature(address_sanitizer) || __has_feature(memory_sanitizer) static const size_t kFuzzPxLimit = 1024 * 1024 / 18; #else static const size_t kFuzzPxLimit = 1024 * 1024; #endif // Demuxed or decoded animation frames. static const int kFuzzFrameLimit = 3; // Reads and sums (up to) 128 spread-out bytes. static WEBP_INLINE uint8_t FuzzHash(const uint8_t* const data, size_t size) { uint8_t value = 0; size_t incr = size / 128; if (!incr) incr = 1; for (size_t i = 0; i < size; i += incr) value += data[i]; return value; } #ifdef __cplusplus extern "C" VP8CPUInfo VP8GetCPUInfo; #else extern VP8CPUInfo VP8GetCPUInfo; #endif //------------------------------------------------------------------------------ constexpr const uint8_t* kImagesData[] = {kImgAlphaData, kImgGridData, kImgPeakData}; constexpr size_t kNumSourceImages = sizeof(kImagesData) / sizeof(kImagesData[0]); WebPPicture GetSourcePicture(int image_index, bool use_argb); static inline auto ArbitraryWebPConfig() { return fuzztest::Map( [](int lossless, int quality, int method, int image_hint, int segments, int sns_strength, int filter_strength, int filter_sharpness, int filter_type, int autofilter, int alpha_compression, int alpha_filtering, int alpha_quality, int pass, int preprocessing, int partitions, int partition_limit, int emulate_jpeg_size, int thread_level, int low_memory, int near_lossless, int exact, int use_delta_palette, int use_sharp_yuv) -> WebPConfig { WebPConfig config; if (!WebPConfigInit(&config)) abort(); config.lossless = lossless; config.quality = quality; config.method = method; config.image_hint = (WebPImageHint)image_hint; config.segments = segments; config.sns_strength = sns_strength; config.filter_strength = filter_strength; config.filter_sharpness = filter_sharpness; config.filter_type = filter_type; config.autofilter = autofilter; config.alpha_compression = alpha_compression; config.alpha_filtering = alpha_filtering; config.alpha_quality = alpha_quality; config.pass = pass; config.show_compressed = 1; config.preprocessing = preprocessing; config.partitions = partitions; config.partition_limit = 10 * partition_limit; config.emulate_jpeg_size = emulate_jpeg_size; config.thread_level = thread_level; config.low_memory = low_memory; config.near_lossless = 20 * near_lossless; config.exact = exact; config.use_delta_palette = use_delta_palette; config.use_sharp_yuv = use_sharp_yuv; if (!WebPValidateConfig(&config)) abort(); return config; }, /*lossless=*/fuzztest::InRange(0, 1), /*quality=*/fuzztest::InRange(0, 100), /*method=*/fuzztest::InRange(0, 6), /*image_hint=*/fuzztest::InRange(0, WEBP_HINT_LAST - 1), /*segments=*/fuzztest::InRange(1, 4), /*sns_strength=*/fuzztest::InRange(0, 100), /*filter_strength=*/fuzztest::InRange(0, 100), /*filter_sharpness=*/fuzztest::InRange(0, 7), /*filter_type=*/fuzztest::InRange(0, 1), /*autofilter=*/fuzztest::InRange(0, 1), /*alpha_compression=*/fuzztest::InRange(0, 1), /*alpha_filtering=*/fuzztest::InRange(0, 2), /*alpha_quality=*/fuzztest::InRange(0, 100), /*pass=*/fuzztest::InRange(1, 10), /*preprocessing=*/fuzztest::InRange(0, 2), /*partitions=*/fuzztest::InRange(0, 3), /*partition_limit=*/fuzztest::InRange(0, 10), /*emulate_jpeg_size=*/fuzztest::InRange(0, 1), /*thread_level=*/fuzztest::InRange(0, 1), /*low_memory=*/fuzztest::InRange(0, 1), /*near_lossless=*/fuzztest::InRange(0, 5), /*exact=*/fuzztest::InRange(0, 1), /*use_delta_palette=*/fuzztest::InRange(0, 1), /*use_sharp_yuv=*/fuzztest::InRange(0, 1)); } struct CropOrScaleParams { bool alter_input; bool crop_or_scale; int width_ratio; int height_ratio; int left_ratio; int top_ratio; }; static inline auto ArbitraryCropOrScaleParams() { return fuzztest::Map( [](const std::optional>& width_height_ratio, const std::optional>& left_top_ratio) -> CropOrScaleParams { CropOrScaleParams params; params.alter_input = width_height_ratio.has_value(); if (params.alter_input) { params.width_ratio = width_height_ratio->first; params.height_ratio = width_height_ratio->second; params.crop_or_scale = left_top_ratio.has_value(); if (params.crop_or_scale) { params.left_ratio = left_top_ratio->first; params.top_ratio = left_top_ratio->second; } } return params; }, fuzztest::OptionalOf( fuzztest::PairOf(fuzztest::InRange(1, 8), fuzztest::InRange(1, 8))), fuzztest::OptionalOf( fuzztest::PairOf(fuzztest::InRange(1, 8), fuzztest::InRange(1, 8)))); } // Crops or scales a picture according to the given params. int CropOrScale(WebPPicture* pic, const CropOrScaleParams& params); // Imposes a level of optimization among one of the kMaxOptimizationIndex+1 // possible values: OnlyC, ForceSlowSSSE3, NoSSE41, NoAVX, default. static constexpr uint32_t kMaxOptimizationIndex = 4; void SetOptimization(VP8CPUInfo default_VP8GetCPUInfo, uint32_t index); //------------------------------------------------------------------------------ // See https://developers.google.com/speed/webp/docs/riff_container. static constexpr size_t kMaxWebPFileSize = (1ull << 32) - 2; // 4 GiB - 2 std::vector GetDictionaryFromFiles( const std::vector& file_paths); // Checks whether the binary blob containing a JPEG or WebP is too big for the // fuzzer. bool IsImageTooBig(const uint8_t* data, size_t size); } // namespace fuzz_utils #endif // WEBP_TESTS_FUZZER_FUZZ_UTILS_H_