mirror of https://github.com/google/oss-fuzz.git
webp_animencoder: Add target to fuzz animation encoding (#1935)
* Add new fuzz target for encoding and misc - Add fuzz_webp_enc_dec and adapt Dockerfile, build.sh - Lint existing targets - Add license headers - Increase fuzz.dict * webp_enc_dec: Convert input images to inline C arrays Local files are not available on oss-fuzz servers. * webp_enc_dec: Fix timeout by skipping crusher The target fuzz_webp_enc_dec with msan crashes (timeout) on a 128*128px image encoding with max compression (crusher). Reduce crusher encoding to 16*16px and below. Bug report 10423 * webp_enc_dec: Replace cruncher by lossy alpha encoding The target fuzz_webp_enc_dec with msan crashes (timeout) during encoding with max compression (cruncher). Reduce alpha cruncher encoding to 16*16px and below. Bug report 10634 * webp_enc_dec: Clamp slow parameters for big images The target fuzz_webp_enc_dec with ubsan crashes (timeout) during encoding with heavy compression. The cause can not be easily removed without reducing performance. Clamp compression parameters for images bigger than 16*16. Bug report 10700 * webp_enc_dec: Limit alpha_quality to 99 when method is 6 The target fuzz_webp_enc_dec with asan crashes (timeout) during encoding with heavy alpha compression. Clamp alpha compression parameters for images bigger than 16*16. Bug report 10838 * webp_animencoder: Add target to fuzz animation encoding Add fuzz_webp_animencoder.cc and modify Dockerfile, build.sh accordingly. The thresholds for input size and encoding parameters are low to prevent timeouts. Some functions used by fuzz_webp_animencoder and fuzz_webp_enc_dec have been moved to fuzz.h.
This commit is contained in:
parent
08bb5d9bd7
commit
1ad8633819
|
@ -27,6 +27,7 @@ COPY img_alpha.h img_grid.h img_peak.h $SRC/
|
|||
COPY fuzz_simple_api.c $SRC/
|
||||
COPY fuzz_advanced_api.c $SRC/
|
||||
COPY fuzz_animation_api.c $SRC/
|
||||
COPY fuzz_webp_animencoder.cc $SRC/
|
||||
COPY fuzz_demux_api.c $SRC/
|
||||
COPY fuzz_webp_enc_dec.cc $SRC/
|
||||
WORKDIR libwebp
|
||||
|
|
|
@ -35,7 +35,7 @@ find $SRC/libwebp-test-data -type f -size -32k -iname "*.webp" \
|
|||
-exec zip -qju fuzz_seed_corpus.zip "{}" \;
|
||||
|
||||
# Simple Decoding API
|
||||
$CC $CFLAGS -Isrc -c $SRC/fuzz_simple_api.c
|
||||
$CC $CFLAGS -Isrc -I. -c $SRC/fuzz_simple_api.c
|
||||
$CXX $CXXFLAGS -lFuzzingEngine \
|
||||
fuzz_simple_api.o -o $OUT/fuzz_simple_api \
|
||||
src/.libs/libwebp.a
|
||||
|
@ -43,7 +43,7 @@ cp fuzz_seed_corpus.zip $OUT/fuzz_simple_api_seed_corpus.zip
|
|||
cp $SRC/fuzz.dict $OUT/fuzz_simple_api.dict
|
||||
|
||||
# Advanced Decoding API
|
||||
$CC $CFLAGS -Isrc -c $SRC/fuzz_advanced_api.c
|
||||
$CC $CFLAGS -Isrc -I. -c $SRC/fuzz_advanced_api.c
|
||||
$CXX $CXXFLAGS -lFuzzingEngine \
|
||||
fuzz_advanced_api.o -o $OUT/fuzz_advanced_api \
|
||||
src/.libs/libwebp.a
|
||||
|
@ -51,7 +51,7 @@ cp fuzz_seed_corpus.zip $OUT/fuzz_advanced_api_seed_corpus.zip
|
|||
cp $SRC/fuzz.dict $OUT/fuzz_advanced_api.dict
|
||||
|
||||
# Animation Decoding API
|
||||
$CC $CFLAGS -Isrc -c $SRC/fuzz_animation_api.c
|
||||
$CC $CFLAGS -Isrc -I. -c $SRC/fuzz_animation_api.c
|
||||
$CXX $CXXFLAGS -lFuzzingEngine \
|
||||
fuzz_animation_api.o -o $OUT/fuzz_animation_api \
|
||||
src/demux/.libs/libwebpdemux.a \
|
||||
|
@ -59,8 +59,16 @@ $CXX $CXXFLAGS -lFuzzingEngine \
|
|||
cp fuzz_seed_corpus.zip $OUT/fuzz_animation_api_seed_corpus.zip
|
||||
cp $SRC/fuzz.dict $OUT/fuzz_animation_api.dict
|
||||
|
||||
# Animation Encoding API
|
||||
$CC $CFLAGS -Isrc -I. -c $SRC/fuzz_webp_animencoder.cc
|
||||
$CXX $CXXFLAGS -lFuzzingEngine \
|
||||
fuzz_webp_animencoder.o -o $OUT/fuzz_webp_animencoder \
|
||||
src/mux/.libs/libwebpmux.a \
|
||||
src/.libs/libwebp.a
|
||||
cp fuzz_seed_corpus.zip $OUT/fuzz_webp_animencoder_seed_corpus.zip
|
||||
|
||||
# (De)mux API
|
||||
$CC $CFLAGS -Isrc -c $SRC/fuzz_demux_api.c
|
||||
$CC $CFLAGS -Isrc -I. -c $SRC/fuzz_demux_api.c
|
||||
$CXX $CXXFLAGS -lFuzzingEngine \
|
||||
fuzz_demux_api.o -o $OUT/fuzz_demux_api \
|
||||
src/demux/.libs/libwebpdemux.a src/mux/.libs/libwebpmux.a \
|
||||
|
|
|
@ -17,6 +17,13 @@
|
|||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "dsp/dsp.h"
|
||||
#include "img_alpha.h"
|
||||
#include "img_grid.h"
|
||||
#include "img_peak.h"
|
||||
#include "webp/encode.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Arbitrary limits to prevent OOM, timeout, or slow execution.
|
||||
//
|
||||
// The decoded image size, and for animations additionally the canvas size.
|
||||
|
@ -32,3 +39,152 @@ uint8_t FuzzHash(const uint8_t* const data, size_t size) {
|
|||
for (size_t i = 0; i < size; i += incr) value += data[i];
|
||||
return value;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Extract an integer in [0, max_value].
|
||||
|
||||
static uint32_t Extract(uint32_t max_value, const uint8_t data[], size_t size,
|
||||
uint32_t* const bit_pos) {
|
||||
uint32_t v = 0;
|
||||
int range = 1;
|
||||
while (*bit_pos < 8 * size && range <= max_value) {
|
||||
const uint8_t mask = 1u << (*bit_pos & 7);
|
||||
v = (v << 1) | !!(data[*bit_pos >> 3] & mask);
|
||||
range <<= 1;
|
||||
++*bit_pos;
|
||||
}
|
||||
return v % (max_value + 1);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Some functions to override VP8GetCPUInfo and disable some optimizations.
|
||||
|
||||
static VP8CPUInfo GetCPUInfo;
|
||||
|
||||
static int GetCPUInfoNoSSE41(CPUFeature feature) {
|
||||
if (feature == kSSE4_1 || feature == kAVX) return 0;
|
||||
return GetCPUInfo(feature);
|
||||
}
|
||||
|
||||
static int GetCPUInfoNoAVX(CPUFeature feature) {
|
||||
if (feature == kAVX) return 0;
|
||||
return GetCPUInfo(feature);
|
||||
}
|
||||
|
||||
static int GetCPUInfoForceSlowSSSE3(CPUFeature feature) {
|
||||
if (feature == kSlowSSSE3 && GetCPUInfo(kSSE3)) {
|
||||
return 1; // we have SSE3 -> force SlowSSSE3
|
||||
}
|
||||
return GetCPUInfo(feature);
|
||||
}
|
||||
|
||||
static int GetCPUInfoOnlyC(CPUFeature feature) { return 0; }
|
||||
|
||||
static void ExtractAndDisableOptimizations(VP8CPUInfo default_VP8GetCPUInfo,
|
||||
const uint8_t data[], size_t size,
|
||||
uint32_t* const bit_pos) {
|
||||
GetCPUInfo = default_VP8GetCPUInfo;
|
||||
const VP8CPUInfo kVP8CPUInfos[5] = {GetCPUInfoOnlyC, GetCPUInfoForceSlowSSSE3,
|
||||
GetCPUInfoNoSSE41, GetCPUInfoNoAVX,
|
||||
GetCPUInfo};
|
||||
int VP8GetCPUInfo_index = Extract(4, data, size, bit_pos);
|
||||
VP8GetCPUInfo = kVP8CPUInfos[VP8GetCPUInfo_index];
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static int ExtractWebPConfig(WebPConfig* const config, const uint8_t data[],
|
||||
size_t size, uint32_t* const bit_pos) {
|
||||
if (config == NULL || !WebPConfigInit(config)) return 0;
|
||||
config->lossless = Extract(1, data, size, bit_pos);
|
||||
config->quality = Extract(100, data, size, bit_pos);
|
||||
config->method = Extract(6, data, size, bit_pos);
|
||||
config->image_hint =
|
||||
(WebPImageHint)Extract(WEBP_HINT_LAST - 1, data, size, bit_pos);
|
||||
config->segments = 1 + Extract(3, data, size, bit_pos);
|
||||
config->sns_strength = Extract(100, data, size, bit_pos);
|
||||
config->filter_strength = Extract(100, data, size, bit_pos);
|
||||
config->filter_sharpness = Extract(7, data, size, bit_pos);
|
||||
config->filter_type = Extract(1, data, size, bit_pos);
|
||||
config->autofilter = Extract(1, data, size, bit_pos);
|
||||
config->alpha_compression = Extract(1, data, size, bit_pos);
|
||||
config->alpha_filtering = Extract(2, data, size, bit_pos);
|
||||
config->alpha_quality = Extract(100, data, size, bit_pos);
|
||||
config->pass = 1 + Extract(9, data, size, bit_pos);
|
||||
config->show_compressed = 1;
|
||||
config->preprocessing = Extract(2, data, size, bit_pos);
|
||||
config->partitions = Extract(3, data, size, bit_pos);
|
||||
config->partition_limit = 10 * Extract(10, data, size, bit_pos);
|
||||
config->emulate_jpeg_size = Extract(1, data, size, bit_pos);
|
||||
config->thread_level = Extract(1, data, size, bit_pos);
|
||||
config->low_memory = Extract(1, data, size, bit_pos);
|
||||
config->near_lossless = 20 * Extract(5, data, size, bit_pos);
|
||||
config->exact = Extract(1, data, size, bit_pos);
|
||||
config->use_delta_palette = Extract(1, data, size, bit_pos);
|
||||
config->use_sharp_yuv = Extract(1, data, size, bit_pos);
|
||||
return WebPValidateConfig(config);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static int ExtractSourcePicture(WebPPicture* const pic,
|
||||
const uint8_t data[], size_t size,
|
||||
uint32_t* const bit_pos) {
|
||||
if (pic == NULL) return 0;
|
||||
|
||||
// Pick a source picture.
|
||||
const uint8_t* kImagesData[] = {
|
||||
kImgAlphaData,
|
||||
kImgGridData,
|
||||
kImgPeakData
|
||||
};
|
||||
const int kImagesWidth[] = {
|
||||
kImgAlphaWidth,
|
||||
kImgGridWidth,
|
||||
kImgPeakWidth
|
||||
};
|
||||
const int kImagesHeight[] = {
|
||||
kImgAlphaHeight,
|
||||
kImgGridHeight,
|
||||
kImgPeakHeight
|
||||
};
|
||||
const size_t kNbImages = sizeof(kImagesData) / sizeof(kImagesData[0]);
|
||||
const size_t image_index = Extract(kNbImages - 1, data, size, bit_pos);
|
||||
const uint8_t* const image_data = kImagesData[image_index];
|
||||
pic->width = kImagesWidth[image_index];
|
||||
pic->height = kImagesHeight[image_index];
|
||||
pic->argb_stride = pic->width * 4 * sizeof(uint8_t);
|
||||
|
||||
// Read the bytes.
|
||||
return WebPPictureImportRGBA(pic, image_data, pic->argb_stride);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static int max(int a, int b) { return ((a < b) ? b : a); }
|
||||
|
||||
static int ExtractAndCropOrScale(WebPPicture* const pic, const uint8_t data[],
|
||||
size_t size, uint32_t* const bit_pos) {
|
||||
if (pic == NULL) return 0;
|
||||
const int alter_input = Extract(1, data, size, bit_pos);
|
||||
const int crop_or_scale = Extract(1, data, size, bit_pos);
|
||||
const int width_ratio = 1 + Extract(7, data, size, bit_pos);
|
||||
const int height_ratio = 1 + Extract(7, data, size, bit_pos);
|
||||
if (alter_input) {
|
||||
if (crop_or_scale) {
|
||||
const uint32_t left_ratio = 1 + Extract(7, data, size, bit_pos);
|
||||
const uint32_t top_ratio = 1 + Extract(7, data, size, bit_pos);
|
||||
const int cropped_width = max(1, pic->width / width_ratio);
|
||||
const int cropped_height = max(1, pic->height / height_ratio);
|
||||
const int cropped_left = (pic->width - cropped_width) / left_ratio;
|
||||
const int cropped_top = (pic->height - cropped_height) / top_ratio;
|
||||
return WebPPictureCrop(pic, cropped_left, cropped_top, cropped_width,
|
||||
cropped_height);
|
||||
} else {
|
||||
const int scaled_width = 1 + (pic->width * width_ratio) / 8;
|
||||
const int scaled_height = 1 + (pic->height * height_ratio) / 8;
|
||||
return WebPPictureRescale(pic, scaled_width, scaled_height);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
// Copyright 2018 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "fuzz.h"
|
||||
#include "webp/encode.h"
|
||||
#include "webp/mux.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const VP8CPUInfo default_VP8GetCPUInfo = VP8GetCPUInfo;
|
||||
|
||||
int AddFrame(WebPAnimEncoder** const enc,
|
||||
const WebPAnimEncoderOptions& anim_config, int* const width,
|
||||
int* const height, int timestamp_ms, const uint8_t data[],
|
||||
size_t size, uint32_t* const bit_pos) {
|
||||
if (enc == nullptr || width == nullptr || height == nullptr) {
|
||||
fprintf(stderr, "NULL parameters.\n");
|
||||
if (enc != nullptr) WebPAnimEncoderDelete(*enc);
|
||||
abort();
|
||||
}
|
||||
|
||||
// Init the source picture.
|
||||
WebPPicture pic;
|
||||
if (!WebPPictureInit(&pic)) {
|
||||
fprintf(stderr, "WebPPictureInit failed.\n");
|
||||
WebPAnimEncoderDelete(*enc);
|
||||
abort();
|
||||
}
|
||||
pic.use_argb = Extract(1, data, size, bit_pos);
|
||||
|
||||
// Read the source picture.
|
||||
if (!ExtractSourcePicture(&pic, data, size, bit_pos)) {
|
||||
fprintf(stderr, "Can't read input image.\n");
|
||||
WebPPictureFree(&pic);
|
||||
abort();
|
||||
}
|
||||
|
||||
// Crop and scale.
|
||||
if (*enc == nullptr) { // First frame will set canvas width and height.
|
||||
if (!ExtractAndCropOrScale(&pic, data, size, bit_pos)) {
|
||||
fprintf(stderr, "ExtractAndCropOrScale failed.");
|
||||
WebPPictureFree(&pic);
|
||||
abort();
|
||||
}
|
||||
} else { // Other frames will be resized to the first frame's dimensions.
|
||||
if (!WebPPictureRescale(&pic, *width, *height)) {
|
||||
fprintf(stderr, "WebPPictureRescale failed. Size: %d,%d\n", *width,
|
||||
*height);
|
||||
WebPAnimEncoderDelete(*enc);
|
||||
WebPPictureFree(&pic);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
// Create encoder if it doesn't exist.
|
||||
if (*enc == nullptr) {
|
||||
*width = pic.width;
|
||||
*height = pic.height;
|
||||
*enc = WebPAnimEncoderNew(*width, *height, &anim_config);
|
||||
if (*enc == nullptr) {
|
||||
fprintf(stderr, "WebPAnimEncoderNew failed.\n");
|
||||
WebPPictureFree(&pic);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
// Create frame encoding config.
|
||||
WebPConfig config;
|
||||
if (!ExtractWebPConfig(&config, data, size, bit_pos)) {
|
||||
fprintf(stderr, "ExtractWebPConfig failed.\n");
|
||||
WebPAnimEncoderDelete(*enc);
|
||||
WebPPictureFree(&pic);
|
||||
abort();
|
||||
}
|
||||
// Skip slow settings on big images, it's likely to timeout.
|
||||
if (pic.width * pic.height > 32 * 32) {
|
||||
config.method = (config.method > 4) ? 4 : config.method;
|
||||
config.quality = (config.quality > 99.0f) ? 99.0f : config.quality;
|
||||
config.alpha_quality =
|
||||
(config.alpha_quality > 99) ? 99 : config.alpha_quality;
|
||||
}
|
||||
|
||||
// Encode.
|
||||
if (!WebPAnimEncoderAdd(*enc, &pic, timestamp_ms, &config)) {
|
||||
fprintf(stderr, "WebPEncode failed. Error code: %d\n", pic.error_code);
|
||||
WebPAnimEncoderDelete(*enc);
|
||||
WebPPictureFree(&pic);
|
||||
abort();
|
||||
}
|
||||
|
||||
WebPPictureFree(&pic);
|
||||
return 1;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
||||
WebPAnimEncoder* enc = nullptr;
|
||||
int width = 0, height = 0, timestamp_ms = 0;
|
||||
uint32_t bit_pos = 0;
|
||||
|
||||
ExtractAndDisableOptimizations(default_VP8GetCPUInfo, data, size, &bit_pos);
|
||||
|
||||
// Extract a configuration from the packed bits.
|
||||
WebPAnimEncoderOptions anim_config;
|
||||
if (!WebPAnimEncoderOptionsInit(&anim_config)) {
|
||||
fprintf(stderr, "WebPAnimEncoderOptionsInit failed.\n");
|
||||
abort();
|
||||
}
|
||||
anim_config.minimize_size = Extract(1, data, size, &bit_pos);
|
||||
anim_config.kmax = Extract(15, data, size, &bit_pos);
|
||||
const int min_kmin = (anim_config.kmax > 1) ? (anim_config.kmax / 2) : 0;
|
||||
const int max_kmin = (anim_config.kmax > 1) ? (anim_config.kmax - 1) : 0;
|
||||
anim_config.kmin =
|
||||
min_kmin + Extract((uint32_t)(max_kmin - min_kmin), data, size, &bit_pos);
|
||||
anim_config.allow_mixed = Extract(1, data, size, &bit_pos);
|
||||
anim_config.verbose = 0;
|
||||
|
||||
const int nb_frames = 1 + Extract(15, data, size, &bit_pos);
|
||||
|
||||
// For each frame.
|
||||
for (int i = 0; i < nb_frames; ++i) {
|
||||
if (!AddFrame(&enc, anim_config, &width, &height, timestamp_ms, data, size,
|
||||
&bit_pos)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
timestamp_ms += (1 << (2 + Extract(15, data, size, &bit_pos))) +
|
||||
Extract(1, data, size, &bit_pos); // [1..131073], arbitrary
|
||||
}
|
||||
|
||||
// Assemble.
|
||||
if (!WebPAnimEncoderAdd(enc, nullptr, timestamp_ms, nullptr)) {
|
||||
fprintf(stderr, "Last WebPAnimEncoderAdd failed.");
|
||||
WebPAnimEncoderDelete(enc);
|
||||
abort();
|
||||
}
|
||||
WebPData webp_data;
|
||||
WebPDataInit(&webp_data);
|
||||
if (!WebPAnimEncoderAssemble(enc, &webp_data)) {
|
||||
fprintf(stderr, "WebPAnimEncoderAssemble failed.");
|
||||
WebPAnimEncoderDelete(enc);
|
||||
WebPDataClear(&webp_data);
|
||||
abort();
|
||||
}
|
||||
|
||||
WebPAnimEncoderDelete(enc);
|
||||
WebPDataClear(&webp_data);
|
||||
return 0;
|
||||
}
|
|
@ -16,98 +16,20 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "fuzz.h"
|
||||
#include "webp/encode.h"
|
||||
#include "webp/decode.h"
|
||||
#include "img_alpha.h"
|
||||
#include "img_grid.h"
|
||||
#include "img_peak.h"
|
||||
#include "dsp/dsp.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const VP8CPUInfo LibGetCPUInfo = VP8GetCPUInfo;
|
||||
const VP8CPUInfo default_VP8GetCPUInfo = VP8GetCPUInfo;
|
||||
|
||||
int GetCPUInfoNoSSE41(CPUFeature feature) {
|
||||
if (feature == kSSE4_1 || feature == kAVX) return 0;
|
||||
return LibGetCPUInfo(feature);
|
||||
}
|
||||
|
||||
int GetCPUInfoNoAVX(CPUFeature feature) {
|
||||
if (feature == kAVX) return 0;
|
||||
return LibGetCPUInfo(feature);
|
||||
}
|
||||
|
||||
int GetCPUInfoForceSlowSSSE3(CPUFeature feature) {
|
||||
if (feature == kSlowSSSE3 && LibGetCPUInfo(kSSE3)) {
|
||||
return 1; // we have SSE3 -> force SlowSSSE3
|
||||
}
|
||||
return LibGetCPUInfo(feature);
|
||||
}
|
||||
|
||||
int GetCPUInfoOnlyC(CPUFeature feature) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const VP8CPUInfo kVP8CPUInfos[5] = {
|
||||
GetCPUInfoOnlyC, GetCPUInfoForceSlowSSSE3,
|
||||
GetCPUInfoNoSSE41, GetCPUInfoNoAVX, LibGetCPUInfo
|
||||
};
|
||||
|
||||
static uint32_t Extract(uint32_t max, const uint8_t data[], size_t size,
|
||||
uint32_t* const bit_pos) {
|
||||
uint32_t v = 0;
|
||||
int range = 1;
|
||||
while (*bit_pos < 8 * size && range <= max) {
|
||||
const uint8_t mask = 1u << (*bit_pos & 7);
|
||||
v = (v << 1) | !!(data[*bit_pos >> 3] & mask);
|
||||
range <<= 1;
|
||||
++*bit_pos;
|
||||
}
|
||||
return v % (max + 1);
|
||||
}
|
||||
|
||||
static int max(int a, int b) { return ((a < b) ? b : a); }
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
||||
// Extract a configuration from the packed bits.
|
||||
WebPConfig config;
|
||||
if (!WebPConfigInit(&config)) {
|
||||
fprintf(stderr, "WebPConfigInit failed.\n");
|
||||
abort();
|
||||
}
|
||||
uint32_t bit_pos = 0;
|
||||
config.lossless = Extract(1, data, size, &bit_pos);
|
||||
config.quality = Extract(100, data, size, &bit_pos);
|
||||
config.method = Extract(6, data, size, &bit_pos);
|
||||
config.image_hint =
|
||||
(WebPImageHint)Extract(WEBP_HINT_LAST - 1, data, size, &bit_pos);
|
||||
config.segments = 1 + Extract(3, data, size, &bit_pos);
|
||||
config.sns_strength = Extract(100, data, size, &bit_pos);
|
||||
config.filter_strength = Extract(100, data, size, &bit_pos);
|
||||
config.filter_sharpness = Extract(7, data, size, &bit_pos);
|
||||
config.filter_type = Extract(1, data, size, &bit_pos);
|
||||
config.autofilter = Extract(1, data, size, &bit_pos);
|
||||
config.alpha_compression = Extract(1, data, size, &bit_pos);
|
||||
config.alpha_filtering = Extract(2, data, size, &bit_pos);
|
||||
config.alpha_quality = Extract(100, data, size, &bit_pos);
|
||||
config.pass = 1 + Extract(9, data, size, &bit_pos);
|
||||
config.show_compressed = 1;
|
||||
config.preprocessing = Extract(2, data, size, &bit_pos);
|
||||
config.partitions = Extract(3, data, size, &bit_pos);
|
||||
config.partition_limit = 10 * Extract(10, data, size, &bit_pos);
|
||||
config.emulate_jpeg_size = Extract(1, data, size, &bit_pos);
|
||||
config.thread_level = Extract(1, data, size, &bit_pos);
|
||||
config.low_memory = Extract(1, data, size, &bit_pos);
|
||||
config.near_lossless = 20 * Extract(5, data, size, &bit_pos);
|
||||
config.exact = Extract(1, data, size, &bit_pos);
|
||||
config.use_delta_palette = Extract(1, data, size, &bit_pos);
|
||||
config.use_sharp_yuv = Extract(1, data, size, &bit_pos);
|
||||
if (!WebPValidateConfig(&config)) {
|
||||
fprintf(stderr, "WebPValidateConfig failed.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
ExtractAndDisableOptimizations(default_VP8GetCPUInfo, data, size, &bit_pos);
|
||||
|
||||
// Init the source picture.
|
||||
WebPPicture pic;
|
||||
|
@ -117,79 +39,35 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
|||
}
|
||||
pic.use_argb = Extract(1, data, size, &bit_pos);
|
||||
|
||||
VP8GetCPUInfo = kVP8CPUInfos[Extract(4, data, size, &bit_pos)];
|
||||
|
||||
// Pick a source picture.
|
||||
const uint8_t* kImagesData[] = {
|
||||
kImgAlphaData,
|
||||
kImgGridData,
|
||||
kImgPeakData
|
||||
};
|
||||
const int kImagesWidth[] = {
|
||||
kImgAlphaWidth,
|
||||
kImgGridWidth,
|
||||
kImgPeakWidth
|
||||
};
|
||||
const int kImagesHeight[] = {
|
||||
kImgAlphaHeight,
|
||||
kImgGridHeight,
|
||||
kImgPeakHeight
|
||||
};
|
||||
const size_t kNbImages = sizeof(kImagesData) / sizeof(kImagesData[0]);
|
||||
const size_t image_index = Extract(kNbImages - 1, data, size, &bit_pos);
|
||||
const uint8_t* const image_data = kImagesData[image_index];
|
||||
pic.width = kImagesWidth[image_index];
|
||||
pic.height = kImagesHeight[image_index];
|
||||
pic.argb_stride = pic.width * 4 * sizeof(uint8_t);
|
||||
|
||||
// Read the bytes.
|
||||
if (!WebPPictureImportRGBA(&pic, image_data, pic.argb_stride)) {
|
||||
fprintf(stderr, "Can't read input image: %zu\n", image_index);
|
||||
// Read the source picture.
|
||||
if (!ExtractSourcePicture(&pic, data, size, &bit_pos)) {
|
||||
fprintf(stderr, "Can't read input image.\n");
|
||||
WebPPictureFree(&pic);
|
||||
abort();
|
||||
}
|
||||
|
||||
// Crop and scale.
|
||||
const bool alter_input = Extract(1, data, size, &bit_pos) != 0;
|
||||
const bool crop_or_scale = Extract(1, data, size, &bit_pos) != 0;
|
||||
const int width_ratio = 1 + Extract(7, data, size, &bit_pos);
|
||||
const int height_ratio = 1 + Extract(7, data, size, &bit_pos);
|
||||
if (alter_input) {
|
||||
if (crop_or_scale) {
|
||||
const uint32_t left_ratio = 1 + Extract(7, data, size, &bit_pos);
|
||||
const uint32_t top_ratio = 1 + Extract(7, data, size, &bit_pos);
|
||||
const int cropped_width = max(1, pic.width / width_ratio);
|
||||
const int cropped_height = max(1, pic.height / height_ratio);
|
||||
const int cropped_left = (pic.width - cropped_width) / left_ratio;
|
||||
const int cropped_top = (pic.height - cropped_height) / top_ratio;
|
||||
if (!WebPPictureCrop(&pic, cropped_left, cropped_top, cropped_width,
|
||||
cropped_height)) {
|
||||
fprintf(stderr, "WebPPictureCrop failed. Parameters: %d,%d,%d,%d\n",
|
||||
cropped_left, cropped_top, cropped_width, cropped_height);
|
||||
WebPPictureFree(&pic);
|
||||
abort();
|
||||
}
|
||||
} else {
|
||||
const int scaled_width = 1 + pic.width * width_ratio / 4;
|
||||
const int scaled_height = 1 + pic.height * height_ratio / 4;
|
||||
if (!WebPPictureRescale(&pic, scaled_width, scaled_height)) {
|
||||
fprintf(stderr, "WebPPictureRescale failed. Parameters: %d,%d\n",
|
||||
scaled_width, scaled_height);
|
||||
WebPPictureFree(&pic);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
if (!ExtractAndCropOrScale(&pic, data, size, &bit_pos)) {
|
||||
fprintf(stderr, "ExtractAndCropOrScale failed.");
|
||||
WebPPictureFree(&pic);
|
||||
abort();
|
||||
}
|
||||
|
||||
// Extract a configuration from the packed bits.
|
||||
WebPConfig config;
|
||||
if (!ExtractWebPConfig(&config, data, size, &bit_pos)) {
|
||||
fprintf(stderr, "ExtractWebPConfig failed.\n");
|
||||
abort();
|
||||
}
|
||||
// Skip slow settings on big images, it's likely to timeout.
|
||||
if (pic.width * pic.height > 16 * 16) {
|
||||
if (pic.width * pic.height > 32 * 32) {
|
||||
if (config.lossless) {
|
||||
if (config.quality >= 99.0f && config.method >= 5) {
|
||||
if (config.quality > 99.0f && config.method >= 5) {
|
||||
config.quality = 99.0f;
|
||||
config.method = 5;
|
||||
}
|
||||
} else {
|
||||
if (config.quality >= 99.0f && config.method == 6) {
|
||||
if (config.quality > 99.0f && config.method == 6) {
|
||||
config.quality = 99.0f;
|
||||
}
|
||||
}
|
||||
|
@ -204,8 +82,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
|||
pic.writer = WebPMemoryWrite;
|
||||
pic.custom_ptr = &memory_writer;
|
||||
if (!WebPEncode(&config, &pic)) {
|
||||
fprintf(stderr, "WebPEncode failed. Error code: %d\nFile: %zu\n",
|
||||
pic.error_code, image_index);
|
||||
fprintf(stderr, "WebPEncode failed. Error code: %d\n", pic.error_code);
|
||||
WebPMemoryWriterClear(&memory_writer);
|
||||
WebPPictureFree(&pic);
|
||||
abort();
|
||||
|
@ -217,7 +94,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
|||
const size_t out_size = memory_writer.size;
|
||||
uint8_t* const rgba = WebPDecodeBGRA(out_data, out_size, &w, &h);
|
||||
if (rgba == nullptr || w != pic.width || h != pic.height) {
|
||||
fprintf(stderr, "WebPDecodeBGRA failed.\nFile: %zu\n", image_index);
|
||||
fprintf(stderr, "WebPDecodeBGRA failed.\n");
|
||||
WebPFree(rgba);
|
||||
WebPMemoryWriterClear(&memory_writer);
|
||||
WebPPictureFree(&pic);
|
||||
|
@ -239,9 +116,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
|||
}
|
||||
}
|
||||
if (v1 != v2) {
|
||||
fprintf(stderr,
|
||||
"Lossless compression failed pixel-exactness.\nFile: %zu\n",
|
||||
image_index);
|
||||
fprintf(stderr, "Lossless compression failed pixel-exactness.\n");
|
||||
WebPFree(rgba);
|
||||
WebPMemoryWriterClear(&memory_writer);
|
||||
WebPPictureFree(&pic);
|
||||
|
|
Loading…
Reference in New Issue