1*b2055c35SXin Li // Copyright 2018 Google Inc.
2*b2055c35SXin Li //
3*b2055c35SXin Li // Licensed under the Apache License, Version 2.0 (the "License");
4*b2055c35SXin Li // you may not use this file except in compliance with the License.
5*b2055c35SXin Li // You may obtain a copy of the License at
6*b2055c35SXin Li //
7*b2055c35SXin Li // http://www.apache.org/licenses/LICENSE-2.0
8*b2055c35SXin Li //
9*b2055c35SXin Li // Unless required by applicable law or agreed to in writing, software
10*b2055c35SXin Li // distributed under the License is distributed on an "AS IS" BASIS,
11*b2055c35SXin Li // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*b2055c35SXin Li // See the License for the specific language governing permissions and
13*b2055c35SXin Li // limitations under the License.
14*b2055c35SXin Li //
15*b2055c35SXin Li ////////////////////////////////////////////////////////////////////////////////
16*b2055c35SXin Li
17*b2055c35SXin Li #include <stdio.h>
18*b2055c35SXin Li #include <stdlib.h>
19*b2055c35SXin Li
20*b2055c35SXin Li #include "./fuzz_utils.h"
21*b2055c35SXin Li #include "src/webp/decode.h"
22*b2055c35SXin Li #include "src/webp/encode.h"
23*b2055c35SXin Li
24*b2055c35SXin Li namespace {
25*b2055c35SXin Li
26*b2055c35SXin Li const VP8CPUInfo default_VP8GetCPUInfo = VP8GetCPUInfo;
27*b2055c35SXin Li
28*b2055c35SXin Li } // namespace
29*b2055c35SXin Li
LLVMFuzzerTestOneInput(const uint8_t * const data,size_t size)30*b2055c35SXin Li extern "C" int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
31*b2055c35SXin Li uint32_t bit_pos = 0;
32*b2055c35SXin Li
33*b2055c35SXin Li ExtractAndDisableOptimizations(default_VP8GetCPUInfo, data, size, &bit_pos);
34*b2055c35SXin Li
35*b2055c35SXin Li // Init the source picture.
36*b2055c35SXin Li WebPPicture pic;
37*b2055c35SXin Li if (!WebPPictureInit(&pic)) {
38*b2055c35SXin Li fprintf(stderr, "WebPPictureInit failed.\n");
39*b2055c35SXin Li abort();
40*b2055c35SXin Li }
41*b2055c35SXin Li pic.use_argb = Extract(1, data, size, &bit_pos);
42*b2055c35SXin Li
43*b2055c35SXin Li // Read the source picture.
44*b2055c35SXin Li if (!ExtractSourcePicture(&pic, data, size, &bit_pos)) {
45*b2055c35SXin Li const WebPEncodingError error_code = pic.error_code;
46*b2055c35SXin Li WebPPictureFree(&pic);
47*b2055c35SXin Li if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY) return 0;
48*b2055c35SXin Li fprintf(stderr, "Can't read input image. Error code: %d\n", error_code);
49*b2055c35SXin Li abort();
50*b2055c35SXin Li }
51*b2055c35SXin Li
52*b2055c35SXin Li // Crop and scale.
53*b2055c35SXin Li if (!ExtractAndCropOrScale(&pic, data, size, &bit_pos)) {
54*b2055c35SXin Li const WebPEncodingError error_code = pic.error_code;
55*b2055c35SXin Li WebPPictureFree(&pic);
56*b2055c35SXin Li if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY) return 0;
57*b2055c35SXin Li fprintf(stderr, "ExtractAndCropOrScale failed. Error code: %d\n",
58*b2055c35SXin Li error_code);
59*b2055c35SXin Li abort();
60*b2055c35SXin Li }
61*b2055c35SXin Li
62*b2055c35SXin Li // Extract a configuration from the packed bits.
63*b2055c35SXin Li WebPConfig config;
64*b2055c35SXin Li if (!ExtractWebPConfig(&config, data, size, &bit_pos)) {
65*b2055c35SXin Li fprintf(stderr, "ExtractWebPConfig failed.\n");
66*b2055c35SXin Li abort();
67*b2055c35SXin Li }
68*b2055c35SXin Li // Skip slow settings on big images, it's likely to timeout.
69*b2055c35SXin Li if (pic.width * pic.height > 32 * 32) {
70*b2055c35SXin Li if (config.lossless) {
71*b2055c35SXin Li if (config.quality > 99.0f && config.method >= 5) {
72*b2055c35SXin Li config.quality = 99.0f;
73*b2055c35SXin Li config.method = 5;
74*b2055c35SXin Li }
75*b2055c35SXin Li } else {
76*b2055c35SXin Li if (config.quality > 99.0f && config.method == 6) {
77*b2055c35SXin Li config.quality = 99.0f;
78*b2055c35SXin Li }
79*b2055c35SXin Li }
80*b2055c35SXin Li if (config.alpha_quality == 100 && config.method == 6) {
81*b2055c35SXin Li config.alpha_quality = 99;
82*b2055c35SXin Li }
83*b2055c35SXin Li }
84*b2055c35SXin Li
85*b2055c35SXin Li // Encode.
86*b2055c35SXin Li WebPMemoryWriter memory_writer;
87*b2055c35SXin Li WebPMemoryWriterInit(&memory_writer);
88*b2055c35SXin Li pic.writer = WebPMemoryWrite;
89*b2055c35SXin Li pic.custom_ptr = &memory_writer;
90*b2055c35SXin Li if (!WebPEncode(&config, &pic)) {
91*b2055c35SXin Li const WebPEncodingError error_code = pic.error_code;
92*b2055c35SXin Li WebPMemoryWriterClear(&memory_writer);
93*b2055c35SXin Li WebPPictureFree(&pic);
94*b2055c35SXin Li if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY ||
95*b2055c35SXin Li error_code == VP8_ENC_ERROR_BAD_WRITE) {
96*b2055c35SXin Li return 0;
97*b2055c35SXin Li }
98*b2055c35SXin Li fprintf(stderr, "WebPEncode failed. Error code: %d\n", error_code);
99*b2055c35SXin Li abort();
100*b2055c35SXin Li }
101*b2055c35SXin Li
102*b2055c35SXin Li // Try decoding the result.
103*b2055c35SXin Li const uint8_t* const out_data = memory_writer.mem;
104*b2055c35SXin Li const size_t out_size = memory_writer.size;
105*b2055c35SXin Li WebPDecoderConfig dec_config;
106*b2055c35SXin Li if (!WebPInitDecoderConfig(&dec_config)) {
107*b2055c35SXin Li fprintf(stderr, "WebPInitDecoderConfig failed.\n");
108*b2055c35SXin Li WebPMemoryWriterClear(&memory_writer);
109*b2055c35SXin Li WebPPictureFree(&pic);
110*b2055c35SXin Li abort();
111*b2055c35SXin Li }
112*b2055c35SXin Li
113*b2055c35SXin Li dec_config.output.colorspace = MODE_BGRA;
114*b2055c35SXin Li const VP8StatusCode status = WebPDecode(out_data, out_size, &dec_config);
115*b2055c35SXin Li if ((status != VP8_STATUS_OK && status != VP8_STATUS_OUT_OF_MEMORY &&
116*b2055c35SXin Li status != VP8_STATUS_USER_ABORT) ||
117*b2055c35SXin Li (status == VP8_STATUS_OK && (dec_config.output.width != pic.width ||
118*b2055c35SXin Li dec_config.output.height != pic.height))) {
119*b2055c35SXin Li fprintf(stderr, "WebPDecode failed. status: %d.\n", status);
120*b2055c35SXin Li WebPFreeDecBuffer(&dec_config.output);
121*b2055c35SXin Li WebPMemoryWriterClear(&memory_writer);
122*b2055c35SXin Li WebPPictureFree(&pic);
123*b2055c35SXin Li abort();
124*b2055c35SXin Li }
125*b2055c35SXin Li
126*b2055c35SXin Li if (status == VP8_STATUS_OK) {
127*b2055c35SXin Li const uint8_t* const rgba = dec_config.output.u.RGBA.rgba;
128*b2055c35SXin Li const int w = dec_config.output.width;
129*b2055c35SXin Li const int h = dec_config.output.height;
130*b2055c35SXin Li
131*b2055c35SXin Li // Compare the results if exact encoding.
132*b2055c35SXin Li if (pic.use_argb && config.lossless && config.near_lossless == 100) {
133*b2055c35SXin Li const uint32_t* src1 = (const uint32_t*)rgba;
134*b2055c35SXin Li const uint32_t* src2 = pic.argb;
135*b2055c35SXin Li for (int y = 0; y < h; ++y, src1 += w, src2 += pic.argb_stride) {
136*b2055c35SXin Li for (int x = 0; x < w; ++x) {
137*b2055c35SXin Li uint32_t v1 = src1[x], v2 = src2[x];
138*b2055c35SXin Li if (!config.exact) {
139*b2055c35SXin Li if ((v1 & 0xff000000u) == 0 || (v2 & 0xff000000u) == 0) {
140*b2055c35SXin Li // Only keep alpha for comparison of fully transparent area.
141*b2055c35SXin Li v1 &= 0xff000000u;
142*b2055c35SXin Li v2 &= 0xff000000u;
143*b2055c35SXin Li }
144*b2055c35SXin Li }
145*b2055c35SXin Li if (v1 != v2) {
146*b2055c35SXin Li fprintf(stderr, "Lossless compression failed pixel-exactness.\n");
147*b2055c35SXin Li WebPFreeDecBuffer(&dec_config.output);
148*b2055c35SXin Li WebPMemoryWriterClear(&memory_writer);
149*b2055c35SXin Li WebPPictureFree(&pic);
150*b2055c35SXin Li abort();
151*b2055c35SXin Li }
152*b2055c35SXin Li }
153*b2055c35SXin Li }
154*b2055c35SXin Li }
155*b2055c35SXin Li }
156*b2055c35SXin Li
157*b2055c35SXin Li WebPFreeDecBuffer(&dec_config.output);
158*b2055c35SXin Li WebPMemoryWriterClear(&memory_writer);
159*b2055c35SXin Li WebPPictureFree(&pic);
160*b2055c35SXin Li return 0;
161*b2055c35SXin Li }
162