1
0
mirror of https://chromium.googlesource.com/webm/libwebp synced 2026-10-24 03:28:59 +03:00
Files
libwebp/fuzzer/sharpyuv_fuzzer.cc
Maryla 2d5f499bcf Fix OOB caused by pixels exceeding the advertised bit depth
Bug: 508312479
Change-Id: Ia26041fd4a1ab687ef927a96ea9a28ee46d43748
2026-05-18 13:30:15 +02:00

131 lines
4.9 KiB
C++

// Copyright 2026 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 <cstddef>
#include <cstdint>
#include <vector>
#include "sharpyuv/sharpyuv.h"
#include "sharpyuv/sharpyuv_csp.h"
#include "testing/base/public/gunit.h"
#include "testing/fuzzing/fuzztest.h"
namespace {
void SharpYuvConvertFuzz(int width, int height, int rgb_bit_depth,
int yuv_bit_depth,
const std::vector<uint16_t>& r_samples,
const std::vector<uint16_t>& g_samples,
const std::vector<uint16_t>& b_samples,
int matrix_type_int, int transfer_type_int) {
const size_t num_pixels = static_cast<size_t>(width) * height;
ASSERT_LE(num_pixels, r_samples.size());
ASSERT_LE(num_pixels, g_samples.size());
ASSERT_LE(num_pixels, b_samples.size());
const SharpYuvMatrixType matrix_type =
static_cast<SharpYuvMatrixType>(matrix_type_int);
const SharpYuvTransferFunctionType transfer_type =
static_cast<SharpYuvTransferFunctionType>(transfer_type_int);
const SharpYuvConversionMatrix* matrix =
SharpYuvGetConversionMatrix(matrix_type);
ASSERT_NE(matrix, nullptr);
SharpYuvOptions options;
ASSERT_TRUE(SharpYuvOptionsInit(matrix, &options));
options.transfer_type = transfer_type;
const int yuv_bytes = (yuv_bit_depth > 8) ? 2 : 1;
const int y_stride = width * yuv_bytes;
const int uv_stride = ((width + 1) / 2) * yuv_bytes;
std::vector<uint8_t> y_dst(y_stride * height);
std::vector<uint8_t> u_dst(uv_stride * ((height + 1) / 2));
std::vector<uint8_t> v_dst(uv_stride * ((height + 1) / 2));
if (rgb_bit_depth == 8) {
std::vector<uint8_t> r8(num_pixels), g8(num_pixels), b8(num_pixels);
for (size_t i = 0; i < num_pixels; ++i) {
r8[i] = static_cast<uint8_t>(r_samples[i]);
g8[i] = static_cast<uint8_t>(g_samples[i]);
b8[i] = static_cast<uint8_t>(b_samples[i]);
}
EXPECT_TRUE(SharpYuvConvertWithOptions(
r8.data(), g8.data(), b8.data(), 1, width, rgb_bit_depth, y_dst.data(),
y_stride, u_dst.data(), uv_stride, v_dst.data(), uv_stride,
yuv_bit_depth, width, height, &options));
} else {
EXPECT_TRUE(SharpYuvConvertWithOptions(
r_samples.data(), g_samples.data(), b_samples.data(), 2, width * 2,
rgb_bit_depth, y_dst.data(), y_stride, u_dst.data(), uv_stride,
v_dst.data(), uv_stride, yuv_bit_depth, width, height, &options));
}
}
auto AnyTransferFunction() {
return fuzztest::ElementOf<int>({
kSharpYuvTransferFunctionBt709,
kSharpYuvTransferFunctionBt470M,
kSharpYuvTransferFunctionBt470Bg,
kSharpYuvTransferFunctionBt601,
kSharpYuvTransferFunctionSmpte240,
kSharpYuvTransferFunctionLinear,
kSharpYuvTransferFunctionLog100,
kSharpYuvTransferFunctionLog100_Sqrt10,
kSharpYuvTransferFunctionIec61966,
kSharpYuvTransferFunctionBt1361,
kSharpYuvTransferFunctionSrgb,
kSharpYuvTransferFunctionBt2020_10Bit,
kSharpYuvTransferFunctionBt2020_12Bit,
kSharpYuvTransferFunctionSmpte2084,
kSharpYuvTransferFunctionSmpte428,
kSharpYuvTransferFunctionHlg,
});
}
auto SharpYuvDomain() {
return fuzztest::FlatMap(
[](int w, int h, int rgb_bd, int yuv_bd) {
// Create input/output buffers of the right size.
const size_t n = static_cast<size_t>(w * h);
return fuzztest::TupleOf(
fuzztest::Just(w), fuzztest::Just(h), fuzztest::Just(rgb_bd),
fuzztest::Just(yuv_bd),
fuzztest::VectorOf(fuzztest::Arbitrary<uint16_t>()).WithSize(n),
fuzztest::VectorOf(fuzztest::Arbitrary<uint16_t>()).WithSize(n),
fuzztest::VectorOf(fuzztest::Arbitrary<uint16_t>()).WithSize(n),
fuzztest::InRange(0, static_cast<int>(kSharpYuvMatrixNum) - 1),
AnyTransferFunction());
},
/*width=*/fuzztest::InRange(1, 128),
/*height=*/fuzztest::InRange(1, 128),
/*rgb_bit_depth=*/fuzztest::ElementOf({8, 10, 12, 16}),
/*yuv_bit_depth=*/fuzztest::ElementOf({8, 10, 12}));
}
void SharpYuvConvertFuzzWrapped(
const std::tuple<int, int, int, int, std::vector<uint16_t>,
std::vector<uint16_t>, std::vector<uint16_t>, int, int>&
args) {
std::apply(SharpYuvConvertFuzz, args);
}
FUZZ_TEST(SharpYuvFuzz, SharpYuvConvertFuzzWrapped)
.WithDomains(SharpYuvDomain());
} // namespace