• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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