Branch data Line data Source code
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 : 0 : void TestOverflow(FuzzedDataProvider& fuzzed_data_provider)
18 : : {
19 : 0 : constexpr auto min{std::numeric_limits<T>::min()};
20 : 0 : 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 : 0 : auto widen = [](T value) -> W { return value; };
26 : 0 : auto clamp = [](W value) -> W { return std::clamp<W>(value, min, max); };
27 : 0 : auto check = [](W value) -> std::optional<W> { if (value >= min && value <= max) return value; else return std::nullopt; };
28 : :
29 : 0 : const T i = fuzzed_data_provider.ConsumeIntegral<T>();
30 : 0 : const T j = fuzzed_data_provider.ConsumeIntegral<T>();
31 : 0 : const unsigned shift = fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, std::numeric_limits<W>::digits - std::numeric_limits<T>::digits);
32 : :
33 [ # # ]: 0 : Assert(clamp(widen(i) + widen(j)) == SaturatingAdd(i, j));
34 [ # # # # ]: 0 : Assert(check(widen(i) + widen(j)) == CheckedAdd(i, j));
35 : :
36 [ # # ]: 0 : Assert(clamp(widen(i) << shift) == SaturatingLeftShift(i, shift));
37 [ # # # # ]: 0 : Assert(check(widen(i) << shift) == CheckedLeftShift(i, shift));
38 : 0 : }
39 : : } // namespace
40 : :
41 [ + - ]: 414 : FUZZ_TARGET(overflow)
42 : : {
43 : 0 : FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
44 : 0 : TestOverflow<int8_t, int64_t>(fuzzed_data_provider);
45 : 0 : TestOverflow<int16_t, int64_t>(fuzzed_data_provider);
46 : 0 : TestOverflow<int32_t, int64_t>(fuzzed_data_provider);
47 : 0 : TestOverflow<uint8_t, uint64_t>(fuzzed_data_provider);
48 : 0 : TestOverflow<uint16_t, uint64_t>(fuzzed_data_provider);
49 : 0 : TestOverflow<uint32_t, uint64_t>(fuzzed_data_provider);
50 : 0 : }
|