--- protobuf-3.14.0/src/google/protobuf/extension_set_inl.h 2024-06-17 08:34:37.710063457 +0200 +++ protobuf-3.14.0/src/google/protobuf/extension_set_inl.h.org 2024-06-17 08:30:35.432690742 +0200 @@ -206,16 +206,21 @@ const char* ptr, const Msg* containing_type, internal::InternalMetadata* metadata, internal::ParseContext* ctx) { std::string payload; + uint32_t type_id; + enum class State { kNoTag, kHasType, kHasPayload, kDone }; + State state = State::kNoTag; + - uint32 type_id = 0; - bool payload_read = false; while (!ctx->Done(&ptr)) { uint32 tag = static_cast(*ptr++); if (tag == WireFormatLite::kMessageSetTypeIdTag) { uint64 tmp; ptr = ParseBigVarint(ptr, &tmp); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); + if (state == State::kNoTag) { + type_id = tmp; + state = State::kHasType; + } else if (state == State::kHasPayload) { + type_id = tmp; - type_id = tmp; - if (payload_read) { ExtensionInfo extension; bool was_packed_on_wire; if (!FindExtension(2, type_id, containing_type, ctx, &extension, @@ -241,20 +236,24 @@ GOOGLE_PROTOBUF_PARSER_ASSERT(value->_InternalParse(p, &tmp_ctx) && tmp_ctx.EndedAtLimit()); } + state = State::kDone; - type_id = 0; } } else if (tag == WireFormatLite::kMessageSetMessageTag) { + if (state == State::kHasType) { - if (type_id != 0) { ptr = ParseFieldMaybeLazily(static_cast(type_id) * 8 + 2, ptr, containing_type, metadata, ctx); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr); + state = State::kDone; - type_id = 0; } else { + std::string tmp; int32 size = ReadSize(&ptr); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); + ptr = ctx->ReadString(ptr, size, &tmp); - ptr = ctx->ReadString(ptr, size, &payload); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); + if (state == State::kNoTag) { + payload = std::move(tmp); + state = State::kHasPayload; + } - payload_read = true; } } else { ptr = ReadTag(ptr - 1, &tag); --- protobuf-3.14.0/src/google/protobuf/wire_format.cc 2024-06-17 08:38:49.003336799 +0200 +++ protobuf-3.14.0/src/google/protobuf/wire_format.cc.org 2024-06-17 08:35:18.445621561 +0200 @@ -659,9 +659,11 @@ const char* _InternalParse(const char* ptr, internal::ParseContext* ctx) { // Parse a MessageSetItem auto metadata = reflection->MutableInternalMetadata(msg); + enum class State { kNoTag, kHasType, kHasPayload, kDone }; + State state = State::kNoTag; + std::string payload; uint32 type_id = 0; - bool payload_read = false; while (!ctx->Done(&ptr)) { // We use 64 bit tags in order to allow typeid's that span the whole // range of 32 bit numbers. @@ -670,8 +668,11 @@ uint64 tmp; ptr = ParseBigVarint(ptr, &tmp); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); + if (state == State::kNoTag) { + type_id = tmp; + state = State::kHasType; + } else if (state == State::kHasPayload) { + type_id = tmp; - type_id = tmp; - if (payload_read) { const FieldDescriptor* field; if (ctx->data().pool == nullptr) { field = reflection->FindKnownExtensionByNumber(type_id); @@ -698,17 +693,17 @@ GOOGLE_PROTOBUF_PARSER_ASSERT(value->_InternalParse(p, &tmp_ctx) && tmp_ctx.EndedAtLimit()); } + state = State::kDone; - type_id = 0; } continue; } else if (tag == WireFormatLite::kMessageSetMessageTag) { + if (state == State::kNoTag) { - if (type_id == 0) { int32 size = ReadSize(&ptr); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); ptr = ctx->ReadString(ptr, size, &payload); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); + state = State::kHasPayload; + } else if (state == State::kHasType) { - payload_read = true; - } else { // We're now parsing the payload const FieldDescriptor* field = nullptr; if (descriptor->IsExtensionNumber(type_id)) { @@ -722,7 +717,12 @@ ptr = WireFormat::_InternalParseAndMergeField( msg, ptr, ctx, static_cast(type_id) * 8 + 2, reflection, field); + state = State::kDone; + } else { + int32_t size = ReadSize(&ptr); + GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); + ptr = ctx->Skip(ptr, size); + GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); - type_id = 0; } } else { // An unknown field in MessageSetItem. --- protobuf-3.14.0/src/google/protobuf/wire_format_lite.h 2024-06-17 08:43:18.156450819 +0200 +++ protobuf-3.14.0/src/google/protobuf/wire_format_lite.h.org 2024-06-17 08:39:03.671177609 +0200 @@ -1798,6 +1798,9 @@ // we can parse it later. std::string message_data; + enum class State { kNoTag, kHasType, kHasPayload, kDone }; + State state = State::kNoTag; + while (true) { const uint32 tag = input->ReadTagNoLastTag(); if (tag == 0) return false; @@ -1806,26 +1809,35 @@ case WireFormatLite::kMessageSetTypeIdTag: { uint32 type_id; if (!input->ReadVarint32(&type_id)) return false; - last_type_id = type_id; + if (state == State::kNoTag) { + last_type_id = type_id; + state = State::kHasType; + } else if (state == State::kHasPayload) { - if (!message_data.empty()) { // We saw some message data before the type_id. Have to parse it // now. io::CodedInputStream sub_input( reinterpret_cast(message_data.data()), static_cast(message_data.size())); sub_input.SetRecursionLimit(input->RecursionBudget()); + if (!ms.ParseField(type_id, &sub_input)) { - if (!ms.ParseField(last_type_id, &sub_input)) { return false; } message_data.clear(); + state = State::kDone; } break; } case WireFormatLite::kMessageSetMessageTag: { + if (state == State::kHasType) { + // Already saw type_id, so we can parse this directly. + if (!ms.ParseField(last_type_id, input)) { + return false; + } + state = State::kDone; + } else if (state == State::kNoTag) { - if (last_type_id == 0) { // We haven't seen a type_id yet. Append this data to message_data. uint32 length; if (!input->ReadVarint32(&length)) return false; @@ -1836,11 +1824,9 @@ auto ptr = reinterpret_cast(&message_data[0]); ptr = io::CodedOutputStream::WriteVarint32ToArray(length, ptr); if (!input->ReadRaw(ptr, length)) return false; + state = State::kHasPayload; } else { + if (!ms.SkipField(tag, input)) return false; - // Already saw type_id, so we can parse this directly. - if (!ms.ParseField(last_type_id, input)) { - return false; - } } break;