From d5e2c4a4097c799433cfc5367c61568fad2c784e Mon Sep 17 00:00:00 2001 From: TheCharlatan Date: Tue, 14 Jan 2025 22:21:45 +0100 Subject: [PATCH] fuzz: Add fuzz test for checked and saturating add and left shift Co-authored-by: Ryan Ofsky --- src/test/fuzz/CMakeLists.txt | 1 + src/test/fuzz/overflow.cpp | 50 ++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 src/test/fuzz/overflow.cpp diff --git a/src/test/fuzz/CMakeLists.txt b/src/test/fuzz/CMakeLists.txt index f65ed62b2d0..a261d3ecea2 100644 --- a/src/test/fuzz/CMakeLists.txt +++ b/src/test/fuzz/CMakeLists.txt @@ -71,6 +71,7 @@ add_executable(fuzz netaddress.cpp netbase_dns_lookup.cpp node_eviction.cpp + overflow.cpp p2p_handshake.cpp p2p_headers_presync.cpp p2p_transport_serialization.cpp diff --git a/src/test/fuzz/overflow.cpp b/src/test/fuzz/overflow.cpp new file mode 100644 index 00000000000..0278bd0f415 --- /dev/null +++ b/src/test/fuzz/overflow.cpp @@ -0,0 +1,50 @@ +// Copyright (c) 2025-present The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include + +#include +#include +#include + +namespace { +//! Test overflow operations for type T using a wider type, W, to verify results. +template +void TestOverflow(FuzzedDataProvider& fuzzed_data_provider) +{ + constexpr auto min{std::numeric_limits::min()}; + constexpr auto max{std::numeric_limits::max()}; + // Range needs to be at least twice as big to allow two numbers to be added without overflowing. + static_assert(min >= std::numeric_limits::min() / 2); + static_assert(max <= std::numeric_limits::max() / 2); + + auto widen = [](T value) -> W { return value; }; + auto clamp = [](W value) -> W { return std::clamp(value, min, max); }; + auto check = [](W value) -> std::optional { if (value >= min && value <= max) return value; else return std::nullopt; }; + + const T i = fuzzed_data_provider.ConsumeIntegral(); + const T j = fuzzed_data_provider.ConsumeIntegral(); + const unsigned shift = fuzzed_data_provider.ConsumeIntegralInRange(0, std::numeric_limits::digits - std::numeric_limits::digits); + + Assert(clamp(widen(i) + widen(j)) == SaturatingAdd(i, j)); + Assert(check(widen(i) + widen(j)) == CheckedAdd(i, j)); + + Assert(clamp(widen(i) << shift) == SaturatingLeftShift(i, shift)); + Assert(check(widen(i) << shift) == CheckedLeftShift(i, shift)); +} +} // namespace + +FUZZ_TARGET(overflow) +{ + FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); + TestOverflow(fuzzed_data_provider); + TestOverflow(fuzzed_data_provider); + TestOverflow(fuzzed_data_provider); + TestOverflow(fuzzed_data_provider); + TestOverflow(fuzzed_data_provider); + TestOverflow(fuzzed_data_provider); +}