Coverage Report

Created: 2025-07-11 06:36

/src/libwebp/tests/fuzzer/enc_dec_fuzzer.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2018 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 <cstdio>
20
#include <cstdlib>
21
22
#include "./fuzz_utils.h"
23
#include "src/dsp/cpu.h"
24
#include "src/webp/decode.h"
25
#include "src/webp/encode.h"
26
27
namespace {
28
29
const VP8CPUInfo default_VP8GetCPUInfo = fuzz_utils::VP8GetCPUInfo;
30
31
void EncDecTest(bool use_argb, int source_image_index, WebPConfig config,
32
                int optimization_index,
33
3.47k
                const fuzz_utils::CropOrScaleParams& crop_or_scale_params) {
34
3.47k
  fuzz_utils::SetOptimization(default_VP8GetCPUInfo, optimization_index);
35
36
  // Init the source picture.
37
3.47k
  WebPPicture pic = fuzz_utils::GetSourcePicture(source_image_index, use_argb);
38
39
  // Crop and scale.
40
3.47k
  if (!fuzz_utils::CropOrScale(&pic, crop_or_scale_params)) {
41
0
    const WebPEncodingError error_code = pic.error_code;
42
0
    WebPPictureFree(&pic);
43
0
    if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY) return;
44
0
    fprintf(stderr, "ExtractAndCropOrScale failed. Error code: %d\n",
45
0
            error_code);
46
0
    std::abort();
47
0
  }
48
49
  // Skip slow settings on big images, it's likely to timeout.
50
3.47k
  if (pic.width * pic.height > 32 * 32) {
51
1.66k
    if (config.lossless) {
52
934
      if (config.quality > 99.0f && config.method >= 5) {
53
28
        config.quality = 99.0f;
54
28
        config.method = 5;
55
28
      }
56
934
    } else {
57
730
      if (config.quality > 99.0f && config.method == 6) {
58
42
        config.quality = 99.0f;
59
42
      }
60
730
    }
61
1.66k
    if (config.alpha_quality == 100 && config.method == 6) {
62
36
      config.alpha_quality = 99;
63
36
    }
64
1.66k
  }
65
66
  // Encode.
67
3.47k
  WebPMemoryWriter memory_writer;
68
3.47k
  WebPMemoryWriterInit(&memory_writer);
69
3.47k
  pic.writer = WebPMemoryWrite;
70
3.47k
  pic.custom_ptr = &memory_writer;
71
3.47k
  if (!WebPEncode(&config, &pic)) {
72
0
    const WebPEncodingError error_code = pic.error_code;
73
0
    WebPMemoryWriterClear(&memory_writer);
74
0
    WebPPictureFree(&pic);
75
0
    if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY ||
76
0
        error_code == VP8_ENC_ERROR_BAD_WRITE) {
77
0
      return;
78
0
    }
79
0
    fprintf(stderr, "WebPEncode failed. Error code: %d\n", error_code);
80
0
    std::abort();
81
0
  }
82
83
  // Try decoding the result.
84
3.47k
  const uint8_t* const out_data = memory_writer.mem;
85
3.47k
  const size_t out_size = memory_writer.size;
86
3.47k
  WebPDecoderConfig dec_config;
87
3.47k
  if (!WebPInitDecoderConfig(&dec_config)) {
88
0
    fprintf(stderr, "WebPInitDecoderConfig failed.\n");
89
0
    WebPMemoryWriterClear(&memory_writer);
90
0
    WebPPictureFree(&pic);
91
0
    std::abort();
92
0
  }
93
94
3.47k
  dec_config.output.colorspace = MODE_BGRA;
95
3.47k
  const VP8StatusCode status = WebPDecode(out_data, out_size, &dec_config);
96
3.47k
  if ((status != VP8_STATUS_OK && status != VP8_STATUS_OUT_OF_MEMORY &&
97
3.47k
       status != VP8_STATUS_USER_ABORT) ||
98
3.47k
      (status == VP8_STATUS_OK && (dec_config.output.width != pic.width ||
99
3.47k
                                   dec_config.output.height != pic.height))) {
100
0
    fprintf(stderr, "WebPDecode failed. status: %d.\n", status);
101
0
    WebPFreeDecBuffer(&dec_config.output);
102
0
    WebPMemoryWriterClear(&memory_writer);
103
0
    WebPPictureFree(&pic);
104
0
    std::abort();
105
0
  }
106
107
3.47k
  if (status == VP8_STATUS_OK) {
108
3.47k
    const uint8_t* const rgba = dec_config.output.u.RGBA.rgba;
109
3.47k
    const int w = dec_config.output.width;
110
3.47k
    const int h = dec_config.output.height;
111
112
    // Compare the results if exact encoding.
113
3.47k
    if (pic.use_argb && config.lossless && config.near_lossless == 100) {
114
214
      const uint32_t* src1 = (const uint32_t*)rgba;
115
214
      const uint32_t* src2 = pic.argb;
116
11.6k
      for (int y = 0; y < h; ++y, src1 += w, src2 += pic.argb_stride) {
117
1.05M
        for (int x = 0; x < w; ++x) {
118
1.04M
          uint32_t v1 = src1[x], v2 = src2[x];
119
1.04M
          if (!config.exact) {
120
519k
            if ((v1 & 0xff000000u) == 0 || (v2 & 0xff000000u) == 0) {
121
              // Only keep alpha for comparison of fully transparent area.
122
0
              v1 &= 0xff000000u;
123
0
              v2 &= 0xff000000u;
124
0
            }
125
519k
          }
126
1.04M
          if (v1 != v2) {
127
0
            fprintf(stderr, "Lossless compression failed pixel-exactness.\n");
128
0
            WebPFreeDecBuffer(&dec_config.output);
129
0
            WebPMemoryWriterClear(&memory_writer);
130
0
            WebPPictureFree(&pic);
131
0
            std::abort();
132
0
          }
133
1.04M
        }
134
11.4k
      }
135
214
    }
136
3.47k
  }
137
138
3.47k
  WebPFreeDecBuffer(&dec_config.output);
139
3.47k
  WebPMemoryWriterClear(&memory_writer);
140
3.47k
  WebPPictureFree(&pic);
141
3.47k
}
142
143
}  // namespace
144
145
FUZZ_TEST(EncDec, EncDecTest)
146
    .WithDomains(/*use_argb=*/fuzztest::Arbitrary<bool>(),
147
                 /*source_image_index=*/
148
                 fuzztest::InRange<int>(0, fuzz_utils::kNumSourceImages - 1),
149
                 fuzz_utils::ArbitraryWebPConfig(),
150
                 /*optimization_index=*/
151
                 fuzztest::InRange<uint32_t>(0,
152
                                             fuzz_utils::kMaxOptimizationIndex),
153
                 fuzz_utils::ArbitraryCropOrScaleParams());