diff options
author | Andrew Morrow <acm@10gen.com> | 2013-08-19 16:54:09 -0400 |
---|---|---|
committer | Andrew Morrow <acm@10gen.com> | 2013-08-20 11:48:46 -0400 |
commit | 95f78edec079e130c58bed831cfe341f45250784 (patch) | |
tree | 90b17d6e3d67740e39532ad5b47f46f7d2f204df /src/mongo/util/safe_num.cpp | |
parent | fce3b4ce8fe848c332657f3accf596e6b087bce9 (diff) | |
download | mongo-95f78edec079e130c58bed831cfe341f45250784.tar.gz |
SERVER-375 Implement multiplication for SafeNum
Diffstat (limited to 'src/mongo/util/safe_num.cpp')
-rw-r--r-- | src/mongo/util/safe_num.cpp | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/src/mongo/util/safe_num.cpp b/src/mongo/util/safe_num.cpp index 98864cdb550..4b26ca4f3e4 100644 --- a/src/mongo/util/safe_num.cpp +++ b/src/mongo/util/safe_num.cpp @@ -193,6 +193,70 @@ namespace mongo { return SafeNum(sum); } + SafeNum mulInt32Int32(int lInt32, int rInt32) { + // NOTE: Please see "Secure Coding in C and C++", Second Edition, page 264-265 for + // details on this algorithm (for an alternative resources, see + // + // https://www.securecoding.cert.org/confluence/display/seccode/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow?showComments=false). + // + // We are using the "Downcast from a larger type" algorithm here. We always perform + // the arithmetic in 64-bit mode, which can never overflow for 32-bit + // integers. Then, if we fall within the allowable range of int, we downcast, + // otherwise, we retain the 64-bit result. + + const long long int result = + static_cast<long long int>(lInt32) * + static_cast<long long int>(rInt32); + + if (result <= std::numeric_limits<int>::max() && + result >= std::numeric_limits<int>::min()) { + return SafeNum(static_cast<int>(result)); + } + + return SafeNum(result); + } + + SafeNum mulInt64Int64(long long lInt64, long long rInt64) { + // NOTE: Please see notes in mulInt32Int32 above for references. In this case, + // since we have no larger integer size, if our precondition test detects overflow + // we must return an invalid SafeNum. Otherwise, the operation is safely performed + // by standard arithmetic. + + if (lInt64 > 0) { + if (rInt64 > 0) { + if (lInt64 > (std::numeric_limits<long long>::max() / rInt64)) { + return SafeNum(); + } + } + else { + if (rInt64 < (std::numeric_limits<long long>::min() / lInt64)) { + return SafeNum(); + } + } + } + else { + if (rInt64 > 0) { + if (lInt64 < (std::numeric_limits<long long>::min() / rInt64)) { + return SafeNum(); + } + } + else { + if ( (lInt64 != 0) && + (rInt64 < (std::numeric_limits<long long>::max() / lInt64))) { + return SafeNum(); + } + } + } + + const long long result = lInt64 * rInt64; + return SafeNum(result); + } + + SafeNum mulFloats(double lDouble, double rDouble) { + const double product = lDouble * rDouble; + return SafeNum(product); + } + } // namespace SafeNum SafeNum::addInternal(const SafeNum& lhs, const SafeNum& rhs) { @@ -223,6 +287,34 @@ namespace mongo { return SafeNum(); } + SafeNum SafeNum::mulInternal(const SafeNum& lhs, const SafeNum& rhs) { + BSONType lType = lhs._type; + BSONType rType = rhs._type; + + if (lType == NumberInt && rType == NumberInt) { + return mulInt32Int32(lhs._value.int32Val, rhs._value.int32Val); + } + + if (lType == NumberInt && rType == NumberLong) { + return mulInt64Int64(lhs._value.int32Val, rhs._value.int64Val); + } + + if (lType == NumberLong && rType == NumberInt) { + return mulInt64Int64(lhs._value.int64Val, rhs._value.int32Val); + } + + if (lType == NumberLong && rType == NumberLong) { + return mulInt64Int64(lhs._value.int64Val, rhs._value.int64Val); + } + + if ((lType == NumberInt || lType == NumberLong || lType == NumberDouble) && + (rType == NumberInt || rType == NumberLong || rType == NumberDouble)) { + return mulFloats(getDouble(lhs), getDouble(rhs)); + } + + return SafeNum(); + } + SafeNum SafeNum::andInternal(const SafeNum& lhs, const SafeNum& rhs) { const BSONType lType = lhs._type; const BSONType rType = rhs._type; |