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