Coverage Report

Created: 2026-04-29 19:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/tmp/bitcoin/src/util/overflow.h
Line
Count
Source
1
// Copyright (c) 2021-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
#ifndef BITCOIN_UTIL_OVERFLOW_H
6
#define BITCOIN_UTIL_OVERFLOW_H
7
8
#include <util/check.h>
9
10
#include <climits>
11
#include <concepts>
12
#include <limits>
13
#include <optional>
14
#include <type_traits>
15
16
template <class T>
17
[[nodiscard]] bool AdditionOverflow(const T i, const T j) noexcept
18
12.3M
{
19
12.3M
    static_assert(std::is_integral_v<T>, "Integral required.");
20
12.3M
    if constexpr (std::numeric_limits<T>::is_signed) {
21
17.9k
        return (i > 0 && j > std::numeric_limits<T>::max() - i) ||
22
17.9k
               (i < 0 && j < std::numeric_limits<T>::min() - i);
23
17.9k
    }
24
0
    return std::numeric_limits<T>::max() - i < j;
25
12.3M
}
bool AdditionOverflow<unsigned long>(unsigned long, unsigned long)
Line
Count
Source
18
12.3M
{
19
12.3M
    static_assert(std::is_integral_v<T>, "Integral required.");
20
    if constexpr (std::numeric_limits<T>::is_signed) {
21
        return (i > 0 && j > std::numeric_limits<T>::max() - i) ||
22
               (i < 0 && j < std::numeric_limits<T>::min() - i);
23
    }
24
12.3M
    return std::numeric_limits<T>::max() - i < j;
25
12.3M
}
bool AdditionOverflow<unsigned int>(unsigned int, unsigned int)
Line
Count
Source
18
12
{
19
12
    static_assert(std::is_integral_v<T>, "Integral required.");
20
    if constexpr (std::numeric_limits<T>::is_signed) {
21
        return (i > 0 && j > std::numeric_limits<T>::max() - i) ||
22
               (i < 0 && j < std::numeric_limits<T>::min() - i);
23
    }
24
12
    return std::numeric_limits<T>::max() - i < j;
25
12
}
bool AdditionOverflow<int>(int, int)
Line
Count
Source
18
24
{
19
24
    static_assert(std::is_integral_v<T>, "Integral required.");
20
24
    if constexpr (std::numeric_limits<T>::is_signed) {
21
24
        return (i > 0 && j > std::numeric_limits<T>::max() - i) ||
22
24
               (i < 0 && j < std::numeric_limits<T>::min() - i);
23
24
    }
24
0
    return std::numeric_limits<T>::max() - i < j;
25
24
}
bool AdditionOverflow<long>(long, long)
Line
Count
Source
18
17.9k
{
19
17.9k
    static_assert(std::is_integral_v<T>, "Integral required.");
20
17.9k
    if constexpr (std::numeric_limits<T>::is_signed) {
21
17.9k
        return (i > 0 && j > std::numeric_limits<T>::max() - i) ||
22
17.9k
               (i < 0 && j < std::numeric_limits<T>::min() - i);
23
17.9k
    }
24
0
    return std::numeric_limits<T>::max() - i < j;
25
17.9k
}
26
27
template <class T>
28
[[nodiscard]] std::optional<T> CheckedAdd(const T i, const T j) noexcept
29
12.3M
{
30
12.3M
    if (AdditionOverflow(i, j)) {
31
12
        return std::nullopt;
32
12
    }
33
12.3M
    return i + j;
34
12.3M
}
std::optional<unsigned long> CheckedAdd<unsigned long>(unsigned long, unsigned long)
Line
Count
Source
29
12.3M
{
30
12.3M
    if (AdditionOverflow(i, j)) {
31
0
        return std::nullopt;
32
0
    }
33
12.3M
    return i + j;
34
12.3M
}
std::optional<unsigned int> CheckedAdd<unsigned int>(unsigned int, unsigned int)
Line
Count
Source
29
12
{
30
12
    if (AdditionOverflow(i, j)) {
31
4
        return std::nullopt;
32
4
    }
33
8
    return i + j;
34
12
}
std::optional<int> CheckedAdd<int>(int, int)
Line
Count
Source
29
24
{
30
24
    if (AdditionOverflow(i, j)) {
31
8
        return std::nullopt;
32
8
    }
33
16
    return i + j;
34
24
}
std::optional<long> CheckedAdd<long>(long, long)
Line
Count
Source
29
17.9k
{
30
17.9k
    if (AdditionOverflow(i, j)) {
31
0
        return std::nullopt;
32
0
    }
33
17.9k
    return i + j;
34
17.9k
}
35
36
template <std::unsigned_integral T, std::unsigned_integral U>
37
[[nodiscard]] constexpr bool TrySub(T& i, const U j) noexcept
38
28.9M
{
39
28.9M
    if (i < T{j}) return false;
40
28.9M
    i -= T{j};
41
28.9M
    return true;
42
28.9M
}
bool TrySub<unsigned long, bool>(unsigned long&, bool)
Line
Count
Source
38
14.8M
{
39
14.8M
    if (i < T{j}) return false;
40
14.8M
    i -= T{j};
41
14.8M
    return true;
42
14.8M
}
bool TrySub<unsigned long, unsigned long>(unsigned long&, unsigned long)
Line
Count
Source
38
14.0M
{
39
14.0M
    if (i < T{j}) return false;
40
14.0M
    i -= T{j};
41
14.0M
    return true;
42
14.0M
}
43
44
template <class T>
45
[[nodiscard]] T SaturatingAdd(const T i, const T j) noexcept
46
1.14k
{
47
1.14k
    if constexpr (std::numeric_limits<T>::is_signed) {
48
1.09k
        if (i > 0 && j > std::numeric_limits<T>::max() - i) {
49
4
            return std::numeric_limits<T>::max();
50
4
        }
51
1.09k
        if (i < 0 && j < std::numeric_limits<T>::min() - i) {
52
4
            return std::numeric_limits<T>::min();
53
4
        }
54
1.09k
    } else {
55
44
        if (std::numeric_limits<T>::max() - i < j) {
56
6
            return std::numeric_limits<T>::max();
57
6
        }
58
44
    }
59
1.12k
    return i + j;
60
1.14k
}
long SaturatingAdd<long>(long, long)
Line
Count
Source
46
1.07k
{
47
1.07k
    if constexpr (std::numeric_limits<T>::is_signed) {
48
1.07k
        if (i > 0 && j > std::numeric_limits<T>::max() - i) {
49
0
            return std::numeric_limits<T>::max();
50
0
        }
51
1.07k
        if (i < 0 && j < std::numeric_limits<T>::min() - i) {
52
0
            return std::numeric_limits<T>::min();
53
0
        }
54
    } else {
55
        if (std::numeric_limits<T>::max() - i < j) {
56
            return std::numeric_limits<T>::max();
57
        }
58
    }
59
1.07k
    return i + j;
60
1.07k
}
unsigned int SaturatingAdd<unsigned int>(unsigned int, unsigned int)
Line
Count
Source
46
12
{
47
    if constexpr (std::numeric_limits<T>::is_signed) {
48
        if (i > 0 && j > std::numeric_limits<T>::max() - i) {
49
            return std::numeric_limits<T>::max();
50
        }
51
        if (i < 0 && j < std::numeric_limits<T>::min() - i) {
52
            return std::numeric_limits<T>::min();
53
        }
54
12
    } else {
55
12
        if (std::numeric_limits<T>::max() - i < j) {
56
4
            return std::numeric_limits<T>::max();
57
4
        }
58
12
    }
59
8
    return i + j;
60
12
}
int SaturatingAdd<int>(int, int)
Line
Count
Source
46
24
{
47
24
    if constexpr (std::numeric_limits<T>::is_signed) {
48
24
        if (i > 0 && j > std::numeric_limits<T>::max() - i) {
49
4
            return std::numeric_limits<T>::max();
50
4
        }
51
20
        if (i < 0 && j < std::numeric_limits<T>::min() - i) {
52
4
            return std::numeric_limits<T>::min();
53
4
        }
54
    } else {
55
        if (std::numeric_limits<T>::max() - i < j) {
56
            return std::numeric_limits<T>::max();
57
        }
58
    }
59
16
    return i + j;
60
24
}
unsigned long SaturatingAdd<unsigned long>(unsigned long, unsigned long)
Line
Count
Source
46
32
{
47
    if constexpr (std::numeric_limits<T>::is_signed) {
48
        if (i > 0 && j > std::numeric_limits<T>::max() - i) {
49
            return std::numeric_limits<T>::max();
50
        }
51
        if (i < 0 && j < std::numeric_limits<T>::min() - i) {
52
            return std::numeric_limits<T>::min();
53
        }
54
32
    } else {
55
32
        if (std::numeric_limits<T>::max() - i < j) {
56
2
            return std::numeric_limits<T>::max();
57
2
        }
58
32
    }
59
30
    return i + j;
60
32
}
61
62
/**
63
 * @brief Integer ceiling division (for unsigned values).
64
 *
65
 * Computes the smallest integer q such that q * divisor >= dividend.
66
 * Both dividend and divisor must be unsigned, and divisor must be non-zero.
67
 *
68
 * The implementation avoids overflow that can occur with `(dividend + divisor - 1) / divisor`.
69
 */
