Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14864956
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
25 KB
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
rABC Bitcoin ABC
Event Timeline
Log In to Comment