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