fuzz_utils.cc (6986B)
1 // Copyright 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 #include "./fuzz_utils.h" 18 19 #include <algorithm> 20 #include <cassert> 21 #include <cstddef> 22 #include <cstdint> 23 #include <cstdlib> 24 #include <string> 25 #include <string_view> 26 #include <tuple> 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/decode.h" 34 #include "src/webp/encode.h" 35 #include "src/webp/types.h" 36 37 namespace fuzz_utils { 38 39 WebPPicture GetSourcePicture(int image_index, bool use_argb) { 40 WebPPicture pic; 41 if (!WebPPictureInit(&pic)) std::abort(); 42 pic.use_argb = use_argb; 43 44 // Pick a source picture. 45 const int kImagesWidth[] = {kImgAlphaWidth, kImgGridWidth, kImgPeakWidth}; 46 const int kImagesHeight[] = {kImgAlphaHeight, kImgGridHeight, kImgPeakHeight}; 47 const uint8_t* const image_data = kImagesData[image_index]; 48 pic.width = kImagesWidth[image_index]; 49 pic.height = kImagesHeight[image_index]; 50 pic.argb_stride = pic.width * 4 * sizeof(uint8_t); 51 52 // Read the bytes. 53 if (!WebPPictureImportRGBA(&pic, image_data, pic.argb_stride)) std::abort(); 54 return pic; 55 } 56 57 //------------------------------------------------------------------------------ 58 59 int CropOrScale(WebPPicture* const pic, const CropOrScaleParams& params) { 60 if (pic == NULL) return 0; 61 #if !defined(WEBP_REDUCE_SIZE) 62 if (params.alter_input) { 63 if (params.crop_or_scale) { 64 const int cropped_width = std::max(1, pic->width / params.width_ratio); 65 const int cropped_height = std::max(1, pic->height / params.height_ratio); 66 const int cropped_left = (pic->width - cropped_width) / params.left_ratio; 67 const int cropped_top = (pic->height - cropped_height) / params.top_ratio; 68 return WebPPictureCrop(pic, cropped_left, cropped_top, cropped_width, 69 cropped_height); 70 } else { 71 const int scaled_width = 1 + (pic->width * params.width_ratio) / 8; 72 const int scaled_height = 1 + (pic->height * params.height_ratio) / 8; 73 return WebPPictureRescale(pic, scaled_width, scaled_height); 74 } 75 } 76 #else // defined(WEBP_REDUCE_SIZE) 77 (void)pic; 78 (void)params; 79 #endif // !defined(WEBP_REDUCE_SIZE) 80 return 1; 81 } 82 83 extern "C" VP8CPUInfo VP8GetCPUInfo; 84 static VP8CPUInfo GetCPUInfo; 85 86 static WEBP_INLINE int GetCPUInfoNoSSE41(CPUFeature feature) { 87 if (feature == kSSE4_1 || feature == kAVX) return 0; 88 return GetCPUInfo(feature); 89 } 90 91 static WEBP_INLINE int GetCPUInfoNoAVX(CPUFeature feature) { 92 if (feature == kAVX) return 0; 93 return GetCPUInfo(feature); 94 } 95 96 static WEBP_INLINE int GetCPUInfoForceSlowSSSE3(CPUFeature feature) { 97 if (feature == kSlowSSSE3 && GetCPUInfo(kSSE3)) { 98 return 1; // we have SSE3 -> force SlowSSSE3 99 } 100 return GetCPUInfo(feature); 101 } 102 103 static WEBP_INLINE int GetCPUInfoOnlyC(CPUFeature feature) { 104 (void)feature; 105 return 0; 106 } 107 108 void SetOptimization(VP8CPUInfo default_VP8GetCPUInfo, uint32_t index) { 109 assert(index <= kMaxOptimizationIndex); 110 GetCPUInfo = default_VP8GetCPUInfo; 111 const VP8CPUInfo kVP8CPUInfos[kMaxOptimizationIndex + 1] = { 112 GetCPUInfoOnlyC, GetCPUInfoForceSlowSSSE3, GetCPUInfoNoSSE41, 113 GetCPUInfoNoAVX, GetCPUInfo}; 114 VP8GetCPUInfo = kVP8CPUInfos[index]; 115 } 116 117 //------------------------------------------------------------------------------ 118 119 std::vector<std::string> ReadFilesFromDirectory(std::string_view dir) { 120 std::vector<std::tuple<std::string>> tuples = 121 fuzztest::ReadFilesFromDirectory(dir); 122 std::vector<std::string> strings(tuples.size()); 123 for (size_t i = 0; i < tuples.size(); ++i) { 124 using std::swap; 125 swap(std::get<0>(tuples[i]), strings[i]); 126 } 127 return strings; 128 } 129 130 //------------------------------------------------------------------------------ 131 // The code in this section is copied from 132 // https://github.com/webmproject/sjpeg/blob/ 133 // 1c025b3dbc2246de3e1d7c287970f1a01291800f/src/jpeg_tools.cc#L47 134 // (same license as this file). 135 136 namespace { 137 // Constants below are marker codes defined in JPEG spec 138 // ISO/IEC 10918-1 : 1993(E) Table B.1 139 // See also: http://www.w3.org/Graphics/JPEG/itu-t81.pdf 140 141 #define M_SOF0 0xffc0 142 #define M_SOF1 0xffc1 143 144 const uint8_t* GetSOFData(const uint8_t* src, int size) { 145 if (src == NULL) return NULL; 146 const uint8_t* const end = src + size - 8; // 8 bytes of safety, for marker 147 src += 2; // skip M_SOI 148 for (; src < end && *src != 0xff; ++src) { /* search first 0xff marker */ 149 } 150 while (src < end) { 151 const uint32_t marker = static_cast<uint32_t>((src[0] << 8) | src[1]); 152 if (marker == M_SOF0 || marker == M_SOF1) return src; 153 const size_t s = 2 + ((src[2] << 8) | src[3]); 154 src += s; 155 } 156 return NULL; // No SOF marker found 157 } 158 159 bool SjpegDimensions(const uint8_t* src0, size_t size, int* width, int* height, 160 int* is_yuv420) { 161 if (width == NULL || height == NULL) return false; 162 const uint8_t* src = GetSOFData(src0, size); 163 const size_t left_over = size - (src - src0); 164 if (src == NULL || left_over < 8 + 3 * 1) return false; 165 if (height != NULL) *height = (src[5] << 8) | src[6]; 166 if (width != NULL) *width = (src[7] << 8) | src[8]; 167 if (is_yuv420 != NULL) { 168 const size_t nb_comps = src[9]; 169 *is_yuv420 = (nb_comps == 3); 170 if (left_over < 11 + 3 * nb_comps) return false; 171 for (int c = 0; *is_yuv420 && c < 3; ++c) { 172 const int expected_dim = (c == 0 ? 0x22 : 0x11); 173 *is_yuv420 &= (src[11 + c * 3] == expected_dim); 174 } 175 } 176 return true; 177 } 178 } // namespace 179 180 //------------------------------------------------------------------------------ 181 182 bool IsImageTooBig(const uint8_t* data, size_t size) { 183 int width, height, components; 184 if (SjpegDimensions(data, size, &width, &height, &components) || 185 WebPGetInfo(data, size, &width, &height)) { 186 // Look at the number of 8x8px blocks rather than the overall pixel count 187 // when comparing to memory and duration thresholds. 188 const size_t ceiled_width = ((size_t)width + 7) / 8 * 8; 189 const size_t ceiled_height = ((size_t)height + 7) / 8 * 8; 190 // Threshold to avoid out-of-memory and timeout issues. 191 // The threshold is arbitrary but below the fuzzer limit of 2 GB. 192 // The value cannot be 2 GB because of the added memory by MSAN. 193 if (ceiled_width * ceiled_height > kFuzzPxLimit) return true; 194 } 195 return false; 196 } 197 198 } // namespace fuzz_utils