Coverage Report

Created: 2018-12-03 14:26

/src/fuzz_webp_animencoder.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 <stdio.h>
18
#include <stdlib.h>
19
#include "fuzz.h"
20
#include "webp/encode.h"
21
#include "webp/mux.h"
22
23
namespace {
24
25
const VP8CPUInfo default_VP8GetCPUInfo = VP8GetCPUInfo;
26
27
int AddFrame(WebPAnimEncoder** const enc,
28
             const WebPAnimEncoderOptions& anim_config, int* const width,
29
             int* const height, int timestamp_ms, const uint8_t data[],
30
34.4k
             size_t size, uint32_t* const bit_pos) {
31
34.4k
  if (enc == nullptr || width == nullptr || height == nullptr) {
32
0
    fprintf(stderr, "NULL parameters.\n");
33
0
    if (enc != nullptr) WebPAnimEncoderDelete(*enc);
34
0
    abort();
35
0
  }
36
34.4k
37
34.4k
  // Init the source picture.
38
34.4k
  WebPPicture pic;
39
34.4k
  if (!WebPPictureInit(&pic)) {
40
0
    fprintf(stderr, "WebPPictureInit failed.\n");
41
0
    WebPAnimEncoderDelete(*enc);
42
0
    abort();
43
0
  }
44
34.4k
  pic.use_argb = Extract(1, data, size, bit_pos);
45
34.4k
46
34.4k
  // Read the source picture.
47
34.4k
  if (!ExtractSourcePicture(&pic, data, size, bit_pos)) {
48
0
    fprintf(stderr, "Can't read input image.\n");
49
0
    WebPPictureFree(&pic);
50
0
    abort();
51
0
  }
52
34.4k
53
34.4k
  // Crop and scale.
54
34.4k
  if (*enc == nullptr) {  // First frame will set canvas width and height.
55
3.44k
    if (!ExtractAndCropOrScale(&pic, data, size, bit_pos)) {
56
0
      fprintf(stderr, "ExtractAndCropOrScale failed.");
57
0
      WebPPictureFree(&pic);
58
0
      abort();
59
0
    }
60
30.9k
  } else {  // Other frames will be resized to the first frame's dimensions.
61
30.9k
    if (!WebPPictureRescale(&pic, *width, *height)) {
62
0
      fprintf(stderr, "WebPPictureRescale failed. Size: %d,%d\n", *width,
63
0
              *height);
64
0
      WebPAnimEncoderDelete(*enc);
65
0
      WebPPictureFree(&pic);
66
0
      abort();
67
0
    }
68
34.4k
  }
69
34.4k
70
34.4k
  // Create encoder if it doesn't exist.
71
34.4k
  if (*enc == nullptr) {
72
3.44k
    *width = pic.width;
73
3.44k
    *height = pic.height;
74
3.44k
    *enc = WebPAnimEncoderNew(*width, *height, &anim_config);
75
3.44k
    if (*enc == nullptr) {
76
0
      fprintf(stderr, "WebPAnimEncoderNew failed.\n");
77
0
      WebPPictureFree(&pic);
78
0
      abort();
79
0
    }
80
34.4k
  }
81
34.4k
82
34.4k
  // Create frame encoding config.
83
34.4k
  WebPConfig config;
84
34.4k
  if (!ExtractWebPConfig(&config, data, size, bit_pos)) {
85
0
    fprintf(stderr, "ExtractWebPConfig failed.\n");
86
0
    WebPAnimEncoderDelete(*enc);
87
0
    WebPPictureFree(&pic);
88
0
    abort();
89
0
  }
90
34.4k
  // Skip slow settings on big images, it's likely to timeout.
91
34.4k
  if (pic.width * pic.height > 32 * 32) {
92
17.0k
    config.method = (config.method > 4) ? 4 : config.method;
93
17.0k
    config.quality = (config.quality > 99.0f) ? 99.0f : config.quality;
94
17.0k
    config.alpha_quality =
95
17.0k
        (config.alpha_quality > 99) ? 99 : config.alpha_quality;
96
17.0k
  }
97
34.4k
98
34.4k
  // Encode.
99
34.4k
  if (!WebPAnimEncoderAdd(*enc, &pic, timestamp_ms, &config)) {
100
0
    fprintf(stderr, "WebPEncode failed. Error code: %d\n", pic.error_code);
101
0
    WebPAnimEncoderDelete(*enc);
102
0
    WebPPictureFree(&pic);
103
0
    abort();
104
0
  }
105
34.4k
106
34.4k
  WebPPictureFree(&pic);
107
34.4k
  return 1;
108
34.4k
}
109
110
}  // namespace
111
112
3.44k
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
113
3.44k
  WebPAnimEncoder* enc = nullptr;
