Page MenuHomePhabricator

No OneTemporary

diff --git a/src/compat/assumptions.h b/src/compat/assumptions.h
index f70506aac..d804df617 100644
--- a/src/compat/assumptions.h
+++ b/src/compat/assumptions.h
@@ -1,102 +1,110 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
// Compile-time verification of assumptions we make.
#ifndef BITCOIN_COMPAT_ASSUMPTIONS_H
#define BITCOIN_COMPAT_ASSUMPTIONS_H
#include <climits>
#include <cstdint>
#include <limits>
#include <type_traits>
// Assumption: We assume that the macro NDEBUG is not defined.
// Example(s): We use assert(...) extensively with the assumption of it never
// being a noop at runtime.
#if defined(NDEBUG)
#error "Bitcoin cannot be compiled without assertions."
#endif
// Assumption: We assume a C++17 (ISO/IEC 14882:2017) compiler (minimum
// requirement).
// Example(s): We assume the presence of C++17 features everywhere :-)
// ISO Standard C++17 [cpp.predefined]p1:
// "The name __cplusplus is defined to the value 201703L when compiling a C++
// translation unit."
static_assert(__cplusplus >= 201703L, "C++17 standard assumed");
// Assumption: We assume the floating-point types to fulfill the requirements of
// IEC 559 (IEEE 754) standard.
// Example(s): Floating-point division by zero in ConnectBlock,
// CreateTransaction
// and EstimateMedianVal.
static_assert(std::numeric_limits<float>::is_iec559, "IEEE 754 float assumed");
static_assert(std::numeric_limits<double>::is_iec559,
"IEEE 754 double assumed");
// Assumption: We assume floating-point widths.
// Example(s): Type punning in serialization code
// (ser_{float,double}_to_uint{32,64}).
static_assert(sizeof(float) == 4, "32-bit float assumed");
static_assert(sizeof(double) == 8, "64-bit double assumed");
// Assumption: We assume integer widths.
// Example(s): GetSizeOfCompactSize and WriteCompactSize in the serialization
// code.
static_assert(sizeof(short) == 2, "16-bit short assumed");
static_assert(sizeof(int) == 4, "32-bit int assumed");
static_assert(sizeof(unsigned) == 4, "32-bit unsigned assumed");
// Assumption: We assume 8-bit bytes, because 32-bit int and 16-bit short are
// assumed.
static_assert(CHAR_BIT == 8, "8-bit bytes assumed");
// Assumption: We assume uint8_t is an alias of unsigned char.
// char, unsigned char, and std::byte (C++17) are the only "byte types"
// according to the C++ Standard. "byte type" means a type that can be used to
// observe an object's value representation. We use uint8_t everywhere to see
// bytes, so we have to ensure that uint8_t is an alias to a "byte type".
// http://eel.is/c++draft/basic.types
// http://eel.is/c++draft/basic.memobj#def:byte
// http://eel.is/c++draft/expr.sizeof#1
// http://eel.is/c++draft/cstdint#syn
static_assert(std::is_same<uint8_t, unsigned char>::value,
"uint8_t is an alias of unsigned char");
// Assumption: We assume size_t to be 32-bit or 64-bit.
// Example(s): size_t assumed to be at least 32-bit in
// ecdsa_signature_parse_der_lax(...).
// size_t assumed to be 32-bit or 64-bit in MallocUsage(...).
static_assert(sizeof(size_t) == 4 || sizeof(size_t) == 8,
"size_t assumed to be 32-bit or 64-bit");
static_assert(sizeof(size_t) == sizeof(void *),
"Sizes of size_t and void* assumed to be equal");
// Some important things we are NOT assuming (non-exhaustive list):
// * We are NOT assuming a specific value for std::endian::native.
// * We are NOT assuming a specific value for std::locale("").name().
// * We are NOT assuming a specific value for
// std::numeric_limits<char>::is_signed.
/**
* /!\ C++ right shift signedness handling is implementation defined. It is
* defined as an arithmetic on all the platform we support, but this
* may not be the case on other platforms.
*
* NB: C++20 defines signed right shift as being arithmetic shifts, so in
* practice, we should see all platforms converge toward that behavior if
* they haven't already.
*/
static_assert((int64_t(-1) >> 1) == int64_t(-1),
"Arithmetic right shift assumed");
/**
* /!\ C++ Does not guarantee 2-complement, but it implementation defined. All
* the platform we support use 2-complement.
*/
static_assert((int64_t(-10) & 0xffff) == 0xfff6, "2-complement assumed");
+/**
+ * Assume int64_t and long long int are the same type.
+ */
+static_assert(std::numeric_limits<long long int>::max() ==
+ std::numeric_limits<int64_t>::max());
+static_assert(std::numeric_limits<long long int>::min() ==
+ std::numeric_limits<int64_t>::min());
+
#endif // BITCOIN_COMPAT_ASSUMPTIONS_H
diff --git a/src/config/CMakeLists.txt b/src/config/CMakeLists.txt
index 484752452..19730aa38 100644
--- a/src/config/CMakeLists.txt
+++ b/src/config/CMakeLists.txt
@@ -1,243 +1,259 @@
# Copyright (c) 2017-2019 The Bitcoin developers
# This generates config.h which provides numerous defines
# about the state of the plateform we are building on.
include(CheckIncludeFiles)
include(CheckSymbolExists)
include(CheckCXXSymbolExists)
include(CheckCXXSourceCompiles)
# Version
set(CLIENT_VERSION_MAJOR ${bitcoin-abc_VERSION_MAJOR})
set(CLIENT_VERSION_MINOR ${bitcoin-abc_VERSION_MINOR})
set(CLIENT_VERSION_REVISION ${bitcoin-abc_VERSION_PATCH})
option(CLIENT_VERSION_IS_RELEASE "Build a release version" OFF)
# Generate the version.h file
configure_file(version.h.cmake.in version.h ESCAPE_QUOTES)
# Endianness
check_include_files("endian.h" HAVE_ENDIAN_H)
check_include_files("sys/endian.h" HAVE_SYS_ENDIAN_H)
if(HAVE_ENDIAN_H)
set(ENDIAN_FILE "endian.h")
elseif(HAVE_SYS_ENDIAN_H)
set(ENDIAN_FILE "sys/endian.h")
else()
endif()
if(ENDIAN_FILE)
check_symbol_exists(htole16 ${ENDIAN_FILE} HAVE_DECL_HTOLE16)
check_symbol_exists(htobe16 ${ENDIAN_FILE} HAVE_DECL_HTOBE16)
check_symbol_exists(be16toh ${ENDIAN_FILE} HAVE_DECL_BE16TOH)
check_symbol_exists(le16toh ${ENDIAN_FILE} HAVE_DECL_LE16TOH)
check_symbol_exists(htobe32 ${ENDIAN_FILE} HAVE_DECL_HTOBE32)
check_symbol_exists(htole32 ${ENDIAN_FILE} HAVE_DECL_HTOLE32)
check_symbol_exists(be32toh ${ENDIAN_FILE} HAVE_DECL_BE32TOH)
check_symbol_exists(le32toh ${ENDIAN_FILE} HAVE_DECL_LE32TOH)
check_symbol_exists(htobe64 ${ENDIAN_FILE} HAVE_DECL_HTOBE64)
check_symbol_exists(htole64 ${ENDIAN_FILE} HAVE_DECL_HTOLE64)
check_symbol_exists(be64toh ${ENDIAN_FILE} HAVE_DECL_BE64TOH)
check_symbol_exists(le64toh ${ENDIAN_FILE} HAVE_DECL_LE64TOH)
endif()
# Byte swap
check_include_files("byteswap.h" HAVE_BYTESWAP_H)
check_symbol_exists(bswap_16 "byteswap.h" HAVE_DECL_BSWAP_16)
check_symbol_exists(bswap_32 "byteswap.h" HAVE_DECL_BSWAP_32)
check_symbol_exists(bswap_64 "byteswap.h" HAVE_DECL_BSWAP_64)
# sys/select.h and sys/prctl.h headers
check_include_files("sys/select.h" HAVE_SYS_SELECT_H)
check_include_files("sys/prctl.h" HAVE_SYS_PRCTL_H)
-# Bitmanip intrinsics
-function(check_builtin_exist SYMBOL VARIABLE)
+# Built-in compiler intrinsics
+function(check_builtin_exist_with_code SYMBOL VARIABLE CODE)
set(
SOURCE_FILE
"${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckBuiltinExists.c"
)
set(
CMAKE_CONFIGURABLE_FILE_CONTENT
- "int main(int argc, char** argv) { (void)argv; return ${SYMBOL}(argc); }\n"
+ "int main(int argc, char** argv) { (void)argv; return ${CODE}; }\n"
)
configure_file(
"${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in"
"${SOURCE_FILE}"
@ONLY
)
if(NOT CMAKE_REQUIRED_QUIET)
message(STATUS "Looking for ${SYMBOL}")
endif()
try_compile(${VARIABLE}
${CMAKE_BINARY_DIR}
${SOURCE_FILE}
OUTPUT_VARIABLE OUTPUT
)
if(${VARIABLE})
if(NOT CMAKE_REQUIRED_QUIET)
message(STATUS "Looking for ${SYMBOL} - found")
endif()
set(${VARIABLE} 1 CACHE INTERNAL "Have symbol ${SYMBOL}" PARENT_SCOPE)
file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
"Determining if the ${SYMBOL} "
"exist passed with the following output:\n"
"${OUTPUT}\nFile ${SOURCEFILE}:\n"
"${CMAKE_CONFIGURABLE_FILE_CONTENT}\n")
else()
if(NOT CMAKE_REQUIRED_QUIET)
message(STATUS "Looking for ${SYMBOL} - not found")
endif()
set(${VARIABLE} "" CACHE INTERNAL "Have symbol ${SYMBOL}" PARENT_SCOPE)
file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
"Determining if the ${SYMBOL} "
"exist failed with the following output:\n"
"${OUTPUT}\nFile ${SOURCEFILE}:\n"
"${CMAKE_CONFIGURABLE_FILE_CONTENT}\n")
endif()
endfunction()
+function(check_builtin_exist SYMBOL VARIABLE)
+ check_builtin_exist_with_code(
+ ${SYMBOL}
+ ${VARIABLE}
+ "${SYMBOL}(argc)"
+ )
+endfunction()
+
+# Bitmanip intrinsics
check_builtin_exist(__builtin_clz HAVE_DECL___BUILTIN_CLZ)
check_builtin_exist(__builtin_clzl HAVE_DECL___BUILTIN_CLZL)
check_builtin_exist(__builtin_clzll HAVE_DECL___BUILTIN_CLZLL)
check_builtin_exist(__builtin_popcount HAVE_DECL___BUILTIN_POPCOUNT)
+# Overflow math
+check_builtin_exist_with_code(
+ __builtin_saddll_overflow HAVE_DECL___BUILTIN_SADDLL_OVERFLOW
+ "__builtin_saddll_overflow(argc, argc, (long long int*)&argc)")
+check_builtin_exist_with_code(
+ __builtin_ssubll_overflow HAVE_DECL___BUILTIN_SSUBLL_OVERFLOW
+ "__builtin_ssubll_overflow(argc, argc, (long long int*)&argc)")
# Memory management capabilities
check_symbol_exists(M_ARENA_MAX "malloc.h" HAVE_MALLOPT_ARENA_MAX)
check_symbol_exists(malloc_info "malloc.h" HAVE_MALLOC_INFO)
# Various system libraries
check_symbol_exists(strnlen "string.h" HAVE_DECL_STRNLEN)
# daemon() is located in unistd.h on linux and in stdlib.h on BSDs and macOS.
check_symbol_exists(daemon "unistd.h;stdlib.h" HAVE_DECL_DAEMON)
# Check for ways to obtain entropy
check_symbol_exists(getentropy "unistd.h" HAVE_GETENTROPY)
# macOS needs unistd.h and sys/random.h to define getentropy
check_symbol_exists(getentropy "unistd.h;sys/random.h" HAVE_GETENTROPY_RAND)
# OSX and BSDs measurement related headers
check_include_files("sys/types.h;vm/vm_params.h" HAVE_VM_VM_PARAM_H)
check_include_files("sys/types.h;sys/vmmeter.h" HAVE_SYS_VMMETER_H)
check_include_files("sys/types.h;sys/resources.h" HAVE_SYS_RESOURCES_H)
# Don't use sysctl on Linux, it's deprecated even when it works
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Linux")
check_symbol_exists(sysctl "sys/types.h;sys/sysctl.h" HAVE_SYSCTL)
endif()
# getifaddrs and freeifaddrs may be unavailable with some Android versions
check_symbol_exists(getifaddrs "sys/types.h;ifaddrs.h" HAVE_DECL_GETIFADDRS)
check_symbol_exists(freeifaddrs "sys/types.h;ifaddrs.h" HAVE_DECL_FREEIFADDRS)
check_cxx_source_compiles("
#include <unistd.h> /* for syscall */
#include <sys/syscall.h> /* for SYS_getrandom */
#include <linux/random.h>
int main() {
syscall(SYS_getrandom, nullptr, 0, 0);
return 0;
}
" HAVE_SYS_GETRANDOM)
check_cxx_source_compiles("
#include <sys/types.h>
#include <sys/sysctl.h>
int main() {
static const int name[2] = {CTL_KERN, KERN_ARND};
sysctl(name, 2, nullptr, nullptr, nullptr, 0);
return 0;
}
" HAVE_SYSCTL_ARND)
check_cxx_source_compiles("
#include <cstdint>
#include <type_traits>
int main() {
static_assert(std::is_same<int8_t, char>::value, \"\");
return 0;
}
" CHAR_EQUALS_INT8)
check_cxx_source_compiles("
#include <sys/types.h>
#include <type_traits>
int main() {
static_assert(sizeof(off_t) == 8, \"\");
return 0;
}
" HAVE_LARGE_FILE_SUPPORT)
check_cxx_source_compiles("
__attribute__((visibility(\"default\"))) int main() {
return 0;
}
" HAVE_FUNC_ATTRIBUTE_VISIBILITY)
check_cxx_source_compiles("
__declspec(dllexport) int main() {
return 0;
}
" HAVE_FUNC_ATTRIBUTE_DLLEXPORT)
check_cxx_source_compiles("
// same as in src/util/system.cpp
#ifdef __linux__
#ifdef _POSIX_C_SOURCE
#undef _POSIX_C_SOURCE
#endif
#define _POSIX_C_SOURCE 200112L
#endif // __linux__
#include <fcntl.h>
int main() {
return posix_fallocate(0, 0, 0);
}
" HAVE_POSIX_FALLOCATE)
#__fdelt_chk's params and return type have changed from long unsigned int to
# long int. See which one is present here.
include(CheckPrototypeDefinition)
set(CMAKE_REQUIRED_DEFINITIONS -D_FORTIFY_SOURCE=2)
# Without some optimization the compiler won't detect the prototype conflict
# and always succeed to build.
set(CMAKE_REQUIRED_FLAGS -O2)
# Activate wallet
set(ENABLE_WALLET ${BUILD_BITCOIN_WALLET})
# Activate ZeroMQ
set(ENABLE_ZMQ ${BUILD_BITCOIN_ZMQ})
# Try to find libqrencode
# Only used in the wallet GUI
if(ENABLE_QRCODE AND BUILD_BITCOIN_WALLET AND BUILD_BITCOIN_QT)
set(USE_QRCODE 1 CACHE INTERNAL "QR code is enabled")
endif()
# Try to find miniupnpc
if(ENABLE_UPNP)
# The expected behavior is as follow:
# - If UPnP is enabled USE_UPNP must be defined
# - If UPnP should be the default port map method, USE_UPNP should be
# defined to 1, otherwise it should be defined to 0.
set(USE_UPNP ${START_WITH_UPNP} CACHE INTERNAL "UPnP is enabled")
endif()
if(ENABLE_DBUS_NOTIFICATIONS)
set(USE_DBUS 1)
endif()
# Check if std::system or ::wsystem is available
check_cxx_symbol_exists(std::system "cstdlib" _HAVE_STD_SYSTEM)
check_cxx_symbol_exists(::wsystem "" _HAVE_WSYSTEM)
if(_HAVE_STD_SYSTEM OR _HAVE_WSYSTEM)
set(HAVE_SYSTEM 1)
endif()
# Generate the config
configure_file(bitcoin-config.h.cmake.in bitcoin-config.h ESCAPE_QUOTES)
diff --git a/src/config/bitcoin-config.h.cmake.in b/src/config/bitcoin-config.h.cmake.in
index 392dd8431..23ff2cbaa 100644
--- a/src/config/bitcoin-config.h.cmake.in
+++ b/src/config/bitcoin-config.h.cmake.in
@@ -1,89 +1,91 @@
// Copyright (c) 2017 The Bitcoin developers
#ifndef BITCOIN_CONFIG_BITCOIN_CONFIG_H
#define BITCOIN_CONFIG_BITCOIN_CONFIG_H
#define PACKAGE_NAME "${PACKAGE_NAME}"
#define PACKAGE_BUGREPORT "${PACKAGE_BUGREPORT}"
#define COPYRIGHT_YEAR "${COPYRIGHT_YEAR}"
#define COPYRIGHT_HOLDERS "${COPYRIGHT_HOLDERS}"
#define COPYRIGHT_HOLDERS_SUBSTITUTION "${COPYRIGHT_HOLDERS_SUBSTITUTION}"
#define COPYRIGHT_HOLDERS_FINAL "${COPYRIGHT_HOLDERS_FINAL}"
#cmakedefine HAVE_ENDIAN_H 1
#cmakedefine HAVE_SYS_ENDIAN_H 1
#cmakedefine HAVE_DECL_HTOLE16 1
#cmakedefine HAVE_DECL_HTOBE16 1
#cmakedefine HAVE_DECL_BE16TOH 1
#cmakedefine HAVE_DECL_LE16TOH 1
#cmakedefine HAVE_DECL_HTOBE32 1
#cmakedefine HAVE_DECL_HTOLE32 1
#cmakedefine HAVE_DECL_BE32TOH 1
#cmakedefine HAVE_DECL_LE32TOH 1
#cmakedefine HAVE_DECL_HTOBE64 1
#cmakedefine HAVE_DECL_HTOLE64 1
#cmakedefine HAVE_DECL_BE64TOH 1
#cmakedefine HAVE_DECL_LE64TOH 1
#cmakedefine HAVE_BYTESWAP_H 1
#cmakedefine HAVE_DECL_BSWAP_16 1
#cmakedefine HAVE_DECL_BSWAP_32 1
#cmakedefine HAVE_DECL_BSWAP_64 1
#cmakedefine HAVE_SYS_SELECT_H 1
#cmakedefine HAVE_SYS_PRCTL_H 1
#cmakedefine HAVE_DECL___BUILTIN_CLZ 1
#cmakedefine HAVE_DECL___BUILTIN_CLZL 1
#cmakedefine HAVE_DECL___BUILTIN_CLZLL 1
#cmakedefine HAVE_DECL___BUILTIN_POPCOUNT 1
+#cmakedefine HAVE_DECL___BUILTIN_SADDLL_OVERFLOW 1
+#cmakedefine HAVE_DECL___BUILTIN_SSUBLL_OVERFLOW 1
#cmakedefine HAVE_MALLOPT_ARENA_MAX 1
#cmakedefine HAVE_MALLOC_INFO 1
#cmakedefine HAVE_DECL_STRNLEN 1
#cmakedefine HAVE_DECL_DAEMON 1
#cmakedefine HAVE_DECL_GETIFADDRS 1
#cmakedefine HAVE_DECL_FREEIFADDRS 1
#cmakedefine HAVE_GETENTROPY 1
#cmakedefine HAVE_GETENTROPY_RAND 1
#cmakedefine HAVE_SYS_GETRANDOM 1
#cmakedefine HAVE_VM_VM_PARAM_H 1
#cmakedefine HAVE_SYS_VMMETER_H 1
#cmakedefine HAVE_SYS_RESOURCES_H 1
#cmakedefine HAVE_SYSCTL 1
#cmakedefine HAVE_SYSCTL_ARND 1
#cmakedefine HAVE_SYSTEM 1
#cmakedefine CHAR_EQUALS_INT8 0
#cmakedefine HAVE_LARGE_FILE_SUPPORT 1
#cmakedefine HAVE_FUNC_ATTRIBUTE_VISIBILITY 1
#cmakedefine HAVE_FUNC_ATTRIBUTE_DLLEXPORT 1
#cmakedefine HAVE_POSIX_FALLOCATE 1
#cmakedefine ENABLE_BIP70 1
#cmakedefine ENABLE_WALLET 1
#cmakedefine ENABLE_ZMQ 1
/* Define if QR support should be compiled in */
#cmakedefine USE_QRCODE 1
/* UPnP support not compiled if undefined */
#cmakedefine ENABLE_UPNP
#ifdef ENABLE_UPNP
/* Value (0 or 1) determines the UPnP default state at startup. */
#cmakedefine01 USE_UPNP
#endif
/* Define if QtDBus support should be enabled */
#cmakedefine USE_DBUS 1
#endif // BITCOIN_BITCOIN_CONFIG_H
diff --git a/src/script/intmath.h b/src/script/intmath.h
index 43d770724..e5e8b396b 100644
--- a/src/script/intmath.h
+++ b/src/script/intmath.h
@@ -1,46 +1,80 @@
// Copyright (c) 2021 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_SCRIPT_INTMATH_H
#define BITCOIN_SCRIPT_INTMATH_H
#include <cstdlib>
#include <limits>
/**
* Computes a + b and stores it in result. If the sum overflows or results in an
* invalid 63+sign-bit integer, return true, otherwise false. Overflow checks
* are emulated and don't rely on built-in overflow checks.
*/
static bool AddInt63OverflowEmulated(int64_t a, int64_t b, int64_t &result) {
if (a > 0 && b > std::numeric_limits<int64_t>::max() - a) {
// integer overflow
return true;
}
if (a < 0 && b <= std::numeric_limits<int64_t>::min() - a) {
// integer underflow
return true;
}
result = a + b;
return result == std::numeric_limits<int64_t>::min();
}
+/**
+ * Computes a + b and stores it in result. If the sum overflows or results in an
+ * invalid 63+sign-bit integer, return true, otherwise false.
+ * Uses built-in overflow functions if available, and emulated overflow math
+ * otherwise.
+ */
+static bool AddInt63Overflow(int64_t a, int64_t b, int64_t &result) {
+#if HAVE_DECL___BUILTIN_SADDLL_OVERFLOW
+ if (__builtin_saddll_overflow(a, b, (long long int *)&result)) {
+ return true;
+ }
+ return result == std::numeric_limits<int64_t>::min();
+#else
+ return AddInt63OverflowEmulated(a, b, result);
+#endif
+}
+
/**
* Computes a - b and stores it in result. If the difference overflows or
* results in an invalid 63+sign-bit integer, return true, otherwise false.
* Overflow checks are emulated and don't rely on built-in overflow checks.
*/
static bool SubInt63OverflowEmulated(int64_t a, int64_t b, int64_t &result) {
if (a < 0 && b > std::numeric_limits<int64_t>::max() + a) {
// integer overflow
return true;
}
if (a > 0 && b <= std::numeric_limits<int64_t>::min() + a) {
// integer underflow
return true;
}
result = a - b;
return result == std::numeric_limits<int64_t>::min();
}
+/**
+ * Computes a - b and stores it in result. If the sum difference or results in
+ * an invalid 63+sign-bit integer, return true, otherwise false.
+ * Uses built-in overflow functions if available, and emulated overflow math
+ * otherwise.
+ */
+static bool SubInt63Overflow(int64_t a, int64_t b, int64_t &result) {
+#if HAVE_DECL___BUILTIN_SSUBLL_OVERFLOW
+ if (__builtin_ssubll_overflow(a, b, (long long int *)&result)) {
+ return true;
+ }
+ return result == std::numeric_limits<int64_t>::min();
+#else
+ return SubInt63OverflowEmulated(a, b, result);
+#endif
+}
+
#endif // BITCOIN_SCRIPT_INTMATH_H
diff --git a/src/test/intmath_tests.cpp b/src/test/intmath_tests.cpp
index 597c410db..3b29d61f1 100644
--- a/src/test/intmath_tests.cpp
+++ b/src/test/intmath_tests.cpp
@@ -1,147 +1,168 @@
// Copyright (c) 2021 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <boost/test/unit_test.hpp>
#include <test/lcg.h>
#include <test/util/setup_common.h>
#include <script/intmath.h>
#include <boost/multiprecision/cpp_int.hpp>
BOOST_FIXTURE_TEST_SUITE(intmath_tests, BasicTestingSetup)
typedef boost::multiprecision::checked_int128_t i128_t;
const i128_t MAX_SCRIPT_63_BIT_INT = 0x7fff'ffff'ffff'ffff;
const i128_t MIN_SCRIPT_63_BIT_INT = -0x7fff'ffff'ffff'ffff;
const static std::vector<int64_t> INTERESTING_63_BIT_NUMBERS({
0,
1,
-1,
2,
-2,
4,
-4,
10,
-10,
100,
-100,
127,
-127,
255,
-255,
256,
-256,
1000,
-1000,
5040,
-5040,
0x7fff,
-0x7fff,
0x1'0000,
-0x1'0000,
0x7f'ffff,
-0x7f'ffff,
0x100'0000,
-0x100'0000,
0x7fff'ffff,
-0x7fff'ffff,
0xffff'ffff,
-0xffff'ffff,
0x1'0000'0000,
-0x1'0000'0000,
0x7f'ffff'ffff,
-0x7f'ffff'ffff,
0xff'ffff'ffff,
-0xff'ffff'ffff,
0x100'0000'0000,
-0x100'0000'0000,
0x7fff'ffff'ffff,
-0x7fff'ffff'ffff,
0xffff'ffff'ffff,
-0xffff'ffff'ffff,
0x1'0000'0000'0000,
-0x1'0000'0000'0000,
0x7f'ffff'ffff'ffff,
-0x7f'ffff'ffff'ffff,
0xff'ffff'ffff'ffff,
-0xff'ffff'ffff'ffff,
0x100'0000'0000'0000,
-0x100'0000'0000'0000,
0x7fff'ffff'ffff'ffff,
-0x7fff'ffff'ffff'ffff,
});
bool IsInScriptBounds(const i128_t &num_int) {
return num_int >= MIN_SCRIPT_63_BIT_INT && num_int <= MAX_SCRIPT_63_BIT_INT;
}
+void CheckArithmeticResult(std::string operation_str, bool expect_overflow,
+ bool had_overflow, int64_t result,
+ i128_t expected_result) {
+ if (expect_overflow) {
+ BOOST_CHECK_MESSAGE(had_overflow,
+ strprintf("%s didn't overflow", operation_str));
+ } else {
+ BOOST_CHECK_MESSAGE(!had_overflow,
+ strprintf("%s overflowed", operation_str));
+ BOOST_CHECK_EQUAL(result, expected_result);
+ }
+}
+
void CheckArithmetic(const int64_t a_64, const int64_t b_64) {
const i128_t a = a_64;
const i128_t b = b_64;
{
+ bool expect_overflow = !IsInScriptBounds(a + b);
// Test AddInt63OverflowEmulated
+ int64_t result_emulated;
+ bool had_overflow_emulated =
+ AddInt63OverflowEmulated(a_64, b_64, result_emulated);
+ CheckArithmeticResult(strprintf("%d + %d", a, b), expect_overflow,
+ had_overflow_emulated, result_emulated, a + b);
+ // Test AddInt63Overflow
int64_t result;
- bool expect_overflow = !IsInScriptBounds(a + b);
- bool had_overflow = AddInt63OverflowEmulated(a_64, b_64, result);
- if (expect_overflow) {
- BOOST_CHECK_MESSAGE(
- had_overflow, strprintf("%d + %d didn't overflow", a_64, b_64));
- } else {
- BOOST_CHECK_MESSAGE(!had_overflow,
- strprintf("%d + %d overflowed", a_64, b_64));
- BOOST_CHECK_EQUAL(result, a + b);
+ bool had_overflow = AddInt63Overflow(a_64, b_64, result);
+ CheckArithmeticResult(strprintf("%d + %d", a, b), expect_overflow,
+ had_overflow_emulated, result_emulated, a + b);
+ if (!expect_overflow) {
+ BOOST_CHECK_EQUAL(result, result_emulated);
}
+ BOOST_CHECK_EQUAL(had_overflow, had_overflow_emulated);
}
{
- // Test SubInt63OverflowEmulated
- int64_t result;
bool expect_overflow = !IsInScriptBounds(a - b);
- bool had_overflow = SubInt63OverflowEmulated(a_64, b_64, result);
- if (expect_overflow) {
- BOOST_CHECK_MESSAGE(
- had_overflow, strprintf("%d - %d didn't overflow", a_64, b_64));
- } else {
- BOOST_CHECK_MESSAGE(!had_overflow,
- strprintf("%d - %d overflowed", a_64, b_64));
- BOOST_CHECK_EQUAL(result, a - b);
+ // Test AddInt63OverflowEmulated
+ int64_t result_emulated;
+ bool had_overflow_emulated =
+ SubInt63OverflowEmulated(a_64, b_64, result_emulated);
+ CheckArithmeticResult(strprintf("%d - %d", a, b), expect_overflow,
+ had_overflow_emulated, result_emulated, a - b);
+ // Test AddInt63Overflow
+ int64_t result;
+ bool had_overflow = SubInt63Overflow(a_64, b_64, result);
+ CheckArithmeticResult(strprintf("%d - %d", a, b), expect_overflow,
+ had_overflow_emulated, result_emulated, a - b);
+ if (!expect_overflow) {
+ BOOST_CHECK_EQUAL(result, result_emulated);
}
+ BOOST_CHECK_EQUAL(had_overflow, had_overflow_emulated);
}
}
/** Generate random number in [-2^63; 2^63]. */
int64_t GenInt63(MMIXLinearCongruentialGenerator &lcg) {
while (true) {
// Uniform number in [-2^63; 2^63].
int64_t val = (int64_t(lcg.next()) << 32) | lcg.next();
// Make bit-length uniformly distributed for better test coverage.
val >>= (lcg.next() % 64);
// Ensure value is in bounds.
if (val != std::numeric_limits<int64_t>::min()) {
return val;
}
}
}
BOOST_AUTO_TEST_CASE(check_arithmetic) {
MMIXLinearCongruentialGenerator lcg;
for (uint32_t test = 0; test < 2048; ++test) {
int64_t a = GenInt63(lcg);
int64_t b = GenInt63(lcg);
CheckArithmetic(a, b);
for (const int64_t &num : INTERESTING_63_BIT_NUMBERS) {
CheckArithmetic(a, num);
CheckArithmetic(num, b);
}
}
for (const int64_t &a : INTERESTING_63_BIT_NUMBERS) {
for (const int64_t &b : INTERESTING_63_BIT_NUMBERS) {
CheckArithmetic(a, b);
}
}
}
BOOST_AUTO_TEST_SUITE_END()

File Metadata

Mime Type
text/x-diff
Expires
Wed, May 21, 23:38 (1 d, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5866165
Default Alt Text
(25 KB)

Event Timeline