70
template <std::unsigned_integral Dividend, std::unsigned_integral Divisor>
71
[[nodiscard]] constexpr auto CeilDiv(const Dividend dividend, const Divisor divisor)
72
136M
{
73
136M
    assert(divisor > 0);
74
136M
    return dividend / divisor + (dividend % divisor != 0);
75
136M
}
auto CeilDiv<unsigned long, unsigned int>(unsigned long, unsigned int)
Line
Count
Source
72
1.86M
{
73
1.86M
    assert(divisor > 0);
74
1.86M
    return dividend / divisor + (dividend % divisor != 0);
75
1.86M
}
auto CeilDiv<unsigned long, unsigned long>(unsigned long, unsigned long)
Line
Count
Source
72
134M
{
73
134M
    assert(divisor > 0);
74
134M
    return dividend / divisor + (dividend % divisor != 0);
75
134M
}
auto CeilDiv<unsigned int, unsigned int>(unsigned int, unsigned int)
Line
Count
Source
72
271k
{
73
271k
    assert(divisor > 0);
74
271k
    return dividend / divisor + (dividend % divisor != 0);
75
271k
}
auto CeilDiv<unsigned int, unsigned long>(unsigned int, unsigned long)
Line
Count
Source
72
214k
{
73
214k
    assert(divisor > 0);
74
214k
    return dividend / divisor + (dividend % divisor != 0);
75
214k
}
76
77
/**
78
 * @brief Left bit shift with overflow checking.
79
 * @param input The input value to be left shifted.
80
 * @param shift The number of bits to left shift.
81
 * @return (input * 2^shift) or nullopt if it would not fit in the return type.
82
 */
