From 61febbd2491ead2140b88afb8623f664f064375a Mon Sep 17 00:00:00 2001 From: Ishtiaque Zahid Date: Thu, 16 Jun 2022 11:41:16 +0600 Subject: [PATCH] formatNumberReadable now prints signed integers as well --- libsolutil/StringUtils.h | 45 ++++++++++---- .../overflow/signed_guard_sum_overflow.sol | 2 +- .../overflow/signed_mul_overflow.sol | 2 +- .../overflow/signed_sub_overflow.sol | 2 +- .../overflow/signed_sum_overflow.sol | 2 +- test/libsolutil/StringUtils.cpp | 58 +++++++++++++++++++ 6 files changed, 97 insertions(+), 14 deletions(-) diff --git a/libsolutil/StringUtils.h b/libsolutil/StringUtils.h index 7a48c296f..a50d679e8 100644 --- a/libsolutil/StringUtils.h +++ b/libsolutil/StringUtils.h @@ -101,17 +101,9 @@ std::string joinHumanReadablePrefixed return _separator + joinHumanReadable(_list, _separator, _lastSeparator); } -/// Formats large numbers to be easily readable by humans. -/// Returns decimal representation for smaller numbers; hex for large numbers. -/// "Special" numbers, powers-of-two and powers-of-two minus 1, are returned in -/// formulaic form like 0x01 * 2**24 - 1. -/// @a T will typically by unsigned, u160, u256 or bigint. -/// @param _value to be formatted -/// @param _useTruncation if true, internal truncation is also applied, -/// like 0x5555...{+56 more}...5555 -/// @example formatNumber((u256)0x7ffffff) +/// Same as @ref formatNumberReadable but only for unsigned numbers template -inline std::string formatNumberReadable( +inline std::string formatUnsignedNumberReadable ( T const& _value, bool _useTruncation = false ) @@ -181,6 +173,39 @@ inline std::string formatNumberReadable( return str; } +/// Formats large numbers to be easily readable by humans. +/// Returns decimal representation for smaller numbers; hex for large numbers. +/// "Special" numbers, powers-of-two and powers-of-two minus 1, are returned in +/// formulaic form like 0x01 * 2**24 - 1. +/// @a T can be any integer variable, will typically be u160, u256 or bigint. +/// @param _value to be formatted +/// @param _useTruncation if true, internal truncation is also applied, +/// like 0x5555...{+56 more}...5555 +/// @example formatNumberReadable((u256)0x7ffffff) = "0x08 * 2**24" +/// @example formatNumberReadable(-57896044618658097711785492504343953926634992332820282019728792003956564819968) = -0x80 * 2**248 +template +inline std::string formatNumberReadable( + T const& _value, + bool _useTruncation = false +) +{ + static_assert( + std::numeric_limits::is_integer, + "only integer numbers are supported" + ); + + if (_value >= 0) + { + bigint const _v = bigint(_value); + return formatUnsignedNumberReadable(_v, _useTruncation); + } + else + { + bigint const _abs_value = bigint(-1) * _value; + return "-" + formatUnsignedNumberReadable(_abs_value, _useTruncation); + } +} + /// Safely converts an usigned integer as string into an unsigned int type. /// /// @return the converted number or nullopt in case of an failure (including if it would not fit). diff --git a/test/libsolidity/smtCheckerTests/overflow/signed_guard_sum_overflow.sol b/test/libsolidity/smtCheckerTests/overflow/signed_guard_sum_overflow.sol index 4635ef966..2e4b84b70 100644 --- a/test/libsolidity/smtCheckerTests/overflow/signed_guard_sum_overflow.sol +++ b/test/libsolidity/smtCheckerTests/overflow/signed_guard_sum_overflow.sol @@ -8,5 +8,5 @@ contract C { // SMTEngine: all // SMTIgnoreCex: yes // ---- -// Warning 3944: (78-83): CHC: Underflow (resulting value less than -57896044618658097711785492504343953926634992332820282019728792003956564819968) happens here. +// Warning 3944: (78-83): CHC: Underflow (resulting value less than -0x80 * 2**248) happens here. // Warning 4984: (78-83): CHC: Overflow (resulting value larger than 0x80 * 2**248 - 1) happens here. diff --git a/test/libsolidity/smtCheckerTests/overflow/signed_mul_overflow.sol b/test/libsolidity/smtCheckerTests/overflow/signed_mul_overflow.sol index 225d00689..e664174df 100644 --- a/test/libsolidity/smtCheckerTests/overflow/signed_mul_overflow.sol +++ b/test/libsolidity/smtCheckerTests/overflow/signed_mul_overflow.sol @@ -7,5 +7,5 @@ contract C { // SMTEngine: all // SMTIgnoreCex: yes // ---- -// Warning 3944: (77-82): CHC: Underflow (resulting value less than -57896044618658097711785492504343953926634992332820282019728792003956564819968) happens here. +// Warning 3944: (77-82): CHC: Underflow (resulting value less than -0x80 * 2**248) happens here. // Warning 4984: (77-82): CHC: Overflow (resulting value larger than 0x80 * 2**248 - 1) happens here. diff --git a/test/libsolidity/smtCheckerTests/overflow/signed_sub_overflow.sol b/test/libsolidity/smtCheckerTests/overflow/signed_sub_overflow.sol index 81de2d5fe..dfb228b9a 100644 --- a/test/libsolidity/smtCheckerTests/overflow/signed_sub_overflow.sol +++ b/test/libsolidity/smtCheckerTests/overflow/signed_sub_overflow.sol @@ -7,5 +7,5 @@ contract C { // SMTEngine: all // SMTIgnoreCex: yes // ---- -// Warning 3944: (77-82): CHC: Underflow (resulting value less than -57896044618658097711785492504343953926634992332820282019728792003956564819968) happens here. +// Warning 3944: (77-82): CHC: Underflow (resulting value less than -0x80 * 2**248) happens here. // Warning 4984: (77-82): CHC: Overflow (resulting value larger than 0x80 * 2**248 - 1) happens here. diff --git a/test/libsolidity/smtCheckerTests/overflow/signed_sum_overflow.sol b/test/libsolidity/smtCheckerTests/overflow/signed_sum_overflow.sol index 7bb6588e3..5ac0c812b 100644 --- a/test/libsolidity/smtCheckerTests/overflow/signed_sum_overflow.sol +++ b/test/libsolidity/smtCheckerTests/overflow/signed_sum_overflow.sol @@ -7,5 +7,5 @@ contract C { // SMTEngine: all // SMTIgnoreCex: yes // ---- -// Warning 3944: (77-82): CHC: Underflow (resulting value less than -57896044618658097711785492504343953926634992332820282019728792003956564819968) happens here. +// Warning 3944: (77-82): CHC: Underflow (resulting value less than -0x80 * 2**248) happens here. // Warning 4984: (77-82): CHC: Overflow (resulting value larger than 0x80 * 2**248 - 1) happens here. diff --git a/test/libsolutil/StringUtils.cpp b/test/libsolutil/StringUtils.cpp index 0ef61cb0a..db72297e7 100644 --- a/test/libsolutil/StringUtils.cpp +++ b/test/libsolutil/StringUtils.cpp @@ -152,6 +152,64 @@ BOOST_AUTO_TEST_CASE(test_format_number_readable) formatNumberReadable(frontend::IntegerType(256).maxValue()), "2**256 - 1"); } +BOOST_AUTO_TEST_CASE(test_format_number_readable_signed) +{ + BOOST_CHECK_EQUAL(formatNumberReadable((-1) * s256(0x8000000)), "-0x08 * 2**24"); + BOOST_CHECK_EQUAL(formatNumberReadable((-1) * s256(0x80000000)), "-0x80 * 2**24"); + BOOST_CHECK_EQUAL(formatNumberReadable((-1) * s256(0x800000000)), "-0x08 * 2**32"); + BOOST_CHECK_EQUAL(formatNumberReadable((-1) * s256(0x8000000000)), "-0x80 * 2**32"); + BOOST_CHECK_EQUAL(formatNumberReadable((-1) * s256(0x80000000000)), "-0x08 * 2**40"); + + BOOST_CHECK_EQUAL(formatNumberReadable((-1) * s256(0x7ffffff)), "-0x08 * 2**24 - 1"); + BOOST_CHECK_EQUAL(formatNumberReadable((-1) * s256(0x7fffffff)), "-0x80 * 2**24 - 1"); + BOOST_CHECK_EQUAL(formatNumberReadable((-1) * s256(0x7ffffffff)), "-0x08 * 2**32 - 1"); + BOOST_CHECK_EQUAL(formatNumberReadable((-1) * s256(0x7fffffffff)), "-0x80 * 2**32 - 1"); + BOOST_CHECK_EQUAL(formatNumberReadable((-1) * s256(0x7ffffffffff)), "-0x08 * 2**40 - 1"); + + BOOST_CHECK_EQUAL(formatNumberReadable((-1) * s256(0x88000000)), "-0x88 * 2**24"); + BOOST_CHECK_EQUAL(formatNumberReadable((-1) * s256(0x8888888888000000)), "-0x8888888888 * 2**24"); + + s256 b = 0; + for (int i = 0; i < 32; i++) + { + b <<= 8; + b |= 0x55; + } + b = b * (-1); + + s256 c = (-1) * u2s((u256)FixedHash<32>( + fromHex("0x0bcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789") + )); + + s256 d = (-1) * u2s( + u256(0x5555555555555555) << 192 | + u256(0xFFFFffffFFFFffff) << 128 | + u256(0xFFFFffffFFFFffff) << 64 | + u256(0xFFFFffffFFFFffff) + ); + + BOOST_CHECK_EQUAL(formatNumberReadable(b, true), "-0x5555...{+56 more}...5555"); + BOOST_CHECK_EQUAL(formatNumberReadable(c, true), "-0x0BCD...{+56 more}...6789"); + BOOST_CHECK_EQUAL(formatNumberReadable(d, true), "-0x5555555555555556 * 2**192 - 1"); + + BOOST_CHECK_EQUAL(formatNumberReadable(s256(-1)), "-1"); + BOOST_CHECK_EQUAL(formatNumberReadable((-1) * s256(0x10000)), "-65536"); + BOOST_CHECK_EQUAL(formatNumberReadable((-1) * s256(0xFFFF)), "-65535"); + + BOOST_CHECK_EQUAL( + formatNumberReadable( + frontend::IntegerType(256, frontend::IntegerType::Modifier::Signed).minValue() + ), + "-0x80 * 2**248" + ); + BOOST_CHECK_EQUAL( + formatNumberReadable( + frontend::IntegerType(256, frontend::IntegerType::Modifier::Signed).maxValue() + ), + "0x80 * 2**248 - 1" + ); +} + BOOST_AUTO_TEST_SUITE_END() }