mirror of
https://github.com/webmproject/libwebp.git
synced 2024-11-19 20:08:28 +01:00
Switch public fuzz tests to fuzztest.
Change-Id: I75afb65058690585bbf2671c27d6a99a87bcaab7
This commit is contained in:
parent
64186bb36c
commit
4f200de591
@ -45,6 +45,7 @@ option(WEBP_BUILD_LIBWEBPMUX "Build the libwebpmux library." ON)
|
|||||||
option(WEBP_BUILD_WEBPMUX "Build the webpmux command line tool." ON)
|
option(WEBP_BUILD_WEBPMUX "Build the webpmux command line tool." ON)
|
||||||
option(WEBP_BUILD_EXTRAS "Build extras." ON)
|
option(WEBP_BUILD_EXTRAS "Build extras." ON)
|
||||||
option(WEBP_BUILD_WEBP_JS "Emscripten build of webp.js." OFF)
|
option(WEBP_BUILD_WEBP_JS "Emscripten build of webp.js." OFF)
|
||||||
|
option(WEBP_BUILD_FUZZTEST "Build the fuzztest tests." OFF)
|
||||||
option(WEBP_USE_THREAD "Enable threading support" ON)
|
option(WEBP_USE_THREAD "Enable threading support" ON)
|
||||||
option(WEBP_NEAR_LOSSLESS "Enable near-lossless encoding" ON)
|
option(WEBP_NEAR_LOSSLESS "Enable near-lossless encoding" ON)
|
||||||
option(WEBP_ENABLE_SWAP_16BIT_CSP "Enable byte swap for 16 bit colorspaces."
|
option(WEBP_ENABLE_SWAP_16BIT_CSP "Enable byte swap for 16 bit colorspaces."
|
||||||
@ -375,9 +376,11 @@ if(XCODE)
|
|||||||
endif()
|
endif()
|
||||||
target_link_libraries(webpdecoder ${WEBP_DEP_LIBRARIES})
|
target_link_libraries(webpdecoder ${WEBP_DEP_LIBRARIES})
|
||||||
target_include_directories(
|
target_include_directories(
|
||||||
webpdecoder PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
|
webpdecoder
|
||||||
INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
|
INTERFACE
|
||||||
|
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_BINARY_DIR}>"
|
||||||
|
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
|
||||||
set_target_properties(
|
set_target_properties(
|
||||||
webpdecoder
|
webpdecoder
|
||||||
PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/src/webp/decode.h;\
|
PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/src/webp/decode.h;\
|
||||||
@ -771,6 +774,10 @@ if(WEBP_BUILD_ANIM_UTILS)
|
|||||||
target_include_directories(anim_dump PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
|
target_include_directories(anim_dump PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(WEBP_BUILD_FUZZTEST)
|
||||||
|
add_subdirectory(tests/fuzzer)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Install the different headers and libraries.
|
# Install the different headers and libraries.
|
||||||
install(
|
install(
|
||||||
TARGETS ${INSTALLED_LIBRARIES}
|
TARGETS ${INSTALLED_LIBRARIES}
|
||||||
|
@ -11,8 +11,9 @@ https://chromium.googlesource.com/webm/libwebp-test-data
|
|||||||
Follow the [build instructions](../doc/building.md) for libwebp, optionally
|
Follow the [build instructions](../doc/building.md) for libwebp, optionally
|
||||||
adding build flags for various sanitizers (e.g., -fsanitize=address).
|
adding build flags for various sanitizers (e.g., -fsanitize=address).
|
||||||
|
|
||||||
`fuzzer/makefile.unix` can then be used to compile the fuzzer targets:
|
`-DWEBP_BUILD_FUZZTEST=ON` can then be used to compile the fuzzer targets:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ make -C fuzzer -f makefile.unix
|
$ cmake -B ./build -S . -DWEBP_BUILD_FUZZTEST=ON
|
||||||
|
$ make -C build
|
||||||
```
|
```
|
||||||
|
61
tests/fuzzer/CMakeLists.txt
Normal file
61
tests/fuzzer/CMakeLists.txt
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
# Copyright (c) 2024 Google LLC
|
||||||
|
#
|
||||||
|
# Use of this source code is governed by a BSD-style license
|
||||||
|
# that can be found in the LICENSE file in the root of the source
|
||||||
|
# tree. An additional intellectual property rights grant can be found
|
||||||
|
# in the file PATENTS. All contributing project authors may
|
||||||
|
# be found in the AUTHORS file in the root of the source tree.
|
||||||
|
|
||||||
|
# Adds a fuzztest from file TEST_NAME.cc located in the gtest folder. Extra
|
||||||
|
# arguments are considered as extra source files.
|
||||||
|
|
||||||
|
if(CMAKE_VERSION VERSION_LESS "3.19.0")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
macro(add_webp_fuzztest TEST_NAME)
|
||||||
|
add_executable(${TEST_NAME} ${TEST_NAME}.cc)
|
||||||
|
# FuzzTest bundles GoogleTest so no need to link to gtest libraries.
|
||||||
|
target_link_libraries(${TEST_NAME} PRIVATE fuzz_utils webp ${ARGN})
|
||||||
|
link_fuzztest(${TEST_NAME})
|
||||||
|
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME})
|
||||||
|
set_property(
|
||||||
|
TEST ${TEST_NAME}
|
||||||
|
PROPERTY ENVIRONMENT "TEST_DATA_DIRS=${CMAKE_CURRENT_SOURCE_DIR}/data/")
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
enable_language(CXX)
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
include(FetchContent)
|
||||||
|
|
||||||
|
set(FETCHCONTENT_QUIET FALSE)
|
||||||
|
set(fuzztest_SOURCE_DIR ${CMAKE_BINARY_DIR}/_deps/fuzztest-src)
|
||||||
|
FetchContent_Declare(
|
||||||
|
fuzztest
|
||||||
|
GIT_REPOSITORY https://github.com/google/fuzztest.git
|
||||||
|
GIT_TAG a40caf40aaf621dd0e04f9d8b47d1153fd2682d2
|
||||||
|
GIT_PROGRESS TRUE
|
||||||
|
PATCH_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/patch.sh)
|
||||||
|
|
||||||
|
FetchContent_MakeAvailable(fuzztest)
|
||||||
|
|
||||||
|
fuzztest_setup_fuzzing_flags()
|
||||||
|
|
||||||
|
add_library(fuzz_utils fuzz_utils.h fuzz_utils.cc img_alpha.h img_grid.h
|
||||||
|
img_peak.h)
|
||||||
|
target_link_libraries(fuzz_utils PUBLIC webpdecoder)
|
||||||
|
link_fuzztest(fuzz_utils)
|
||||||
|
|
||||||
|
add_webp_fuzztest(advanced_api_fuzzer)
|
||||||
|
add_webp_fuzztest(enc_dec_fuzzer)
|
||||||
|
add_webp_fuzztest(huffman_fuzzer)
|
||||||
|
add_webp_fuzztest(simple_api_fuzzer)
|
||||||
|
|
||||||
|
if(WEBP_BUILD_LIBWEBPMUX)
|
||||||
|
add_webp_fuzztest(animation_api_fuzzer webpdemux)
|
||||||
|
add_webp_fuzztest(animdecoder_fuzzer imageioutil webpdemux)
|
||||||
|
add_webp_fuzztest(animencoder_fuzzer libwebpmux)
|
||||||
|
add_webp_fuzztest(mux_demux_api_fuzzer libwebpmux webpdemux)
|
||||||
|
endif()
|
@ -14,54 +14,59 @@
|
|||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <algorithm>
|
||||||
#include <string.h>
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
#include "./fuzz_utils.h"
|
#include "./fuzz_utils.h"
|
||||||
#include "src/utils/rescaler_utils.h"
|
#include "src/utils/rescaler_utils.h"
|
||||||
#include "src/webp/decode.h"
|
#include "src/webp/decode.h"
|
||||||
|
|
||||||
int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
namespace {
|
||||||
|
|
||||||
|
void AdvancedApiTest(std::string_view blob, uint8_t factor_u8, bool flip,
|
||||||
|
bool bypass_filtering, bool no_fancy_upsampling,
|
||||||
|
bool use_threads, bool use_cropping, bool use_scaling,
|
||||||
|
bool use_dithering, int colorspace, bool incremental) {
|
||||||
WebPDecoderConfig config;
|
WebPDecoderConfig config;
|
||||||
if (!WebPInitDecoderConfig(&config)) return 0;
|
if (!WebPInitDecoderConfig(&config)) return;
|
||||||
if (WebPGetFeatures(data, size, &config.input) != VP8_STATUS_OK) return 0;
|
const uint8_t* const data = reinterpret_cast<const uint8_t*>(blob.data());
|
||||||
if ((size_t)config.input.width * config.input.height > kFuzzPxLimit) return 0;
|
const size_t size = blob.size();
|
||||||
|
if (WebPGetFeatures(data, size, &config.input) != VP8_STATUS_OK) return;
|
||||||
|
if ((size_t)config.input.width * config.input.height >
|
||||||
|
fuzz_utils::kFuzzPxLimit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Using two independent criteria ensures that all combinations of options
|
// Using two independent criteria ensures that all combinations of options
|
||||||
// can reach each path at the decoding stage, with meaningful differences.
|
// can reach each path at the decoding stage, with meaningful differences.
|
||||||
|
|
||||||
const uint8_t value = FuzzHash(data, size);
|
const uint8_t value = fuzz_utils::FuzzHash(data, size);
|
||||||
const float factor = value / 255.f; // 0-1
|
const float factor = factor_u8 / 255.f; // 0-1
|
||||||
|
|
||||||
config.options.flip = value & 1;
|
config.options.flip = flip;
|
||||||
config.options.bypass_filtering = value & 2;
|
config.options.bypass_filtering = bypass_filtering;
|
||||||
config.options.no_fancy_upsampling = value & 4;
|
config.options.no_fancy_upsampling = no_fancy_upsampling;
|
||||||
config.options.use_threads = value & 8;
|
config.options.use_threads = use_threads;
|
||||||
if (size & 1) {
|
if (use_cropping) {
|
||||||
config.options.use_cropping = 1;
|
config.options.use_cropping = 1;
|
||||||
config.options.crop_width = (int)(config.input.width * (1 - factor));
|
config.options.crop_width = (int)(config.input.width * (1 - factor));
|
||||||
config.options.crop_height = (int)(config.input.height * (1 - factor));
|
config.options.crop_height = (int)(config.input.height * (1 - factor));
|
||||||
config.options.crop_left = config.input.width - config.options.crop_width;
|
config.options.crop_left = config.input.width - config.options.crop_width;
|
||||||
config.options.crop_top = config.input.height - config.options.crop_height;
|
config.options.crop_top = config.input.height - config.options.crop_height;
|
||||||
}
|
}
|
||||||
if (size & 2) {
|
if (use_dithering) {
|
||||||
int strength = (int)(factor * 100);
|
int strength = (int)(factor * 100);
|
||||||
config.options.dithering_strength = strength;
|
config.options.dithering_strength = strength;
|
||||||
config.options.alpha_dithering_strength = 100 - strength;
|
config.options.alpha_dithering_strength = 100 - strength;
|
||||||
}
|
}
|
||||||
if (size & 4) {
|
if (use_scaling) {
|
||||||
config.options.use_scaling = 1;
|
config.options.use_scaling = 1;
|
||||||
config.options.scaled_width = (int)(config.input.width * factor * 2);
|
config.options.scaled_width = (int)(config.input.width * factor * 2);
|
||||||
config.options.scaled_height = (int)(config.input.height * factor * 2);
|
config.options.scaled_height = (int)(config.input.height * factor * 2);
|
||||||
}
|
}
|
||||||
|
config.output.colorspace = static_cast<WEBP_CSP_MODE>(colorspace);
|
||||||
#if defined(WEBP_REDUCE_CSP)
|
|
||||||
config.output.colorspace = (value & 1)
|
|
||||||
? ((value & 2) ? MODE_RGBA : MODE_BGRA)
|
|
||||||
: ((value & 2) ? MODE_rgbA : MODE_bgrA);
|
|
||||||
#else
|
|
||||||
config.output.colorspace = (WEBP_CSP_MODE)(value % MODE_LAST);
|
|
||||||
#endif // WEBP_REDUCE_CSP
|
|
||||||
|
|
||||||
for (int i = 0; i < 2; ++i) {
|
for (int i = 0; i < 2; ++i) {
|
||||||
if (i == 1) {
|
if (i == 1) {
|
||||||
@ -80,7 +85,7 @@ int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
|||||||
if (WebPRescalerGetScaledDimensions(config.input.width,
|
if (WebPRescalerGetScaledDimensions(config.input.width,
|
||||||
config.input.height, &scaled_width,
|
config.input.height, &scaled_width,
|
||||||
&scaled_height)) {
|
&scaled_height)) {
|
||||||
size_t fuzz_px_limit = kFuzzPxLimit;
|
size_t fuzz_px_limit = fuzz_utils::kFuzzPxLimit;
|
||||||
if (scaled_width != config.input.width ||
|
if (scaled_width != config.input.width ||
|
||||||
scaled_height != config.input.height) {
|
scaled_height != config.input.height) {
|
||||||
// Using the WebPRescalerImport internally can significantly slow
|
// Using the WebPRescalerImport internally can significantly slow
|
||||||
@ -92,18 +97,18 @@ int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
|||||||
// very wide input image to a very tall canvas can be as slow as
|
// very wide input image to a very tall canvas can be as slow as
|
||||||
// decoding a huge number of pixels. Avoid timeouts due to these.
|
// decoding a huge number of pixels. Avoid timeouts due to these.
|
||||||
const uint64_t max_num_operations =
|
const uint64_t max_num_operations =
|
||||||
(uint64_t)Max(scaled_width, config.input.width) *
|
(uint64_t)std::max(scaled_width, config.input.width) *
|
||||||
Max(scaled_height, config.input.height);
|
std::max(scaled_height, config.input.height);
|
||||||
if (max_num_operations > fuzz_px_limit) {
|
if (max_num_operations > fuzz_px_limit) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (size % 3) {
|
if (incremental) {
|
||||||
// Decodes incrementally in chunks of increasing size.
|
// Decodes incrementally in chunks of increasing size.
|
||||||
WebPIDecoder* idec = WebPIDecode(NULL, 0, &config);
|
WebPIDecoder* idec = WebPIDecode(NULL, 0, &config);
|
||||||
if (!idec) return 0;
|
if (!idec) return;
|
||||||
VP8StatusCode status;
|
VP8StatusCode status;
|
||||||
if (size & 8) {
|
if (size & 8) {
|
||||||
size_t available_size = value + 1;
|
size_t available_size = value + 1;
|
||||||
@ -135,5 +140,28 @@ int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
|||||||
|
|
||||||
WebPFreeDecBuffer(&config.output);
|
WebPFreeDecBuffer(&config.output);
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
FUZZ_TEST(AdvancedApi, AdvancedApiTest)
|
||||||
|
.WithDomains(
|
||||||
|
fuzztest::String()
|
||||||
|
.WithMaxSize(fuzz_utils::kMaxWebPFileSize + 1),
|
||||||
|
/*factor_u8=*/fuzztest::Arbitrary<uint8_t>(),
|
||||||
|
/*flip=*/fuzztest::Arbitrary<bool>(),
|
||||||
|
/*bypass_filtering=*/fuzztest::Arbitrary<bool>(),
|
||||||
|
/*no_fancy_upsampling=*/fuzztest::Arbitrary<bool>(),
|
||||||
|
/*use_threads=*/fuzztest::Arbitrary<bool>(),
|
||||||
|
/*use_cropping=*/fuzztest::Arbitrary<bool>(),
|
||||||
|
/*use_scaling=*/fuzztest::Arbitrary<bool>(),
|
||||||
|
/*use_dithering=*/fuzztest::Arbitrary<bool>(),
|
||||||
|
#if defined(WEBP_REDUCE_CSP)
|
||||||
|
fuzztest::ElementOf<int>({static_cast<int>(MODE_RGBA),
|
||||||
|
static_cast<int>(MODE_BGRA),
|
||||||
|
static_cast<int>(MODE_rgbA),
|
||||||
|
static_cast<int>(MODE_bgrA)}),
|
||||||
|
#else
|
||||||
|
fuzztest::InRange<int>(0, static_cast<int>(MODE_LAST) - 1),
|
||||||
|
#endif
|
||||||
|
/*incremental=*/fuzztest::Arbitrary<bool>());
|
@ -14,37 +14,46 @@
|
|||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
#include "./fuzz_utils.h"
|
#include "./fuzz_utils.h"
|
||||||
#include "src/webp/decode.h"
|
#include "src/webp/decode.h"
|
||||||
#include "src/webp/demux.h"
|
#include "src/webp/demux.h"
|
||||||
#include "src/webp/mux_types.h"
|
#include "src/webp/mux_types.h"
|
||||||
|
|
||||||
int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
namespace {
|
||||||
|
|
||||||
|
void AnimationApiTest(std::string_view blob, bool use_threads,
|
||||||
|
WEBP_CSP_MODE color_mode) {
|
||||||
|
const size_t size = blob.size();
|
||||||
WebPData webp_data;
|
WebPData webp_data;
|
||||||
WebPDataInit(&webp_data);
|
WebPDataInit(&webp_data);
|
||||||
webp_data.size = size;
|
webp_data.size = size;
|
||||||
webp_data.bytes = data;
|
webp_data.bytes = reinterpret_cast<const uint8_t*>(blob.data());
|
||||||
|
|
||||||
// WebPAnimDecoderNew uses WebPDemux internally to calloc canvas size.
|
// WebPAnimDecoderNew uses WebPDemux internally to calloc canvas size.
|
||||||
WebPDemuxer* const demux = WebPDemux(&webp_data);
|
WebPDemuxer* const demux = WebPDemux(&webp_data);
|
||||||
if (!demux) return 0;
|
if (!demux) return;
|
||||||
const uint32_t cw = WebPDemuxGetI(demux, WEBP_FF_CANVAS_WIDTH);
|
const uint32_t cw = WebPDemuxGetI(demux, WEBP_FF_CANVAS_WIDTH);
|
||||||
const uint32_t ch = WebPDemuxGetI(demux, WEBP_FF_CANVAS_HEIGHT);
|
const uint32_t ch = WebPDemuxGetI(demux, WEBP_FF_CANVAS_HEIGHT);
|
||||||
if ((size_t)cw * ch > kFuzzPxLimit) {
|
if ((size_t)cw * ch > fuzz_utils::kFuzzPxLimit) {
|
||||||
WebPDemuxDelete(demux);
|
WebPDemuxDelete(demux);
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// In addition to canvas size, check each frame separately.
|
// In addition to canvas size, check each frame separately.
|
||||||
WebPIterator iter;
|
WebPIterator iter;
|
||||||
for (int i = 0; i < kFuzzFrameLimit; i++) {
|
for (int i = 0; i < fuzz_utils::kFuzzFrameLimit; i++) {
|
||||||
if (!WebPDemuxGetFrame(demux, i + 1, &iter)) break;
|
if (!WebPDemuxGetFrame(demux, i + 1, &iter)) break;
|
||||||
int w, h;
|
int w, h;
|
||||||
if (WebPGetInfo(iter.fragment.bytes, iter.fragment.size, &w, &h)) {
|
if (WebPGetInfo(iter.fragment.bytes, iter.fragment.size, &w, &h)) {
|
||||||
if ((size_t)w * h > kFuzzPxLimit) { // image size of the frame payload
|
if ((size_t)w * h >
|
||||||
|
fuzz_utils::kFuzzPxLimit) { // image size of the frame payload
|
||||||
WebPDemuxReleaseIterator(&iter);
|
WebPDemuxReleaseIterator(&iter);
|
||||||
WebPDemuxDelete(demux);
|
WebPDemuxDelete(demux);
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -53,26 +62,30 @@ int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
|||||||
WebPDemuxDelete(demux);
|
WebPDemuxDelete(demux);
|
||||||
|
|
||||||
WebPAnimDecoderOptions dec_options;
|
WebPAnimDecoderOptions dec_options;
|
||||||
if (!WebPAnimDecoderOptionsInit(&dec_options)) return 0;
|
if (!WebPAnimDecoderOptionsInit(&dec_options)) return;
|
||||||
|
|
||||||
dec_options.use_threads = size & 1;
|
dec_options.use_threads = use_threads;
|
||||||
// Animations only support 4 (of 12) modes.
|
dec_options.color_mode = color_mode;
|
||||||
dec_options.color_mode = (WEBP_CSP_MODE)(size % MODE_LAST);
|
|
||||||
if (dec_options.color_mode != MODE_BGRA &&
|
|
||||||
dec_options.color_mode != MODE_rgbA &&
|
|
||||||
dec_options.color_mode != MODE_bgrA) {
|
|
||||||
dec_options.color_mode = MODE_RGBA;
|
|
||||||
}
|
|
||||||
|
|
||||||
WebPAnimDecoder* dec = WebPAnimDecoderNew(&webp_data, &dec_options);
|
WebPAnimDecoder* dec = WebPAnimDecoderNew(&webp_data, &dec_options);
|
||||||
if (!dec) return 0;
|
if (!dec) return;
|
||||||
|
|
||||||
for (int i = 0; i < kFuzzFrameLimit; i++) {
|
for (int i = 0; i < fuzz_utils::kFuzzFrameLimit; i++) {
|
||||||
uint8_t* buf;
|
uint8_t* buf;
|
||||||
int timestamp;
|
int timestamp;
|
||||||
if (!WebPAnimDecoderGetNext(dec, &buf, ×tamp)) break;
|
if (!WebPAnimDecoderGetNext(dec, &buf, ×tamp)) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
WebPAnimDecoderDelete(dec);
|
WebPAnimDecoderDelete(dec);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
FUZZ_TEST(AnimationApi, AnimationApiTest)
|
||||||
|
.WithDomains(
|
||||||
|
fuzztest::String()
|
||||||
|
.WithMaxSize(fuzz_utils::kMaxWebPFileSize + 1),
|
||||||
|
/*use_threads=*/fuzztest::Arbitrary<bool>(),
|
||||||
|
// Animations only support 4 (out of 12) modes.
|
||||||
|
fuzztest::ElementOf<WEBP_CSP_MODE>({MODE_RGBA, MODE_BGRA, MODE_rgbA,
|
||||||
|
MODE_bgrA}));
|
@ -16,13 +16,20 @@
|
|||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
#include "./fuzz_utils.h"
|
||||||
#include "imageio/imageio_util.h"
|
#include "imageio/imageio_util.h"
|
||||||
#include "src/webp/decode.h"
|
#include "src/webp/decode.h"
|
||||||
#include "src/webp/demux.h"
|
#include "src/webp/demux.h"
|
||||||
#include "src/webp/mux_types.h"
|
#include "src/webp/mux_types.h"
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
namespace {
|
||||||
|
|
||||||
|
void AnimDecoderTest(std::string_view blob) {
|
||||||
|
const uint8_t* const data = reinterpret_cast<const uint8_t*>(blob.data());
|
||||||
|
const size_t size = blob.size();
|
||||||
|
|
||||||
// WebPAnimDecoderGetInfo() is too late to check the canvas size as
|
// WebPAnimDecoderGetInfo() is too late to check the canvas size as
|
||||||
// WebPAnimDecoderNew() will handle the allocations.
|
// WebPAnimDecoderNew() will handle the allocations.
|
||||||
const size_t kMaxNumBytes = 2684354560; // RSS (resident set size) limit.
|
const size_t kMaxNumBytes = 2684354560; // RSS (resident set size) limit.
|
||||||
@ -34,14 +41,14 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
|||||||
features.height) ||
|
features.height) ||
|
||||||
static_cast<size_t>(features.width) * features.height >
|
static_cast<size_t>(features.width) * features.height >
|
||||||
kMaxNumPixelsSafe) {
|
kMaxNumPixelsSafe) {
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// decode everything as an animation
|
// decode everything as an animation
|
||||||
WebPData webp_data = {data, size};
|
WebPData webp_data = {data, size};
|
||||||
WebPAnimDecoder* const dec = WebPAnimDecoderNew(&webp_data, nullptr);
|
WebPAnimDecoder* const dec = WebPAnimDecoderNew(&webp_data, nullptr);
|
||||||
if (dec == nullptr) return 0;
|
if (dec == nullptr) return;
|
||||||
|
|
||||||
WebPAnimInfo info;
|
WebPAnimInfo info;
|
||||||
if (!WebPAnimDecoderGetInfo(dec, &info)) goto End;
|
if (!WebPAnimDecoderGetInfo(dec, &info)) goto End;
|
||||||
@ -57,5 +64,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
|||||||
}
|
}
|
||||||
End:
|
End:
|
||||||
WebPAnimDecoderDelete(dec);
|
WebPAnimDecoderDelete(dec);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
FUZZ_TEST(AnimDecoder, AnimDecoderTest)
|
||||||
|
.WithDomains(
|
||||||
|
fuzztest::String()
|
||||||
|
.WithMaxSize(fuzz_utils::kMaxWebPFileSize + 1));
|
||||||
|
@ -14,21 +14,48 @@
|
|||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <cstddef>
|
||||||
#include <stdlib.h>
|
#include <cstdint>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <string_view>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "./fuzz_utils.h"
|
#include "./fuzz_utils.h"
|
||||||
|
#include "src/dsp/cpu.h"
|
||||||
#include "src/webp/encode.h"
|
#include "src/webp/encode.h"
|
||||||
#include "src/webp/mux.h"
|
#include "src/webp/mux.h"
|
||||||
|
#include "src/webp/mux_types.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const VP8CPUInfo default_VP8GetCPUInfo = VP8GetCPUInfo;
|
const VP8CPUInfo default_VP8GetCPUInfo = fuzz_utils::VP8GetCPUInfo;
|
||||||
|
|
||||||
|
struct FrameConfig {
|
||||||
|
int use_argb;
|
||||||
|
int timestamp;
|
||||||
|
WebPConfig webp_config;
|
||||||
|
fuzz_utils::CropOrScaleParams crop_or_scale_params;
|
||||||
|
int source_image_index;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto ArbitraryKMinKMax() {
|
||||||
|
return fuzztest::FlatMap(
|
||||||
|
[](int kmax) {
|
||||||
|
const int min_kmin = (kmax > 1) ? (kmax / 2) : 0;
|
||||||
|
const int max_kmin = (kmax > 1) ? (kmax - 1) : 0;
|
||||||
|
return fuzztest::PairOf(fuzztest::InRange(min_kmin, max_kmin),
|
||||||
|
fuzztest::Just(kmax));
|
||||||
|
},
|
||||||
|
fuzztest::InRange(0, 15));
|
||||||
|
}
|
||||||
|
|
||||||
int AddFrame(WebPAnimEncoder** const enc,
|
int AddFrame(WebPAnimEncoder** const enc,
|
||||||
const WebPAnimEncoderOptions& anim_config, int* const width,
|
const WebPAnimEncoderOptions& anim_config, int* const width,
|
||||||
int* const height, int timestamp_ms, const uint8_t data[],
|
int* const height, int timestamp_ms,
|
||||||
size_t size, uint32_t* const bit_pos) {
|
const FrameConfig& frame_config, const uint8_t data[], size_t size,
|
||||||
|
uint32_t* const bit_pos) {
|
||||||
if (enc == nullptr || width == nullptr || height == nullptr) {
|
if (enc == nullptr || width == nullptr || height == nullptr) {
|
||||||
fprintf(stderr, "NULL parameters.\n");
|
fprintf(stderr, "NULL parameters.\n");
|
||||||
if (enc != nullptr) WebPAnimEncoderDelete(*enc);
|
if (enc != nullptr) WebPAnimEncoderDelete(*enc);
|
||||||
@ -36,27 +63,12 @@ int AddFrame(WebPAnimEncoder** const enc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Init the source picture.
|
// Init the source picture.
|
||||||
WebPPicture pic;
|
WebPPicture pic = fuzz_utils::GetSourcePicture(
|
||||||
if (!WebPPictureInit(&pic)) {
|
frame_config.source_image_index, frame_config.use_argb);
|
||||||
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)) {
|
|
||||||
const WebPEncodingError error_code = pic.error_code;
|
|
||||||
WebPAnimEncoderDelete(*enc);
|
|
||||||
WebPPictureFree(&pic);
|
|
||||||
if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY) return 0;
|
|
||||||
fprintf(stderr, "Can't read input image. Error code: %d\n", error_code);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Crop and scale.
|
// Crop and scale.
|
||||||
if (*enc == nullptr) { // First frame will set canvas width and height.
|
if (*enc == nullptr) { // First frame will set canvas width and height.
|
||||||
if (!ExtractAndCropOrScale(&pic, data, size, bit_pos)) {
|
if (!fuzz_utils::CropOrScale(&pic, frame_config.crop_or_scale_params)) {
|
||||||
const WebPEncodingError error_code = pic.error_code;
|
const WebPEncodingError error_code = pic.error_code;
|
||||||
WebPPictureFree(&pic);
|
WebPPictureFree(&pic);
|
||||||
if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY) return 0;
|
if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY) return 0;
|
||||||
@ -89,13 +101,7 @@ int AddFrame(WebPAnimEncoder** const enc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create frame encoding config.
|
// Create frame encoding config.
|
||||||
WebPConfig config;
|
WebPConfig config = frame_config.webp_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.
|
// Skip slow settings on big images, it's likely to timeout.
|
||||||
if (pic.width * pic.height > 32 * 32) {
|
if (pic.width * pic.height > 32 * 32) {
|
||||||
config.method = (config.method > 4) ? 4 : config.method;
|
config.method = (config.method > 4) ? 4 : config.method;
|
||||||
@ -125,14 +131,17 @@ int AddFrame(WebPAnimEncoder** const enc,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
void AnimEncoderTest(std::string_view blob, bool minimize_size,
|
||||||
|
std::pair<int, int> kmin_kmax, bool allow_mixed,
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
const std::vector<FrameConfig>& frame_configs,
|
||||||
|
int optimization_index) {
|
||||||
WebPAnimEncoder* enc = nullptr;
|
WebPAnimEncoder* enc = nullptr;
|
||||||
int width = 0, height = 0, timestamp_ms = 0;
|
int width = 0, height = 0, timestamp_ms = 0;
|
||||||
uint32_t bit_pos = 0;
|
uint32_t bit_pos = 0;
|
||||||
|
const uint8_t* const data = reinterpret_cast<const uint8_t*>(blob.data());
|
||||||
|
const size_t size = blob.size();
|
||||||
|
|
||||||
ExtractAndDisableOptimizations(default_VP8GetCPUInfo, data, size, &bit_pos);
|
fuzz_utils::SetOptimization(default_VP8GetCPUInfo, optimization_index);
|
||||||
|
|
||||||
// Extract a configuration from the packed bits.
|
// Extract a configuration from the packed bits.
|
||||||
WebPAnimEncoderOptions anim_config;
|
WebPAnimEncoderOptions anim_config;
|
||||||
@ -140,26 +149,20 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
|||||||
fprintf(stderr, "WebPAnimEncoderOptionsInit failed.\n");
|
fprintf(stderr, "WebPAnimEncoderOptionsInit failed.\n");
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
anim_config.minimize_size = Extract(1, data, size, &bit_pos);
|
anim_config.minimize_size = minimize_size;
|
||||||
anim_config.kmax = Extract(15, data, size, &bit_pos);
|
anim_config.kmin = kmin_kmax.first;
|
||||||
const int min_kmin = (anim_config.kmax > 1) ? (anim_config.kmax / 2) : 0;
|
anim_config.kmax = kmin_kmax.second;
|
||||||
const int max_kmin = (anim_config.kmax > 1) ? (anim_config.kmax - 1) : 0;
|
anim_config.allow_mixed = allow_mixed;
|
||||||
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;
|
anim_config.verbose = 0;
|
||||||
|
|
||||||
const int nb_frames = 1 + Extract(15, data, size, &bit_pos);
|
|
||||||
|
|
||||||
// For each frame.
|
// For each frame.
|
||||||
for (int i = 0; i < nb_frames; ++i) {
|
for (const FrameConfig& frame_config : frame_configs) {
|
||||||
if (!AddFrame(&enc, anim_config, &width, &height, timestamp_ms, data, size,
|
if (!AddFrame(&enc, anim_config, &width, &height, timestamp_ms,
|
||||||
&bit_pos)) {
|
frame_config, data, size, &bit_pos)) {
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
timestamp_ms += (1 << (2 + Extract(15, data, size, &bit_pos))) +
|
timestamp_ms += frame_config.timestamp;
|
||||||
Extract(1, data, size, &bit_pos); // [1..131073], arbitrary
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assemble.
|
// Assemble.
|
||||||
@ -184,5 +187,22 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
|||||||
|
|
||||||
WebPAnimEncoderDelete(enc);
|
WebPAnimEncoderDelete(enc);
|
||||||
WebPDataClear(&webp_data);
|
WebPDataClear(&webp_data);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
FUZZ_TEST(AnimEncoder, AnimEncoderTest)
|
||||||
|
.WithDomains(
|
||||||
|
fuzztest::String(),
|
||||||
|
/*minimize_size=*/fuzztest::Arbitrary<bool>(), ArbitraryKMinKMax(),
|
||||||
|
/*allow_mixed=*/fuzztest::Arbitrary<bool>(),
|
||||||
|
fuzztest::VectorOf(
|
||||||
|
fuzztest::StructOf<FrameConfig>(
|
||||||
|
fuzztest::InRange<int>(0, 1), fuzztest::InRange<int>(0, 131073),
|
||||||
|
fuzz_utils::ArbitraryWebPConfig(),
|
||||||
|
fuzz_utils::ArbitraryCropOrScaleParams(),
|
||||||
|
fuzztest::InRange<int>(0, fuzz_utils::kNumSourceImages - 1)))
|
||||||
|
.WithMinSize(1)
|
||||||
|
.WithMaxSize(15),
|
||||||
|
/*optimization_index=*/
|
||||||
|
fuzztest::InRange<uint32_t>(0, fuzz_utils::kMaxOptimizationIndex));
|
||||||
|
@ -14,57 +14,37 @@
|
|||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <cstddef>
|
||||||
#include <stdlib.h>
|
#include <cstdint>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
#include "./fuzz_utils.h"
|
#include "./fuzz_utils.h"
|
||||||
|
#include "src/dsp/cpu.h"
|
||||||
#include "src/webp/decode.h"
|
#include "src/webp/decode.h"
|
||||||
#include "src/webp/encode.h"
|
#include "src/webp/encode.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const VP8CPUInfo default_VP8GetCPUInfo = VP8GetCPUInfo;
|
const VP8CPUInfo default_VP8GetCPUInfo = fuzz_utils::VP8GetCPUInfo;
|
||||||
|
|
||||||
} // namespace
|
void EncDecTest(bool use_argb, int source_image_index, WebPConfig config,
|
||||||
|
int optimization_index,
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
const fuzz_utils::CropOrScaleParams& crop_or_scale_params) {
|
||||||
uint32_t bit_pos = 0;
|
fuzz_utils::SetOptimization(default_VP8GetCPUInfo, optimization_index);
|
||||||
|
|
||||||
ExtractAndDisableOptimizations(default_VP8GetCPUInfo, data, size, &bit_pos);
|
|
||||||
|
|
||||||
// Init the source picture.
|
// Init the source picture.
|
||||||
WebPPicture pic;
|
WebPPicture pic = fuzz_utils::GetSourcePicture(source_image_index, use_argb);
|
||||||
if (!WebPPictureInit(&pic)) {
|
|
||||||
fprintf(stderr, "WebPPictureInit failed.\n");
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
pic.use_argb = Extract(1, data, size, &bit_pos);
|
|
||||||
|
|
||||||
// Read the source picture.
|
|
||||||
if (!ExtractSourcePicture(&pic, data, size, &bit_pos)) {
|
|
||||||
const WebPEncodingError error_code = pic.error_code;
|
|
||||||
WebPPictureFree(&pic);
|
|
||||||
if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY) return 0;
|
|
||||||
fprintf(stderr, "Can't read input image. Error code: %d\n", error_code);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Crop and scale.
|
// Crop and scale.
|
||||||
if (!ExtractAndCropOrScale(&pic, data, size, &bit_pos)) {
|
if (!fuzz_utils::CropOrScale(&pic, crop_or_scale_params)) {
|
||||||
const WebPEncodingError error_code = pic.error_code;
|
const WebPEncodingError error_code = pic.error_code;
|
||||||
WebPPictureFree(&pic);
|
WebPPictureFree(&pic);
|
||||||
if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY) return 0;
|
if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY) return;
|
||||||
fprintf(stderr, "ExtractAndCropOrScale failed. Error code: %d\n",
|
fprintf(stderr, "ExtractAndCropOrScale failed. Error code: %d\n",
|
||||||
error_code);
|
error_code);
|
||||||
abort();
|
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.
|
// Skip slow settings on big images, it's likely to timeout.
|
||||||
if (pic.width * pic.height > 32 * 32) {
|
if (pic.width * pic.height > 32 * 32) {
|
||||||
if (config.lossless) {
|
if (config.lossless) {
|
||||||
@ -93,7 +73,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
|||||||
WebPPictureFree(&pic);
|
WebPPictureFree(&pic);
|
||||||
if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY ||
|
if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY ||
|
||||||
error_code == VP8_ENC_ERROR_BAD_WRITE) {
|
error_code == VP8_ENC_ERROR_BAD_WRITE) {
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
fprintf(stderr, "WebPEncode failed. Error code: %d\n", error_code);
|
fprintf(stderr, "WebPEncode failed. Error code: %d\n", error_code);
|
||||||
abort();
|
abort();
|
||||||
@ -157,5 +137,16 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
|||||||
WebPFreeDecBuffer(&dec_config.output);
|
WebPFreeDecBuffer(&dec_config.output);
|
||||||
WebPMemoryWriterClear(&memory_writer);
|
WebPMemoryWriterClear(&memory_writer);
|
||||||
WebPPictureFree(&pic);
|
WebPPictureFree(&pic);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
FUZZ_TEST(EncDec, EncDecTest)
|
||||||
|
.WithDomains(/*use_argb=*/fuzztest::Arbitrary<bool>(),
|
||||||
|
/*source_image_index=*/
|
||||||
|
fuzztest::InRange<int>(0, fuzz_utils::kNumSourceImages - 1),
|
||||||
|
fuzz_utils::ArbitraryWebPConfig(),
|
||||||
|
/*optimization_index=*/
|
||||||
|
fuzztest::InRange<uint32_t>(0,
|
||||||
|
fuzz_utils::kMaxOptimizationIndex),
|
||||||
|
fuzz_utils::ArbitraryCropOrScaleParams());
|
||||||
|
201
tests/fuzzer/fuzz_utils.cc
Normal file
201
tests/fuzzer/fuzz_utils.cc
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
// Copyright 2024 Google LLC
|
||||||
|
//
|
||||||
|
// 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 "./fuzz_utils.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <tuple>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "./img_alpha.h"
|
||||||
|
#include "./img_grid.h"
|
||||||
|
#include "./img_peak.h"
|
||||||
|
#include "src/dsp/cpu.h"
|
||||||
|
#include "src/webp/decode.h"
|
||||||
|
#include "src/webp/encode.h"
|
||||||
|
#include "src/webp/types.h"
|
||||||
|
|
||||||
|
namespace fuzz_utils {
|
||||||
|
|
||||||
|
WebPPicture GetSourcePicture(int image_index, bool use_argb) {
|
||||||
|
WebPPicture pic;
|
||||||
|
if (!WebPPictureInit(&pic)) abort();
|
||||||
|
pic.use_argb = use_argb;
|
||||||
|
|
||||||
|
// Pick a source picture.
|
||||||
|
const int kImagesWidth[] = {kImgAlphaWidth, kImgGridWidth, kImgPeakWidth};
|
||||||
|
const int kImagesHeight[] = {kImgAlphaHeight, kImgGridHeight, kImgPeakHeight};
|
||||||
|
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)) abort();
|
||||||
|
return pic;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
int CropOrScale(WebPPicture* const pic, const CropOrScaleParams& params) {
|
||||||
|
if (pic == NULL) return 0;
|
||||||
|
#if !defined(WEBP_REDUCE_SIZE)
|
||||||
|
if (params.alter_input) {
|
||||||
|
if (params.crop_or_scale) {
|
||||||
|
const int cropped_width = std::max(1, pic->width / params.width_ratio);
|
||||||
|
const int cropped_height = std::max(1, pic->height / params.height_ratio);
|
||||||
|
const int cropped_left = (pic->width - cropped_width) / params.left_ratio;
|
||||||
|
const int cropped_top = (pic->height - cropped_height) / params.top_ratio;
|
||||||
|
return WebPPictureCrop(pic, cropped_left, cropped_top, cropped_width,
|
||||||
|
cropped_height);
|
||||||
|
} else {
|
||||||
|
const int scaled_width = 1 + (pic->width * params.width_ratio) / 8;
|
||||||
|
const int scaled_height = 1 + (pic->height * params.height_ratio) / 8;
|
||||||
|
return WebPPictureRescale(pic, scaled_width, scaled_height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else // defined(WEBP_REDUCE_SIZE)
|
||||||
|
(void)data;
|
||||||
|
(void)size;
|
||||||
|
(void)bit_pos;
|
||||||
|
#endif // !defined(WEBP_REDUCE_SIZE)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VP8CPUInfo VP8GetCPUInfo;
|
||||||
|
static VP8CPUInfo GetCPUInfo;
|
||||||
|
|
||||||
|
static WEBP_INLINE int GetCPUInfoNoSSE41(CPUFeature feature) {
|
||||||
|
if (feature == kSSE4_1 || feature == kAVX) return 0;
|
||||||
|
return GetCPUInfo(feature);
|
||||||
|
}
|
||||||
|
|
||||||
|
static WEBP_INLINE int GetCPUInfoNoAVX(CPUFeature feature) {
|
||||||
|
if (feature == kAVX) return 0;
|
||||||
|
return GetCPUInfo(feature);
|
||||||
|
}
|
||||||
|
|
||||||
|
static WEBP_INLINE int GetCPUInfoForceSlowSSSE3(CPUFeature feature) {
|
||||||
|
if (feature == kSlowSSSE3 && GetCPUInfo(kSSE3)) {
|
||||||
|
return 1; // we have SSE3 -> force SlowSSSE3
|
||||||
|
}
|
||||||
|
return GetCPUInfo(feature);
|
||||||
|
}
|
||||||
|
|
||||||
|
static WEBP_INLINE int GetCPUInfoOnlyC(CPUFeature feature) {
|
||||||
|
(void)feature;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetOptimization(VP8CPUInfo default_VP8GetCPUInfo, uint32_t index) {
|
||||||
|
assert(index <= kMaxOptimizationIndex);
|
||||||
|
GetCPUInfo = default_VP8GetCPUInfo;
|
||||||
|
const VP8CPUInfo kVP8CPUInfos[kMaxOptimizationIndex + 1] = {
|
||||||
|
GetCPUInfoOnlyC, GetCPUInfoForceSlowSSSE3, GetCPUInfoNoSSE41,
|
||||||
|
GetCPUInfoNoAVX, GetCPUInfo};
|
||||||
|
VP8GetCPUInfo = kVP8CPUInfos[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
std::vector<std::string> ReadFilesFromDirectory(std::string_view dir) {
|
||||||
|
std::vector<std::tuple<std::string>> tuples =
|
||||||
|
fuzztest::ReadFilesFromDirectory(dir);
|
||||||
|
std::vector<std::string> strings(tuples.size());
|
||||||
|
for (size_t i = 0; i < tuples.size(); ++i) {
|
||||||
|
using std::swap;
|
||||||
|
swap(std::get<0>(tuples[i]), strings[i]);
|
||||||
|
}
|
||||||
|
return strings;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// The code in this section is copied from
|
||||||
|
// https://github.com/webmproject/sjpeg/blob/
|
||||||
|
// 1c025b3dbc2246de3e1d7c287970f1a01291800f/src/jpeg_tools.cc#L47
|
||||||
|
// (same license as this file).
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// Constants below are marker codes defined in JPEG spec
|
||||||
|
// ISO/IEC 10918-1 : 1993(E) Table B.1
|
||||||
|
// See also: http://www.w3.org/Graphics/JPEG/itu-t81.pdf
|
||||||
|
|
||||||
|
#define M_SOF0 0xffc0
|
||||||
|
#define M_SOF1 0xffc1
|
||||||
|
|
||||||
|
const uint8_t* GetSOFData(const uint8_t* src, int size) {
|
||||||
|
if (src == NULL) return NULL;
|
||||||
|
const uint8_t* const end = src + size - 8; // 8 bytes of safety, for marker
|
||||||
|
src += 2; // skip M_SOI
|
||||||
|
for (; src < end && *src != 0xff; ++src) { /* search first 0xff marker */
|
||||||
|
}
|
||||||
|
while (src < end) {
|
||||||
|
const uint32_t marker = static_cast<uint32_t>((src[0] << 8) | src[1]);
|
||||||
|
if (marker == M_SOF0 || marker == M_SOF1) return src;
|
||||||
|
const size_t s = 2 + ((src[2] << 8) | src[3]);
|
||||||
|
src += s;
|
||||||
|
}
|
||||||
|
return NULL; // No SOF marker found
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SjpegDimensions(const uint8_t* src0, size_t size, int* width, int* height,
|
||||||
|
int* is_yuv420) {
|
||||||
|
if (width == NULL || height == NULL) return false;
|
||||||
|
const uint8_t* src = GetSOFData(src0, size);
|
||||||
|
const size_t left_over = size - (src - src0);
|
||||||
|
if (src == NULL || left_over < 8 + 3 * 1) return false;
|
||||||
|
if (height != NULL) *height = (src[5] << 8) | src[6];
|
||||||
|
if (width != NULL) *width = (src[7] << 8) | src[8];
|
||||||
|
if (is_yuv420 != NULL) {
|
||||||
|
const size_t nb_comps = src[9];
|
||||||
|
*is_yuv420 = (nb_comps == 3);
|
||||||
|
if (left_over < 11 + 3 * nb_comps) return false;
|
||||||
|
for (int c = 0; *is_yuv420 && c < 3; ++c) {
|
||||||
|
const int expected_dim = (c == 0 ? 0x22 : 0x11);
|
||||||
|
*is_yuv420 &= (src[11 + c * 3] == expected_dim);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool IsImageTooBig(const uint8_t* data, size_t size) {
|
||||||
|
int width, height, components;
|
||||||
|
if (SjpegDimensions(data, size, &width, &height, &components) ||
|
||||||
|
WebPGetInfo(data, size, &width, &height)) {
|
||||||
|
// Look at the number of 8x8px blocks rather than the overall pixel count
|
||||||
|
// when comparing to memory and duration thresholds.
|
||||||
|
const size_t ceiled_width = ((size_t)width + 7) / 8 * 8;
|
||||||
|
const size_t ceiled_height = ((size_t)height + 7) / 8 * 8;
|
||||||
|
// Threshold to avoid out-of-memory and timeout issues.
|
||||||
|
// The threshold is arbitrary but below the fuzzer limit of 2 GB.
|
||||||
|
// The value cannot be 2 GB because of the added memory by MSAN.
|
||||||
|
if (ceiled_width * ceiled_height > kFuzzPxLimit) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fuzz_utils
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2018 Google Inc.
|
// Copyright 2018-2024 Google LLC
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
@ -17,14 +17,23 @@
|
|||||||
#ifndef WEBP_TESTS_FUZZER_FUZZ_UTILS_H_
|
#ifndef WEBP_TESTS_FUZZER_FUZZ_UTILS_H_
|
||||||
#define WEBP_TESTS_FUZZER_FUZZ_UTILS_H_
|
#define WEBP_TESTS_FUZZER_FUZZ_UTILS_H_
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <cstddef>
|
||||||
#include <stdlib.h>
|
#include <cstdint>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "./img_alpha.h"
|
#include "./img_alpha.h"
|
||||||
#include "./img_grid.h"
|
#include "./img_grid.h"
|
||||||
#include "./img_peak.h"
|
#include "./img_peak.h"
|
||||||
#include "src/dsp/dsp.h"
|
#include "src/dsp/cpu.h"
|
||||||
#include "src/webp/encode.h"
|
#include "src/webp/encode.h"
|
||||||
|
#include "fuzztest/fuzztest.h"
|
||||||
|
|
||||||
|
namespace fuzz_utils {
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Arbitrary limits to prevent OOM, timeout, or slow execution.
|
// Arbitrary limits to prevent OOM, timeout, or slow execution.
|
||||||
@ -54,170 +63,139 @@ static WEBP_INLINE uint8_t FuzzHash(const uint8_t* const data, size_t size) {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
// Extract an integer in [0, max_value].
|
|
||||||
|
|
||||||
static WEBP_INLINE uint32_t Extract(uint32_t max_value,
|
|
||||||
const uint8_t data[], size_t size,
|
|
||||||
uint32_t* const bit_pos) {
|
|
||||||
uint32_t v = 0;
|
|
||||||
uint32_t 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.
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" VP8CPUInfo VP8GetCPUInfo;
|
extern "C" VP8CPUInfo VP8GetCPUInfo;
|
||||||
#else
|
#else
|
||||||
extern VP8CPUInfo VP8GetCPUInfo;
|
extern VP8CPUInfo VP8GetCPUInfo;
|
||||||
#endif
|
#endif
|
||||||
static VP8CPUInfo GetCPUInfo;
|
|
||||||
|
|
||||||
static WEBP_INLINE int GetCPUInfoNoSSE41(CPUFeature feature) {
|
|
||||||
if (feature == kSSE4_1 || feature == kAVX) return 0;
|
|
||||||
return GetCPUInfo(feature);
|
|
||||||
}
|
|
||||||
|
|
||||||
static WEBP_INLINE int GetCPUInfoNoAVX(CPUFeature feature) {
|
|
||||||
if (feature == kAVX) return 0;
|
|
||||||
return GetCPUInfo(feature);
|
|
||||||
}
|
|
||||||
|
|
||||||
static WEBP_INLINE int GetCPUInfoForceSlowSSSE3(CPUFeature feature) {
|
|
||||||
if (feature == kSlowSSSE3 && GetCPUInfo(kSSE3)) {
|
|
||||||
return 1; // we have SSE3 -> force SlowSSSE3
|
|
||||||
}
|
|
||||||
return GetCPUInfo(feature);
|
|
||||||
}
|
|
||||||
|
|
||||||
static WEBP_INLINE int GetCPUInfoOnlyC(CPUFeature feature) {
|
|
||||||
(void)feature;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static WEBP_INLINE 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 WEBP_INLINE int ExtractWebPConfig(WebPConfig* const config,
|
constexpr const uint8_t* kImagesData[] = {kImgAlphaData, kImgGridData,
|
||||||
const uint8_t data[], size_t size,
|
kImgPeakData};
|
||||||
uint32_t* const bit_pos) {
|
constexpr size_t kNumSourceImages =
|
||||||
if (config == NULL || !WebPConfigInit(config)) return 0;
|
sizeof(kImagesData) / sizeof(kImagesData[0]);
|
||||||
config->lossless = Extract(1, data, size, bit_pos);
|
|
||||||
config->quality = Extract(100, data, size, bit_pos);
|
WebPPicture GetSourcePicture(int image_index, bool use_argb);
|
||||||
config->method = Extract(6, data, size, bit_pos);
|
|
||||||
config->image_hint =
|
static inline auto ArbitraryWebPConfig() {
|
||||||
(WebPImageHint)Extract(WEBP_HINT_LAST - 1, data, size, bit_pos);
|
return fuzztest::Map(
|
||||||
config->segments = 1 + Extract(3, data, size, bit_pos);
|
[](int lossless, int quality, int method, int image_hint, int segments,
|
||||||
config->sns_strength = Extract(100, data, size, bit_pos);
|
int sns_strength, int filter_strength, int filter_sharpness,
|
||||||
config->filter_strength = Extract(100, data, size, bit_pos);
|
int filter_type, int autofilter, int alpha_compression,
|
||||||
config->filter_sharpness = Extract(7, data, size, bit_pos);
|
int alpha_filtering, int alpha_quality, int pass, int preprocessing,
|
||||||
config->filter_type = Extract(1, data, size, bit_pos);
|
int partitions, int partition_limit, int emulate_jpeg_size,
|
||||||
config->autofilter = Extract(1, data, size, bit_pos);
|
int thread_level, int low_memory, int near_lossless, int exact,
|
||||||
config->alpha_compression = Extract(1, data, size, bit_pos);
|
int use_delta_palette, int use_sharp_yuv) -> WebPConfig {
|
||||||
config->alpha_filtering = Extract(2, data, size, bit_pos);
|
WebPConfig config;
|
||||||
config->alpha_quality = Extract(100, data, size, bit_pos);
|
if (!WebPConfigInit(&config)) abort();
|
||||||
config->pass = 1 + Extract(9, data, size, bit_pos);
|
config.lossless = lossless;
|
||||||
config->show_compressed = 1;
|
config.quality = quality;
|
||||||
config->preprocessing = Extract(2, data, size, bit_pos);
|
config.method = method;
|
||||||
config->partitions = Extract(3, data, size, bit_pos);
|
config.image_hint = (WebPImageHint)image_hint;
|
||||||
config->partition_limit = 10 * Extract(10, data, size, bit_pos);
|
config.segments = segments;
|
||||||
config->emulate_jpeg_size = Extract(1, data, size, bit_pos);
|
config.sns_strength = sns_strength;
|
||||||
config->thread_level = Extract(1, data, size, bit_pos);
|
config.filter_strength = filter_strength;
|
||||||
config->low_memory = Extract(1, data, size, bit_pos);
|
config.filter_sharpness = filter_sharpness;
|
||||||
config->near_lossless = 20 * Extract(5, data, size, bit_pos);
|
config.filter_type = filter_type;
|
||||||
config->exact = Extract(1, data, size, bit_pos);
|
config.autofilter = autofilter;
|
||||||
config->use_delta_palette = Extract(1, data, size, bit_pos);
|
config.alpha_compression = alpha_compression;
|
||||||
config->use_sharp_yuv = Extract(1, data, size, bit_pos);
|
config.alpha_filtering = alpha_filtering;
|
||||||
return WebPValidateConfig(config);
|
config.alpha_quality = alpha_quality;
|
||||||
|
config.pass = pass;
|
||||||
|
config.show_compressed = 1;
|
||||||
|
config.preprocessing = preprocessing;
|
||||||
|
config.partitions = partitions;
|
||||||
|
config.partition_limit = 10 * partition_limit;
|
||||||
|
config.emulate_jpeg_size = emulate_jpeg_size;
|
||||||
|
config.thread_level = thread_level;
|
||||||
|
config.low_memory = low_memory;
|
||||||
|
config.near_lossless = 20 * near_lossless;
|
||||||
|
config.exact = exact;
|
||||||
|
config.use_delta_palette = use_delta_palette;
|
||||||
|
config.use_sharp_yuv = use_sharp_yuv;
|
||||||
|
if (!WebPValidateConfig(&config)) abort();
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
/*lossless=*/fuzztest::InRange<int>(0, 1),
|
||||||
|
/*quality=*/fuzztest::InRange<int>(0, 100),
|
||||||
|
/*method=*/fuzztest::InRange<int>(0, 6),
|
||||||
|
/*image_hint=*/fuzztest::InRange<int>(0, WEBP_HINT_LAST - 1),
|
||||||
|
/*segments=*/fuzztest::InRange<int>(1, 4),
|
||||||
|
/*sns_strength=*/fuzztest::InRange<int>(0, 100),
|
||||||
|
/*filter_strength=*/fuzztest::InRange<int>(0, 100),
|
||||||
|
/*filter_sharpness=*/fuzztest::InRange<int>(0, 7),
|
||||||
|
/*filter_type=*/fuzztest::InRange<int>(0, 1),
|
||||||
|
/*autofilter=*/fuzztest::InRange<int>(0, 1),
|
||||||
|
/*alpha_compression=*/fuzztest::InRange<int>(0, 1),
|
||||||
|
/*alpha_filtering=*/fuzztest::InRange<int>(0, 2),
|
||||||
|
/*alpha_quality=*/fuzztest::InRange<int>(0, 100),
|
||||||
|
/*pass=*/fuzztest::InRange<int>(1, 10),
|
||||||
|
/*preprocessing=*/fuzztest::InRange<int>(0, 2),
|
||||||
|
/*partitions=*/fuzztest::InRange<int>(0, 3),
|
||||||
|
/*partition_limit=*/fuzztest::InRange<int>(0, 10),
|
||||||
|
/*emulate_jpeg_size=*/fuzztest::InRange<int>(0, 1),
|
||||||
|
/*thread_level=*/fuzztest::InRange<int>(0, 1),
|
||||||
|
/*low_memory=*/fuzztest::InRange<int>(0, 1),
|
||||||
|
/*near_lossless=*/fuzztest::InRange<int>(0, 5),
|
||||||
|
/*exact=*/fuzztest::InRange<int>(0, 1),
|
||||||
|
/*use_delta_palette=*/fuzztest::InRange<int>(0, 1),
|
||||||
|
/*use_sharp_yuv=*/fuzztest::InRange<int>(0, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct CropOrScaleParams {
|
||||||
|
bool alter_input;
|
||||||
|
bool crop_or_scale;
|
||||||
|
int width_ratio;
|
||||||
|
int height_ratio;
|
||||||
|
int left_ratio;
|
||||||
|
int top_ratio;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline auto ArbitraryCropOrScaleParams() {
|
||||||
|
return fuzztest::Map(
|
||||||
|
[](const std::optional<std::pair<int, int>>& width_height_ratio,
|
||||||
|
const std::optional<std::pair<int, int>>& left_top_ratio)
|
||||||
|
-> CropOrScaleParams {
|
||||||
|
CropOrScaleParams params;
|
||||||
|
params.alter_input = width_height_ratio.has_value();
|
||||||
|
if (params.alter_input) {
|
||||||
|
params.width_ratio = width_height_ratio->first;
|
||||||
|
params.height_ratio = width_height_ratio->second;
|
||||||
|
params.crop_or_scale = left_top_ratio.has_value();
|
||||||
|
if (params.crop_or_scale) {
|
||||||
|
params.left_ratio = left_top_ratio->first;
|
||||||
|
params.top_ratio = left_top_ratio->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return params;
|
||||||
|
},
|
||||||
|
fuzztest::OptionalOf(
|
||||||
|
fuzztest::PairOf(fuzztest::InRange(1, 8), fuzztest::InRange(1, 8))),
|
||||||
|
fuzztest::OptionalOf(
|
||||||
|
fuzztest::PairOf(fuzztest::InRange(1, 8), fuzztest::InRange(1, 8))));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Crops or scales a picture according to the given params.
|
||||||
|
int CropOrScale(WebPPicture* pic, const CropOrScaleParams& params);
|
||||||
|
|
||||||
|
// Imposes a level of optimization among one of the kMaxOptimizationIndex+1
|
||||||
|
// possible values: OnlyC, ForceSlowSSSE3, NoSSE41, NoAVX, default.
|
||||||
|
static constexpr uint32_t kMaxOptimizationIndex = 4;
|
||||||
|
void SetOptimization(VP8CPUInfo default_VP8GetCPUInfo, uint32_t index);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
static WEBP_INLINE int ExtractSourcePicture(WebPPicture* const pic,
|
// See https://developers.google.com/speed/webp/docs/riff_container.
|
||||||
const uint8_t data[], size_t size,
|
static constexpr size_t kMaxWebPFileSize = (1ull << 32) - 2; // 4 GiB - 2
|
||||||
uint32_t* const bit_pos) {
|
|
||||||
if (pic == NULL) return 0;
|
|
||||||
|
|
||||||
// Pick a source picture.
|
std::vector<std::string> GetDictionaryFromFiles(
|
||||||
const uint8_t* kImagesData[] = {
|
const std::vector<std::string_view>& file_paths);
|
||||||
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.
|
// Checks whether the binary blob containing a JPEG or WebP is too big for the
|
||||||
return WebPPictureImportRGBA(pic, image_data, pic->argb_stride);
|
// fuzzer.
|
||||||
}
|
bool IsImageTooBig(const uint8_t* data, size_t size);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
} // namespace fuzz_utils
|
||||||
|
|
||||||
static WEBP_INLINE int Max(int a, int b) { return ((a < b) ? b : a); }
|
|
||||||
|
|
||||||
static WEBP_INLINE int ExtractAndCropOrScale(WebPPicture* const pic,
|
|
||||||
const uint8_t data[], size_t size,
|
|
||||||
uint32_t* const bit_pos) {
|
|
||||||
if (pic == NULL) return 0;
|
|
||||||
#if !defined(WEBP_REDUCE_SIZE)
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else // defined(WEBP_REDUCE_SIZE)
|
|
||||||
(void)data;
|
|
||||||
(void)size;
|
|
||||||
(void)bit_pos;
|
|
||||||
#endif // !defined(WEBP_REDUCE_SIZE)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // WEBP_TESTS_FUZZER_FUZZ_UTILS_H_
|
#endif // WEBP_TESTS_FUZZER_FUZZ_UTILS_H_
|
||||||
|
@ -14,22 +14,29 @@
|
|||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <cstddef>
|
||||||
#include <string.h>
|
#include <cstdint>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
#include "./fuzz_utils.h"
|
||||||
#include "src/dec/vp8li_dec.h"
|
#include "src/dec/vp8li_dec.h"
|
||||||
#include "src/utils/bit_reader_utils.h"
|
#include "src/utils/bit_reader_utils.h"
|
||||||
#include "src/utils/huffman_utils.h"
|
#include "src/utils/huffman_utils.h"
|
||||||
#include "src/utils/utils.h"
|
#include "src/utils/utils.h"
|
||||||
#include "src/webp/format_constants.h"
|
#include "src/webp/format_constants.h"
|
||||||
|
|
||||||
int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
namespace {
|
||||||
|
|
||||||
|
void HuffmanTest(std::string_view blob) {
|
||||||
|
const uint8_t* const data = reinterpret_cast<const uint8_t*>(blob.data());
|
||||||
|
const size_t size = blob.size();
|
||||||
|
|
||||||
// Number of bits to initialize data.
|
// Number of bits to initialize data.
|
||||||
static const int kColorCacheBitsBits = 4;
|
static const int kColorCacheBitsBits = 4;
|
||||||
// 'num_htree_groups' is contained in the RG channel, hence 16 bits.
|
// 'num_htree_groups' is contained in the RG channel, hence 16 bits.
|
||||||
static const int kNumHtreeGroupsBits = 16;
|
static const int kNumHtreeGroupsBits = 16;
|
||||||
if (size * sizeof(*data) < kColorCacheBitsBits + kNumHtreeGroupsBits) {
|
if (size * sizeof(*data) < kColorCacheBitsBits + kNumHtreeGroupsBits) {
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A non-NULL mapping brings minor changes that are tested by the normal
|
// A non-NULL mapping brings minor changes that are tested by the normal
|
||||||
@ -39,27 +46,32 @@ int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
|||||||
memset(&huffman_tables, 0, sizeof(huffman_tables));
|
memset(&huffman_tables, 0, sizeof(huffman_tables));
|
||||||
HTreeGroup* htree_groups = NULL;
|
HTreeGroup* htree_groups = NULL;
|
||||||
|
|
||||||
|
int num_htree_groups, num_htree_groups_max, color_cache_bits;
|
||||||
|
VP8LBitReader* br;
|
||||||
VP8LDecoder* dec = VP8LNew();
|
VP8LDecoder* dec = VP8LNew();
|
||||||
if (dec == NULL) goto Error;
|
if (dec == NULL) goto Error;
|
||||||
VP8LBitReader* const br = &dec->br_;
|
br = &dec->br_;
|
||||||
VP8LInitBitReader(br, data, size);
|
VP8LInitBitReader(br, data, size);
|
||||||
|
|
||||||
const int color_cache_bits = VP8LReadBits(br, kColorCacheBitsBits);
|
color_cache_bits = VP8LReadBits(br, kColorCacheBitsBits);
|
||||||
if (color_cache_bits < 1 || color_cache_bits > MAX_CACHE_BITS) goto Error;
|
if (color_cache_bits < 1 || color_cache_bits > MAX_CACHE_BITS) goto Error;
|
||||||
|
|
||||||
const int num_htree_groups = VP8LReadBits(br, kNumHtreeGroupsBits);
|
num_htree_groups = VP8LReadBits(br, kNumHtreeGroupsBits);
|
||||||
// 'num_htree_groups' cannot be 0 as it is built from a non-empty image.
|
// 'num_htree_groups' cannot be 0 as it is built from a non-empty image.
|
||||||
if (num_htree_groups == 0) goto Error;
|
if (num_htree_groups == 0) return;
|
||||||
// This variable is only useful when mapping is not NULL.
|
// This variable is only useful when mapping is not NULL.
|
||||||
const int num_htree_groups_max = num_htree_groups;
|
num_htree_groups_max = num_htree_groups;
|
||||||
(void)ReadHuffmanCodesHelper(color_cache_bits, num_htree_groups,
|
(void)ReadHuffmanCodesHelper(color_cache_bits, num_htree_groups,
|
||||||
num_htree_groups_max, mapping, dec,
|
num_htree_groups_max, mapping, dec,
|
||||||
&huffman_tables, &htree_groups);
|
&huffman_tables, &htree_groups);
|
||||||
|
|
||||||
Error:
|
Error:
|
||||||
WebPSafeFree(mapping);
|
WebPSafeFree(mapping);
|
||||||
VP8LHtreeGroupsFree(htree_groups);
|
VP8LHtreeGroupsFree(htree_groups);
|
||||||
VP8LHuffmanTablesDeallocate(&huffman_tables);
|
VP8LHuffmanTablesDeallocate(&huffman_tables);
|
||||||
VP8LDelete(dec);
|
VP8LDelete(dec);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
FUZZ_TEST(Huffman, HuffmanTest).WithDomains(fuzztest::String());
|
@ -1,31 +0,0 @@
|
|||||||
# This Makefile will compile all fuzzing targets. It doesn't check tool
|
|
||||||
# requirements and paths may need to be updated depending on your environment.
|
|
||||||
# Note a clang 6+ toolchain is assumed for use of -fsanitize=fuzzer.
|
|
||||||
|
|
||||||
CC = clang
|
|
||||||
CXX = clang++
|
|
||||||
CFLAGS = -fsanitize=fuzzer -I../../src -I../.. -Wall -Wextra
|
|
||||||
CXXFLAGS = $(CFLAGS)
|
|
||||||
LDFLAGS = -fsanitize=fuzzer
|
|
||||||
LDLIBS = ../../src/mux/libwebpmux.a ../../src/demux/libwebpdemux.a
|
|
||||||
LDLIBS += ../../src/libwebp.a ../../imageio/libimageio_util.a
|
|
||||||
LDLIBS += ../../sharpyuv/libsharpyuv.a
|
|
||||||
|
|
||||||
FUZZERS = advanced_api_fuzzer animation_api_fuzzer animdecoder_fuzzer
|
|
||||||
FUZZERS += animencoder_fuzzer enc_dec_fuzzer huffman_fuzzer
|
|
||||||
FUZZERS += mux_demux_api_fuzzer simple_api_fuzzer
|
|
||||||
|
|
||||||
%.o: fuzz_utils.h img_alpha.h img_grid.h img_peak.h
|
|
||||||
all: $(FUZZERS)
|
|
||||||
|
|
||||||
define FUZZER_template
|
|
||||||
$(1): $$(addsuffix .o, $(1)) $(LDLIBS)
|
|
||||||
OBJS += $$(addsuffix .o, $(1))
|
|
||||||
endef
|
|
||||||
|
|
||||||
$(foreach fuzzer, $(FUZZERS), $(eval $(call FUZZER_template, $(fuzzer))))
|
|
||||||
|
|
||||||
clean:
|
|
||||||
$(RM) $(FUZZERS) $(OBJS)
|
|
||||||
|
|
||||||
.PHONY: all clean
|
|
@ -14,23 +14,30 @@
|
|||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
#include "./fuzz_utils.h"
|
#include "./fuzz_utils.h"
|
||||||
#include "src/webp/demux.h"
|
#include "src/webp/demux.h"
|
||||||
#include "src/webp/mux.h"
|
#include "src/webp/mux.h"
|
||||||
|
|
||||||
int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
namespace {
|
||||||
|
|
||||||
|
void MuxDemuxApiTest(std::string_view data_in, bool mux) {
|
||||||
|
const size_t size = data_in.size();
|
||||||
WebPData webp_data;
|
WebPData webp_data;
|
||||||
WebPDataInit(&webp_data);
|
WebPDataInit(&webp_data);
|
||||||
webp_data.size = size;
|
webp_data.size = size;
|
||||||
webp_data.bytes = data;
|
webp_data.bytes = reinterpret_cast<const uint8_t*>(data_in.data());
|
||||||
|
|
||||||
// Extracted chunks and frames are not processed or decoded,
|
// Extracted chunks and frames are not processed or decoded,
|
||||||
// which is already covered extensively by the other fuzz targets.
|
// which is already covered extensively by the other fuzz targets.
|
||||||
|
|
||||||
if (size & 1) {
|
if (mux) {
|
||||||
// Mux API
|
// Mux API
|
||||||
WebPMux* mux = WebPMuxCreate(&webp_data, size & 2);
|
WebPMux* mux = WebPMuxCreate(&webp_data, size & 2);
|
||||||
if (!mux) return 0;
|
if (!mux) return;
|
||||||
|
|
||||||
WebPData chunk;
|
WebPData chunk;
|
||||||
(void)WebPMuxGetChunk(mux, "EXIF", &chunk);
|
(void)WebPMuxGetChunk(mux, "EXIF", &chunk);
|
||||||
@ -45,7 +52,7 @@ int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
|||||||
|
|
||||||
WebPMuxError status;
|
WebPMuxError status;
|
||||||
WebPMuxFrameInfo info;
|
WebPMuxFrameInfo info;
|
||||||
for (int i = 0; i < kFuzzFrameLimit; i++) {
|
for (int i = 0; i < fuzz_utils::kFuzzFrameLimit; i++) {
|
||||||
status = WebPMuxGetFrame(mux, i + 1, &info);
|
status = WebPMuxGetFrame(mux, i + 1, &info);
|
||||||
if (status == WEBP_MUX_NOT_FOUND) {
|
if (status == WEBP_MUX_NOT_FOUND) {
|
||||||
break;
|
break;
|
||||||
@ -63,11 +70,11 @@ int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
|||||||
demux = WebPDemuxPartial(&webp_data, &state);
|
demux = WebPDemuxPartial(&webp_data, &state);
|
||||||
if (state < WEBP_DEMUX_PARSED_HEADER) {
|
if (state < WEBP_DEMUX_PARSED_HEADER) {
|
||||||
WebPDemuxDelete(demux);
|
WebPDemuxDelete(demux);
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
demux = WebPDemux(&webp_data);
|
demux = WebPDemux(&webp_data);
|
||||||
if (!demux) return 0;
|
if (!demux) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
WebPChunkIterator chunk_iter;
|
WebPChunkIterator chunk_iter;
|
||||||
@ -83,7 +90,7 @@ int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
|||||||
|
|
||||||
WebPIterator iter;
|
WebPIterator iter;
|
||||||
if (WebPDemuxGetFrame(demux, 1, &iter)) {
|
if (WebPDemuxGetFrame(demux, 1, &iter)) {
|
||||||
for (int i = 1; i < kFuzzFrameLimit; i++) {
|
for (int i = 1; i < fuzz_utils::kFuzzFrameLimit; i++) {
|
||||||
if (!WebPDemuxNextFrame(&iter)) break;
|
if (!WebPDemuxNextFrame(&iter)) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -91,6 +98,12 @@ int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
|||||||
WebPDemuxReleaseIterator(&iter);
|
WebPDemuxReleaseIterator(&iter);
|
||||||
WebPDemuxDelete(demux);
|
WebPDemuxDelete(demux);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
FUZZ_TEST(MuxDemuxApi, MuxDemuxApiTest)
|
||||||
|
.WithDomains(
|
||||||
|
fuzztest::String()
|
||||||
|
.WithMaxSize(fuzz_utils::kMaxWebPFileSize + 1),
|
||||||
|
/*mux=*/fuzztest::Arbitrary<bool>());
|
@ -15,61 +15,69 @@
|
|||||||
#
|
#
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
|
# This script is meant to be run by the oss-fuzz infrastructure from the script
|
||||||
|
# https://github.com/google/oss-fuzz/blob/master/projects/libwebp/build.sh
|
||||||
|
# It builds the different fuzz targets.
|
||||||
|
|
||||||
|
# To test changes to this file:
|
||||||
|
# - make changes and commit to your REPO
|
||||||
|
# - run:
|
||||||
|
# git clone --depth=1 git@github.com:google/oss-fuzz.git
|
||||||
|
# cd oss-fuzz
|
||||||
|
# - modify projects/libwebp/Dockerfile to point to your REPO
|
||||||
|
# - run:
|
||||||
|
# python3 infra/helper.py build_image libwebp
|
||||||
|
# # enter 'y' and wait for everything to be downloaded
|
||||||
|
# - run:
|
||||||
|
# python3 infra/helper.py build_fuzzers --sanitizer address libwebp
|
||||||
|
# # wait for the tests to be built
|
||||||
|
# And then run the fuzzer locally, for example:
|
||||||
|
# python3 infra/helper.py run_fuzzer libwebp \
|
||||||
|
# --sanitizer address \
|
||||||
|
# animencoder_fuzzer__AnimEncoder.AnimEncoderTest
|
||||||
|
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
# limit allocation size to reduce spurious OOMs
|
# limit allocation size to reduce spurious OOMs
|
||||||
WEBP_CFLAGS="$CFLAGS -DWEBP_MAX_IMAGE_SIZE=838860800" # 800MiB
|
WEBP_CFLAGS="$CFLAGS -DWEBP_MAX_IMAGE_SIZE=838860800" # 800MiB
|
||||||
|
|
||||||
./autogen.sh
|
export CFLAGS="$WEBP_CFLAGS"
|
||||||
CFLAGS="$WEBP_CFLAGS" ./configure \
|
cmake -S . -B build -DWEBP_BUILD_FUZZTEST=ON
|
||||||
--enable-asserts \
|
cd build && make -j$(nproc) && cd ..
|
||||||
--enable-libwebpdemux \
|
|
||||||
--enable-libwebpmux \
|
|
||||||
--disable-shared \
|
|
||||||
--disable-jpeg \
|
|
||||||
--disable-tiff \
|
|
||||||
--disable-gif \
|
|
||||||
--disable-wic
|
|
||||||
make clean
|
|
||||||
make -j$(nproc)
|
|
||||||
|
|
||||||
find $SRC/libwebp-test-data -type f -size -32k -iname "*.webp" \
|
find $SRC/libwebp-test-data -type f -size -32k -iname "*.webp" \
|
||||||
-exec zip -qju fuzz_seed_corpus.zip "{}" \;
|
-exec zip -qju fuzz_seed_corpus.zip "{}" \;
|
||||||
|
|
||||||
webp_libs=(
|
# Restrict fuzztest tests to the only compatible fuzz engine: libfuzzer.
|
||||||
src/demux/.libs/libwebpdemux.a
|
if [[ "$FUZZING_ENGINE" == "libfuzzer" ]]; then
|
||||||
src/mux/.libs/libwebpmux.a
|
# build fuzztests
|
||||||
src/.libs/libwebp.a
|
# The following is taken from https://github.com/google/oss-fuzz/blob/31ac7244748ea7390015455fb034b1f4eda039d9/infra/base-images/base-builder/compile_fuzztests.sh#L59
|
||||||
imageio/.libs/libimageio_util.a
|
# Iterate the fuzz binaries and list each fuzz entrypoint in the binary. For
|
||||||
sharpyuv/.libs/libsharpyuv.a
|
# each entrypoint create a wrapper script that calls into the binaries the
|
||||||
)
|
# given entrypoint as argument.
|
||||||
webp_c_fuzzers=(
|
# The scripts will be named:
|
||||||
advanced_api_fuzzer
|
# {binary_name}@{fuzztest_entrypoint}
|
||||||
animation_api_fuzzer
|
FUZZ_TEST_BINARIES_OUT_PATHS=$(find ./build/tests/fuzzer/ -executable -type f)
|
||||||
huffman_fuzzer
|
echo "Fuzz binaries: $FUZZ_TEST_BINARIES_OUT_PATHS"
|
||||||
mux_demux_api_fuzzer
|
for fuzz_main_file in $FUZZ_TEST_BINARIES_OUT_PATHS; do
|
||||||
simple_api_fuzzer
|
FUZZ_TESTS=$($fuzz_main_file --list_fuzz_tests | cut -d ' ' -f 4)
|
||||||
)
|
cp -f ${fuzz_main_file} $OUT/
|
||||||
webp_cxx_fuzzers=(
|
fuzz_basename=$(basename $fuzz_main_file)
|
||||||
animdecoder_fuzzer
|
chmod -x $OUT/$fuzz_basename
|
||||||
animencoder_fuzzer
|
for fuzz_entrypoint in $FUZZ_TESTS; do
|
||||||
enc_dec_fuzzer
|
TARGET_FUZZER="${fuzz_basename}@$fuzz_entrypoint"
|
||||||
)
|
# Write executer script
|
||||||
|
echo "#!/bin/sh
|
||||||
for fuzzer in "${webp_c_fuzzers[@]}"; do
|
# LLVMFuzzerTestOneInput for fuzzer detection.
|
||||||
$CC $CFLAGS -Isrc -I. tests/fuzzer/${fuzzer}.c -c -o tests/fuzzer/${fuzzer}.o
|
this_dir=\$(dirname \"\$0\")
|
||||||
$CXX $CXXFLAGS $LIB_FUZZING_ENGINE \
|
export TEST_DATA_DIRS=\$this_dir/corpus
|
||||||
tests/fuzzer/${fuzzer}.o -o $OUT/${fuzzer} \
|
chmod +x \$this_dir/$fuzz_basename
|
||||||
"${webp_libs[@]}"
|
\$this_dir/$fuzz_basename --fuzz=$fuzz_entrypoint -- \$@
|
||||||
done
|
chmod -x \$this_dir/$fuzz_basename" > $OUT/$TARGET_FUZZER
|
||||||
|
chmod +x $OUT/$TARGET_FUZZER
|
||||||
for fuzzer in "${webp_cxx_fuzzers[@]}"; do
|
done
|
||||||
$CXX $CXXFLAGS -Isrc -I. $LIB_FUZZING_ENGINE \
|
# Copy data.
|
||||||
tests/fuzzer/${fuzzer}.cc -o $OUT/${fuzzer} \
|
cp fuzz_seed_corpus.zip $OUT/${fuzz_basename}_seed_corpus.zip
|
||||||
"${webp_libs[@]}"
|
cp tests/fuzzer/fuzz.dict $OUT/${fuzz_basename}.dict
|
||||||
done
|
done
|
||||||
|
fi
|
||||||
for fuzzer in "${webp_c_fuzzers[@]}" "${webp_cxx_fuzzers[@]}"; do
|
|
||||||
cp fuzz_seed_corpus.zip $OUT/${fuzzer}_seed_corpus.zip
|
|
||||||
cp tests/fuzzer/fuzz.dict $OUT/${fuzzer}.dict
|
|
||||||
done
|
|
||||||
|
10
tests/fuzzer/patch.sh
Executable file
10
tests/fuzzer/patch.sh
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Fixes for https://github.com/google/fuzztest/issues/1124
|
||||||
|
sed -i -e "s/-fsanitize=address//g" -e "s/-DADDRESS_SANITIZER//g" \
|
||||||
|
./cmake/FuzzTestFlagSetup.cmake
|
||||||
|
# Fixes for https://github.com/google/fuzztest/issues/1125
|
||||||
|
before="if (IsEnginePlaceholderInput(data)) return;"
|
||||||
|
after="if (data.size() == 0) return;"
|
||||||
|
sed -i "s/${before}/${after}/" ./fuzztest/internal/compatibility_mode.cc
|
||||||
|
sed -i "s/set(GTEST_HAS_ABSL ON)/set(GTEST_HAS_ABSL OFF)/" \
|
||||||
|
./cmake/BuildDependencies.cmake
|
@ -14,15 +14,23 @@
|
|||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
#include "./fuzz_utils.h"
|
#include "./fuzz_utils.h"
|
||||||
#include "src/webp/decode.h"
|
#include "src/webp/decode.h"
|
||||||
|
|
||||||
int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
namespace {
|
||||||
int w, h;
|
|
||||||
if (!WebPGetInfo(data, size, &w, &h)) return 0;
|
|
||||||
if ((size_t)w * h > kFuzzPxLimit) return 0;
|
|
||||||
|
|
||||||
const uint8_t value = FuzzHash(data, size);
|
void SimpleApiTest(std::string_view data_in) {
|
||||||
|
const uint8_t* const data = reinterpret_cast<const uint8_t*>(data_in.data());
|
||||||
|
const size_t size = data_in.size();
|
||||||
|
int w, h;
|
||||||
|
if (!WebPGetInfo(data, size, &w, &h)) return;
|
||||||
|
if ((size_t)w * h > fuzz_utils::kFuzzPxLimit) return;
|
||||||
|
|
||||||
|
const uint8_t value = fuzz_utils::FuzzHash(data, size);
|
||||||
uint8_t* buf = NULL;
|
uint8_t* buf = NULL;
|
||||||
|
|
||||||
// For *Into functions, which decode into an external buffer, an
|
// For *Into functions, which decode into an external buffer, an
|
||||||
@ -84,6 +92,11 @@ int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (buf) WebPFree(buf);
|
if (buf) WebPFree(buf);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
FUZZ_TEST(SimpleApi, SimpleApiTest)
|
||||||
|
.WithDomains(
|
||||||
|
fuzztest::String()
|
||||||
|
.WithMaxSize(fuzz_utils::kMaxWebPFileSize + 1));
|
Loading…
Reference in New Issue
Block a user