83
template <std::integral T>
84
constexpr std::optional<T> CheckedLeftShift(T input, unsigned shift) noexcept
85
128
{
86
128
    if (shift == 0 || input == 0) return input;
87
    // Avoid undefined c++ behaviour if shift is >= number of bits in T.
88
108
    if (shift >= sizeof(T) * CHAR_BIT) return std::nullopt;
89
    // If input << shift is too big to fit in T, return nullopt.
90
88
    if (input > (std::numeric_limits<T>::max() >> shift)) return std::nullopt;
91
64
    if (input < (std::numeric_limits<T>::min() >> shift)) return std::nullopt;
92
56
    return input << shift;
93
64
}
Unexecuted instantiation: std::optional<unsigned long long> CheckedLeftShift<unsigned long long>(unsigned long long, unsigned int)
std::optional<unsigned char> CheckedLeftShift<unsigned char>(unsigned char, unsigned int)
Line
Count
Source
85
20
{
86
20
    if (shift == 0 || input == 0) return input;
87
    // Avoid undefined c++ behaviour if shift is >= number of bits in T.
88
16
    if (shift >= sizeof(T) * CHAR_BIT) return std::nullopt;
89
    // If input << shift is too big to fit in T, return nullopt.
90
12
    if (input > (std::numeric_limits<T>::max() >> shift)) return std::nullopt;
91
8
    if (input < (std::numeric_limits<T>::min() >> shift)) return std::nullopt;
92
8
    return input << shift;
93
8
}
std::optional<signed char> CheckedLeftShift<signed char>(signed char, unsigned int)
Line
Count
Source
85
34
{
86
34
    if (shift == 0 || input == 0) return input;
87
    // Avoid undefined c++ behaviour if shift is >= number of bits in T.
88
30
    if (shift >= sizeof(T) * CHAR_BIT) return std::nullopt;
89
    // If input << shift is too big to fit in T, return nullopt.
90
26
    if (input > (std::numeric_limits<T>::max() >> shift)) return std::nullopt;
91
20
    if (input < (std::numeric_limits<T>::min() >> shift)) return std::nullopt;
92
16
    return input << shift;
93
20
}
std::optional<unsigned long> CheckedLeftShift<unsigned long>(unsigned long, unsigned int)
Line
Count
Source
85
40
{
86
40
    if (shift == 0 || input == 0) return input;
87
    // Avoid undefined c++ behaviour if shift is >= number of bits in T.
88
32
    if (shift >= sizeof(T) * CHAR_BIT) return std::nullopt;
89
    // If input << shift is too big to fit in T, return nullopt.
90
24
    if (input > (std::numeric_limits<T>::max() >> shift)) return std::nullopt;
91
16
    if (input < (std::numeric_limits<T>::min() >> shift)) return std::nullopt;
92
16
    return input << shift;
93
16
}
std::optional<long> CheckedLeftShift<long>(long, unsigned int)
Line
Count
Source
85
34
{
86
34
    if (shift == 0 || input == 0) return input;
87
    // Avoid undefined c++ behaviour if shift is >= number of bits in T.
88
30
    if (shift >= sizeof(T) * CHAR_BIT) return std::nullopt;
89
    // If input << shift is too big to fit in T, return nullopt.
90
26
    if (input > (std::numeric_limits<T>::max() >> shift)) return std::nullopt;
91
20
    if (input < (std::numeric_limits<T>::min() >> shift)) return std::nullopt;
92
16
    return input << shift;
93
20
}
94
95
/**
96
 * @brief Left bit shift with safe minimum and maximum values.
97
 * @param input The input value to be left shifted.
98
 * @param shift The number of bits to left shift.
99
 * @return (input * 2^shift) clamped to fit between the lowest and highest
100
 *         representable values of the type T.
101
 */
