Coverage Report

Created: 2025-06-10 13:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/bitcoin/src/util/overflow.h
Line
Count
Source
1
// Copyright (c) 2021-2022 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
#ifndef BITCOIN_UTIL_OVERFLOW_H
6
#define BITCOIN_UTIL_OVERFLOW_H
7
8
#include <climits>
9
#include <concepts>
10
#include <limits>
11
#include <optional>
12
#include <type_traits>
13
14
template <class T>
15
[[nodiscard]] bool AdditionOverflow(const T i, const T j) noexcept
16
98.6M
{
17
98.6M
    static_assert(std::is_integral_v<T>, "Integral required.");
18
98.6M
    if constexpr (std::numeric_limits<T>::is_signed) {
19
0
        return (i > 0 && j > std::numeric_limits<T>::max() - i) ||
  Branch (19:17): [True: 0, False: 0]
  Branch (19:26): [True: 0, False: 0]
20
0
               (i < 0 && j < std::numeric_limits<T>::min() - i);
  Branch (20:17): [True: 0, False: 0]
  Branch (20:26): [True: 0, False: 0]
21
0
    }
22
0
    return std::numeric_limits<T>::max() - i < j;
23
98.6M
}
bool AdditionOverflow<unsigned long>(unsigned long, unsigned long)
Line
Count
Source
16
98.6M
{
17
98.6M
    static_assert(std::is_integral_v<T>, "Integral required.");
18
    if constexpr (std::numeric_limits<T>::is_signed) {
19
        return (i > 0 && j > std::numeric_limits<T>::max() - i) ||
20
               (i < 0 && j < std::numeric_limits<T>::min() - i);
21
    }
22
98.6M
    return std::numeric_limits<T>::max() - i < j;
23
98.6M
}
Unexecuted instantiation: bool AdditionOverflow<long>(long, long)
24
25
template <class T>
26
[[nodiscard]] std::optional<T> CheckedAdd(const T i, const T j) noexcept
27
98.6M
{
28
98.6M
    if (AdditionOverflow(i, j)) {
  Branch (28:9): [True: 0, False: 98.6M]
  Branch (28:9): [True: 0, False: 0]
29
0
        return std::nullopt;
30
0
    }
31
98.6M
    return i + j;
32
98.6M
}
std::optional<unsigned long> CheckedAdd<unsigned long>(unsigned long, unsigned long)
Line
Count
Source
27
98.6M
{
28
98.6M
    if (AdditionOverflow(i, j)) {
  Branch (28:9): [True: 0, False: 98.6M]
29
0
        return std::nullopt;
30
0
    }
31
98.6M
    return i + j;
32
98.6M
}
Unexecuted instantiation: std::optional<long> CheckedAdd<long>(long, long)
33
34
template <class T>
35
[[nodiscard]] T SaturatingAdd(const T i, const T j) noexcept
36
499k
{
37
499k
    if constexpr (std::numeric_limits<T>::is_signed) {
38
499k
        if (i > 0 && j > std::numeric_limits<T>::max() - i) {
  Branch (38:13): [True: 491k, False: 8.22k]
  Branch (38:22): [True: 0, False: 491k]
39
0
            return std::numeric_limits<T>::max();
40
0
        }
41
499k
        if (i < 0 && j < std::numeric_limits<T>::min() - i) {
  Branch (41:13): [True: 0, False: 499k]
  Branch (41:22): [True: 0, False: 0]
42
0
            return std::numeric_limits<T>::min();
43
0
        }
44
    } else {
45
        if (std::numeric_limits<T>::max() - i < j) {
46
            return std::numeric_limits<T>::max();
47
        }
48
    }
49
499k
    return i + j;
50
499k
}
51
52
/**
53
 * @brief Left bit shift with overflow checking.
54
 * @param input The input value to be left shifted.
55
 * @param shift The number of bits to left shift.
56
 * @return (input * 2^shift) or nullopt if it would not fit in the return type.
57
 */
58
template <std::integral T>
59
constexpr std::optional<T> CheckedLeftShift(T input, unsigned shift) noexcept
60
11.0k
{
61
11.0k
    if (shift == 0 || input == 0) return input;
  Branch (61:9): [True: 0, False: 11.0k]
  Branch (61:23): [True: 0, False: 11.0k]
62
    // Avoid undefined c++ behaviour if shift is >= number of bits in T.
63
11.0k
    if (shift >= sizeof(T) * CHAR_BIT) return std::nullopt;
  Branch (63:9): [True: 0, False: 11.0k]
64
    // If input << shift is too big to fit in T, return nullopt.
65
11.0k
    if (input > (std::numeric_limits<T>::max() >> shift)) return std::nullopt;
  Branch (65:9): [True: 0, False: 11.0k]
66
11.0k
    if (input < (std::numeric_limits<T>::min() >> shift)) return std::nullopt;
  Branch (66:9): [True: 0, False: 11.0k]
67
11.0k
    return input << shift;
68
11.0k
}
Unexecuted instantiation: _Z16CheckedLeftShiftITkSt8integralyESt8optionalIT_ES1_j
_Z16CheckedLeftShiftITkSt8integralmESt8optionalIT_ES1_j
Line
Count
Source
60
11.0k
{
61
11.0k
    if (shift == 0 || input == 0) return input;
  Branch (61:9): [True: 0, False: 11.0k]
  Branch (61:23): [True: 0, False: 11.0k]
62
    // Avoid undefined c++ behaviour if shift is >= number of bits in T.
63
11.0k
    if (shift >= sizeof(T) * CHAR_BIT) return std::nullopt;
  Branch (63:9): [True: 0, False: 11.0k]
64
    // If input << shift is too big to fit in T, return nullopt.
65
11.0k
    if (input > (std::numeric_limits<T>::max() >> shift)) return std::nullopt;
  Branch (65:9): [True: 0, False: 11.0k]
66
11.0k
    if (input < (std::numeric_limits<T>::min() >> shift)) return std::nullopt;
  Branch (66:9): [True: 0, False: 11.0k]
67
11.0k
    return input << shift;
68
11.0k
}
69
70
/**
71
 * @brief Left bit shift with safe minimum and maximum values.
72
 * @param input The input value to be left shifted.
73
 * @param shift The number of bits to left shift.
74
 * @return (input * 2^shift) clamped to fit between the lowest and highest
75
 *         representable values of the type T.
76
 */
77
template <std::integral T>
78
constexpr T SaturatingLeftShift(T input, unsigned shift) noexcept
79
11.0k
{
80
11.0k
    if (auto result{CheckedLeftShift(input, shift)}) return *result;
  Branch (80:14): [True: 11.0k, False: 0]
81
    // If input << shift is too big to fit in T, return biggest positive or negative
82
    // number that fits.
83
0
    return input < 0 ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max();
  Branch (83:12): [True: 0, False: 0]
84
11.0k
}
85
86
#endif // BITCOIN_UTIL_OVERFLOW_H