overflow.cpp raw

   1  // Copyright (c) 2025-present The Bitcoin Core developers
   2  // Distributed under the MIT software license, see the accompanying
   3  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
   4  
   5  #include <test/fuzz/FuzzedDataProvider.h>
   6  #include <test/fuzz/fuzz.h>
   7  #include <util/check.h>
   8  #include <util/overflow.h>
   9  
  10  #include <algorithm>
  11  #include <limits>
  12  #include <optional>
  13  
  14  namespace {
  15  //! Test overflow operations for type T using a wider type, W, to verify results.
  16  template <typename T, typename W>
  17  void TestOverflow(FuzzedDataProvider& fuzzed_data_provider)
  18  {
  19      constexpr auto min{std::numeric_limits<T>::min()};
  20      constexpr auto max{std::numeric_limits<T>::max()};
  21      // Range needs to be at least twice as big to allow two numbers to be added without overflowing.
  22      static_assert(min >= std::numeric_limits<W>::min() / 2);
  23      static_assert(max <= std::numeric_limits<W>::max() / 2);
  24  
  25      auto widen = [](T value) -> W { return value; };
  26      auto clamp = [](W value) -> W { return std::clamp<W>(value, min, max); };
  27      auto check = [](W value) -> std::optional<W> { if (value >= min && value <= max) return value; else return std::nullopt; };
  28  
  29      const T i = fuzzed_data_provider.ConsumeIntegral<T>();
  30      const T j = fuzzed_data_provider.ConsumeIntegral<T>();
  31      const unsigned shift = fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, std::numeric_limits<W>::digits - std::numeric_limits<T>::digits);
  32  
  33      Assert(clamp(widen(i) + widen(j)) == SaturatingAdd(i, j));
  34      Assert(check(widen(i) + widen(j)) == CheckedAdd(i, j));
  35  
  36      Assert(clamp(widen(i) << shift) == SaturatingLeftShift(i, shift));
  37      Assert(check(widen(i) << shift) == CheckedLeftShift(i, shift));
  38  }
  39  } // namespace
  40  
  41  FUZZ_TARGET(overflow)
  42  {
  43      FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
  44      TestOverflow<int8_t, int64_t>(fuzzed_data_provider);
  45      TestOverflow<int16_t, int64_t>(fuzzed_data_provider);
  46      TestOverflow<int32_t, int64_t>(fuzzed_data_provider);
  47      TestOverflow<uint8_t, uint64_t>(fuzzed_data_provider);
  48      TestOverflow<uint16_t, uint64_t>(fuzzed_data_provider);
  49      TestOverflow<uint32_t, uint64_t>(fuzzed_data_provider);
  50  }
  51