desc_validate.go (16546B)
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.Syntax() == protoreflect.Proto3 { 49 if v := e.Values().Get(0); v.Number() != 0 { 50 return errors.New("enum %q using proto3 semantics must have zero number for the first value", v.FullName()) 51 } 52 // Verify that value names in proto3 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 proto3 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(ms []filedesc.Message, mds []*descriptorpb.DescriptorProto) error { 84 for i, md := range mds { 85 m := &ms[i] 86 87 // Handle the message descriptor itself. 88 isMessageSet := md.GetOptions().GetMessageSetWireFormat() 89 if err := m.L2.ReservedNames.CheckValid(); err != nil { 90 return errors.New("message %q reserved names has %v", m.FullName(), err) 91 } 92 if err := m.L2.ReservedRanges.CheckValid(isMessageSet); err != nil { 93 return errors.New("message %q reserved ranges has %v", m.FullName(), err) 94 } 95 if err := m.L2.ExtensionRanges.CheckValid(isMessageSet); err != nil { 96 return errors.New("message %q extension ranges has %v", m.FullName(), err) 97 } 98 if err := (*filedesc.FieldRanges).CheckOverlap(&m.L2.ReservedRanges, &m.L2.ExtensionRanges); err != nil { 99 return errors.New("message %q reserved and extension ranges has %v", m.FullName(), err) 100 } 101 for i := 0; i < m.Fields().Len(); i++ { 102 f1 := m.Fields().Get(i) 103 if f2 := m.Fields().ByNumber(f1.Number()); f1 != f2 { 104 return errors.New("message %q has conflicting fields: %q with %q", m.FullName(), f1.Name(), f2.Name()) 105 } 106 } 107 if isMessageSet && !flags.ProtoLegacy { 108 return errors.New("message %q is a MessageSet, which is a legacy proto1 feature that is no longer supported", m.FullName()) 109 } 110 if isMessageSet && (m.Syntax() != protoreflect.Proto2 || m.Fields().Len() > 0 || m.ExtensionRanges().Len() == 0) { 111 return errors.New("message %q is an invalid proto1 MessageSet", m.FullName()) 112 } 113 if m.Syntax() == protoreflect.Proto3 { 114 if m.ExtensionRanges().Len() > 0 { 115 return errors.New("message %q using proto3 semantics cannot have extension ranges", m.FullName()) 116 } 117 // Verify that field names in proto3 do not conflict if lowercased 118 // with all underscores removed. 119 // See protoc v3.8.0: src/google/protobuf/descriptor.cc:5830-5847 120 names := map[string]protoreflect.FieldDescriptor{} 121 for i := 0; i < m.Fields().Len(); i++ { 122 f1 := m.Fields().Get(i) 123 s := strings.Replace(strings.ToLower(string(f1.Name())), "_", "", -1) 124 if f2, ok := names[s]; ok { 125 return errors.New("message %q using proto3 semantics has conflict: %q with %q", m.FullName(), f1.Name(), f2.Name()) 126 } 127 names[s] = f1 128 } 129 } 130 131 for j, fd := range md.GetField() { 132 f := &m.L2.Fields.List[j] 133 if m.L2.ReservedNames.Has(f.Name()) { 134 return errors.New("message field %q must not use reserved name", f.FullName()) 135 } 136 if !f.Number().IsValid() { 137 return errors.New("message field %q has an invalid number: %d", f.FullName(), f.Number()) 138 } 139 if !f.Cardinality().IsValid() { 140 return errors.New("message field %q has an invalid cardinality: %d", f.FullName(), f.Cardinality()) 141 } 142 if m.L2.ReservedRanges.Has(f.Number()) { 143 return errors.New("message field %q must not use reserved number %d", f.FullName(), f.Number()) 144 } 145 if m.L2.ExtensionRanges.Has(f.Number()) { 146 return errors.New("message field %q with number %d in extension range", f.FullName(), f.Number()) 147 } 148 if fd.Extendee != nil { 149 return errors.New("message field %q may not have extendee: %q", f.FullName(), fd.GetExtendee()) 150 } 151 if f.L1.IsProto3Optional { 152 if f.Syntax() != protoreflect.Proto3 { 153 return errors.New("message field %q under proto3 optional semantics must be specified in the proto3 syntax", f.FullName()) 154 } 155 if f.Cardinality() != protoreflect.Optional { 156 return errors.New("message field %q under proto3 optional semantics must have optional cardinality", f.FullName()) 157 } 158 if f.ContainingOneof() != nil && f.ContainingOneof().Fields().Len() != 1 { 159 return errors.New("message field %q under proto3 optional semantics must be within a single element oneof", f.FullName()) 160 } 161 } 162 if f.IsWeak() && !flags.ProtoLegacy { 163 return errors.New("message field %q is a weak field, which is a legacy proto1 feature that is no longer supported", f.FullName()) 164 } 165 if f.IsWeak() && (f.Syntax() != protoreflect.Proto2 || !isOptionalMessage(f) || f.ContainingOneof() != nil) { 166 return errors.New("message field %q may only be weak for an optional message", f.FullName()) 167 } 168 if f.IsPacked() && !isPackable(f) { 169 return errors.New("message field %q is not packable", f.FullName()) 170 } 171 if err := checkValidGroup(f); err != nil { 172 return errors.New("message field %q is an invalid group: %v", f.FullName(), err) 173 } 174 if err := checkValidMap(f); err != nil { 175 return errors.New("message field %q is an invalid map: %v", f.FullName(), err) 176 } 177 if f.Syntax() == protoreflect.Proto3 { 178 if f.Cardinality() == protoreflect.Required { 179 return errors.New("message field %q using proto3 semantics cannot be required", f.FullName()) 180 } 181 if f.Enum() != nil && !f.Enum().IsPlaceholder() && f.Enum().Syntax() != protoreflect.Proto3 { 182 return errors.New("message field %q using proto3 semantics may only depend on a proto3 enum", f.FullName()) 183 } 184 } 185 } 186 seenSynthetic := false // synthetic oneofs for proto3 optional must come after real oneofs 187 for j := range md.GetOneofDecl() { 188 o := &m.L2.Oneofs.List[j] 189 if o.Fields().Len() == 0 { 190 return errors.New("message oneof %q must contain at least one field declaration", o.FullName()) 191 } 192 if n := o.Fields().Len(); n-1 != (o.Fields().Get(n-1).Index() - o.Fields().Get(0).Index()) { 193 return errors.New("message oneof %q must have consecutively declared fields", o.FullName()) 194 } 195 196 if o.IsSynthetic() { 197 seenSynthetic = true 198 continue 199 } 200 if !o.IsSynthetic() && seenSynthetic { 201 return errors.New("message oneof %q must be declared before synthetic oneofs", o.FullName()) 202 } 203 204 for i := 0; i < o.Fields().Len(); i++ { 205 f := o.Fields().Get(i) 206 if f.Cardinality() != protoreflect.Optional { 207 return errors.New("message field %q belongs in a oneof and must be optional", f.FullName()) 208 } 209 if f.IsWeak() { 210 return errors.New("message field %q belongs in a oneof and must not be a weak reference", f.FullName()) 211 } 212 } 213 } 214 215 if err := validateEnumDeclarations(m.L1.Enums.List, md.GetEnumType()); err != nil { 216 return err 217 } 218 if err := validateMessageDeclarations(m.L1.Messages.List, md.GetNestedType()); err != nil { 219 return err 220 } 221 if err := validateExtensionDeclarations(m.L1.Extensions.List, md.GetExtension()); err != nil { 222 return err 223 } 224 } 225 return nil 226 } 227 228 func validateExtensionDeclarations(xs []filedesc.Extension, xds []*descriptorpb.FieldDescriptorProto) error { 229 for i, xd := range xds { 230 x := &xs[i] 231 // NOTE: Avoid using the IsValid method since extensions to MessageSet 232 // may have a field number higher than normal. This check only verifies 233 // that the number is not negative or reserved. We check again later 234 // if we know that the extendee is definitely not a MessageSet. 235 if n := x.Number(); n < 0 || (protowire.FirstReservedNumber <= n && n <= protowire.LastReservedNumber) { 236 return errors.New("extension field %q has an invalid number: %d", x.FullName(), x.Number()) 237 } 238 if !x.Cardinality().IsValid() || x.Cardinality() == protoreflect.Required { 239 return errors.New("extension field %q has an invalid cardinality: %d", x.FullName(), x.Cardinality()) 240 } 241 if xd.JsonName != nil { 242 // A bug in older versions of protoc would always populate the 243 // "json_name" option for extensions when it is meaningless. 244 // When it did so, it would always use the camel-cased field name. 245 if xd.GetJsonName() != strs.JSONCamelCase(string(x.Name())) { 246 return errors.New("extension field %q may not have an explicitly set JSON name: %q", x.FullName(), xd.GetJsonName()) 247 } 248 } 249 if xd.OneofIndex != nil { 250 return errors.New("extension field %q may not be part of a oneof", x.FullName()) 251 } 252 if md := x.ContainingMessage(); !md.IsPlaceholder() { 253 if !md.ExtensionRanges().Has(x.Number()) { 254 return errors.New("extension field %q extends %q with non-extension field number: %d", x.FullName(), md.FullName(), x.Number()) 255 } 256 isMessageSet := md.Options().(*descriptorpb.MessageOptions).GetMessageSetWireFormat() 257 if isMessageSet && !isOptionalMessage(x) { 258 return errors.New("extension field %q extends MessageSet and must be an optional message", x.FullName()) 259 } 260 if !isMessageSet && !x.Number().IsValid() { 261 return errors.New("extension field %q has an invalid number: %d", x.FullName(), x.Number()) 262 } 263 } 264 if xd.GetOptions().GetWeak() { 265 return errors.New("extension field %q cannot be a weak reference", x.FullName()) 266 } 267 if x.IsPacked() && !isPackable(x) { 268 return errors.New("extension field %q is not packable", x.FullName()) 269 } 270 if err := checkValidGroup(x); err != nil { 271 return errors.New("extension field %q is an invalid group: %v", x.FullName(), err) 272 } 273 if md := x.Message(); md != nil && md.IsMapEntry() { 274 return errors.New("extension field %q cannot be a map entry", x.FullName()) 275 } 276 if x.Syntax() == protoreflect.Proto3 { 277 switch x.ContainingMessage().FullName() { 278 case (*descriptorpb.FileOptions)(nil).ProtoReflect().Descriptor().FullName(): 279 case (*descriptorpb.EnumOptions)(nil).ProtoReflect().Descriptor().FullName(): 280 case (*descriptorpb.EnumValueOptions)(nil).ProtoReflect().Descriptor().FullName(): 281 case (*descriptorpb.MessageOptions)(nil).ProtoReflect().Descriptor().FullName(): 282 case (*descriptorpb.FieldOptions)(nil).ProtoReflect().Descriptor().FullName(): 283 case (*descriptorpb.OneofOptions)(nil).ProtoReflect().Descriptor().FullName(): 284 case (*descriptorpb.ExtensionRangeOptions)(nil).ProtoReflect().Descriptor().FullName(): 285 case (*descriptorpb.ServiceOptions)(nil).ProtoReflect().Descriptor().FullName(): 286 case (*descriptorpb.MethodOptions)(nil).ProtoReflect().Descriptor().FullName(): 287 default: 288 return errors.New("extension field %q cannot be declared in proto3 unless extended descriptor options", x.FullName()) 289 } 290 } 291 } 292 return nil 293 } 294 295 // isOptionalMessage reports whether this is an optional message. 296 // If the kind is unknown, it is assumed to be a message. 297 func isOptionalMessage(fd protoreflect.FieldDescriptor) bool { 298 return (fd.Kind() == 0 || fd.Kind() == protoreflect.MessageKind) && fd.Cardinality() == protoreflect.Optional 299 } 300 301 // isPackable checks whether the pack option can be specified. 302 func isPackable(fd protoreflect.FieldDescriptor) bool { 303 switch fd.Kind() { 304 case protoreflect.StringKind, protoreflect.BytesKind, protoreflect.MessageKind, protoreflect.GroupKind: 305 return false 306 } 307 return fd.IsList() 308 } 309 310 // checkValidGroup reports whether fd is a valid group according to the same 311 // rules that protoc imposes. 312 func checkValidGroup(fd protoreflect.FieldDescriptor) error { 313 md := fd.Message() 314 switch { 315 case fd.Kind() != protoreflect.GroupKind: 316 return nil 317 case fd.Syntax() != protoreflect.Proto2: 318 return errors.New("invalid under proto2 semantics") 319 case md == nil || md.IsPlaceholder(): 320 return errors.New("message must be resolvable") 321 case fd.FullName().Parent() != md.FullName().Parent(): 322 return errors.New("message and field must be declared in the same scope") 323 case !unicode.IsUpper(rune(md.Name()[0])): 324 return errors.New("message name must start with an uppercase") 325 case fd.Name() != protoreflect.Name(strings.ToLower(string(md.Name()))): 326 return errors.New("field name must be lowercased form of the message name") 327 } 328 return nil 329 } 330 331 // checkValidMap checks whether the field is a valid map according to the same 332 // rules that protoc imposes. 333 // See protoc v3.8.0: src/google/protobuf/descriptor.cc:6045-6115 334 func checkValidMap(fd protoreflect.FieldDescriptor) error { 335 md := fd.Message() 336 switch { 337 case md == nil || !md.IsMapEntry(): 338 return nil 339 case fd.FullName().Parent() != md.FullName().Parent(): 340 return errors.New("message and field must be declared in the same scope") 341 case md.Name() != protoreflect.Name(strs.MapEntryName(string(fd.Name()))): 342 return errors.New("incorrect implicit map entry name") 343 case fd.Cardinality() != protoreflect.Repeated: 344 return errors.New("field must be repeated") 345 case md.Fields().Len() != 2: 346 return errors.New("message must have exactly two fields") 347 case md.ExtensionRanges().Len() > 0: 348 return errors.New("message must not have any extension ranges") 349 case md.Enums().Len()+md.Messages().Len()+md.Extensions().Len() > 0: 350 return errors.New("message must not have any nested declarations") 351 } 352 kf := md.Fields().Get(0) 353 vf := md.Fields().Get(1) 354 switch { 355 case kf.Name() != genid.MapEntry_Key_field_name || kf.Number() != genid.MapEntry_Key_field_number || kf.Cardinality() != protoreflect.Optional || kf.ContainingOneof() != nil || kf.HasDefault(): 356 return errors.New("invalid key field") 357 case vf.Name() != genid.MapEntry_Value_field_name || vf.Number() != genid.MapEntry_Value_field_number || vf.Cardinality() != protoreflect.Optional || vf.ContainingOneof() != nil || vf.HasDefault(): 358 return errors.New("invalid value field") 359 } 360 switch kf.Kind() { 361 case protoreflect.BoolKind: // bool 362 case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: // int32 363 case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: // int64 364 case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: // uint32 365 case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: // uint64 366 case protoreflect.StringKind: // string 367 default: 368 return errors.New("invalid key kind: %v", kf.Kind()) 369 } 370 if e := vf.Enum(); e != nil && e.Values().Len() > 0 && e.Values().Get(0).Number() != 0 { 371 return errors.New("map enum value must have zero number for the first value") 372 } 373 return nil 374 }