diff options
author | antonyzhilin <[email protected]> | 2025-07-02 23:51:43 +0300 |
---|---|---|
committer | antonyzhilin <[email protected]> | 2025-07-03 00:45:25 +0300 |
commit | d11200a4d35cc819df88cc5b06797babda5bd01b (patch) | |
tree | 7fb262a07c81fa979ba658ef3cb859563223c0a2 | |
parent | f55f9e065c15f97eeb86da5d6fe14e1ce6730a93 (diff) |
fix protobuf: backport "Use RAII instead of explicit delete."
This fixes a memory leak if a `ZeroCopyOutputStream` implementation throws.
https://github.com/protocolbuffers/protobuf/commit/be875d0aaf37dbe6948717ea621278e75e89c9c7
commit_hash:34bf698fbbb16786653d00e2106bedfcbbee6128
-rw-r--r-- | contrib/libs/protobuf/patches/text-format-print-field-raii.patch | 134 | ||||
-rw-r--r-- | contrib/libs/protobuf/src/google/protobuf/text_format.cc | 65 |
2 files changed, 167 insertions, 32 deletions
diff --git a/contrib/libs/protobuf/patches/text-format-print-field-raii.patch b/contrib/libs/protobuf/patches/text-format-print-field-raii.patch new file mode 100644 index 00000000000..8ceb28835b6 --- /dev/null +++ b/contrib/libs/protobuf/patches/text-format-print-field-raii.patch @@ -0,0 +1,134 @@ +--- a/contrib/libs/protobuf/src/google/protobuf/text_format.cc (revision 0aeb3fd964b80cb80d7b17e28f06b65f974da75a) ++++ b/contrib/libs/protobuf/src/google/protobuf/text_format.cc (date 1751482029353) +@@ -47,6 +47,7 @@ + #include <vector> + + #include "y_absl/container/btree_set.h" ++#include "y_absl/memory/memory.h" + #include "y_absl/strings/ascii.h" + #include "y_absl/strings/escaping.h" + #include "y_absl/strings/numbers.h" +@@ -2341,32 +2342,38 @@ + }; + + namespace internal { ++ ++struct MapEntries { ++ std::vector<std::unique_ptr<const Message>> owned_entries; ++ std::vector<const Message*> all_entries; ++}; ++ + class MapFieldPrinterHelper { + public: + // DynamicMapSorter::Sort cannot be used because it enforces syncing with + // repeated field. +- static bool SortMap(const Message& message, const Reflection* reflection, +- const FieldDescriptor* field, +- std::vector<const Message*>* sorted_map_field); ++ static MapEntries SortMap(const Message& message, ++ const Reflection* reflection, ++ const FieldDescriptor* field); + static void CopyKey(const MapKey& key, Message* message, + const FieldDescriptor* field_desc); + static void CopyValue(const MapValueRef& value, Message* message, + const FieldDescriptor* field_desc); + }; + +-// Returns true if elements contained in sorted_map_field need to be released. +-bool MapFieldPrinterHelper::SortMap( +- const Message& message, const Reflection* reflection, +- const FieldDescriptor* field, +- std::vector<const Message*>* sorted_map_field) { +- bool need_release = false; ++MapEntries MapFieldPrinterHelper::SortMap(const Message& message, ++ const Reflection* reflection, ++ const FieldDescriptor* field) { + const MapFieldBase& base = *reflection->GetMapData(message, field); + ++ std::vector<const Message*> all_entries; ++ std::vector<std::unique_ptr<const Message>> owned_entries; + if (base.IsRepeatedFieldValid()) { + const RepeatedPtrField<Message>& map_field = + reflection->GetRepeatedPtrFieldInternal<Message>(message, field); ++ all_entries.reserve(map_field.size()); + for (int i = 0; i < map_field.size(); ++i) { +- sorted_map_field->push_back( ++ all_entries.push_back( + const_cast<RepeatedPtrField<Message>*>(&map_field)->Mutable(i)); + } + } else { +@@ -2375,23 +2382,25 @@ + const Descriptor* map_entry_desc = field->message_type(); + const Message* prototype = + reflection->GetMessageFactory()->GetPrototype(map_entry_desc); ++ all_entries.reserve(reflection->MapSize(message, field)); ++ owned_entries.reserve(reflection->MapSize(message, field)); + for (MapIterator iter = + reflection->MapBegin(const_cast<Message*>(&message), field); + iter != reflection->MapEnd(const_cast<Message*>(&message), field); + ++iter) { +- Message* map_entry_message = prototype->New(); +- CopyKey(iter.GetKey(), map_entry_message, map_entry_desc->field(0)); +- CopyValue(iter.GetValueRef(), map_entry_message, ++ std::unique_ptr<Message> map_entry_message = ++ y_absl::WrapUnique(prototype->New()); ++ CopyKey(iter.GetKey(), map_entry_message.get(), map_entry_desc->field(0)); ++ CopyValue(iter.GetValueRef(), map_entry_message.get(), + map_entry_desc->field(1)); +- sorted_map_field->push_back(map_entry_message); ++ all_entries.push_back(map_entry_message.get()); ++ owned_entries.push_back(std::move(map_entry_message)); + } +- need_release = true; + } + +- MapEntryMessageComparator comparator(field->message_type()); +- std::stable_sort(sorted_map_field->begin(), sorted_map_field->end(), +- comparator); +- return need_release; ++ std::stable_sort(all_entries.begin(), all_entries.end(), ++ MapEntryMessageComparator(field->message_type())); ++ return {std::move(owned_entries), std::move(all_entries)}; + } + + void MapFieldPrinterHelper::CopyKey(const MapKey& key, Message* message, +@@ -2487,13 +2496,11 @@ + count = 1; + } + +- std::vector<const Message*> sorted_map_field; +- bool need_release = false; + bool is_map = field->is_map(); +- if (is_map) { +- need_release = internal::MapFieldPrinterHelper::SortMap( +- message, reflection, field, &sorted_map_field); +- } ++ const internal::MapEntries map_entries = ++ is_map ++ ? internal::MapFieldPrinterHelper::SortMap(message, reflection, field) ++ : internal::MapEntries(); + + for (int j = 0; j < count; ++j) { + const int field_index = field->is_repeated() ? j : -1; +@@ -2504,7 +2511,7 @@ + const FastFieldValuePrinter* printer = GetFieldPrinter(field); + const Message& sub_message = + field->is_repeated() +- ? (is_map ? *sorted_map_field[j] ++ ? (is_map ? *map_entries.all_entries[j] + : reflection->GetRepeatedMessage(message, field, j)) + : reflection->GetMessage(message, field); + printer->PrintMessageStart(sub_message, field_index, count, +@@ -2528,12 +2535,6 @@ + } + } + } +- +- if (need_release) { +- for (const Message* message_to_delete : sorted_map_field) { +- delete message_to_delete; +- } +- } + } + + void TextFormat::Printer::PrintShortRepeatedField( diff --git a/contrib/libs/protobuf/src/google/protobuf/text_format.cc b/contrib/libs/protobuf/src/google/protobuf/text_format.cc index 3355d1d3db6..5ec37f1e3ee 100644 --- a/contrib/libs/protobuf/src/google/protobuf/text_format.cc +++ b/contrib/libs/protobuf/src/google/protobuf/text_format.cc @@ -47,6 +47,7 @@ #include <vector> #include "y_absl/container/btree_set.h" +#include "y_absl/memory/memory.h" #include "y_absl/strings/ascii.h" #include "y_absl/strings/escaping.h" #include "y_absl/strings/numbers.h" @@ -2341,32 +2342,38 @@ class MapEntryMessageComparator { }; namespace internal { + +struct MapEntries { + std::vector<std::unique_ptr<const Message>> owned_entries; + std::vector<const Message*> all_entries; +}; + class MapFieldPrinterHelper { public: // DynamicMapSorter::Sort cannot be used because it enforces syncing with // repeated field. - static bool SortMap(const Message& message, const Reflection* reflection, - const FieldDescriptor* field, - std::vector<const Message*>* sorted_map_field); + static MapEntries SortMap(const Message& message, + const Reflection* reflection, + const FieldDescriptor* field); static void CopyKey(const MapKey& key, Message* message, const FieldDescriptor* field_desc); static void CopyValue(const MapValueRef& value, Message* message, const FieldDescriptor* field_desc); }; -// Returns true if elements contained in sorted_map_field need to be released. -bool MapFieldPrinterHelper::SortMap( - const Message& message, const Reflection* reflection, - const FieldDescriptor* field, - std::vector<const Message*>* sorted_map_field) { - bool need_release = false; +MapEntries MapFieldPrinterHelper::SortMap(const Message& message, + const Reflection* reflection, + const FieldDescriptor* field) { const MapFieldBase& base = *reflection->GetMapData(message, field); + std::vector<const Message*> all_entries; + std::vector<std::unique_ptr<const Message>> owned_entries; if (base.IsRepeatedFieldValid()) { const RepeatedPtrField<Message>& map_field = reflection->GetRepeatedPtrFieldInternal<Message>(message, field); + all_entries.reserve(map_field.size()); for (int i = 0; i < map_field.size(); ++i) { - sorted_map_field->push_back( + all_entries.push_back( const_cast<RepeatedPtrField<Message>*>(&map_field)->Mutable(i)); } } else { @@ -2375,23 +2382,25 @@ bool MapFieldPrinterHelper::SortMap( const Descriptor* map_entry_desc = field->message_type(); const Message* prototype = reflection->GetMessageFactory()->GetPrototype(map_entry_desc); + all_entries.reserve(reflection->MapSize(message, field)); + owned_entries.reserve(reflection->MapSize(message, field)); for (MapIterator iter = reflection->MapBegin(const_cast<Message*>(&message), field); iter != reflection->MapEnd(const_cast<Message*>(&message), field); ++iter) { - Message* map_entry_message = prototype->New(); - CopyKey(iter.GetKey(), map_entry_message, map_entry_desc->field(0)); - CopyValue(iter.GetValueRef(), map_entry_message, + std::unique_ptr<Message> map_entry_message = + y_absl::WrapUnique(prototype->New()); + CopyKey(iter.GetKey(), map_entry_message.get(), map_entry_desc->field(0)); + CopyValue(iter.GetValueRef(), map_entry_message.get(), map_entry_desc->field(1)); - sorted_map_field->push_back(map_entry_message); + all_entries.push_back(map_entry_message.get()); + owned_entries.push_back(std::move(map_entry_message)); } - need_release = true; } - MapEntryMessageComparator comparator(field->message_type()); - std::stable_sort(sorted_map_field->begin(), sorted_map_field->end(), - comparator); - return need_release; + std::stable_sort(all_entries.begin(), all_entries.end(), + MapEntryMessageComparator(field->message_type())); + return {std::move(owned_entries), std::move(all_entries)}; } void MapFieldPrinterHelper::CopyKey(const MapKey& key, Message* message, @@ -2487,13 +2496,11 @@ void TextFormat::Printer::PrintField(const Message& message, count = 1; } - std::vector<const Message*> sorted_map_field; - bool need_release = false; bool is_map = field->is_map(); - if (is_map) { - need_release = internal::MapFieldPrinterHelper::SortMap( - message, reflection, field, &sorted_map_field); - } + const internal::MapEntries map_entries = + is_map + ? internal::MapFieldPrinterHelper::SortMap(message, reflection, field) + : internal::MapEntries(); for (int j = 0; j < count; ++j) { const int field_index = field->is_repeated() ? j : -1; @@ -2504,7 +2511,7 @@ void TextFormat::Printer::PrintField(const Message& message, const FastFieldValuePrinter* printer = GetFieldPrinter(field); const Message& sub_message = field->is_repeated() - ? (is_map ? *sorted_map_field[j] + ? (is_map ? *map_entries.all_entries[j] : reflection->GetRepeatedMessage(message, field, j)) : reflection->GetMessage(message, field); printer->PrintMessageStart(sub_message, field_index, count, @@ -2528,12 +2535,6 @@ void TextFormat::Printer::PrintField(const Message& message, } } } - - if (need_release) { - for (const Message* message_to_delete : sorted_map_field) { - delete message_to_delete; - } - } } void TextFormat::Printer::PrintShortRepeatedField( |