1616#include < vector>
1717
1818#include " absl/container/btree_set.h"
19+ #include " absl/container/flat_hash_set.h"
1920#include " absl/log/absl_check.h"
2021#include " absl/log/absl_log.h"
2122#include " absl/status/status.h"
@@ -70,11 +71,14 @@ using FieldDescriptorSet =
7071// Recursively searches the given message to collect extensions.
7172// Returns true if all the extensions can be recognized. The extensions will be
7273// appended in to the extensions parameter.
73- // Unknown extensions may be present in the case of option imports and will be
74- // ignored .
75- void CollectExtensions (const Message& message, FieldDescriptorSet* extensions) {
74+ // Returns false when there are unknown fields, in which case the data in the
75+ // extensions output parameter is not reliable and should be discarded .
76+ bool CollectExtensions (const Message& message, FieldDescriptorSet* extensions) {
7677 const Reflection* reflection = message.GetReflection ();
7778
79+ // There are unknown fields that could be extensions, thus this call fails.
80+ if (reflection->GetUnknownFields (message).field_count () > 0 ) return false ;
81+
7882 std::vector<const FieldDescriptor*> fields;
7983 reflection->ListFields (message, &fields);
8084
@@ -89,14 +93,25 @@ void CollectExtensions(const Message& message, FieldDescriptorSet* extensions) {
8993 for (int j = 0 ; j < size; j++) {
9094 const Message& sub_message =
9195 reflection->GetRepeatedMessage (message, fields[i], j);
92- CollectExtensions (sub_message, extensions);
96+ if (! CollectExtensions (sub_message, extensions)) return false ;
9397 }
9498 } else {
9599 const Message& sub_message = reflection->GetMessage (message, fields[i]);
96- CollectExtensions (sub_message, extensions);
100+ if (! CollectExtensions (sub_message, extensions)) return false ;
97101 }
98102 }
99103 }
104+
105+ return true ;
106+ }
107+
108+ void CollectPublicDependencies (
109+ const FileDescriptor* file,
110+ absl::flat_hash_set<const FileDescriptor*>* dependencies) {
111+ if (file == nullptr || !dependencies->insert (file).second ) return ;
112+ for (int i = 0 ; file != nullptr && i < file->public_dependency_count (); i++) {
113+ CollectPublicDependencies (file->public_dependency (i), dependencies);
114+ }
100115}
101116
102117// Finds all extensions for custom options in the given file descriptor with the
@@ -123,6 +138,20 @@ void CollectExtensions(const FileDescriptor& file,
123138 extensions->clear ();
124139 // Unknown extensions are ok and expected in the case of option imports.
125140 CollectExtensions (*dynamic_file_proto, extensions);
141+
142+ // TODO: Remove descriptor pool pollution from protoc full.
143+ // Check against dependencies to handle option dependencies polluting pool
144+ // from using protoc_full with built-in generators instead of plugins.
145+ // Option dependencies and transitive dependencies are not allowed, except in
146+ // the case of import public.
147+ absl::flat_hash_set<const FileDescriptor*> dependencies;
148+ dependencies.insert (&file);
149+ for (int i = 0 ; i < file.dependency_count (); i++) {
150+ CollectPublicDependencies (file.dependency (i), &dependencies);
151+ }
152+ absl::erase_if (*extensions, [&](const FieldDescriptor* fieldDescriptor) {
153+ return !dependencies.contains (fieldDescriptor->file ());
154+ });
126155}
127156
128157// Our static initialization methods can become very, very large.
0 commit comments