diff --git a/Core/MMKV_IO.cpp b/Core/MMKV_IO.cpp index 7fd6d607..a0983699 100755 --- a/Core/MMKV_IO.cpp +++ b/Core/MMKV_IO.cpp @@ -449,6 +449,7 @@ static bool encodedEntrySize(size_t keyDataLength, uint32_t originKeyLength, size_t dataLength, bool isDataHolder, + bool needsPlainHolder, EncodedEntrySize &result) { constexpr auto MaxEncodedLength = numeric_limits::max(); if (originKeyLength > KeySizeLimit || keyDataLength < originKeyLength || keyDataLength > MaxEncodedLength) { @@ -460,11 +461,14 @@ static bool encodedEntrySize(size_t keyDataLength, return false; } - uint64_t totalSize = - static_cast(keyDataLength) + result.valueLength + pbRawVarint32Size(result.valueLength); + uint64_t keyValueSize = static_cast(keyDataLength) + pbRawVarint32Size(result.valueLength); if (!result.keyAlreadyEncoded) { - totalSize += pbRawVarint32Size(static_cast(keyDataLength)); + keyValueSize += pbRawVarint32Size(static_cast(keyDataLength)); } + if (needsPlainHolder && keyValueSize > numeric_limits::max()) { + return false; + } + auto totalSize = keyValueSize + result.valueLength; if (totalSize > MaxEncodedLength) { return false; } @@ -962,7 +966,8 @@ bool MMKV::removeDataForKey(MMKVKey_t key) { KVHolderRet_t MMKV::doAppendDataWithKey(const MMBuffer &data, const MMBuffer &keyData, bool isDataHolder, uint32_t originKeyLength) { EncodedEntrySize entry; - if (!encodedEntrySize(keyData.length(), originKeyLength, data.length(), isDataHolder, entry)) { + if (!encodedEntrySize(keyData.length(), originKeyLength, data.length(), isDataHolder, m_crypter == nullptr, + entry)) { MMKVError("[%s] reject unrepresentable key/value lengths, keyData=%zu, key=%u, value=%zu", m_mmapID.c_str(), keyData.length(), originKeyLength, data.length()); return make_pair(false, KeyValueHolder()); @@ -1024,7 +1029,8 @@ KVHolderRet_t MMKV::doOverrideDataWithKey(const MMBuffer &data, bool isDataHolder, uint32_t originKeyLength) { EncodedEntrySize entry; - if (!encodedEntrySize(keyData.length(), originKeyLength, data.length(), isDataHolder, entry)) { + if (!encodedEntrySize(keyData.length(), originKeyLength, data.length(), isDataHolder, m_crypter == nullptr, + entry)) { MMKVError("[%s] reject unrepresentable key/value lengths, keyData=%zu, key=%u, value=%zu", m_mmapID.c_str(), keyData.length(), originKeyLength, data.length()); return make_pair(false, KeyValueHolder()); @@ -1139,7 +1145,7 @@ KVHolderRet_t MMKV::appendDataWithKey(const MMBuffer &data, const KeyValueHolder // ensureMemorySize() might change kvHolder.offset, so have to do it early { EncodedEntrySize entry; - if (!encodedEntrySize(rawKeySize, keyLength, data.length(), isDataHolder, entry)) { + if (!encodedEntrySize(rawKeySize, keyLength, data.length(), isDataHolder, m_crypter == nullptr, entry)) { return make_pair(false, KeyValueHolder()); } bool hasEnoughSize = ensureMemorySize(entry.totalSize); @@ -1166,7 +1172,7 @@ KVHolderRet_t MMKV::overrideDataWithKey(const MMBuffer &data, const KeyValueHold // might change kvHolder.offset, so have to do it early { EncodedEntrySize entry; - if (!encodedEntrySize(rawKeySize, keyLength, data.length(), isDataHolder, entry)) { + if (!encodedEntrySize(rawKeySize, keyLength, data.length(), isDataHolder, m_crypter == nullptr, entry)) { return make_pair(false, KeyValueHolder()); } bool hasEnoughSize = checkSizeForOverride(entry.totalSize); diff --git a/POSIX/demo/UnitTest.cpp b/POSIX/demo/UnitTest.cpp index 1c9ec7c8..07e52a6f 100644 --- a/POSIX/demo/UnitTest.cpp +++ b/POSIX/demo/UnitTest.cpp @@ -221,7 +221,14 @@ void testOversizedKey(MMKV *mmkv) { string out; ret = mmkv->getString(key, out); assert(ret && out == "V"); + + // The key still fits, but a two-byte value-length prefix would overflow + // KeyValueHolder::computedKVSize. Reject the update before writing it. + assert(!mmkv->set(string(127, 'V'), key)); + assert(mmkv->getString(key, out) && out == "V"); mmkv->removeValueForKey(key); + assert(!mmkv->set(string(127, 'V'), key)); + assert(!mmkv->containsKey(key)); } // Keys at 65532 bytes and above must be rejected (would overflow uint16_t fields) {