From 998c51baca374092927e372484983cd620b8800a Mon Sep 17 00:00:00 2001 From: guoling Date: Thu, 3 Sep 2026 17:06:41 +0800 Subject: [PATCH] Support unsigned protobuf value lengths --- Core/CodedInputData.cpp | 39 +++++++------------------- Core/CodedInputDataCrypt.cpp | 21 +++++--------- Core/CodedInputDataCrypt_OSX.cpp | 6 +--- Core/CodedInputData_OSX.cpp | 18 ++---------- Core/MMKV.cpp | 10 +++---- POSIX/demo/UnitTest.cpp | 48 ++++++++++++++++++++++++++------ 6 files changed, 65 insertions(+), 77 deletions(-) diff --git a/Core/CodedInputData.cpp b/Core/CodedInputData.cpp index efc0edb4..5decb9f6 100644 --- a/Core/CodedInputData.cpp +++ b/Core/CodedInputData.cpp @@ -85,11 +85,7 @@ bool CodedInputData::readBool() { } string CodedInputData::readString() { - int32_t size = readRawVarint32(); - if (size < 0) { - throw length_error("InvalidProtocolBuffer negativeSize"); - } - + uint32_t size = readUInt32(); auto s_size = static_cast(size); if (s_size <= m_size - m_position) { string result((char *) (m_ptr + m_position), s_size); @@ -101,11 +97,7 @@ string CodedInputData::readString() { } void CodedInputData::readString(string &s) { - int32_t size = readRawVarint32(); - if (size < 0) { - throw length_error("InvalidProtocolBuffer negativeSize"); - } - + uint32_t size = readUInt32(); auto s_size = static_cast(size); if (s_size <= m_size - m_position) { s.resize(s_size); @@ -119,11 +111,7 @@ void CodedInputData::readString(string &s) { string CodedInputData::readString(KeyValueHolder &kvHolder) { kvHolder.offset = static_cast(m_position); - int32_t size = this->readRawVarint32(); - if (size < 0) { - throw length_error("InvalidProtocolBuffer negativeSize"); - } - + uint32_t size = readUInt32(); auto s_size = static_cast(size); if (s_size <= m_size - m_position) { if (s_size > mmkv::KeySizeLimit) { @@ -146,11 +134,7 @@ MMBuffer CodedInputData::readRealData(mmkv::MMBuffer & data) { } MMBuffer CodedInputData::readData(bool copy, bool exactly) { - int32_t size = this->readRawVarint32(); - if (size < 0) { - throw length_error("InvalidProtocolBuffer negativeSize"); - } - + uint32_t size = readUInt32(); auto s_size = static_cast(size); bool isSizeValid = exactly ? (s_size == m_size - m_position) : (s_size <= m_size - m_position); if (isSizeValid) { @@ -164,11 +148,7 @@ MMBuffer CodedInputData::readData(bool copy, bool exactly) { } void CodedInputData::readData(KeyValueHolder &kvHolder) { - int32_t size = this->readRawVarint32(); - if (size < 0) { - throw length_error("InvalidProtocolBuffer negativeSize"); - } - + uint32_t size = readUInt32(); auto s_size = static_cast(size); if (s_size <= m_size - m_position) { auto kvSize = m_position - kvHolder.offset; @@ -189,7 +169,7 @@ int32_t CodedInputData::readRawVarint32() { if (tmp >= 0) { return tmp; } - int32_t result = tmp & 0x7f; + uint32_t result = tmp & 0x7f; if ((tmp = this->readRawByte()) >= 0) { result |= tmp << 7; } else { @@ -202,12 +182,13 @@ int32_t CodedInputData::readRawVarint32() { result |= tmp << 21; } else { result |= (tmp & 0x7f) << 21; - result |= (tmp = this->readRawByte()) << 28; + tmp = this->readRawByte(); + result |= static_cast(static_cast(tmp)) << 28; if (tmp < 0) { // discard upper 32 bits for (int i = 0; i < 5; i++) { if (this->readRawByte() >= 0) { - return result; + return UInt32ToInt32(result); } } throw invalid_argument("InvalidProtocolBuffer malformed varint32"); @@ -215,7 +196,7 @@ int32_t CodedInputData::readRawVarint32() { } } } - return result; + return UInt32ToInt32(result); } int32_t CodedInputData::readRawLittleEndian32() { diff --git a/Core/CodedInputDataCrypt.cpp b/Core/CodedInputDataCrypt.cpp index 4e225741..824928e7 100644 --- a/Core/CodedInputDataCrypt.cpp +++ b/Core/CodedInputDataCrypt.cpp @@ -185,7 +185,7 @@ int32_t CodedInputDataCrypt::readRawVarint32(bool discardPreData) { if (tmp >= 0) { return tmp; } - int32_t result = tmp & 0x7f; + uint32_t result = tmp & 0x7f; if ((tmp = this->readRawByte()) >= 0) { result |= tmp << 7; } else { @@ -198,12 +198,13 @@ int32_t CodedInputDataCrypt::readRawVarint32(bool discardPreData) { result |= tmp << 21; } else { result |= (tmp & 0x7f) << 21; - result |= (tmp = this->readRawByte()) << 28; + tmp = this->readRawByte(); + result |= static_cast(static_cast(tmp)) << 28; if (tmp < 0) { // discard upper 32 bits for (int i = 0; i < 5; i++) { if (this->readRawByte() >= 0) { - return result; + return UInt32ToInt32(result); } } throw invalid_argument("InvalidProtocolBuffer malformed varint32"); @@ -211,7 +212,7 @@ int32_t CodedInputDataCrypt::readRawVarint32(bool discardPreData) { } } } - return result; + return UInt32ToInt32(result); } int32_t CodedInputDataCrypt::readInt32() { @@ -221,11 +222,7 @@ int32_t CodedInputDataCrypt::readInt32() { string CodedInputDataCrypt::readString(KeyValueHolderCrypt &kvHolder) { kvHolder.offset = static_cast(m_position); - int32_t size = this->readRawVarint32(true); - if (size < 0) { - throw length_error("InvalidProtocolBuffer negativeSize"); - } - + uint32_t size = static_cast(readRawVarint32(true)); auto s_size = static_cast(size); if (s_size <= m_size - m_position) { consumeBytes(s_size); @@ -245,11 +242,7 @@ string CodedInputDataCrypt::readString(KeyValueHolderCrypt &kvHolder) { } void CodedInputDataCrypt::readData(KeyValueHolderCrypt &kvHolder) { - int32_t size = this->readRawVarint32(); - if (size < 0) { - throw length_error("InvalidProtocolBuffer negativeSize"); - } - + uint32_t size = static_cast(readRawVarint32()); auto s_size = static_cast(size); if (s_size <= m_size - m_position) { if (KeyValueHolderCrypt::isValueStoredAsOffset(s_size)) { diff --git a/Core/CodedInputDataCrypt_OSX.cpp b/Core/CodedInputDataCrypt_OSX.cpp index e084b69f..b6bb1634 100644 --- a/Core/CodedInputDataCrypt_OSX.cpp +++ b/Core/CodedInputDataCrypt_OSX.cpp @@ -36,11 +36,7 @@ namespace mmkv { NSString *CodedInputDataCrypt::readNSString(KeyValueHolderCrypt &kvHolder) { kvHolder.offset = static_cast(m_position); - int32_t size = this->readRawVarint32(true); - if (size < 0) { - throw length_error("InvalidProtocolBuffer negativeSize"); - } - + uint32_t size = static_cast(readRawVarint32(true)); auto s_size = static_cast(size); if (s_size <= m_size - m_position) { if (s_size > mmkv::KeySizeLimit) { diff --git a/Core/CodedInputData_OSX.cpp b/Core/CodedInputData_OSX.cpp index f5b7e9e6..58ca4ed0 100644 --- a/Core/CodedInputData_OSX.cpp +++ b/Core/CodedInputData_OSX.cpp @@ -34,11 +34,7 @@ using namespace std; namespace mmkv { NSString *CodedInputData::readNSString() { - int32_t size = this->readRawVarint32(); - if (size < 0) { - throw length_error("InvalidProtocolBuffer negativeSize"); - } - + uint32_t size = readUInt32(); auto s_size = static_cast(size); if (s_size <= m_size - m_position) { auto ptr = m_ptr + m_position; @@ -53,11 +49,7 @@ NSString *CodedInputData::readNSString() { NSString *CodedInputData::readNSString(KeyValueHolder &kvHolder) { kvHolder.offset = static_cast(m_position); - int32_t size = this->readRawVarint32(); - if (size < 0) { - throw length_error("InvalidProtocolBuffer negativeSize"); - } - + uint32_t size = readUInt32(); auto s_size = static_cast(size); if (s_size <= m_size - m_position) { if (s_size > mmkv::KeySizeLimit) { @@ -75,11 +67,7 @@ NSString *CodedInputData::readNSString(KeyValueHolder &kvHolder) { } NSData *CodedInputData::readNSData() { - int32_t size = this->readRawVarint32(); - if (size < 0) { - throw length_error("InvalidProtocolBuffer negativeSize"); - } - + uint32_t size = readUInt32(); auto s_size = static_cast(size); if (s_size <= m_size - m_position) { NSData *result = [NSData dataWithBytes:(m_ptr + m_position) length:s_size]; diff --git a/Core/MMKV.cpp b/Core/MMKV.cpp index bd3c3608..38f9e8b8 100755 --- a/Core/MMKV.cpp +++ b/Core/MMKV.cpp @@ -1039,12 +1039,10 @@ size_t MMKV::getValueSize(MMKVKey_t key, bool actualSize) { if (actualSize) { try { CodedInputData input(data.getPtr(), data.length()); - auto length = input.readInt32(); - if (length >= 0) { - auto s_length = static_cast(length); - if (pbRawVarint32Size(length) + s_length == data.length()) { - return s_length; - } + auto length = input.readUInt32(); + auto s_length = static_cast(length); + if (pbRawVarint32Size(length) + s_length == data.length()) { + return s_length; } } catch (std::exception &exception) { MMKVError("%s", exception.what()); diff --git a/POSIX/demo/UnitTest.cpp b/POSIX/demo/UnitTest.cpp index ad8fc9eb..3fc08b31 100644 --- a/POSIX/demo/UnitTest.cpp +++ b/POSIX/demo/UnitTest.cpp @@ -19,6 +19,7 @@ */ #include +#include "CodedInputData.h" #include "CodedOutputData.h" #include "PBUtility.h" #include "aes/AESCrypt.h" @@ -289,16 +290,19 @@ void testOversizedValue(MMKV *mmkv) { assert(mmkv->getString("value", value) && value == "before"); assert(mmkv->set("after", "value")); assert(mmkv->getString("value", value) && value == "after"); - - auto expiring = MMKV::mmkvWithID("oversized_expiring_value_test"); - expiring->clearAll(); - assert(expiring->enableAutoKeyExpire()); - assert(!expiring->set(oversized, "value", 60)); - assert(expiring->set("after", "value", 60)); - assert(expiring->getString("value", value) && value == "after"); - expiring->clearAll(); } + auto expiring = MMKV::mmkvWithID("oversized_expiring_value_test"); + expiring->clearAll(); + assert(expiring->enableAutoKeyExpire()); + if (numeric_limits::max() > numeric_limits::max()) { + MMBuffer oversized(&sentinel, static_cast(numeric_limits::max()) + 1, MMBufferNoCopy); + assert(!expiring->set(oversized, "value", 60)); + } + assert(expiring->set("after", "value", 60)); + assert(expiring->getString("value", value) && value == "after"); + expiring->clearAll(); + printf("test oversized value: passed\n"); } @@ -420,6 +424,22 @@ void testCodedOutputBounds() { assert(equal(expected32[index].begin(), expected32[index].end(), storage.begin())); } + constexpr array wideLength = {0x80, 0x80, 0x80, 0x80, 0x08}; + CodedInputData wideInput(wideLength.data(), wideLength.size()); + rejected = false; + try { + wideInput.readData(false); + } catch (const out_of_range &) { + rejected = true; + } + assert(rejected); + + storage.fill(0); + CodedOutputData signedOutput(storage.data(), storage.size()); + signedOutput.writeInt32(-1); + CodedInputData signedInput(storage.data(), signedOutput.getPosition()); + assert(signedInput.readInt32() == -1); + constexpr array values64 = {0, 127, 128, 16383, 16384, numeric_limits::max()}; const vector> expected64 = { {0x00}, @@ -485,6 +505,18 @@ void testCodedOutputBounds() { } assert(rejected && positionOutput.getPosition() == 2); + if (numeric_limits::max() > numeric_limits::max()) { + storage.fill(0xA5); + MMBuffer wideValue(storage.data(), static_cast(numeric_limits::max()) + 1, MMBufferNoCopy); + CodedOutputData output(storage.data(), storage.size()); + rejected = false; + try { + output.writeData(wideValue); + } catch (const out_of_range &) { + rejected = true; + } + assert(rejected && output.getPosition() == 0 && storage[0] == 0xA5); + } if (numeric_limits::max() > numeric_limits::max()) { storage.fill(0xA5); MMBuffer oversized(storage.data(), static_cast(numeric_limits::max()) + 1,