102
template <std::integral T>
103
constexpr T SaturatingLeftShift(T input, unsigned shift) noexcept
104
64
{
105
64
    if (auto result{CheckedLeftShift(input, shift)}) return *result;
106
    // If input << shift is too big to fit in T, return biggest positive or negative
107
    // number that fits.
108
26
    return input < 0 ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max();
109
64
}
unsigned char SaturatingLeftShift<unsigned char>(unsigned char, unsigned int)
Line
Count
Source
104
10
{
105
10
    if (auto result{CheckedLeftShift(input, shift)}) return *result;
106
    // If input << shift is too big to fit in T, return biggest positive or negative
107
    // number that fits.
108
4
    return input < 0 ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max();
109
10
}
signed char SaturatingLeftShift<signed char>(signed char, unsigned int)
Line
Count
Source
104
17
{
105
17
    if (auto result{CheckedLeftShift(input, shift)}) return *result;
106
    // If input << shift is too big to fit in T, return biggest positive or negative
107
    // number that fits.
108
7
    return input < 0 ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max();
109
17
}
unsigned long SaturatingLeftShift<unsigned long>(unsigned long, unsigned int)
Line
Count
Source
104
20
{
105
20
    if (auto result{CheckedLeftShift(input, shift)}) return *result;
106
    // If input << shift is too big to fit in T, return biggest positive or negative
107
    // number that fits.
108
8
    return input < 0 ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max();
109
20
}
long SaturatingLeftShift<long>(long, unsigned int)
Line
Count
Source
104
17
{
105
17
    if (auto result{CheckedLeftShift(input, shift)}) return *result;
106
    // If input << shift is too big to fit in T, return biggest positive or negative
107
    // number that fits.
108
7
    return input < 0 ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max();
109
17
}
110
111
#endif // BITCOIN_UTIL_OVERFLOW_H