/root/bitcoin/src/test/fuzz/overflow.cpp
Line | Count | Source |
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 | 396 | { |
19 | 396 | constexpr auto min{std::numeric_limits<T>::min()}; |
20 | 396 | 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 | 396 | static_assert(min >= std::numeric_limits<W>::min() / 2); |
23 | 396 | static_assert(max <= std::numeric_limits<W>::max() / 2); |
24 | | |
25 | 2.37k | auto widen = [](T value) -> W { return value; };overflow.cpp:_ZZN12_GLOBAL__N_112TestOverflowIalEEvR18FuzzedDataProviderENKUlaE_clEa Line | Count | Source | 25 | 396 | auto widen = [](T value) -> W { return value; }; |
overflow.cpp:_ZZN12_GLOBAL__N_112TestOverflowIslEEvR18FuzzedDataProviderENKUlsE_clEs Line | Count | Source | 25 | 396 | auto widen = [](T value) -> W { return value; }; |
overflow.cpp:_ZZN12_GLOBAL__N_112TestOverflowIilEEvR18FuzzedDataProviderENKUliE_clEi Line | Count | Source | 25 | 396 | auto widen = [](T value) -> W { return value; }; |
overflow.cpp:_ZZN12_GLOBAL__N_112TestOverflowIhmEEvR18FuzzedDataProviderENKUlhE_clEh Line | Count | Source | 25 | 396 | auto widen = [](T value) -> W { return value; }; |
overflow.cpp:_ZZN12_GLOBAL__N_112TestOverflowItmEEvR18FuzzedDataProviderENKUltE_clEt Line | Count | Source | 25 | 396 | auto widen = [](T value) -> W { return value; }; |
overflow.cpp:_ZZN12_GLOBAL__N_112TestOverflowIjmEEvR18FuzzedDataProviderENKUljE_clEj Line | Count | Source | 25 | 396 | auto widen = [](T value) -> W { return value; }; |
|
26 | 792 | auto clamp = [](W value) -> W { return std::clamp<W>(value, min, max); };overflow.cpp:_ZZN12_GLOBAL__N_112TestOverflowIalEEvR18FuzzedDataProviderENKUllE_clEl Line | Count | Source | 26 | 132 | auto clamp = [](W value) -> W { return std::clamp<W>(value, min, max); }; |
overflow.cpp:_ZZN12_GLOBAL__N_112TestOverflowIslEEvR18FuzzedDataProviderENKUllE_clEl Line | Count | Source | 26 | 132 | auto clamp = [](W value) -> W { return std::clamp<W>(value, min, max); }; |
overflow.cpp:_ZZN12_GLOBAL__N_112TestOverflowIilEEvR18FuzzedDataProviderENKUllE_clEl Line | Count | Source | 26 | 132 | auto clamp = [](W value) -> W { return std::clamp<W>(value, min, max); }; |
overflow.cpp:_ZZN12_GLOBAL__N_112TestOverflowIhmEEvR18FuzzedDataProviderENKUlmE_clEm Line | Count | Source | 26 | 132 | auto clamp = [](W value) -> W { return std::clamp<W>(value, min, max); }; |
overflow.cpp:_ZZN12_GLOBAL__N_112TestOverflowItmEEvR18FuzzedDataProviderENKUlmE_clEm Line | Count | Source | 26 | 132 | auto clamp = [](W value) -> W { return std::clamp<W>(value, min, max); }; |
overflow.cpp:_ZZN12_GLOBAL__N_112TestOverflowIjmEEvR18FuzzedDataProviderENKUlmE_clEm Line | Count | Source | 26 | 132 | auto clamp = [](W value) -> W { return std::clamp<W>(value, min, max); }; |
|
27 | 792 | auto check = [](W value) -> std::optional<W> { if (value >= min && value <= max) return value; else return std::nullopt; };overflow.cpp:_ZZN12_GLOBAL__N_112TestOverflowIalEEvR18FuzzedDataProviderENKUllE0_clEl Line | Count | Source | 27 | 132 | auto check = [](W value) -> std::optional<W> { if (value >= min && value <= max) return value; else return std::nullopt; }; |
overflow.cpp:_ZZN12_GLOBAL__N_112TestOverflowIslEEvR18FuzzedDataProviderENKUllE0_clEl Line | Count | Source | 27 | 132 | auto check = [](W value) -> std::optional<W> { if (value >= min && value <= max) return value; else return std::nullopt; }; |
overflow.cpp:_ZZN12_GLOBAL__N_112TestOverflowIilEEvR18FuzzedDataProviderENKUllE0_clEl Line | Count | Source | 27 | 132 | auto check = [](W value) -> std::optional<W> { if (value >= min && value <= max) return value; else return std::nullopt; }; |
overflow.cpp:_ZZN12_GLOBAL__N_112TestOverflowIhmEEvR18FuzzedDataProviderENKUlmE0_clEm Line | Count | Source | 27 | 132 | auto check = [](W value) -> std::optional<W> { if (value >= min && value <= max) return value; else return std::nullopt; }; |
overflow.cpp:_ZZN12_GLOBAL__N_112TestOverflowItmEEvR18FuzzedDataProviderENKUlmE0_clEm Line | Count | Source | 27 | 132 | auto check = [](W value) -> std::optional<W> { if (value >= min && value <= max) return value; else return std::nullopt; }; |
overflow.cpp:_ZZN12_GLOBAL__N_112TestOverflowIjmEEvR18FuzzedDataProviderENKUlmE0_clEm Line | Count | Source | 27 | 132 | auto check = [](W value) -> std::optional<W> { if (value >= min && value <= max) return value; else return std::nullopt; }; |
|
28 | | |
29 | 396 | const T i = fuzzed_data_provider.ConsumeIntegral<T>(); |
30 | 396 | const T j = fuzzed_data_provider.ConsumeIntegral<T>(); |
31 | 396 | const unsigned shift = fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, std::numeric_limits<W>::digits - std::numeric_limits<T>::digits); |
32 | | |
33 | 396 | Assert(clamp(widen(i) + widen(j)) == SaturatingAdd(i, j)); |
34 | 396 | Assert(check(widen(i) + widen(j)) == CheckedAdd(i, j)); |
35 | | |
36 | 396 | Assert(clamp(widen(i) << shift) == SaturatingLeftShift(i, shift)); |
37 | 396 | Assert(check(widen(i) << shift) == CheckedLeftShift(i, shift)); |
38 | 396 | } overflow.cpp:_ZN12_GLOBAL__N_112TestOverflowIalEEvR18FuzzedDataProvider Line | Count | Source | 18 | 66 | { | 19 | 66 | constexpr auto min{std::numeric_limits<T>::min()}; | 20 | 66 | 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 | 66 | static_assert(min >= std::numeric_limits<W>::min() / 2); | 23 | 66 | static_assert(max <= std::numeric_limits<W>::max() / 2); | 24 | | | 25 | 66 | auto widen = [](T value) -> W { return value; }; | 26 | 66 | auto clamp = [](W value) -> W { return std::clamp<W>(value, min, max); }; | 27 | 66 | auto check = [](W value) -> std::optional<W> { if (value >= min && value <= max) return value; else return std::nullopt; }; | 28 | | | 29 | 66 | const T i = fuzzed_data_provider.ConsumeIntegral<T>(); | 30 | 66 | const T j = fuzzed_data_provider.ConsumeIntegral<T>(); | 31 | 66 | const unsigned shift = fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, std::numeric_limits<W>::digits - std::numeric_limits<T>::digits); | 32 | | | 33 | 66 | Assert(clamp(widen(i) + widen(j)) == SaturatingAdd(i, j)); | 34 | 66 | Assert(check(widen(i) + widen(j)) == CheckedAdd(i, j)); | 35 | | | 36 | 66 | Assert(clamp(widen(i) << shift) == SaturatingLeftShift(i, shift)); | 37 | 66 | Assert(check(widen(i) << shift) == CheckedLeftShift(i, shift)); | 38 | 66 | } |
overflow.cpp:_ZN12_GLOBAL__N_112TestOverflowIslEEvR18FuzzedDataProvider Line | Count | Source | 18 | 66 | { | 19 | 66 | constexpr auto min{std::numeric_limits<T>::min()}; | 20 | 66 | 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 | 66 | static_assert(min >= std::numeric_limits<W>::min() / 2); | 23 | 66 | static_assert(max <= std::numeric_limits<W>::max() / 2); | 24 | | | 25 | 66 | auto widen = [](T value) -> W { return value; }; | 26 | 66 | auto clamp = [](W value) -> W { return std::clamp<W>(value, min, max); }; | 27 | 66 | auto check = [](W value) -> std::optional<W> { if (value >= min && value <= max) return value; else return std::nullopt; }; | 28 | | | 29 | 66 | const T i = fuzzed_data_provider.ConsumeIntegral<T>(); | 30 | 66 | const T j = fuzzed_data_provider.ConsumeIntegral<T>(); | 31 | 66 | const unsigned shift = fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, std::numeric_limits<W>::digits - std::numeric_limits<T>::digits); | 32 | | | 33 | 66 | Assert(clamp(widen(i) + widen(j)) == SaturatingAdd(i, j)); | 34 | 66 | Assert(check(widen(i) + widen(j)) == CheckedAdd(i, j)); | 35 | | | 36 | 66 | Assert(clamp(widen(i) << shift) == SaturatingLeftShift(i, shift)); | 37 | 66 | Assert(check(widen(i) << shift) == CheckedLeftShift(i, shift)); | 38 | 66 | } |
overflow.cpp:_ZN12_GLOBAL__N_112TestOverflowIilEEvR18FuzzedDataProvider Line | Count | Source | 18 | 66 | { | 19 | 66 | constexpr auto min{std::numeric_limits<T>::min()}; | 20 | 66 | 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 | 66 | static_assert(min >= std::numeric_limits<W>::min() / 2); | 23 | 66 | static_assert(max <= std::numeric_limits<W>::max() / 2); | 24 | | | 25 | 66 | auto widen = [](T value) -> W { return value; }; | 26 | 66 | auto clamp = [](W value) -> W { return std::clamp<W>(value, min, max); }; | 27 | 66 | auto check = [](W value) -> std::optional<W> { if (value >= min && value <= max) return value; else return std::nullopt; }; | 28 | | | 29 | 66 | const T i = fuzzed_data_provider.ConsumeIntegral<T>(); | 30 | 66 | const T j = fuzzed_data_provider.ConsumeIntegral<T>(); | 31 | 66 | const unsigned shift = fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, std::numeric_limits<W>::digits - std::numeric_limits<T>::digits); | 32 | | | 33 | 66 | Assert(clamp(widen(i) + widen(j)) == SaturatingAdd(i, j)); | 34 | 66 | Assert(check(widen(i) + widen(j)) == CheckedAdd(i, j)); | 35 | | | 36 | 66 | Assert(clamp(widen(i) << shift) == SaturatingLeftShift(i, shift)); | 37 | 66 | Assert(check(widen(i) << shift) == CheckedLeftShift(i, shift)); | 38 | 66 | } |
overflow.cpp:_ZN12_GLOBAL__N_112TestOverflowIhmEEvR18FuzzedDataProvider Line | Count | Source | 18 | 66 | { | 19 | 66 | constexpr auto min{std::numeric_limits<T>::min()}; | 20 | 66 | 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 | 66 | static_assert(min >= std::numeric_limits<W>::min() / 2); | 23 | 66 | static_assert(max <= std::numeric_limits<W>::max() / 2); | 24 | | | 25 | 66 | auto widen = [](T value) -> W { return value; }; | 26 | 66 | auto clamp = [](W value) -> W { return std::clamp<W>(value, min, max); }; | 27 | 66 | auto check = [](W value) -> std::optional<W> { if (value >= min && value <= max) return value; else return std::nullopt; }; | 28 | | | 29 | 66 | const T i = fuzzed_data_provider.ConsumeIntegral<T>(); | 30 | 66 | const T j = fuzzed_data_provider.ConsumeIntegral<T>(); | 31 | 66 | const unsigned shift = fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, std::numeric_limits<W>::digits - std::numeric_limits<T>::digits); | 32 | | | 33 | 66 | Assert(clamp(widen(i) + widen(j)) == SaturatingAdd(i, j)); | 34 | 66 | Assert(check(widen(i) + widen(j)) == CheckedAdd(i, j)); | 35 | | | 36 | 66 | Assert(clamp(widen(i) << shift) == SaturatingLeftShift(i, shift)); | 37 | 66 | Assert(check(widen(i) << shift) == CheckedLeftShift(i, shift)); | 38 | 66 | } |
overflow.cpp:_ZN12_GLOBAL__N_112TestOverflowItmEEvR18FuzzedDataProvider Line | Count | Source | 18 | 66 | { | 19 | 66 | constexpr auto min{std::numeric_limits<T>::min()}; | 20 | 66 | 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 | 66 | static_assert(min >= std::numeric_limits<W>::min() / 2); | 23 | 66 | static_assert(max <= std::numeric_limits<W>::max() / 2); | 24 | | | 25 | 66 | auto widen = [](T value) -> W { return value; }; | 26 | 66 | auto clamp = [](W value) -> W { return std::clamp<W>(value, min, max); }; | 27 | 66 | auto check = [](W value) -> std::optional<W> { if (value >= min && value <= max) return value; else return std::nullopt; }; | 28 | | | 29 | 66 | const T i = fuzzed_data_provider.ConsumeIntegral<T>(); | 30 | 66 | const T j = fuzzed_data_provider.ConsumeIntegral<T>(); | 31 | 66 | const unsigned shift = fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, std::numeric_limits<W>::digits - std::numeric_limits<T>::digits); | 32 | | | 33 | 66 | Assert(clamp(widen(i) + widen(j)) == SaturatingAdd(i, j)); | 34 | 66 | Assert(check(widen(i) + widen(j)) == CheckedAdd(i, j)); | 35 | | | 36 | 66 | Assert(clamp(widen(i) << shift) == SaturatingLeftShift(i, shift)); | 37 | 66 | Assert(check(widen(i) << shift) == CheckedLeftShift(i, shift)); | 38 | 66 | } |
overflow.cpp:_ZN12_GLOBAL__N_112TestOverflowIjmEEvR18FuzzedDataProvider Line | Count | Source | 18 | 66 | { | 19 | 66 | constexpr auto min{std::numeric_limits<T>::min()}; | 20 | 66 | 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 | 66 | static_assert(min >= std::numeric_limits<W>::min() / 2); | 23 | 66 | static_assert(max <= std::numeric_limits<W>::max() / 2); | 24 | | | 25 | 66 | auto widen = [](T value) -> W { return value; }; | 26 | 66 | auto clamp = [](W value) -> W { return std::clamp<W>(value, min, max); }; | 27 | 66 | auto check = [](W value) -> std::optional<W> { if (value >= min && value <= max) return value; else return std::nullopt; }; | 28 | | | 29 | 66 | const T i = fuzzed_data_provider.ConsumeIntegral<T>(); | 30 | 66 | const T j = fuzzed_data_provider.ConsumeIntegral<T>(); | 31 | 66 | const unsigned shift = fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, std::numeric_limits<W>::digits - std::numeric_limits<T>::digits); | 32 | | | 33 | 66 | Assert(clamp(widen(i) + widen(j)) == SaturatingAdd(i, j)); | 34 | 66 | Assert(check(widen(i) + widen(j)) == CheckedAdd(i, j)); | 35 | | | 36 | 66 | Assert(clamp(widen(i) << shift) == SaturatingLeftShift(i, shift)); | 37 | 66 | Assert(check(widen(i) << shift) == CheckedLeftShift(i, shift)); | 38 | 66 | } |
|
39 | | } // namespace |
40 | | |
41 | | FUZZ_TARGET(overflow) |
42 | 66 | { |
43 | 66 | FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); |
44 | 66 | TestOverflow<int8_t, int64_t>(fuzzed_data_provider); |
45 | 66 | TestOverflow<int16_t, int64_t>(fuzzed_data_provider); |
46 | 66 | TestOverflow<int32_t, int64_t>(fuzzed_data_provider); |
47 | 66 | TestOverflow<uint8_t, uint64_t>(fuzzed_data_provider); |
48 | 66 | TestOverflow<uint16_t, uint64_t>(fuzzed_data_provider); |
49 | 66 | TestOverflow<uint32_t, uint64_t>(fuzzed_data_provider); |
50 | 66 | } |