go-libwebp

Experimental translation from libwebp to Go source.
Log | Files | Refs | README | LICENSE

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