fuzz_utils.h (7837B)
1 // Copyright 2018-2024 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 //////////////////////////////////////////////////////////////////////////////// 16 17 #ifndef WEBP_TESTS_FUZZER_FUZZ_UTILS_H_ 18 #define WEBP_TESTS_FUZZER_FUZZ_UTILS_H_ 19 20 #include <cstddef> 21 #include <cstdint> 22 #include <cstdlib> 23 #include <optional> 24 #include <string> 25 #include <string_view> 26 #include <utility> 27 #include <vector> 28 29 #include "./img_alpha.h" 30 #include "./img_grid.h" 31 #include "./img_peak.h" 32 #include "fuzztest/fuzztest.h" 33 #include "src/dsp/cpu.h" 34 #include "src/webp/encode.h" 35 #include "src/webp/types.h" 36 37 namespace fuzz_utils { 38 39 //------------------------------------------------------------------------------ 40 // Arbitrary limits to prevent OOM, timeout, or slow execution. 41 42 // The decoded image size, and for animations additionally the canvas size. 43 // Enabling some sanitizers slow down runtime significantly. 44 // Use a very low threshold in this case to avoid timeouts. 45 #if defined(__SANITIZE_ADDRESS__) // GCC 46 static const size_t kFuzzPxLimit = 1024 * 1024 / 10; 47 #elif !defined(__has_feature) // Clang 48 static const size_t kFuzzPxLimit = 1024 * 1024; 49 #elif __has_feature(address_sanitizer) || __has_feature(memory_sanitizer) 50 static const size_t kFuzzPxLimit = 1024 * 1024 / 18; 51 #else 52 static const size_t kFuzzPxLimit = 1024 * 1024; 53 #endif 54 55 // Demuxed or decoded animation frames. 56 static const int kFuzzFrameLimit = 3; 57 58 // Reads and sums (up to) 128 spread-out bytes. 59 static WEBP_INLINE uint8_t FuzzHash(const uint8_t* const data, size_t size) { 60 uint8_t value = 0; 61 size_t incr = size / 128; 62 if (!incr) incr = 1; 63 for (size_t i = 0; i < size; i += incr) value += data[i]; 64 return value; 65 } 66 67 #ifdef __cplusplus 68 extern "C" VP8CPUInfo VP8GetCPUInfo; 69 #else 70 extern VP8CPUInfo VP8GetCPUInfo; 71 #endif 72 73 //------------------------------------------------------------------------------ 74 75 constexpr const uint8_t* kImagesData[] = {kImgAlphaData, kImgGridData, 76 kImgPeakData}; 77 constexpr size_t kNumSourceImages = 78 sizeof(kImagesData) / sizeof(kImagesData[0]); 79 80 WebPPicture GetSourcePicture(int image_index, bool use_argb); 81 82 static inline auto ArbitraryWebPConfig() { 83 return fuzztest::Map( 84 [](int lossless, int quality, int method, int image_hint, int segments, 85 int sns_strength, int filter_strength, int filter_sharpness, 86 int filter_type, int autofilter, int alpha_compression, 87 int alpha_filtering, int alpha_quality, int pass, int preprocessing, 88 int partitions, int partition_limit, int emulate_jpeg_size, 89 int thread_level, int low_memory, int near_lossless, int exact, 90 int use_delta_palette, int use_sharp_yuv) -> WebPConfig { 91 WebPConfig config; 92 if (!WebPConfigInit(&config)) abort(); 93 config.lossless = lossless; 94 config.quality = quality; 95 config.method = method; 96 config.image_hint = (WebPImageHint)image_hint; 97 config.segments = segments; 98 config.sns_strength = sns_strength; 99 config.filter_strength = filter_strength; 100 config.filter_sharpness = filter_sharpness; 101 config.filter_type = filter_type; 102 config.autofilter = autofilter; 103 config.alpha_compression = alpha_compression; 104 config.alpha_filtering = alpha_filtering; 105 config.alpha_quality = alpha_quality; 106 config.pass = pass; 107 config.show_compressed = 1; 108 config.preprocessing = preprocessing; 109 config.partitions = partitions; 110 config.partition_limit = 10 * partition_limit; 111 config.emulate_jpeg_size = emulate_jpeg_size; 112 config.thread_level = thread_level; 113 config.low_memory = low_memory; 114 config.near_lossless = 20 * near_lossless; 115 config.exact = exact; 116 config.use_delta_palette = use_delta_palette; 117 config.use_sharp_yuv = use_sharp_yuv; 118 if (!WebPValidateConfig(&config)) abort(); 119 return config; 120 }, 121 /*lossless=*/fuzztest::InRange<int>(0, 1), 122 /*quality=*/fuzztest::InRange<int>(0, 100), 123 /*method=*/fuzztest::InRange<int>(0, 6), 124 /*image_hint=*/fuzztest::InRange<int>(0, WEBP_HINT_LAST - 1), 125 /*segments=*/fuzztest::InRange<int>(1, 4), 126 /*sns_strength=*/fuzztest::InRange<int>(0, 100), 127 /*filter_strength=*/fuzztest::InRange<int>(0, 100), 128 /*filter_sharpness=*/fuzztest::InRange<int>(0, 7), 129 /*filter_type=*/fuzztest::InRange<int>(0, 1), 130 /*autofilter=*/fuzztest::InRange<int>(0, 1), 131 /*alpha_compression=*/fuzztest::InRange<int>(0, 1), 132 /*alpha_filtering=*/fuzztest::InRange<int>(0, 2), 133 /*alpha_quality=*/fuzztest::InRange<int>(0, 100), 134 /*pass=*/fuzztest::InRange<int>(1, 10), 135 /*preprocessing=*/fuzztest::InRange<int>(0, 2), 136 /*partitions=*/fuzztest::InRange<int>(0, 3), 137 /*partition_limit=*/fuzztest::InRange<int>(0, 10), 138 /*emulate_jpeg_size=*/fuzztest::InRange<int>(0, 1), 139 /*thread_level=*/fuzztest::InRange<int>(0, 1), 140 /*low_memory=*/fuzztest::InRange<int>(0, 1), 141 /*near_lossless=*/fuzztest::InRange<int>(0, 5), 142 /*exact=*/fuzztest::InRange<int>(0, 1), 143 /*use_delta_palette=*/fuzztest::InRange<int>(0, 1), 144 /*use_sharp_yuv=*/fuzztest::InRange<int>(0, 1)); 145 } 146 147 struct CropOrScaleParams { 148 bool alter_input; 149 bool crop_or_scale; 150 int width_ratio; 151 int height_ratio; 152 int left_ratio; 153 int top_ratio; 154 }; 155 156 static inline auto ArbitraryCropOrScaleParams() { 157 return fuzztest::Map( 158 [](const std::optional<std::pair<int, int>>& width_height_ratio, 159 const std::optional<std::pair<int, int>>& left_top_ratio) 160 -> CropOrScaleParams { 161 CropOrScaleParams params; 162 params.alter_input = width_height_ratio.has_value(); 163 if (params.alter_input) { 164 params.width_ratio = width_height_ratio->first; 165 params.height_ratio = width_height_ratio->second; 166 params.crop_or_scale = left_top_ratio.has_value(); 167 if (params.crop_or_scale) { 168 params.left_ratio = left_top_ratio->first; 169 params.top_ratio = left_top_ratio->second; 170 } 171 } 172 return params; 173 }, 174 fuzztest::OptionalOf( 175 fuzztest::PairOf(fuzztest::InRange(1, 8), fuzztest::InRange(1, 8))), 176 fuzztest::OptionalOf( 177 fuzztest::PairOf(fuzztest::InRange(1, 8), fuzztest::InRange(1, 8)))); 178 } 179 180 // Crops or scales a picture according to the given params. 181 int CropOrScale(WebPPicture* pic, const CropOrScaleParams& params); 182 183 // Imposes a level of optimization among one of the kMaxOptimizationIndex+1 184 // possible values: OnlyC, ForceSlowSSSE3, NoSSE41, NoAVX, default. 185 static constexpr uint32_t kMaxOptimizationIndex = 4; 186 void SetOptimization(VP8CPUInfo default_VP8GetCPUInfo, uint32_t index); 187 188 //------------------------------------------------------------------------------ 189 190 // See https://developers.google.com/speed/webp/docs/riff_container. 191 static constexpr size_t kMaxWebPFileSize = (1ull << 32) - 2; // 4 GiB - 2 192 193 std::vector<std::string> GetDictionaryFromFiles( 194 const std::vector<std::string_view>& file_paths); 195 196 // Checks whether the binary blob containing a JPEG or WebP is too big for the 197 // fuzzer. 198 bool IsImageTooBig(const uint8_t* data, size_t size); 199 200 } // namespace fuzz_utils 201 202 #endif // WEBP_TESTS_FUZZER_FUZZ_UTILS_H_