1diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc 2index 9a448ffc8..40510b46c 100644 3--- a/src/google/protobuf/descriptor.cc 4+++ b/src/google/protobuf/descriptor.cc 5@@ -1090,7 +1090,7 @@ inline void DescriptorPool::Tables::FindAllExtensions( 6 7 bool DescriptorPool::Tables::AddSymbol(const std::string& full_name, 8 Symbol symbol) { 9- if (InsertIfNotPresent(&symbols_by_name_, full_name.c_str(), symbol)) { 10+ if (InsertIfNotPresent(&symbols_by_name_, full_name, symbol)) { 11 symbols_after_checkpoint_.push_back(full_name.c_str()); 12 return true; 13 } else { 14@@ -1106,7 +1106,7 @@ bool FileDescriptorTables::AddAliasUnderParent(const void* parent, 15 } 16 17 bool DescriptorPool::Tables::AddFile(const FileDescriptor* file) { 18- if (InsertIfNotPresent(&files_by_name_, file->name().c_str(), file)) { 19+ if (InsertIfNotPresent(&files_by_name_, file->name(), file)) { 20 files_after_checkpoint_.push_back(file->name().c_str()); 21 return true; 22 } else { 23@@ -2628,6 +2628,8 @@ void Descriptor::DebugString(int depth, std::string* contents, 24 const Descriptor::ReservedRange* range = reserved_range(i); 25 if (range->end == range->start + 1) { 26 strings::SubstituteAndAppend(contents, "$0, ", range->start); 27+ } else if (range->end > FieldDescriptor::kMaxNumber) { 28+ strings::SubstituteAndAppend(contents, "$0 to max, ", range->start); 29 } else { 30 strings::SubstituteAndAppend(contents, "$0 to $1, ", range->start, 31 range->end - 1); 32@@ -2831,6 +2833,8 @@ void EnumDescriptor::DebugString( 33 const EnumDescriptor::ReservedRange* range = reserved_range(i); 34 if (range->end == range->start) { 35 strings::SubstituteAndAppend(contents, "$0, ", range->start); 36+ } else if (range->end == INT_MAX) { 37+ strings::SubstituteAndAppend(contents, "$0 to max, ", range->start); 38 } else { 39 strings::SubstituteAndAppend(contents, "$0 to $1, ", range->start, 40 range->end); 41@@ -4022,6 +4026,12 @@ bool DescriptorBuilder::AddSymbol(const std::string& full_name, 42 // Use its file as the parent instead. 43 if (parent == nullptr) parent = file_; 44 45+ if (full_name.find('\0') != std::string::npos) { 46+ AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME, 47+ "\"" + full_name + "\" contains null character."); 48+ return false; 49+ } 50+ 51 if (tables_->AddSymbol(full_name, symbol)) { 52 if (!file_tables_->AddAliasUnderParent(parent, name, symbol)) { 53 // This is only possible if there was already an error adding something of 54@@ -4061,6 +4071,11 @@ bool DescriptorBuilder::AddSymbol(const std::string& full_name, 55 void DescriptorBuilder::AddPackage(const std::string& name, 56 const Message& proto, 57 const FileDescriptor* file) { 58+ if (name.find('\0') != std::string::npos) { 59+ AddError(name, proto, DescriptorPool::ErrorCollector::NAME, 60+ "\"" + name + "\" contains null character."); 61+ return; 62+ } 63 if (tables_->AddSymbol(name, Symbol(file))) { 64 // Success. Also add parent package, if any. 65 std::string::size_type dot_pos = name.find_last_of('.'); 66@@ -4374,6 +4389,12 @@ FileDescriptor* DescriptorBuilder::BuildFileImpl( 67 } 68 result->pool_ = pool_; 69 70+ if (result->name().find('\0') != std::string::npos) { 71+ AddError(result->name(), proto, DescriptorPool::ErrorCollector::NAME, 72+ "\"" + result->name() + "\" contains null character."); 73+ return nullptr; 74+ } 75+ 76 // Add to tables. 77 if (!tables_->AddFile(result)) { 78 AddError(proto.name(), proto, DescriptorPool::ErrorCollector::OTHER, 79diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc 80index 6085a122a..56c180aa4 100644 81--- a/src/google/protobuf/descriptor_unittest.cc 82+++ b/src/google/protobuf/descriptor_unittest.cc 83@@ -3786,6 +3786,45 @@ TEST_F(ValidationErrorTest, InvalidPackageName) { 84 "foo.proto: foo.$: NAME: \"$\" is not a valid identifier.\n"); 85 } 86 87+// 'str' is a static C-style string that may contain '\0' 88+#define STATIC_STR(str) std::string((str), sizeof(str) - 1) 89+ 90+TEST_F(ValidationErrorTest, NullCharSymbolName) { 91+ BuildFileWithErrors( 92+ "name: \"bar.proto\" " 93+ "package: \"foo\"" 94+ "message_type { " 95+ " name: '\\000\\001\\013.Bar' " 96+ " field { name: \"foo\" number: 9 label:LABEL_OPTIONAL type:TYPE_INT32 " 97+ "} " 98+ "}", 99+ STATIC_STR("bar.proto: foo.\0\x1\v.Bar: NAME: \"\0\x1\v.Bar\" is not a " 100+ "valid identifier.\nbar.proto: foo.\0\x1\v.Bar: NAME: " 101+ "\"\0\x1\v.Bar\" is not a valid identifier.\nbar.proto: " 102+ "foo.\0\x1\v.Bar: NAME: \"\0\x1\v.Bar\" is not a valid " 103+ "identifier.\nbar.proto: foo.\0\x1\v.Bar: NAME: " 104+ "\"\0\x1\v.Bar\" is not a valid identifier.\nbar.proto: " 105+ "foo.\0\x1\v.Bar.foo: NAME: \"foo.\0\x1\v.Bar.foo\" contains " 106+ "null character.\nbar.proto: foo.\0\x1\v.Bar: NAME: " 107+ "\"foo.\0\x1\v.Bar\" contains null character.\n")); 108+} 109+ 110+TEST_F(ValidationErrorTest, NullCharFileName) { 111+ BuildFileWithErrors( 112+ "name: \"bar\\000\\001\\013.proto\" " 113+ "package: \"outer.foo\"", 114+ STATIC_STR("bar\0\x1\v.proto: bar\0\x1\v.proto: NAME: " 115+ "\"bar\0\x1\v.proto\" contains null character.\n")); 116+} 117+ 118+TEST_F(ValidationErrorTest, NullCharPackageName) { 119+ BuildFileWithErrors( 120+ "name: \"bar.proto\" " 121+ "package: \"\\000\\001\\013.\"", 122+ STATIC_STR("bar.proto: \0\x1\v.: NAME: \"\0\x1\v.\" contains null " 123+ "character.\n")); 124+} 125+ 126 TEST_F(ValidationErrorTest, MissingFileName) { 127 BuildFileWithErrors("", 128 129@@ -4001,6 +4040,32 @@ TEST_F(ValidationErrorTest, ReservedFieldsDebugString) { 130 file->DebugString()); 131 } 132 133+TEST_F(ValidationErrorTest, DebugStringReservedRangeMax) { 134+ const FileDescriptor* file = BuildFile(strings::Substitute( 135+ "name: \"foo.proto\" " 136+ "enum_type { " 137+ " name: \"Bar\"" 138+ " value { name:\"BAR\" number:1 }" 139+ " reserved_range { start: 5 end: $0 }" 140+ "}" 141+ "message_type {" 142+ " name: \"Foo\"" 143+ " reserved_range { start: 5 end: $1 }" 144+ "}", 145+ std::numeric_limits<int>::max(), FieldDescriptor::kMaxNumber + 1)); 146+ 147+ ASSERT_EQ( 148+ "syntax = \"proto2\";\n\n" 149+ "enum Bar {\n" 150+ " BAR = 1;\n" 151+ " reserved 5 to max;\n" 152+ "}\n\n" 153+ "message Foo {\n" 154+ " reserved 5 to max;\n" 155+ "}\n\n", 156+ file->DebugString()); 157+} 158+ 159 TEST_F(ValidationErrorTest, EnumReservedFieldError) { 160 BuildFileWithErrors( 161 "name: \"foo.proto\" " 162 163 164