summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorantonyzhilin <[email protected]>2025-07-02 23:51:43 +0300
committerantonyzhilin <[email protected]>2025-07-03 00:45:25 +0300
commitd11200a4d35cc819df88cc5b06797babda5bd01b (patch)
tree7fb262a07c81fa979ba658ef3cb859563223c0a2
parentf55f9e065c15f97eeb86da5d6fe14e1ce6730a93 (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.patch134
-rw-r--r--contrib/libs/protobuf/src/google/protobuf/text_format.cc65
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(