Move AdditionOverflow to util, Add CheckedAdd with unit tests

This commit is contained in:
MarcoFalke 2021-11-02 09:48:10 +01:00
parent fa526d8fb6
commit fac01888d1
No known key found for this signature in database
GPG key ID: CE2B75697E69A548
9 changed files with 70 additions and 11 deletions

View file

@ -248,6 +248,7 @@ BITCOIN_CORE_H = \
util/macros.h \
util/message.h \
util/moneystr.h \
util/overflow.h \
util/overloaded.h \
util/rbf.h \
util/readwritefile.h \

View file

@ -5,6 +5,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <util/overflow.h>
#include <cstdint>
#include <string>

View file

@ -7,6 +7,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <util/overflow.h>
#include <cassert>
#include <cstdint>

View file

@ -26,6 +26,7 @@
#include <univalue.h>
#include <util/check.h>
#include <util/moneystr.h>
#include <util/overflow.h>
#include <util/strencodings.h>
#include <util/string.h>
#include <util/system.h>

View file

@ -9,6 +9,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <util/overflow.h>
#include <cstdint>
#include <optional>

View file

@ -8,6 +8,7 @@
#include <pubkey.h>
#include <test/fuzz/util.h>
#include <test/util/script.h>
#include <util/overflow.h>
#include <util/rbf.h>
#include <util/time.h>
#include <version.h>

View file

@ -193,17 +193,6 @@ template <typename T>
}
}
template <class T>
[[nodiscard]] bool AdditionOverflow(const T i, const T j) noexcept
{
static_assert(std::is_integral<T>::value, "Integral required.");
if (std::numeric_limits<T>::is_signed) {
return (i > 0 && j > std::numeric_limits<T>::max() - i) ||
(i < 0 && j < std::numeric_limits<T>::min() - i);
}
return std::numeric_limits<T>::max() - i < j;
}
[[nodiscard]] bool ContainsSpentInput(const CTransaction& tx, const CCoinsViewCache& inputs) noexcept;
/**

View file

@ -15,6 +15,7 @@
#include <util/getuniquepath.h>
#include <util/message.h> // For MessageSign(), MessageVerify(), MESSAGE_MAGIC
#include <util/moneystr.h>
#include <util/overflow.h>
#include <util/spanparsing.h>
#include <util/strencodings.h>
#include <util/string.h>
@ -1463,6 +1464,38 @@ BOOST_AUTO_TEST_CASE(test_IsDigit)
BOOST_CHECK_EQUAL(IsDigit(9), false);
}
/* Check for overflow */
template <typename T>
static void TestAddMatrixOverflow()
{
constexpr T MAXI{std::numeric_limits<T>::max()};
BOOST_CHECK(!CheckedAdd(T{1}, MAXI));
BOOST_CHECK(!CheckedAdd(MAXI, MAXI));
BOOST_CHECK_EQUAL(0, CheckedAdd(T{0}, T{0}).value());
BOOST_CHECK_EQUAL(MAXI, CheckedAdd(T{0}, MAXI).value());
BOOST_CHECK_EQUAL(MAXI, CheckedAdd(T{1}, MAXI - 1).value());
}
/* Check for overflow or underflow */
template <typename T>
static void TestAddMatrix()
{
TestAddMatrixOverflow<T>();
constexpr T MINI{std::numeric_limits<T>::min()};
constexpr T MAXI{std::numeric_limits<T>::max()};
BOOST_CHECK(!CheckedAdd(T{-1}, MINI));
BOOST_CHECK(!CheckedAdd(MINI, MINI));
BOOST_CHECK_EQUAL(MINI, CheckedAdd(T{0}, MINI).value());
BOOST_CHECK_EQUAL(MINI, CheckedAdd(T{-1}, MINI + 1).value());
BOOST_CHECK_EQUAL(-1, CheckedAdd(MINI, MAXI).value());
}
BOOST_AUTO_TEST_CASE(util_overflow)
{
TestAddMatrixOverflow<unsigned>();
TestAddMatrix<signed>();
}
BOOST_AUTO_TEST_CASE(test_ParseInt32)
{
int32_t n;

31
src/util/overflow.h Normal file
View file

@ -0,0 +1,31 @@
// Copyright (c) 2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_UTIL_OVERFLOW_H
#define BITCOIN_UTIL_OVERFLOW_H
#include <limits>
#include <type_traits>
template <class T>
[[nodiscard]] bool AdditionOverflow(const T i, const T j) noexcept
{
static_assert(std::is_integral<T>::value, "Integral required.");
if (std::numeric_limits<T>::is_signed) {
return (i > 0 && j > std::numeric_limits<T>::max() - i) ||
(i < 0 && j < std::numeric_limits<T>::min() - i);
}
return std::numeric_limits<T>::max() - i < j;
}
template <class T>
[[nodiscard]] std::optional<T> CheckedAdd(const T i, const T j) noexcept
{
if (AdditionOverflow(i, j)) {
return std::nullopt;
}
return i + j;
}
#endif // BITCOIN_UTIL_OVERFLOW_H