diff options
author | Anton Korshunov <anton.korshunov@mongodb.com> | 2019-03-08 14:48:45 +0000 |
---|---|---|
committer | Anton Korshunov <anton.korshunov@mongodb.com> | 2019-03-13 06:50:28 +0000 |
commit | 330c59b671ba62ad72f0a80e0c32beca7c69be2b (patch) | |
tree | 27f8c57dcb2feec4844b6cf12a7ec7f252adeb55 /src/mongo/db/sorter | |
parent | b0a74faa300b4448b9dfb04d4a646f366d9f4572 (diff) | |
download | mongo-330c59b671ba62ad72f0a80e0c32beca7c69be2b.tar.gz |
SERVER-39788 Large values in $skip and $limit stages may cause an arithmetic overflow
Diffstat (limited to 'src/mongo/db/sorter')
-rw-r--r-- | src/mongo/db/sorter/sorter.cpp | 24 |
1 files changed, 20 insertions, 4 deletions
diff --git a/src/mongo/db/sorter/sorter.cpp b/src/mongo/db/sorter/sorter.cpp index a6e038191fe..0e3e1ad7f38 100644 --- a/src/mongo/db/sorter/sorter.cpp +++ b/src/mongo/db/sorter/sorter.cpp @@ -59,6 +59,7 @@ #include "mongo/db/storage/encryption_hooks.h" #include "mongo/db/storage/storage_options.h" #include "mongo/platform/atomic_word.h" +#include "mongo/platform/overflow_arithmetic.h" #include "mongo/s/is_mongos.h" #include "mongo/util/assert_util.h" #include "mongo/util/bufreader.h" @@ -655,10 +656,25 @@ public: _fileName = _opts.tempDir + "/" + nextFileName(); } - // Preallocate a fixed sized vector of the required size if we - // don't expect it to have a major impact on our memory budget. - // This is the common case with small limits. - if ((sizeof(Data) * opts.limit) < opts.maxMemoryUsageBytes / 10) { + // Preallocate a fixed sized vector of the required size if we don't expect it to have a + // major impact on our memory budget. This is the common case with small limits. If the + // limit is really large, we need to take care when doing the check below. Both 'opts.limit' + // and 'sizeof(Data)' are unsigned long's, it's always clearly defined behaviour to multiply + // these two numbers, but the result may be wrapped around (truncated) due to modular + // arithmetics. So, the result of the multiplication may be < maxMemoryUsageBytes / 10, but + // 'opts.limit' may be still large enough to trigger an std::length_error exception and + // abnormally terminate the program. So, we'll check here if the multiply operation was safe + // and whether the limit fits into the maximum allowed vector size. + using MultiplicationType = size_t; + // Just in case, since we're passing an address of an unsigned 64bit below. + static_assert(std::is_unsigned<MultiplicationType>::value && + sizeof(MultiplicationType) == 8); + + MultiplicationType requiredBytes; + auto isSafeMultiplication = mongoUnsignedMultiplyOverflow64( + sizeof(typename decltype(_data)::value_type), opts.limit, &requiredBytes); + if (isSafeMultiplication && requiredBytes < opts.maxMemoryUsageBytes / 10 && + opts.limit <= _data.max_size()) { _data.reserve(opts.limit); } } |