]> git.feebdaed.xyz Git - 0xmirror/containerd.git/commitdiff
build(deps): bump google.golang.org/protobuf from 1.36.10 to 1.36.11
authordependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Tue, 16 Dec 2025 04:16:25 +0000 (04:16 +0000)
committerGitHub <noreply@github.com>
Tue, 16 Dec 2025 04:16:25 +0000 (04:16 +0000)
Bumps google.golang.org/protobuf from 1.36.10 to 1.36.11.

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-version: 1.36.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
18 files changed:
go.mod
go.sum
vendor/google.golang.org/protobuf/compiler/protogen/protogen.go
vendor/google.golang.org/protobuf/internal/encoding/tag/tag.go
vendor/google.golang.org/protobuf/internal/encoding/text/decode.go
vendor/google.golang.org/protobuf/internal/filedesc/desc.go
vendor/google.golang.org/protobuf/internal/filedesc/desc_lazy.go
vendor/google.golang.org/protobuf/internal/genid/descriptor_gen.go
vendor/google.golang.org/protobuf/internal/impl/codec_map.go
vendor/google.golang.org/protobuf/internal/impl/decode.go
vendor/google.golang.org/protobuf/internal/impl/validate.go
vendor/google.golang.org/protobuf/internal/version/version.go
vendor/google.golang.org/protobuf/proto/decode.go
vendor/google.golang.org/protobuf/reflect/protodesc/desc.go
vendor/google.golang.org/protobuf/reflect/protodesc/editions.go
vendor/google.golang.org/protobuf/types/descriptorpb/descriptor.pb.go
vendor/google.golang.org/protobuf/types/known/timestamppb/timestamp.pb.go
vendor/modules.txt

