Skip to content

Commit fac0188

Browse files
author
MarcoFalke
committed
Move AdditionOverflow to util, Add CheckedAdd with unit tests
1 parent fa526d8 commit fac0188

File tree

9 files changed

+70
-11
lines changed

9 files changed

+70
-11
lines changed

src/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ BITCOIN_CORE_H = \
248248
util/macros.h \
249249
util/message.h \
250250
util/moneystr.h \
251+
util/overflow.h \
251252
util/overloaded.h \
252253
util/rbf.h \
253254
util/readwritefile.h \

src/test/fuzz/addition_overflow.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <test/fuzz/FuzzedDataProvider.h>
66
#include <test/fuzz/fuzz.h>
77
#include <test/fuzz/util.h>
8+
#include <util/overflow.h>
89

910
#include <cstdint>
1011
#include <string>

src/test/fuzz/crypto_chacha20_poly1305_aead.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <test/fuzz/FuzzedDataProvider.h>
88
#include <test/fuzz/fuzz.h>
99
#include <test/fuzz/util.h>
10+
#include <util/overflow.h>
1011

1112
#include <cassert>
1213
#include <cstdint>

src/test/fuzz/integer.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <univalue.h>
2727
#include <util/check.h>
2828
#include <util/moneystr.h>
29+
#include <util/overflow.h>
2930
#include <util/strencodings.h>
3031
#include <util/string.h>
3132
#include <util/system.h>

src/test/fuzz/pow.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <test/fuzz/FuzzedDataProvider.h>
1010
#include <test/fuzz/fuzz.h>
1111
#include <test/fuzz/util.h>
12+
#include <util/overflow.h>
1213

1314
#include <cstdint>
1415
#include <optional>

src/test/fuzz/util.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <pubkey.h>
99
#include <test/fuzz/util.h>
1010
#include <test/util/script.h>
11+
#include <util/overflow.h>
1112
#include <util/rbf.h>
1213
#include <util/time.h>
1314
#include <version.h>

src/test/fuzz/util.h

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -193,17 +193,6 @@ template <typename T>
193193
}
194194
}
195195

196-
template <class T>
197-
[[nodiscard]] bool AdditionOverflow(const T i, const T j) noexcept
198-
{
199-
static_assert(std::is_integral<T>::value, "Integral required.");
200-
if (std::numeric_limits<T>::is_signed) {
201-
return (i > 0 && j > std::numeric_limits<T>::max() - i) ||
202-
(i < 0 && j < std::numeric_limits<T>::min() - i);
203-
}
204-
return std::numeric_limits<T>::max() - i < j;
205-
}
206-
207196
[[nodiscard]] bool ContainsSpentInput(const CTransaction& tx, const CCoinsViewCache& inputs) noexcept;
208197

209198
/**

src/test/util_tests.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <util/getuniquepath.h>
1616
#include <util/message.h> // For MessageSign(), MessageVerify(), MESSAGE_MAGIC
1717
#include <util/moneystr.h>
18+
#include <util/overflow.h>
1819
#include <util/spanparsing.h>
1920
#include <util/strencodings.h>
2021
#include <util/string.h>
@@ -1463,6 +1464,38 @@ BOOST_AUTO_TEST_CASE(test_IsDigit)
14631464
BOOST_CHECK_EQUAL(IsDigit(9), false);
14641465
}
14651466

1467+
/* Check for overflow */
1468+
template <typename T>
1469+
static void TestAddMatrixOverflow()
1470+
{
1471+
constexpr T MAXI{std::numeric_limits<T>::max()};
1472+
BOOST_CHECK(!CheckedAdd(T{1}, MAXI));
1473+
BOOST_CHECK(!CheckedAdd(MAXI, MAXI));
1474+
BOOST_CHECK_EQUAL(0, CheckedAdd(T{0}, T{0}).value());
1475+
BOOST_CHECK_EQUAL(MAXI, CheckedAdd(T{0}, MAXI).value());
1476+
BOOST_CHECK_EQUAL(MAXI, CheckedAdd(T{1}, MAXI - 1).value());
1477+
}
1478+
1479+
/* Check for overflow or underflow */
1480+
template <typename T>
1481+
static void TestAddMatrix()
1482+
{
1483+
TestAddMatrixOverflow<T>();
1484+
constexpr T MINI{std::numeric_limits<T>::min()};
1485+
constexpr T MAXI{std::numeric_limits<T>::max()};
1486+
BOOST_CHECK(!CheckedAdd(T{-1}, MINI));
1487+
BOOST_CHECK(!CheckedAdd(MINI, MINI));
1488+
BOOST_CHECK_EQUAL(MINI, CheckedAdd(T{0}, MINI).value());
1489+
BOOST_CHECK_EQUAL(MINI, CheckedAdd(T{-1}, MINI + 1).value());
1490+
BOOST_CHECK_EQUAL(-1, CheckedAdd(MINI, MAXI).value());
1491+
}
1492+
1493+
BOOST_AUTO_TEST_CASE(util_overflow)
1494+
{
1495+
TestAddMatrixOverflow<unsigned>();
1496+
TestAddMatrix<signed>();
1497+
}
1498+
14661499
BOOST_AUTO_TEST_CASE(test_ParseInt32)
14671500
{
14681501
int32_t n;

src/util/overflow.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (c) 2021 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 <limits>
9+
#include <type_traits>
10+
11+
template <class T>
12+
[[nodiscard]] bool AdditionOverflow(const T i, const T j) noexcept
13+
{
14+
static_assert(std::is_integral<T>::value, "Integral required.");
15+
if (std::numeric_limits<T>::is_signed) {
16+
return (i > 0 && j > std::numeric_limits<T>::max() - i) ||
17+
(i < 0 && j < std::numeric_limits<T>::min() - i);
18+
}
19+
return std::numeric_limits<T>::max() - i < j;
20+
}
21+
22+
template <class T>
23+
[[nodiscard]] std::optional<T> CheckedAdd(const T i, const T j) noexcept
24+
{
25+
if (AdditionOverflow(i, j)) {
26+
return std::nullopt;
27+
}
28+
return i + j;
29+
}
30+
31+
#endif // BITCOIN_UTIL_OVERFLOW_H

0 commit comments

Comments
 (0)