1 // Copyright 2019 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4 5 package protodesc
6 7 import (
8 "strings"
9 "unicode"
10 11 "google.golang.org/protobuf/encoding/protowire"
12 "google.golang.org/protobuf/internal/errors"
13 "google.golang.org/protobuf/internal/filedesc"
14 "google.golang.org/protobuf/internal/flags"
15 "google.golang.org/protobuf/internal/genid"
16 "google.golang.org/protobuf/internal/strs"
17 "google.golang.org/protobuf/reflect/protoreflect"
18 19 "google.golang.org/protobuf/types/descriptorpb"
20 )
21 22 func validateEnumDeclarations(es []filedesc.Enum, eds []*descriptorpb.EnumDescriptorProto) error {
23 for i, ed := range eds {
24 e := &es[i]
25 if err := e.L2.ReservedNames.CheckValid(); err != nil {
26 return errors.New("enum %q reserved names has %v", e.FullName(), err)
27 }
28 if err := e.L2.ReservedRanges.CheckValid(); err != nil {
29 return errors.New("enum %q reserved ranges has %v", e.FullName(), err)
30 }
31 if len(ed.GetValue()) == 0 {
32 return errors.New("enum %q must contain at least one value declaration", e.FullName())
33 }
34 allowAlias := ed.GetOptions().GetAllowAlias()
35 foundAlias := false
36 for i := 0; i < e.Values().Len(); i++ {
37 v1 := e.Values().Get(i)
38 if v2 := e.Values().ByNumber(v1.Number()); v1 != v2 {
39 foundAlias = true
40 if !allowAlias {
41 return errors.New("enum %q has conflicting non-aliased values on number %d: %q with %q", e.FullName(), v1.Number(), v1.Name(), v2.Name())
42 }
43 }
44 }
45 if allowAlias && !foundAlias {
46 return errors.New("enum %q allows aliases, but none were found", e.FullName())
47 }
48 if !e.IsClosed() {
49 if v := e.Values().Get(0); v.Number() != 0 {
50 return errors.New("enum %q using open semantics must have zero number for the first value", v.FullName())
51 }
52 // Verify that value names in open enums do not conflict if the
53 // case-insensitive prefix is removed.
54 // See protoc v3.8.0: src/google/protobuf/descriptor.cc:4991-5055
55 names := map[string]protoreflect.EnumValueDescriptor{}
56 prefix := strings.Replace(strings.ToLower(string(e.Name())), "_", "", -1)
57 for i := 0; i < e.Values().Len(); i++ {
58 v1 := e.Values().Get(i)
59 s := strs.EnumValueName(strs.TrimEnumPrefix(string(v1.Name()), prefix))
60 if v2, ok := names[s]; ok && v1.Number() != v2.Number() {
61 return errors.New("enum %q using open semantics has conflict: %q with %q", e.FullName(), v1.Name(), v2.Name())
62 }
63 names[s] = v1
64 }
65 }
66 67 for j, vd := range ed.GetValue() {
68 v := &e.L2.Values.List[j]
69 if vd.Number == nil {
70 return errors.New("enum value %q must have a specified number", v.FullName())
71 }
72 if e.L2.ReservedNames.Has(v.Name()) {
73 return errors.New("enum value %q must not use reserved name", v.FullName())
74 }
75 if e.L2.ReservedRanges.Has(v.Number()) {
76 return errors.New("enum value %q must not use reserved number %d", v.FullName(), v.Number())
77 }
78 }
79 }
80 return nil
81 }
82 83 func validateMessageDeclarations(file *filedesc.File, ms []filedesc.Message, mds []*descriptorpb.DescriptorProto) error {
84 // There are a few limited exceptions only for proto3
85 isProto3 := file.L1.Edition == fromEditionProto(descriptorpb.Edition_EDITION_PROTO3)
86 for i, md := range mds {
87 m := &ms[i]
88 89 // Handle the message descriptor itself.
90 isMessageSet := md.GetOptions().GetMessageSetWireFormat()
91 if err := m.L2.ReservedNames.CheckValid(); err != nil {
92 return errors.New("message %q reserved names has %v", m.FullName(), err)
93 }
94 if err := m.L2.ReservedRanges.CheckValid(isMessageSet); err != nil {
95 return errors.New("message %q reserved ranges has %v", m.FullName(), err)
96 }
97 if err := m.L2.ExtensionRanges.CheckValid(isMessageSet); err != nil {
98 return errors.New("message %q extension ranges has %v", m.FullName(), err)
99 }
100 if err := (*filedesc.FieldRanges).CheckOverlap(&m.L2.ReservedRanges, &m.L2.ExtensionRanges); err != nil {
101 return errors.New("message %q reserved and extension ranges has %v", m.FullName(), err)
102 }
103 for i := 0; i < m.Fields().Len(); i++ {
104 f1 := m.Fields().Get(i)
105 if f2 := m.Fields().ByNumber(f1.Number()); f1 != f2 {
106 return errors.New("message %q has conflicting fields: %q with %q", m.FullName(), f1.Name(), f2.Name())
107 }
108 }
109 if isMessageSet && !flags.ProtoLegacy {
110 return errors.New("message %q is a MessageSet, which is a legacy proto1 feature that is no longer supported", m.FullName())
111 }
112 if isMessageSet && (isProto3 || m.Fields().Len() > 0 || m.ExtensionRanges().Len() == 0) {
113 return errors.New("message %q is an invalid proto1 MessageSet", m.FullName())
114 }
115 if isProto3 {
116 if m.ExtensionRanges().Len() > 0 {
117 return errors.New("message %q using proto3 semantics cannot have extension ranges", m.FullName())
118 }
119 }
120 121 for j, fd := range md.GetField() {
122 f := &m.L2.Fields.List[j]
123 if m.L2.ReservedNames.Has(f.Name()) {
124 return errors.New("message field %q must not use reserved name", f.FullName())
125 }
126 if !f.Number().IsValid() {
127 return errors.New("message field %q has an invalid number: %d", f.FullName(), f.Number())
128 }
129 if !f.Cardinality().IsValid() {
130 return errors.New("message field %q has an invalid cardinality: %d", f.FullName(), f.Cardinality())
131 }
132 if m.L2.ReservedRanges.Has(f.Number()) {
133 return errors.New("message field %q must not use reserved number %d", f.FullName(), f.Number())
134 }
135 if m.L2.ExtensionRanges.Has(f.Number()) {
136 return errors.New("message field %q with number %d in extension range", f.FullName(), f.Number())
137 }
138 if fd.Extendee != nil {
139 return errors.New("message field %q may not have extendee: %q", f.FullName(), fd.GetExtendee())
140 }
141 if f.L1.IsProto3Optional {
142 if !isProto3 {
143 return errors.New("message field %q under proto3 optional semantics must be specified in the proto3 syntax", f.FullName())
144 }
145 if f.Cardinality() != protoreflect.Optional {
146 return errors.New("message field %q under proto3 optional semantics must have optional cardinality", f.FullName())
147 }
148 if f.ContainingOneof() != nil && f.ContainingOneof().Fields().Len() != 1 {
149 return errors.New("message field %q under proto3 optional semantics must be within a single element oneof", f.FullName())
150 }
151 }
152 if f.IsPacked() && !isPackable(f) {
153 return errors.New("message field %q is not packable", f.FullName())
154 }
155 if err := checkValidGroup(file, f); err != nil {
156 return errors.New("message field %q is an invalid group: %v", f.FullName(), err)
157 }
158 if err := checkValidMap(f); err != nil {
159 return errors.New("message field %q is an invalid map: %v", f.FullName(), err)
160 }
161 if isProto3 {
162 if f.Cardinality() == protoreflect.Required {
163 return errors.New("message field %q using proto3 semantics cannot be required", f.FullName())
164 }
165 if f.Enum() != nil && !f.Enum().IsPlaceholder() && f.Enum().IsClosed() {
166 return errors.New("message field %q using proto3 semantics may only depend on open enums", f.FullName())
167 }
168 }
169 if f.Cardinality() == protoreflect.Optional && !f.HasPresence() && f.Enum() != nil && !f.Enum().IsPlaceholder() && f.Enum().IsClosed() {
170 return errors.New("message field %q with implicit presence may only use open enums", f.FullName())
171 }
172 }
173 seenSynthetic := false // synthetic oneofs for proto3 optional must come after real oneofs
174 for j := range md.GetOneofDecl() {
175 o := &m.L2.Oneofs.List[j]
176 if o.Fields().Len() == 0 {
177 return errors.New("message oneof %q must contain at least one field declaration", o.FullName())
178 }
179 if n := o.Fields().Len(); n-1 != (o.Fields().Get(n-1).Index() - o.Fields().Get(0).Index()) {
180 return errors.New("message oneof %q must have consecutively declared fields", o.FullName())
181 }
182 183 if o.IsSynthetic() {
184 seenSynthetic = true
185 continue
186 }
187 if !o.IsSynthetic() && seenSynthetic {
188 return errors.New("message oneof %q must be declared before synthetic oneofs", o.FullName())
189 }
190 191 for i := 0; i < o.Fields().Len(); i++ {
192 f := o.Fields().Get(i)
193 if f.Cardinality() != protoreflect.Optional {
194 return errors.New("message field %q belongs in a oneof and must be optional", f.FullName())
195 }
196 }
197 }
198 199 if err := validateEnumDeclarations(m.L1.Enums.List, md.GetEnumType()); err != nil {
200 return err
201 }
202 if err := validateMessageDeclarations(file, m.L1.Messages.List, md.GetNestedType()); err != nil {
203 return err
204 }
205 if err := validateExtensionDeclarations(file, m.L1.Extensions.List, md.GetExtension()); err != nil {
206 return err
207 }
208 }
209 return nil
210 }
211 212 func validateExtensionDeclarations(f *filedesc.File, xs []filedesc.Extension, xds []*descriptorpb.FieldDescriptorProto) error {
213 for i, xd := range xds {
214 x := &xs[i]
215 // NOTE: Avoid using the IsValid method since extensions to MessageSet
216 // may have a field number higher than normal. This check only verifies
217 // that the number is not negative or reserved. We check again later
218 // if we know that the extendee is definitely not a MessageSet.
219 if n := x.Number(); n < 0 || (protowire.FirstReservedNumber <= n && n <= protowire.LastReservedNumber) {
220 return errors.New("extension field %q has an invalid number: %d", x.FullName(), x.Number())
221 }
222 if !x.Cardinality().IsValid() || x.Cardinality() == protoreflect.Required {
223 return errors.New("extension field %q has an invalid cardinality: %d", x.FullName(), x.Cardinality())
224 }
225 if xd.JsonName != nil {
226 // A bug in older versions of protoc would always populate the
227 // "json_name" option for extensions when it is meaningless.
228 // When it did so, it would always use the camel-cased field name.
229 if xd.GetJsonName() != strs.JSONCamelCase(string(x.Name())) {
230 return errors.New("extension field %q may not have an explicitly set JSON name: %q", x.FullName(), xd.GetJsonName())
231 }
232 }
233 if xd.OneofIndex != nil {
234 return errors.New("extension field %q may not be part of a oneof", x.FullName())
235 }
236 if md := x.ContainingMessage(); !md.IsPlaceholder() {
237 if !md.ExtensionRanges().Has(x.Number()) {
238 return errors.New("extension field %q extends %q with non-extension field number: %d", x.FullName(), md.FullName(), x.Number())
239 }
240 isMessageSet := md.Options().(*descriptorpb.MessageOptions).GetMessageSetWireFormat()
241 if isMessageSet && !isOptionalMessage(x) {
242 return errors.New("extension field %q extends MessageSet and must be an optional message", x.FullName())
243 }
244 if !isMessageSet && !x.Number().IsValid() {
245 return errors.New("extension field %q has an invalid number: %d", x.FullName(), x.Number())
246 }
247 }
248 if x.IsPacked() && !isPackable(x) {
249 return errors.New("extension field %q is not packable", x.FullName())
250 }
251 if err := checkValidGroup(f, x); err != nil {
252 return errors.New("extension field %q is an invalid group: %v", x.FullName(), err)
253 }
254 if md := x.Message(); md != nil && md.IsMapEntry() {
255 return errors.New("extension field %q cannot be a map entry", x.FullName())
256 }
257 if f.L1.Edition == fromEditionProto(descriptorpb.Edition_EDITION_PROTO3) {
258 switch x.ContainingMessage().FullName() {
259 case (*descriptorpb.FileOptions)(nil).ProtoReflect().Descriptor().FullName():
260 case (*descriptorpb.EnumOptions)(nil).ProtoReflect().Descriptor().FullName():
261 case (*descriptorpb.EnumValueOptions)(nil).ProtoReflect().Descriptor().FullName():
262 case (*descriptorpb.MessageOptions)(nil).ProtoReflect().Descriptor().FullName():
263 case (*descriptorpb.FieldOptions)(nil).ProtoReflect().Descriptor().FullName():
264 case (*descriptorpb.OneofOptions)(nil).ProtoReflect().Descriptor().FullName():
265 case (*descriptorpb.ExtensionRangeOptions)(nil).ProtoReflect().Descriptor().FullName():
266 case (*descriptorpb.ServiceOptions)(nil).ProtoReflect().Descriptor().FullName():
267 case (*descriptorpb.MethodOptions)(nil).ProtoReflect().Descriptor().FullName():
268 default:
269 return errors.New("extension field %q cannot be declared in proto3 unless extended descriptor options", x.FullName())
270 }
271 }
272 }
273 return nil
274 }
275 276 // isOptionalMessage reports whether this is an optional message.
277 // If the kind is unknown, it is assumed to be a message.
278 func isOptionalMessage(fd protoreflect.FieldDescriptor) bool {
279 return (fd.Kind() == 0 || fd.Kind() == protoreflect.MessageKind) && fd.Cardinality() == protoreflect.Optional
280 }
281 282 // isPackable checks whether the pack option can be specified.
283 func isPackable(fd protoreflect.FieldDescriptor) bool {
284 switch fd.Kind() {
285 case protoreflect.StringKind, protoreflect.BytesKind, protoreflect.MessageKind, protoreflect.GroupKind:
286 return false
287 }
288 return fd.IsList()
289 }
290 291 // checkValidGroup reports whether fd is a valid group according to the same
292 // rules that protoc imposes.
293 func checkValidGroup(f *filedesc.File, fd protoreflect.FieldDescriptor) error {
294 md := fd.Message()
295 switch {
296 case fd.Kind() != protoreflect.GroupKind:
297 return nil
298 case f.L1.Edition == fromEditionProto(descriptorpb.Edition_EDITION_PROTO3):
299 return errors.New("invalid under proto3 semantics")
300 case md == nil || md.IsPlaceholder():
301 return errors.New("message must be resolvable")
302 }
303 if f.L1.Edition < fromEditionProto(descriptorpb.Edition_EDITION_2023) {
304 switch {
305 case fd.FullName().Parent() != md.FullName().Parent():
306 return errors.New("message and field must be declared in the same scope")
307 case !unicode.IsUpper(rune(md.Name()[0])):
308 return errors.New("message name must start with an uppercase")
309 case fd.Name() != protoreflect.Name(strings.ToLower(string(md.Name()))):
310 return errors.New("field name must be lowercased form of the message name")
311 }
312 }
313 return nil
314 }
315 316 // checkValidMap checks whether the field is a valid map according to the same
317 // rules that protoc imposes.
318 // See protoc v3.8.0: src/google/protobuf/descriptor.cc:6045-6115
319 func checkValidMap(fd protoreflect.FieldDescriptor) error {
320 md := fd.Message()
321 switch {
322 case md == nil || !md.IsMapEntry():
323 return nil
324 case fd.FullName().Parent() != md.FullName().Parent():
325 return errors.New("message and field must be declared in the same scope")
326 case md.Name() != protoreflect.Name(strs.MapEntryName(string(fd.Name()))):
327 return errors.New("incorrect implicit map entry name")
328 case fd.Cardinality() != protoreflect.Repeated:
329 return errors.New("field must be repeated")
330 case md.Fields().Len() != 2:
331 return errors.New("message must have exactly two fields")
332 case md.ExtensionRanges().Len() > 0:
333 return errors.New("message must not have any extension ranges")
334 case md.Enums().Len()+md.Messages().Len()+md.Extensions().Len() > 0:
335 return errors.New("message must not have any nested declarations")
336 }
337 kf := md.Fields().Get(0)
338 vf := md.Fields().Get(1)
339 switch {
340 case kf.Name() != genid.MapEntry_Key_field_name || kf.Number() != genid.MapEntry_Key_field_number || kf.Cardinality() != protoreflect.Optional || kf.ContainingOneof() != nil || kf.HasDefault():
341 return errors.New("invalid key field")
342 case vf.Name() != genid.MapEntry_Value_field_name || vf.Number() != genid.MapEntry_Value_field_number || vf.Cardinality() != protoreflect.Optional || vf.ContainingOneof() != nil || vf.HasDefault():
343 return errors.New("invalid value field")
344 }
345 switch kf.Kind() {
346 case protoreflect.BoolKind: // bool
347 case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: // int32
348 case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: // int64
349 case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: // uint32
350 case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: // uint64
351 case protoreflect.StringKind: // string
352 default:
353 return errors.New("invalid key kind: %v", kf.Kind())
354 }
355 if e := vf.Enum(); e != nil && e.Values().Len() > 0 && e.Values().Get(0).Number() != 0 {
356 return errors.New("map enum value must have zero number for the first value")
357 }
358 return nil
359 }
360