enc_fuzzer.cc (4739B)
1 // Copyright 2024 Google Inc. 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 <cstddef> 18 #include <cstdint> 19 #include <cstdlib> 20 #include <iostream> 21 #include <string> 22 #include <string_view> 23 24 #include "imageio/image_dec.h" 25 #include "src/dsp/cpu.h" 26 #include "src/webp/decode.h" 27 #include "src/webp/encode.h" 28 #include "src/webp/types.h" 29 #include "tests/fuzzer/fuzz_utils.h" 30 31 namespace { 32 33 const VP8CPUInfo default_VP8GetCPUInfo = fuzz_utils::VP8GetCPUInfo; 34 35 void EncTest(std::string_view file, uint32_t optimization_index, bool use_argb, 36 WebPConfig config, 37 const fuzz_utils::CropOrScaleParams& crop_or_scale_params) { 38 fuzz_utils::SetOptimization(default_VP8GetCPUInfo, optimization_index); 39 40 // Init the source picture. 41 WebPPicture pic; 42 if (!WebPPictureInit(&pic)) { 43 std::cerr << "WebPPictureInit failed.\n"; 44 std::abort(); 45 } 46 pic.use_argb = use_argb; 47 48 const uint8_t* const file_data = 49 reinterpret_cast<const uint8_t*>(file.data()); 50 if (fuzz_utils::IsImageTooBig(file_data, file.size())) return; 51 WebPImageReader reader = WebPGuessImageReader(file_data, file.size()); 52 if (!reader(file_data, file.size(), &pic, 1, NULL)) return; 53 54 // Crop and scale. 55 if (!CropOrScale(&pic, crop_or_scale_params)) { 56 const WebPEncodingError error_code = pic.error_code; 57 WebPPictureFree(&pic); 58 if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY) return; 59 std::cerr << "CropOrScale failed. Error code: " << error_code << "\n"; 60 std::abort(); 61 } 62 63 // Skip the cruncher except on small images, it's likely to timeout. 64 if (config.lossless && config.quality == 100. && config.method == 6 && 65 pic.width * pic.height >= 16384) { 66 config.lossless = 0; 67 } 68 69 // Encode. 70 WebPMemoryWriter memory_writer; 71 WebPMemoryWriterInit(&memory_writer); 72 pic.writer = WebPMemoryWrite; 73 pic.custom_ptr = &memory_writer; 74 if (!WebPEncode(&config, &pic)) { 75 const WebPEncodingError error_code = pic.error_code; 76 WebPMemoryWriterClear(&memory_writer); 77 WebPPictureFree(&pic); 78 if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY) return; 79 std::cerr << "WebPEncode failed. Error code: " << error_code 80 << " \nFile starts with: " << file.substr(0, 20) << "\n"; 81 std::abort(); 82 } 83 84 // Try decoding the result. 85 int w, h; 86 const uint8_t* const out_data = memory_writer.mem; 87 const size_t out_size = memory_writer.size; 88 uint8_t* const rgba = WebPDecodeBGRA(out_data, out_size, &w, &h); 89 if (rgba == nullptr || w != pic.width || h != pic.height) { 90 std::cerr << "WebPDecodeBGRA failed.\nFile starts with: " 91 << file.substr(0, 20) << "\n"; 92 WebPFree(rgba); 93 WebPMemoryWriterClear(&memory_writer); 94 WebPPictureFree(&pic); 95 std::abort(); 96 } 97 98 // Compare the results if exact encoding. 99 if (pic.use_argb && config.lossless && config.near_lossless == 100) { 100 const uint32_t* src1 = (const uint32_t*)rgba; 101 const uint32_t* src2 = pic.argb; 102 for (int y = 0; y < h; ++y, src1 += w, src2 += pic.argb_stride) { 103 for (int x = 0; x < w; ++x) { 104 uint32_t v1 = src1[x], v2 = src2[x]; 105 if (!config.exact) { 106 if ((v1 & 0xff000000u) == 0 || (v2 & 0xff000000u) == 0) { 107 // Only keep alpha for comparison of fully transparent area. 108 v1 &= 0xff000000u; 109 v2 &= 0xff000000u; 110 } 111 } 112 if (v1 != v2) { 113 std::cerr 114 << "Lossless compression failed pixel-exactness.\nFile starts " 115 "with: " 116 << file.substr(0, 20) << "\n"; 117 WebPFree(rgba); 118 WebPMemoryWriterClear(&memory_writer); 119 WebPPictureFree(&pic); 120 std::abort(); 121 } 122 } 123 } 124 } 125 126 WebPFree(rgba); 127 WebPMemoryWriterClear(&memory_writer); 128 WebPPictureFree(&pic); 129 } 130 131 } // namespace 132 133 FUZZ_TEST(Enc, EncTest) 134 .WithDomains( 135 fuzztest::Arbitrary<std::string>(), 136 /*optimization_index=*/ 137 fuzztest::InRange<uint32_t>(0, fuzz_utils::kMaxOptimizationIndex), 138 /*use_argb=*/fuzztest::Arbitrary<bool>(), 139 fuzz_utils::ArbitraryWebPConfig(), 140 fuzz_utils::ArbitraryCropOrScaleParams());