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