diff --git a/go.mod b/go.mod
index 6762fcc7b36682cceba3ce2021d3531e3a6c3700..cda6f0150bb544355147d12de0040f4aa4a4a381 100644 (file)
--- a/go.mod
+++ b/go.mod
@@ -81,7 +81,7 @@ require (
        golang.org/x/time v0.14.0
        google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217
        google.golang.org/grpc v1.77.0
-       google.golang.org/protobuf v1.36.10
+       google.golang.org/protobuf v1.36.11
        gopkg.in/inf.v0 v0.9.1
        k8s.io/apimachinery v0.34.3
        k8s.io/client-go v0.34.3
diff --git a/go.sum b/go.sum
index 5d9c13cb51495d5a5db61ecf98908674f85c541b..c9f25d91cb50a67453b04d8a5c65de9e1831a8d0 100644 (file)
--- a/go.sum
+++ b/go.sum
@@ -544,8 +544,8 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
-google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
-google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
+google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
+google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
index f7f295aa5582c4ebe7fc55215a6c09a5e817c45e..f68418bb1aa66a232ad439352aba670333f50045 100644 (file)
@@ -267,6 +267,12 @@ func (opts Options) New(req *pluginpb.CodeGeneratorRequest) (*Plugin, error) {
                return nil, fmt.Errorf("cannot use module= with paths=source_relative")
        }
 
+       // Instead of generating each gen.Request.ProtoFile,
+       // generate gen.Request.FileToGenerate and its transitive dependencies.
+       //
+       // This effectively filters out 'import option' dependencies.
+       files := gatherTransitiveDependencies(gen.Request)
+
        // Figure out the import path and package name for each file.
        //
        // The rules here are complicated and have grown organically over time.
@@ -281,7 +287,7 @@ func (opts Options) New(req *pluginpb.CodeGeneratorRequest) (*Plugin, error) {
        //
        // Alternatively, build systems which want to exert full control over
        // import paths may specify M<filename>=<import_path> flags.
-       for _, fdesc := range gen.Request.ProtoFile {
+       for _, fdesc := range files {
                filename := fdesc.GetName()
                // The "M" command-line flags take precedence over
                // the "go_package" option in the .proto source file.
@@ -351,7 +357,7 @@ func (opts Options) New(req *pluginpb.CodeGeneratorRequest) (*Plugin, error) {
 
        // The extracted types from the full import set
        typeRegistry := newExtensionRegistry()
-       for _, fdesc := range gen.Request.ProtoFile {
+       for _, fdesc := range files {
                filename := fdesc.GetName()
                if gen.FilesByPath[filename] != nil {
                        return nil, fmt.Errorf("duplicate file name: %q", filename)
@@ -390,6 +396,50 @@ func (opts Options) New(req *pluginpb.CodeGeneratorRequest) (*Plugin, error) {
        return gen, nil
 }
 
+type transitiveDependencies struct {
+       files      map[string]*descriptorpb.FileDescriptorProto
+       deps       map[string]bool
+       sortedDeps []*descriptorpb.FileDescriptorProto
+}
+
+func newTransitiveDependencies(req *pluginpb.CodeGeneratorRequest) *transitiveDependencies {
+       files := make(map[string]*descriptorpb.FileDescriptorProto)
+       for _, f := range req.GetProtoFile() {
+               files[f.GetName()] = f
+       }
+       return &transitiveDependencies{
+               files: files,
+               deps:  make(map[string]bool),
+       }
+}
+
+func (td *transitiveDependencies) add(name string) {
+       if td.deps[name] {
+               return
+       }
+       f := td.files[name]
+       if f == nil {
+               // This shouldn't happen, but will fail later if it does.
+               return
+       }
+       td.deps[name] = true
+       for _, dep := range f.GetDependency() {
+               td.add(dep)
+       }
+       td.sortedDeps = append(td.sortedDeps, f)
+}
+
+func gatherTransitiveDependencies(req *pluginpb.CodeGeneratorRequest) []*descriptorpb.FileDescriptorProto {
+       if len(req.GetFileToGenerate()) == 0 {
+               return req.GetProtoFile()
+       }
+       td := newTransitiveDependencies(req)
+       for _, f := range req.GetFileToGenerate() {
+               td.add(f)
+       }
+       return td.sortedDeps
+}
+
 // InternalStripForEditionsDiff returns whether or not to strip non-functional
 // codegen for editions diff testing.
 //
index 669133d04dc9c84a649324a102728b256b110176..c96e4483460af47cc667d8f92acdbe87cc69ea9a 100644 (file)
@@ -32,7 +32,7 @@ var byteType = reflect.TypeOf(byte(0))
 func Unmarshal(tag string, goType reflect.Type, evs protoreflect.EnumValueDescriptors) protoreflect.FieldDescriptor {
        f := new(filedesc.Field)
        f.L0.ParentFile = filedesc.SurrogateProto2
-       f.L1.EditionFeatures = f.L0.ParentFile.L1.EditionFeatures
+       packed := false
        for len(tag) > 0 {
                i := strings.IndexByte(tag, ',')
                if i < 0 {
@@ -108,7 +108,7 @@ func Unmarshal(tag string, goType reflect.Type, evs protoreflect.EnumValueDescri
                                f.L1.StringName.InitJSON(jsonName)
                        }
                case s == "packed":
-                       f.L1.EditionFeatures.IsPacked = true
+                       packed = true
                case strings.HasPrefix(s, "def="):
                        // The default tag is special in that everything afterwards is the
                        // default regardless of the presence of commas.
@@ -121,6 +121,13 @@ func Unmarshal(tag string, goType reflect.Type, evs protoreflect.EnumValueDescri
                tag = strings.TrimPrefix(tag[i:], ",")
        }
 
+       // Update EditionFeatures after the loop and after we know whether this is
+       // a proto2 or proto3 field.
+       f.L1.EditionFeatures = f.L0.ParentFile.L1.EditionFeatures
+       if packed {
+               f.L1.EditionFeatures.IsPacked = true
+       }
+
        // The generator uses the group message name instead of the field name.
        // We obtain the real field name by lowercasing the group name.
        if f.L1.Kind == protoreflect.GroupKind {
index 099b2bf451b5c59dd42942c1dea5e37c83b69c78..9aa7a9bb7760609fd55da6cb353a5903f1252ff4 100644 (file)
@@ -424,27 +424,34 @@ func (d *Decoder) parseFieldName() (tok Token, err error) {
        return Token{}, d.newSyntaxError("invalid field name: %s", errId(d.in))
 }
 
-// parseTypeName parses Any type URL or extension field name. The name is
-// enclosed in [ and ] characters. The C++ parser does not handle many legal URL
-// strings. This implementation is more liberal and allows for the pattern
-// ^[-_a-zA-Z0-9]+([./][-_a-zA-Z0-9]+)*`). Whitespaces and comments are allowed
-// in between [ ], '.', '/' and the sub names.
+// parseTypeName parses an Any type URL or an extension field name. The name is
+// enclosed in [ and ] characters. We allow almost arbitrary type URL prefixes,
+// closely following the text-format spec [1,2]. We implement "ExtensionName |
+// AnyName" as follows (with some exceptions for backwards compatibility):
+//
+// char      = [-_a-zA-Z0-9]
+// url_char  = char | [.~!$&'()*+,;=] | "%", hex, hex
+//
+// Ident         = char, { char }
+// TypeName      = Ident, { ".", Ident } ;
+// UrlPrefix     = url_char, { url_char | "/" } ;
+// ExtensionName = "[", TypeName, "]" ;
+// AnyName       = "[", UrlPrefix, "/", TypeName, "]" ;
+//
+// Additionally, we allow arbitrary whitespace and comments between [ and ].
+//
+// [1] https://protobuf.dev/reference/protobuf/textformat-spec/#characters
+// [2] https://protobuf.dev/reference/protobuf/textformat-spec/#field-names
 func (d *Decoder) parseTypeName() (Token, error) {
-       startPos := len(d.orig) - len(d.in)
        // Use alias s to advance first in order to use d.in for error handling.
-       // Caller already checks for [ as first character.
+       // Caller already checks for [ as first character (d.in[0] == '[').
        s := consume(d.in[1:], 0)
        if len(s) == 0 {
                return Token{}, ErrUnexpectedEOF
        }
 
+       // Collect everything between [ and ] in name.
        var name []byte
-       for len(s) > 0 && isTypeNameChar(s[0]) {
-               name = append(name, s[0])
-               s = s[1:]
-       }
-       s = consume(s, 0)
-
        var closed bool
        for len(s) > 0 && !closed {
                switch {
@@ -452,23 +459,20 @@ func (d *Decoder) parseTypeName() (Token, error) {
                        s = s[1:]
                        closed = true
 
-               case s[0] == '/', s[0] == '.':
-                       if len(name) > 0 && (name[len(name)-1] == '/' || name[len(name)-1] == '.') {
-                               return Token{}, d.newSyntaxError("invalid type URL/extension field name: %s",
-                                       d.orig[startPos:len(d.orig)-len(s)+1])
-                       }
+               case s[0] == '/' || isTypeNameChar(s[0]) || isUrlExtraChar(s[0]):
                        name = append(name, s[0])
-                       s = s[1:]
-                       s = consume(s, 0)
-                       for len(s) > 0 && isTypeNameChar(s[0]) {
-                               name = append(name, s[0])
-                               s = s[1:]
+                       s = consume(s[1:], 0)
+
+               // URL percent-encoded chars
+               case s[0] == '%':
+                       if len(s) < 3 || !isHexChar(s[1]) || !isHexChar(s[2]) {
+                               return Token{}, d.parseTypeNameError(s, 3)
                        }
-                       s = consume(s, 0)
+                       name = append(name, s[0], s[1], s[2])
+                       s = consume(s[3:], 0)
 
                default:
-                       return Token{}, d.newSyntaxError(
-                               "invalid type URL/extension field name: %s", d.orig[startPos:len(d.orig)-len(s)+1])
+                       return Token{}, d.parseTypeNameError(s, 1)
                }
        }
 
@@ -476,15 +480,38 @@ func (d *Decoder) parseTypeName() (Token, error) {
                return Token{}, ErrUnexpectedEOF
        }
 
-       // First character cannot be '.'. Last character cannot be '.' or '/'.
-       size := len(name)
-       if size == 0 || name[0] == '.' || name[size-1] == '.' || name[size-1] == '/' {
-               return Token{}, d.newSyntaxError("invalid type URL/extension field name: %s",
-                       d.orig[startPos:len(d.orig)-len(s)])
+       // Split collected name on last '/' into urlPrefix and typeName (if '/' is
+       // present).
+       typeName := name
+       if i := bytes.LastIndexByte(name, '/'); i != -1 {
+               urlPrefix := name[:i]
+               typeName = name[i+1:]
+
+               // urlPrefix may be empty (for backwards compatibility).
+               // If non-empty, it must not start with '/'.
+               if len(urlPrefix) > 0 && urlPrefix[0] == '/' {
+                       return Token{}, d.parseTypeNameError(s, 0)
+               }
        }
 
+       // typeName must not be empty (note: "" splits to [""]) and all identifier
+       // parts must not be empty.
+       for _, ident := range bytes.Split(typeName, []byte{'.'}) {
+               if len(ident) == 0 {
+                       return Token{}, d.parseTypeNameError(s, 0)
+               }
+       }
+
+       // typeName must not contain any percent-encoded or special URL chars.
+       for _, b := range typeName {
+               if b == '%' || (b != '.' && isUrlExtraChar(b)) {
+                       return Token{}, d.parseTypeNameError(s, 0)
+               }
+       }
+
+       startPos := len(d.orig) - len(d.in)
+       endPos := len(d.orig) - len(s)
        d.in = s
-       endPos := len(d.orig) - len(d.in)
        d.consume(0)
 
        return Token{
@@ -496,16 +523,32 @@ func (d *Decoder) parseTypeName() (Token, error) {
        }, nil
 }
 
+func (d *Decoder) parseTypeNameError(s []byte, numUnconsumedChars int) error {
+       return d.newSyntaxError(
+               "invalid type URL/extension field name: %s",
+               d.in[:len(d.in)-len(s)+min(numUnconsumedChars, len(s))],
+       )
+}
+
+func isHexChar(b byte) bool {
+       return ('0' <= b && b <= '9') ||
+               ('a' <= b && b <= 'f') ||
+               ('A' <= b && b <= 'F')
+}
+
 func isTypeNameChar(b byte) bool {
-       return (b == '-' || b == '_' ||
+       return b == '-' || b == '_' ||
                ('0' <= b && b <= '9') ||
                ('a' <= b && b <= 'z') ||
-               ('A' <= b && b <= 'Z'))
+               ('A' <= b && b <= 'Z')
 }
 
-func isWhiteSpace(b byte) bool {
+// isUrlExtraChar complements isTypeNameChar with extra characters that we allow
+// in URLs but not in type names. Note that '/' is not included so that it can
+// be treated specially.
+func isUrlExtraChar(b byte) bool {
        switch b {
-       case ' ', '\n', '\r', '\t':
+       case '.', '~', '!', '$', '&', '(', ')', '*', '+', ',', ';', '=':
                return true
        default:
                return false
index dbcf90b871fd710449022f4f55c4dbaecf557a93..c775e5832f01a87d94a36bf3f869943311441323 100644 (file)
@@ -32,6 +32,7 @@ const (
        EditionProto3      Edition = 999
        Edition2023        Edition = 1000
        Edition2024        Edition = 1001
+       EditionUnstable    Edition = 9999
        EditionUnsupported Edition = 100000
 )
 
index dd31faaeb0a006f43998119ec1add210035fde02..78f02b1b4959e273ef44346d25e3cd57311b7435 100644 (file)
@@ -330,7 +330,6 @@ func (md *Message) unmarshalFull(b []byte, sb *strs.Builder) {
                                md.L1.Extensions.List[extensionIdx].unmarshalFull(v, sb)
                                extensionIdx++
                        case genid.DescriptorProto_Options_field_number:
-                               md.unmarshalOptions(v)
                                rawOptions = appendOptions(rawOptions, v)
                        }
                default:
@@ -356,27 +355,6 @@ func (md *Message) unmarshalFull(b []byte, sb *strs.Builder) {
        md.L2.Options = md.L0.ParentFile.builder.optionsUnmarshaler(&descopts.Message, rawOptions)
 }
 
-func (md *Message) unmarshalOptions(b []byte) {
-       for len(b) > 0 {
-               num, typ, n := protowire.ConsumeTag(b)
-               b = b[n:]
-               switch typ {
-               case protowire.VarintType:
-                       v, m := protowire.ConsumeVarint(b)
-                       b = b[m:]
-                       switch num {
-                       case genid.MessageOptions_MapEntry_field_number:
-                               md.L1.IsMapEntry = protowire.DecodeBool(v)
-                       case genid.MessageOptions_MessageSetWireFormat_field_number:
-                               md.L1.IsMessageSet = protowire.DecodeBool(v)
-                       }
-               default:
-                       m := protowire.ConsumeFieldValue(num, typ, b)
-                       b = b[m:]
-               }
-       }
-}
-
 func unmarshalMessageReservedRange(b []byte) (r [2]protoreflect.FieldNumber) {
        for len(b) > 0 {
                num, typ, n := protowire.ConsumeTag(b)
index 950a6a325a477b65a147a3c76cd61b75fed91fbb..65aaf4d210af0654dc5386bc9127d016382ab395 100644 (file)
@@ -26,6 +26,7 @@ const (
        Edition_EDITION_PROTO3_enum_value          = 999
        Edition_EDITION_2023_enum_value            = 1000
        Edition_EDITION_2024_enum_value            = 1001
+       Edition_EDITION_UNSTABLE_enum_value        = 9999
        Edition_EDITION_1_TEST_ONLY_enum_value     = 1
        Edition_EDITION_2_TEST_ONLY_enum_value     = 2
        Edition_EDITION_99997_TEST_ONLY_enum_value = 99997
index 229c69801386517b0d40a69b0c8155b4666994a1..4a3bf393ef4cfca75a00bae077e72c6162c2124b 100644 (file)
@@ -113,6 +113,9 @@ func sizeMap(mapv reflect.Value, mapi *mapInfo, f *coderFieldInfo, opts marshalO
 }
 
 func consumeMap(b []byte, mapv reflect.Value, wtyp protowire.Type, mapi *mapInfo, f *coderFieldInfo, opts unmarshalOptions) (out unmarshalOutput, err error) {
+       if opts.depth--; opts.depth < 0 {
+               return out, errRecursionDepth
+       }
        if wtyp != protowire.BytesType {
                return out, errUnknown
        }
@@ -170,6 +173,9 @@ func consumeMap(b []byte, mapv reflect.Value, wtyp protowire.Type, mapi *mapInfo
 }
 
 func consumeMapOfMessage(b []byte, mapv reflect.Value, wtyp protowire.Type, mapi *mapInfo, f *coderFieldInfo, opts unmarshalOptions) (out unmarshalOutput, err error) {
+       if opts.depth--; opts.depth < 0 {
+               return out, errRecursionDepth
+       }
        if wtyp != protowire.BytesType {
                return out, errUnknown
        }
index e0dd21fa5f4ff619303f38e9188fd265c07b071f..1228b5c8c271f2f04ca5f7af543c6cc613eb3928 100644 (file)
@@ -102,8 +102,7 @@ var errUnknown = errors.New("unknown")
 
 func (mi *MessageInfo) unmarshalPointer(b []byte, p pointer, groupTag protowire.Number, opts unmarshalOptions) (out unmarshalOutput, err error) {
        mi.init()
-       opts.depth--
-       if opts.depth < 0 {
+       if opts.depth--; opts.depth < 0 {
                return out, errRecursionDepth
        }
        if flags.ProtoLegacy && mi.isMessageSet {
index 7b2995dde5ebee0d348a9b98c27ae96362a7249f..99a1eb95f7c48eda86b0a232237aeb0b2b8a8374 100644 (file)
@@ -68,9 +68,13 @@ func Validate(mt protoreflect.MessageType, in protoiface.UnmarshalInput) (out pr
        if in.Resolver == nil {
                in.Resolver = protoregistry.GlobalTypes
        }
+       if in.Depth == 0 {
+               in.Depth = protowire.DefaultRecursionLimit
+       }
        o, st := mi.validate(in.Buf, 0, unmarshalOptions{
                flags:    in.Flags,
                resolver: in.Resolver,
+               depth:    in.Depth,
        })
        if o.initialized {
                out.Flags |= protoiface.UnmarshalInitialized
@@ -257,6 +261,9 @@ func (mi *MessageInfo) validate(b []byte, groupTag protowire.Number, opts unmars
                states[0].typ = validationTypeGroup
                states[0].endGroup = groupTag
        }
+       if opts.depth--; opts.depth < 0 {
+               return out, ValidationInvalid
+       }
        initialized := true
        start := len(b)
 State:
@@ -451,6 +458,13 @@ State:
                                                mi:      vi.mi,
                                                tail:    b,
                                        })
+                                       if vi.typ == validationTypeMessage ||
+                                               vi.typ == validationTypeGroup ||
+                                               vi.typ == validationTypeMap {
+                                               if opts.depth--; opts.depth < 0 {
+                                                       return out, ValidationInvalid
+                                               }
+                                       }
                                        b = v
                                        continue State
                                case validationTypeRepeatedVarint:
@@ -499,6 +513,9 @@ State:
                                                mi:       vi.mi,
                                                endGroup: num,
                                        })
+                                       if opts.depth--; opts.depth < 0 {
+                                               return out, ValidationInvalid
+                                       }
                                        continue State
                                case flags.ProtoLegacy && vi.typ == validationTypeMessageSetItem:
                                        typeid, v, n, err := messageset.ConsumeFieldValue(b, false)
@@ -521,6 +538,13 @@ State:
                                                        mi:   xvi.mi,
                                                        tail: b[n:],
                                                })
+                                               if xvi.typ == validationTypeMessage ||
+                                                       xvi.typ == validationTypeGroup ||
+                                                       xvi.typ == validationTypeMap {
+                                                       if opts.depth--; opts.depth < 0 {
+                                                               return out, ValidationInvalid
+                                                       }
+                                               }
                                                b = v
                                                continue State
                                        }
@@ -547,12 +571,14 @@ State:
                switch st.typ {
                case validationTypeMessage, validationTypeGroup:
                        numRequiredFields = int(st.mi.numRequiredFields)
+                       opts.depth++
                case validationTypeMap:
                        // If this is a map field with a message value that contains
                        // required fields, require that the value be present.
                        if st.mi != nil && st.mi.numRequiredFields > 0 {
                                numRequiredFields = 1
                        }
+                       opts.depth++
                }
                // If there are more than 64 required fields, this check will
                // always fail and we will report that the message is potentially
index 77de0f238ce88182011ba12f1da32ca22721608a..763fd82841cc55355c32ea1f385bc5d4f69b30f6 100644 (file)
@@ -52,7 +52,7 @@ import (
 const (
        Major      = 1
        Minor      = 36
-       Patch      = 10
+       Patch      = 11
        PreRelease = ""
 )
 
index 4cbf1aeaf79c93e5b9474f69b792970e1a0cefaa..889d8511d2759cf186944bc4362d117ce79b7bde 100644 (file)
@@ -121,9 +121,8 @@ func (o UnmarshalOptions) unmarshal(b []byte, m protoreflect.Message) (out proto
 
                out, err = methods.Unmarshal(in)
        } else {
-               o.RecursionLimit--
-               if o.RecursionLimit < 0 {
-                       return out, errors.New("exceeded max recursion depth")
+               if o.RecursionLimit--; o.RecursionLimit < 0 {
+                       return out, errRecursionDepth
                }
                err = o.unmarshalMessageSlow(b, m)
        }
@@ -220,6 +219,9 @@ func (o UnmarshalOptions) unmarshalSingular(b []byte, wtyp protowire.Type, m pro
 }
 
 func (o UnmarshalOptions) unmarshalMap(b []byte, wtyp protowire.Type, mapv protoreflect.Map, fd protoreflect.FieldDescriptor) (n int, err error) {
+       if o.RecursionLimit--; o.RecursionLimit < 0 {
+               return 0, errRecursionDepth
+       }
        if wtyp != protowire.BytesType {
                return 0, errUnknown
        }
@@ -305,3 +307,5 @@ func (o UnmarshalOptions) unmarshalMap(b []byte, wtyp protowire.Type, mapv proto
 var errUnknown = errors.New("BUG: internal error (unknown)")
 
 var errDecode = errors.New("cannot parse invalid wire-format data")
+
+var errRecursionDepth = errors.New("exceeded maximum recursion depth")
index 9196288e4acee670f003ac14846fa183b91a23b7..40f17af4e3cb84e5c71fe138def67c6ed0004322 100644 (file)
@@ -108,7 +108,9 @@ func (o FileOptions) New(fd *descriptorpb.FileDescriptorProto, r Resolver) (prot
        if f.L1.Path == "" {
                return nil, errors.New("file path must be populated")
        }
-       if f.L1.Syntax == protoreflect.Editions && (fd.GetEdition() < editionssupport.Minimum || fd.GetEdition() > editionssupport.Maximum) {
+       if f.L1.Syntax == protoreflect.Editions &&
+               (fd.GetEdition() < editionssupport.Minimum || fd.GetEdition() > editionssupport.Maximum) &&
+               fd.GetEdition() != descriptorpb.Edition_EDITION_UNSTABLE {
                // Allow cmd/protoc-gen-go/testdata to use any edition for easier
                // testing of upcoming edition features.
                if !strings.HasPrefix(fd.GetName(), "cmd/protoc-gen-go/testdata/") {
@@ -152,6 +154,7 @@ func (o FileOptions) New(fd *descriptorpb.FileDescriptorProto, r Resolver) (prot
                imp := &f.L2.Imports[i]
                imps.importPublic(imp.Imports())
        }
+       optionImps := importSet{f.Path(): true}
        if len(fd.GetOptionDependency()) > 0 {
                optionImports := make(filedesc.FileImports, len(fd.GetOptionDependency()))
                for i, path := range fd.GetOptionDependency() {
@@ -165,10 +168,12 @@ func (o FileOptions) New(fd *descriptorpb.FileDescriptorProto, r Resolver) (prot
                        }
                        imp.FileDescriptor = f
 
-                       if imps[imp.Path()] {
+                       if imps[imp.Path()] || optionImps[imp.Path()] {
                                return nil, errors.New("already imported %q", path)
                        }
-                       imps[imp.Path()] = true
+                       // This needs to be a separate map so that we don't recognize non-options
+                       // symbols coming from option imports.
+                       optionImps[imp.Path()] = true
                }
                f.L2.OptionImports = func() protoreflect.FileImports {
                        return &optionImports
index 697a61b290ebbf9aa4998a44c38f97db634316e3..147b8c7398d5d3773806e5ddbbff5991915c7193 100644 (file)
@@ -46,6 +46,8 @@ func toEditionProto(ed filedesc.Edition) descriptorpb.Edition {
                return descriptorpb.Edition_EDITION_2023
        case filedesc.Edition2024:
                return descriptorpb.Edition_EDITION_2024
+       case filedesc.EditionUnstable:
+               return descriptorpb.Edition_EDITION_UNSTABLE
        default:
                panic(fmt.Sprintf("unknown value for edition: %v", ed))
        }
@@ -58,7 +60,7 @@ func getFeatureSetFor(ed filedesc.Edition) *descriptorpb.FeatureSet {
                return def
        }
        edpb := toEditionProto(ed)
-       if defaults.GetMinimumEdition() > edpb || defaults.GetMaximumEdition() < edpb {
+       if (defaults.GetMinimumEdition() > edpb || defaults.GetMaximumEdition() < edpb) && edpb != descriptorpb.Edition_EDITION_UNSTABLE {
                // This should never happen protodesc.(FileOptions).New would fail when
                // initializing the file descriptor.
                // This most likely means the embedded defaults were not updated.
index 4eacb523c33a5dd18101dcfc4cd44a28a9f99d03..0b23faa957c9d5d4beda7915b6a141efad64159a 100644 (file)
@@ -69,6 +69,8 @@ const (
        // comparison.
        Edition_EDITION_2023 Edition = 1000
        Edition_EDITION_2024 Edition = 1001
+       // A placeholder edition for developing and testing unscheduled features.
+       Edition_EDITION_UNSTABLE Edition = 9999
        // Placeholder editions for testing feature resolution.  These should not be
        // used or relied on outside of tests.
        Edition_EDITION_1_TEST_ONLY     Edition = 1
@@ -91,6 +93,7 @@ var (
                999:        "EDITION_PROTO3",
                1000:       "EDITION_2023",
                1001:       "EDITION_2024",
+               9999:       "EDITION_UNSTABLE",
                1:          "EDITION_1_TEST_ONLY",
                2:          "EDITION_2_TEST_ONLY",
                99997:      "EDITION_99997_TEST_ONLY",
@@ -105,6 +108,7 @@ var (
                "EDITION_PROTO3":          999,
                "EDITION_2023":            1000,
                "EDITION_2024":            1001,
+               "EDITION_UNSTABLE":        9999,
                "EDITION_1_TEST_ONLY":     1,
                "EDITION_2_TEST_ONLY":     2,
                "EDITION_99997_TEST_ONLY": 99997,
@@ -4793,11 +4797,11 @@ const file_google_protobuf_descriptor_proto_rawDesc = "" +
        "\x18EnumValueDescriptorProto\x12\x12\n" +
        "\x04name\x18\x01 \x01(\tR\x04name\x12\x16\n" +
        "\x06number\x18\x02 \x01(\x05R\x06number\x12;\n" +
-       "\aoptions\x18\x03 \x01(\v2!.google.protobuf.EnumValueOptionsR\aoptions\"\xa7\x01\n" +
+       "\aoptions\x18\x03 \x01(\v2!.google.protobuf.EnumValueOptionsR\aoptions\"\xb5\x01\n" +
        "\x16ServiceDescriptorProto\x12\x12\n" +
        "\x04name\x18\x01 \x01(\tR\x04name\x12>\n" +
        "\x06method\x18\x02 \x03(\v2&.google.protobuf.MethodDescriptorProtoR\x06method\x129\n" +
-       "\aoptions\x18\x03 \x01(\v2\x1f.google.protobuf.ServiceOptionsR\aoptions\"\x89\x02\n" +
+       "\aoptions\x18\x03 \x01(\v2\x1f.google.protobuf.ServiceOptionsR\aoptionsJ\x04\b\x04\x10\x05R\x06stream\"\x89\x02\n" +
        "\x15MethodDescriptorProto\x12\x12\n" +
        "\x04name\x18\x01 \x01(\tR\x04name\x12\x1d\n" +
        "\n" +
@@ -5033,14 +5037,15 @@ const file_google_protobuf_descriptor_proto_rawDesc = "" +
        "\bSemantic\x12\b\n" +
        "\x04NONE\x10\x00\x12\a\n" +
        "\x03SET\x10\x01\x12\t\n" +
-       "\x05ALIAS\x10\x02*\xa7\x02\n" +
+       "\x05ALIAS\x10\x02*\xbe\x02\n" +
        "\aEdition\x12\x13\n" +
        "\x0fEDITION_UNKNOWN\x10\x00\x12\x13\n" +
        "\x0eEDITION_LEGACY\x10\x84\a\x12\x13\n" +
        "\x0eEDITION_PROTO2\x10\xe6\a\x12\x13\n" +
        "\x0eEDITION_PROTO3\x10\xe7\a\x12\x11\n" +
        "\fEDITION_2023\x10\xe8\a\x12\x11\n" +
-       "\fEDITION_2024\x10\xe9\a\x12\x17\n" +
+       "\fEDITION_2024\x10\xe9\a\x12\x15\n" +
+       "\x10EDITION_UNSTABLE\x10\x8fN\x12\x17\n" +
        "\x13EDITION_1_TEST_ONLY\x10\x01\x12\x17\n" +
        "\x13EDITION_2_TEST_ONLY\x10\x02\x12\x1d\n" +
        "\x17EDITION_99997_TEST_ONLY\x10\x9d\x8d\x06\x12\x1d\n" +
index 06d584c14beabd65a9b185c31ee8f457bbbaea9e..484c21fd536c66a99855e94d186e6204fcf8f2cc 100644 (file)
@@ -172,13 +172,14 @@ import (
 // ) to obtain a formatter capable of generating timestamps in this format.
 type Timestamp struct {
        state protoimpl.MessageState `protogen:"open.v1"`
-       // Represents seconds of UTC time since Unix epoch
-       // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
-       // 9999-12-31T23:59:59Z inclusive.
+       // Represents seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z. Must
+       // be between -315576000000 and 315576000000 inclusive (which corresponds to
+       // 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z).
        Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"`
-       // Non-negative fractions of a second at nanosecond resolution. Negative
-       // second values with fractions must still have non-negative nanos values
-       // that count forward in time. Must be from 0 to 999,999,999
+       // Non-negative fractions of a second at nanosecond resolution. This field is
+       // the nanosecond portion of the duration, not an alternative to seconds.
+       // Negative second values with fractions must still have non-negative nanos
+       // values that count forward in time. Must be between 0 and 999,999,999
        // inclusive.
        Nanos         int32 `protobuf:"varint,2,opt,name=nanos,proto3" json:"nanos,omitempty"`
        unknownFields protoimpl.UnknownFields
index 4e11a8d438fe4162701382c270c159d27b353756..aac9632d2da54db027488703998628e609c42003 100644 (file)
@@ -801,7 +801,7 @@ google.golang.org/grpc/serviceconfig
 google.golang.org/grpc/stats
 google.golang.org/grpc/status
 google.golang.org/grpc/tap
-# google.golang.org/protobuf v1.36.10
+# google.golang.org/protobuf v1.36.11
 ## explicit; go 1.23
 google.golang.org/protobuf/compiler/protogen
 google.golang.org/protobuf/encoding/protodelim