Reject dependency and option_dependency containing null characters in C++ DescriptorPool `DescriptorBuilder::BuildFileImpl` validates that `FileDescriptorProto.name`, `package`, and symbol names do not contain embedded null characters (`'\0'`), but previously did not check `dependency` or `option_dependency`. As a result, `BuildFile` accepted `option_dependency` (and unknown/weak/lazy `dependency`) strings with embedded null characters, creating placeholder `FileDescriptor`s with null characters in their names or truncating/failing during lazy dependency initialization in `InternalDependenciesOnceInit`. PiperOrigin-RevId: 1000977826
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc index 742ac12..e0fe270 100644 --- a/src/google/protobuf/descriptor.cc +++ b/src/google/protobuf/descriptor.cc
@@ -5571,7 +5571,8 @@ i >= proto.dependency_size() ? proto.option_dependency(i - proto.dependency_size()) : proto.dependency(i); - if (tables_->FindFile(name) == nullptr && + if (!absl::StrContains(name, '\0') && + tables_->FindFile(name) == nullptr && (pool_->underlay_ == nullptr || pool_->underlay_->FindFileByName(name) == nullptr)) { // We don't care what this returns since we'll find out below anyway. @@ -5725,6 +5726,12 @@ absl::string_view name = is_option_dep ? proto.option_dependency(i - proto.dependency_size()) : proto.dependency(i); + if (absl::StrContains(name, '\0')) { + AddError(name, proto, DescriptorPool::ErrorCollector::IMPORT, [&] { + return absl::StrCat("\"", name, "\" contains null character."); + }); + return nullptr; + } if (!seen_dependencies.insert(name).second) { AddTwiceListedError(proto, name); }
diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc index 9cd95ef..eb3bb73 100644 --- a/src/google/protobuf/descriptor_unittest.cc +++ b/src/google/protobuf/descriptor_unittest.cc
@@ -5395,6 +5395,25 @@ "character.\n")); } +TEST_F(ValidationErrorTest, NullCharDependency) { + pool_.AllowUnknownDependencies(); + BuildFileWithErrors( + "name: \"bar.proto\" " + "dependency: \"foo\\000\\001\\013.proto\"", + STATIC_STR("bar.proto: foo\0\x1\v.proto: IMPORT: " + "\"foo\0\x1\v.proto\" contains null character.\n")); +} + +TEST_F(ValidationErrorTest, NullCharOptionDependency) { + BuildFileWithErrors( + "name: \"bar.proto\" " + "syntax: \"editions\" " + "edition: EDITION_2024 " + "option_dependency: \"foo\\000\\001\\013.proto\"", + STATIC_STR("bar.proto: foo\0\x1\v.proto: IMPORT: " + "\"foo\0\x1\v.proto\" contains null character.\n")); +} + TEST_F(ValidationErrorTest, MissingFileName) { BuildFileWithErrors("",