From 7213fb9f2172a202624e833f7501ac2f38675805 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 30 Jan 2013 10:12:43 -0800 Subject: [PATCH] Fix underflow and overflow handling in the STAmount class. Add unit test. --- src/cpp/ripple/Amount.cpp | 50 ++++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/src/cpp/ripple/Amount.cpp b/src/cpp/ripple/Amount.cpp index 7d5049482..347f3642c 100644 --- a/src/cpp/ripple/Amount.cpp +++ b/src/cpp/ripple/Amount.cpp @@ -479,23 +479,30 @@ void STAmount::canonicalize() return; } - while (mValue < cMinValue) + while ((mValue < cMinValue) && (mOffset > cMinOffset)) { - if (mOffset <= cMinOffset) - throw std::runtime_error("value overflow"); mValue *= 10; - if (mValue >= cMaxValue) - throw std::runtime_error("value overflow"); --mOffset; } while (mValue > cMaxValue) { if (mOffset >= cMaxOffset) - throw std::runtime_error("value underflow"); + throw std::runtime_error("value overflow"); mValue /= 10; ++mOffset; } + + if (mOffset < cMinOffset) + { + mValue = 0; + mOffset = 0; + mIsNegative = false; + } + + if (mOffset > cMaxOffset) + throw std::runtime_error("value overflow"); + assert((mValue == 0) || ((mValue >= cMinValue) && (mValue <= cMaxValue))); assert((mValue == 0) || ((mOffset >= cMinOffset) && (mOffset <= cMaxOffset))); assert((mValue != 0) || (mOffset != -100)); @@ -1556,6 +1563,37 @@ BOOST_AUTO_TEST_CASE( CurrencyMulDivTests ) mulTest(rand() % 10000000, rand() % 10000000); } +BOOST_AUTO_TEST_CASE( UnderFlowTests ) +{ + STAmount bigNative(STAmount::cMaxNative / 2); + STAmount bigValue(CURRENCY_ONE, ACCOUNT_ONE, + (STAmount::cMinValue + STAmount::cMaxValue) / 2, STAmount::cMaxOffset - 1); + STAmount smallValue(CURRENCY_ONE, ACCOUNT_ONE, + (STAmount::cMinValue + STAmount::cMaxValue) / 2, STAmount::cMinOffset + 1); + STAmount zero(CURRENCY_ONE, ACCOUNT_ONE, 0); + + STAmount smallXsmall = STAmount::multiply(smallValue, smallValue, CURRENCY_ONE, ACCOUNT_ONE); + if (!smallXsmall.isZero()) + BOOST_FAIL("STAmount: smallXsmall != 0"); + + STAmount bigDsmall = STAmount::divide(smallValue, bigValue, CURRENCY_ONE, ACCOUNT_ONE); + if (!bigDsmall.isZero()) + BOOST_FAIL("STAmount: small/big != 0: " << bigDsmall); + + bigDsmall = STAmount::divide(smallValue, bigNative, CURRENCY_ONE, uint160()); + if (!bigDsmall.isZero()) + BOOST_FAIL("STAmount: small/bigNative != 0: " << bigDsmall); + + bigDsmall = STAmount::divide(smallValue, bigValue, uint160(), uint160()); + if (!bigDsmall.isZero()) + BOOST_FAIL("STAmount: (small/big)->N != 0: " << bigDsmall); + + bigDsmall = STAmount::divide(smallValue, bigNative, uint160(), uint160()); + if (!bigDsmall.isZero()) + BOOST_FAIL("STAmount: (small/bigNative)->N != 0: " << bigDsmall); + +} + BOOST_AUTO_TEST_SUITE_END() // vim:ts=4