114
3.44k
  int width = 0, height = 0, timestamp_ms = 0;
115
3.44k
  uint32_t bit_pos = 0;
116
3.44k
117
3.44k
  ExtractAndDisableOptimizations(default_VP8GetCPUInfo, data, size, &bit_pos);
118
3.44k
119
3.44k
  // Extract a configuration from the packed bits.
120
3.44k
  WebPAnimEncoderOptions anim_config;
121
3.44k
  if (!WebPAnimEncoderOptionsInit(&anim_config)) {
122
0
    fprintf(stderr, "WebPAnimEncoderOptionsInit failed.\n");
123
0
    abort();
124
0
  }
125
3.44k
  anim_config.minimize_size = Extract(1, data, size, &bit_pos);
126
3.44k
  anim_config.kmax = Extract(15, data, size, &bit_pos);
127
3.44k
  const int min_kmin = (anim_config.kmax > 1) ? (anim_config.kmax / 2) : 0;
128
3.44k
  const int max_kmin = (anim_config.kmax > 1) ? (anim_config.kmax - 1) : 0;
129
3.44k
  anim_config.kmin =
130
3.44k
      min_kmin + Extract((uint32_t)(max_kmin - min_kmin), data, size, &bit_pos);
131
3.44k
  anim_config.allow_mixed = Extract(1, data, size, &bit_pos);
132
3.44k
  anim_config.verbose = 0;
133
3.44k
134
3.44k
  const int nb_frames = 1 + Extract(15, data, size, &bit_pos);
135
3.44k
136
3.44k
  // For each frame.
137
37.8k
  for (int i = 0; i < nb_frames; ++i) {
138
34.4k
    if (!AddFrame(&enc, anim_config, &width, &height, timestamp_ms, data, size,
139
34.4k
                  &bit_pos)) {
140
0
      return 0;
141
0
    }
142
34.4k
143
34.4k
    timestamp_ms += (1 << (2 + Extract(15, data, size, &bit_pos))) +
144
34.4k
                    Extract(1, data, size, &bit_pos);  // [1..131073], arbitrary
145
34.4k
  }
146
3.44k
147
3.44k
  // Assemble.
148
3.44k
  if (!WebPAnimEncoderAdd(enc, nullptr, timestamp_ms, nullptr)) {
149
0
    fprintf(stderr, "Last WebPAnimEncoderAdd failed.");
150
0
    WebPAnimEncoderDelete(enc);
151
0
    abort();
152
0
  }
153
3.44k
  WebPData webp_data;
154
3.44k
  WebPDataInit(&webp_data);
155
3.44k
  if (!WebPAnimEncoderAssemble(enc, &webp_data)) {
156
0
    fprintf(stderr, "WebPAnimEncoderAssemble failed.");
157
0
    WebPAnimEncoderDelete(enc);
158
0
    WebPDataClear(&webp_data);
159
0
    abort();
160
0
  }
161
3.44k
162
3.44k
  WebPAnimEncoderDelete(enc);
163
3.44k
  WebPDataClear(&webp_data);
164
3.44k
  return 0;
165
3.44k
}