blob: bb00cd0d91c41f5916127a1b992cb50b0fbcde99 [file] [log] [blame]
Damien Neilb0c26f12019-12-16 09:37:59 -08001// 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 impl
6
7import (
8 "fmt"
9 "math"
10 "math/bits"
11 "reflect"
12 "unicode/utf8"
13
Damien Neil9afe9bb2020-02-07 10:06:53 -080014 "google.golang.org/protobuf/internal/encoding/messageset"
Damien Neilb0c26f12019-12-16 09:37:59 -080015 "google.golang.org/protobuf/internal/encoding/wire"
Damien Neil0bf97b72020-01-24 09:00:33 -080016 "google.golang.org/protobuf/internal/flags"
Damien Neilb0c26f12019-12-16 09:37:59 -080017 "google.golang.org/protobuf/internal/strs"
18 pref "google.golang.org/protobuf/reflect/protoreflect"
19 preg "google.golang.org/protobuf/reflect/protoregistry"
20 piface "google.golang.org/protobuf/runtime/protoiface"
21)
22
23// ValidationStatus is the result of validating the wire-format encoding of a message.
24type ValidationStatus int
25
26const (
27 // ValidationUnknown indicates that unmarshaling the message might succeed or fail.
28 // The validator was unable to render a judgement.
29 //
30 // The only causes of this status are an aberrant message type appearing somewhere
31 // in the message or a failure in the extension resolver.
32 ValidationUnknown ValidationStatus = iota + 1
33
34 // ValidationInvalid indicates that unmarshaling the message will fail.
35 ValidationInvalid
36
Damien Neilcadb4ab2020-02-03 16:17:31 -080037 // ValidationValid indicates that unmarshaling the message will succeed.
38 ValidationValid
Damien Neilb0c26f12019-12-16 09:37:59 -080039)
40
41func (v ValidationStatus) String() string {
42 switch v {
43 case ValidationUnknown:
44 return "ValidationUnknown"
45 case ValidationInvalid:
46 return "ValidationInvalid"
Damien Neilcadb4ab2020-02-03 16:17:31 -080047 case ValidationValid:
48 return "ValidationValid"
Damien Neilb0c26f12019-12-16 09:37:59 -080049 default:
50 return fmt.Sprintf("ValidationStatus(%d)", int(v))
51 }
52}
53
54// Validate determines whether the contents of the buffer are a valid wire encoding
55// of the message type.
56//
57// This function is exposed for testing.
Damien Neilcadb4ab2020-02-03 16:17:31 -080058func Validate(b []byte, mt pref.MessageType, opts piface.UnmarshalOptions) (out piface.UnmarshalOutput, _ ValidationStatus) {
Damien Neilb0c26f12019-12-16 09:37:59 -080059 mi, ok := mt.(*MessageInfo)
60 if !ok {
Damien Neilcadb4ab2020-02-03 16:17:31 -080061 return out, ValidationUnknown
Damien Neilb0c26f12019-12-16 09:37:59 -080062 }
Damien Neilcadb4ab2020-02-03 16:17:31 -080063 o, st := mi.validate(b, 0, unmarshalOptions(opts))
64 out.Initialized = o.initialized
65 return out, st
Damien Neilb0c26f12019-12-16 09:37:59 -080066}
67
68type validationInfo struct {
69 mi *MessageInfo
70 typ validationType
71 keyType, valType validationType
72
Damien Neil170b2bf2020-01-24 16:42:42 -080073 // For non-required fields, requiredBit is 0.
Damien Neilb0c26f12019-12-16 09:37:59 -080074 //
Damien Neil170b2bf2020-01-24 16:42:42 -080075 // For required fields, requiredBit's nth bit is set, where n is a
76 // unique index in the range [0, MessageInfo.numRequiredFields).
77 //
78 // If there are more than 64 required fields, requiredBit is 0.
79 requiredBit uint64
Damien Neilb0c26f12019-12-16 09:37:59 -080080}
81
82type validationType uint8
83
84const (
85 validationTypeOther validationType = iota
86 validationTypeMessage
87 validationTypeGroup
88 validationTypeMap
89 validationTypeRepeatedVarint
90 validationTypeRepeatedFixed32
91 validationTypeRepeatedFixed64
92 validationTypeVarint
93 validationTypeFixed32
94 validationTypeFixed64
95 validationTypeBytes
96 validationTypeUTF8String
Damien Neil9afe9bb2020-02-07 10:06:53 -080097 validationTypeMessageSetItem
Damien Neilb0c26f12019-12-16 09:37:59 -080098)
99
100func newFieldValidationInfo(mi *MessageInfo, si structInfo, fd pref.FieldDescriptor, ft reflect.Type) validationInfo {
101 var vi validationInfo
102 switch {
103 case fd.ContainingOneof() != nil:
104 switch fd.Kind() {
105 case pref.MessageKind:
106 vi.typ = validationTypeMessage
107 if ot, ok := si.oneofWrappersByNumber[fd.Number()]; ok {
108 vi.mi = getMessageInfo(ot.Field(0).Type)
109 }
110 case pref.GroupKind:
111 vi.typ = validationTypeGroup
112 if ot, ok := si.oneofWrappersByNumber[fd.Number()]; ok {
113 vi.mi = getMessageInfo(ot.Field(0).Type)
114 }
115 case pref.StringKind:
116 if strs.EnforceUTF8(fd) {
117 vi.typ = validationTypeUTF8String
118 }
119 }
120 default:
121 vi = newValidationInfo(fd, ft)
122 }
123 if fd.Cardinality() == pref.Required {
124 // Avoid overflow. The required field check is done with a 64-bit mask, with
125 // any message containing more than 64 required fields always reported as
126 // potentially uninitialized, so it is not important to get a precise count
127 // of the required fields past 64.
128 if mi.numRequiredFields < math.MaxUint8 {
129 mi.numRequiredFields++
Damien Neil170b2bf2020-01-24 16:42:42 -0800130 vi.requiredBit = 1 << (mi.numRequiredFields - 1)
Damien Neilb0c26f12019-12-16 09:37:59 -0800131 }
132 }
133 return vi
134}
135
136func newValidationInfo(fd pref.FieldDescriptor, ft reflect.Type) validationInfo {
137 var vi validationInfo
138 switch {
139 case fd.IsList():
140 switch fd.Kind() {
141 case pref.MessageKind:
142 vi.typ = validationTypeMessage
143 if ft.Kind() == reflect.Slice {
144 vi.mi = getMessageInfo(ft.Elem())
145 }
146 case pref.GroupKind:
147 vi.typ = validationTypeGroup
148 if ft.Kind() == reflect.Slice {
149 vi.mi = getMessageInfo(ft.Elem())
150 }
151 case pref.StringKind:
152 vi.typ = validationTypeBytes
153 if strs.EnforceUTF8(fd) {
154 vi.typ = validationTypeUTF8String
155 }
156 default:
157 switch wireTypes[fd.Kind()] {
158 case wire.VarintType:
159 vi.typ = validationTypeRepeatedVarint
160 case wire.Fixed32Type:
161 vi.typ = validationTypeRepeatedFixed32
162 case wire.Fixed64Type:
163 vi.typ = validationTypeRepeatedFixed64
164 }
165 }
166 case fd.IsMap():
167 vi.typ = validationTypeMap
168 switch fd.MapKey().Kind() {
169 case pref.StringKind:
170 if strs.EnforceUTF8(fd) {
171 vi.keyType = validationTypeUTF8String
172 }
173 }
174 switch fd.MapValue().Kind() {
175 case pref.MessageKind:
176 vi.valType = validationTypeMessage
177 if ft.Kind() == reflect.Map {
178 vi.mi = getMessageInfo(ft.Elem())
179 }
180 case pref.StringKind:
181 if strs.EnforceUTF8(fd) {
182 vi.valType = validationTypeUTF8String
183 }
184 }
185 default:
186 switch fd.Kind() {
187 case pref.MessageKind:
188 vi.typ = validationTypeMessage
189 if !fd.IsWeak() {
190 vi.mi = getMessageInfo(ft)
191 }
192 case pref.GroupKind:
193 vi.typ = validationTypeGroup
194 vi.mi = getMessageInfo(ft)
195 case pref.StringKind:
196 vi.typ = validationTypeBytes
197 if strs.EnforceUTF8(fd) {
198 vi.typ = validationTypeUTF8String
199 }
200 default:
201 switch wireTypes[fd.Kind()] {
202 case wire.VarintType:
203 vi.typ = validationTypeVarint
204 case wire.Fixed32Type:
205 vi.typ = validationTypeFixed32
206 case wire.Fixed64Type:
207 vi.typ = validationTypeFixed64
Damien Neil6635e7d2020-01-15 15:08:57 -0800208 case wire.BytesType:
209 vi.typ = validationTypeBytes
Damien Neilb0c26f12019-12-16 09:37:59 -0800210 }
211 }
212 }
213 return vi
214}
215
Damien Neilcadb4ab2020-02-03 16:17:31 -0800216func (mi *MessageInfo) validate(b []byte, groupTag wire.Number, opts unmarshalOptions) (out unmarshalOutput, result ValidationStatus) {
Damien Neilcb0bfd02020-01-28 09:11:12 -0800217 mi.init()
Damien Neilb0c26f12019-12-16 09:37:59 -0800218 type validationState struct {
219 typ validationType
220 keyType, valType validationType
221 endGroup wire.Number
222 mi *MessageInfo
223 tail []byte
224 requiredMask uint64
225 }
226
227 // Pre-allocate some slots to avoid repeated slice reallocation.
228 states := make([]validationState, 0, 16)
229 states = append(states, validationState{
230 typ: validationTypeMessage,
231 mi: mi,
232 })
233 if groupTag > 0 {
234 states[0].typ = validationTypeGroup
235 states[0].endGroup = groupTag
236 }
237 initialized := true
Damien Neilcadb4ab2020-02-03 16:17:31 -0800238 start := len(b)
Damien Neilb0c26f12019-12-16 09:37:59 -0800239State:
240 for len(states) > 0 {
241 st := &states[len(states)-1]
Damien Neilb0c26f12019-12-16 09:37:59 -0800242 for len(b) > 0 {
Damien Neil5d828832020-01-28 08:06:12 -0800243 // Parse the tag (field number and wire type).
244 var tag uint64
245 if b[0] < 0x80 {
246 tag = uint64(b[0])
247 b = b[1:]
248 } else if len(b) >= 2 && b[1] < 128 {
249 tag = uint64(b[0]&0x7f) + uint64(b[1])<<7
250 b = b[2:]
251 } else {
252 var n int
253 tag, n = wire.ConsumeVarint(b)
254 if n < 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800255 return out, ValidationInvalid
Damien Neil5d828832020-01-28 08:06:12 -0800256 }
257 b = b[n:]
Damien Neilb0c26f12019-12-16 09:37:59 -0800258 }
Damien Neil5d828832020-01-28 08:06:12 -0800259 var num wire.Number
260 if n := tag >> 3; n < uint64(wire.MinValidNumber) || n > uint64(wire.MaxValidNumber) {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800261 return out, ValidationInvalid
Damien Neil5d828832020-01-28 08:06:12 -0800262 } else {
263 num = wire.Number(n)
Damien Neilb0c26f12019-12-16 09:37:59 -0800264 }
Damien Neil5d828832020-01-28 08:06:12 -0800265 wtyp := wire.Type(tag & 7)
266
Damien Neilb0c26f12019-12-16 09:37:59 -0800267 if wtyp == wire.EndGroupType {
268 if st.endGroup == num {
269 goto PopState
270 }
Damien Neilcadb4ab2020-02-03 16:17:31 -0800271 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800272 }
273 var vi validationInfo
Damien Neil9afe9bb2020-02-07 10:06:53 -0800274 switch {
275 case st.typ == validationTypeMap:
Damien Neilb0c26f12019-12-16 09:37:59 -0800276 switch num {
277 case 1:
278 vi.typ = st.keyType
279 case 2:
280 vi.typ = st.valType
281 vi.mi = st.mi
Damien Neil170b2bf2020-01-24 16:42:42 -0800282 vi.requiredBit = 1
Damien Neilb0c26f12019-12-16 09:37:59 -0800283 }
Damien Neil9afe9bb2020-02-07 10:06:53 -0800284 case flags.ProtoLegacy && st.mi.isMessageSet:
285 switch num {
286 case messageset.FieldItem:
287 vi.typ = validationTypeMessageSetItem
288 }
Damien Neilb0c26f12019-12-16 09:37:59 -0800289 default:
290 var f *coderFieldInfo
291 if int(num) < len(st.mi.denseCoderFields) {
292 f = st.mi.denseCoderFields[num]
293 } else {
294 f = st.mi.coderFields[num]
295 }
296 if f != nil {
297 vi = f.validation
298 if vi.typ == validationTypeMessage && vi.mi == nil {
299 // Probable weak field.
300 //
301 // TODO: Consider storing the results of this lookup somewhere
302 // rather than recomputing it on every validation.
303 fd := st.mi.Desc.Fields().ByNumber(num)
304 if fd == nil || !fd.IsWeak() {
305 break
306 }
307 messageName := fd.Message().FullName()
308 messageType, err := preg.GlobalTypes.FindMessageByName(messageName)
309 switch err {
310 case nil:
311 vi.mi, _ = messageType.(*MessageInfo)
312 case preg.NotFound:
313 vi.typ = validationTypeBytes
314 default:
Damien Neilcadb4ab2020-02-03 16:17:31 -0800315 return out, ValidationUnknown
Damien Neilb0c26f12019-12-16 09:37:59 -0800316 }
317 }
318 break
319 }
320 // Possible extension field.
321 //
322 // TODO: We should return ValidationUnknown when:
323 // 1. The resolver is not frozen. (More extensions may be added to it.)
324 // 2. The resolver returns preg.NotFound.
325 // In this case, a type added to the resolver in the future could cause
326 // unmarshaling to begin failing. Supporting this requires some way to
327 // determine if the resolver is frozen.
Damien Neil524c6062020-01-28 13:32:01 -0800328 xt, err := opts.Resolver.FindExtensionByNumber(st.mi.Desc.FullName(), num)
Damien Neilb0c26f12019-12-16 09:37:59 -0800329 if err != nil && err != preg.NotFound {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800330 return out, ValidationUnknown
Damien Neilb0c26f12019-12-16 09:37:59 -0800331 }
332 if err == nil {
333 vi = getExtensionFieldInfo(xt).validation
334 }
335 }
Damien Neil170b2bf2020-01-24 16:42:42 -0800336 if vi.requiredBit != 0 {
Damien Neilb0c26f12019-12-16 09:37:59 -0800337 // Check that the field has a compatible wire type.
338 // We only need to consider non-repeated field types,
339 // since repeated fields (and maps) can never be required.
340 ok := false
341 switch vi.typ {
342 case validationTypeVarint:
343 ok = wtyp == wire.VarintType
344 case validationTypeFixed32:
345 ok = wtyp == wire.Fixed32Type
346 case validationTypeFixed64:
347 ok = wtyp == wire.Fixed64Type
Damien Neilf9d4fdf2020-02-07 11:42:45 -0800348 case validationTypeBytes, validationTypeUTF8String, validationTypeMessage:
Damien Neilb0c26f12019-12-16 09:37:59 -0800349 ok = wtyp == wire.BytesType
Damien Neilf9d4fdf2020-02-07 11:42:45 -0800350 case validationTypeGroup:
351 ok = wtyp == wire.StartGroupType
Damien Neilb0c26f12019-12-16 09:37:59 -0800352 }
353 if ok {
Damien Neil170b2bf2020-01-24 16:42:42 -0800354 st.requiredMask |= vi.requiredBit
Damien Neilb0c26f12019-12-16 09:37:59 -0800355 }
356 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800357
358 switch wtyp {
359 case wire.VarintType:
Damien Neil0f783d82020-02-05 07:34:41 -0800360 if len(b) >= 10 {
Damien Neil8fa11b12020-01-28 08:31:04 -0800361 switch {
362 case b[0] < 0x80:
363 b = b[1:]
364 case b[1] < 0x80:
365 b = b[2:]
366 case b[2] < 0x80:
367 b = b[3:]
368 case b[3] < 0x80:
369 b = b[4:]
370 case b[4] < 0x80:
371 b = b[5:]
372 case b[5] < 0x80:
373 b = b[6:]
374 case b[6] < 0x80:
375 b = b[7:]
376 case b[7] < 0x80:
377 b = b[8:]
378 case b[8] < 0x80:
379 b = b[9:]
Damien Neil4d918162020-02-01 10:39:11 -0800380 case b[9] < 0x80 && b[9] < 2:
Damien Neil8fa11b12020-01-28 08:31:04 -0800381 b = b[10:]
382 default:
Damien Neilcadb4ab2020-02-03 16:17:31 -0800383 return out, ValidationInvalid
Damien Neil8fa11b12020-01-28 08:31:04 -0800384 }
385 } else {
386 switch {
387 case len(b) > 0 && b[0] < 0x80:
388 b = b[1:]
389 case len(b) > 1 && b[1] < 0x80:
390 b = b[2:]
391 case len(b) > 2 && b[2] < 0x80:
392 b = b[3:]
393 case len(b) > 3 && b[3] < 0x80:
394 b = b[4:]
395 case len(b) > 4 && b[4] < 0x80:
396 b = b[5:]
397 case len(b) > 5 && b[5] < 0x80:
398 b = b[6:]
399 case len(b) > 6 && b[6] < 0x80:
400 b = b[7:]
401 case len(b) > 7 && b[7] < 0x80:
402 b = b[8:]
403 case len(b) > 8 && b[8] < 0x80:
404 b = b[9:]
Damien Neil4d918162020-02-01 10:39:11 -0800405 case len(b) > 9 && b[9] < 2:
Damien Neil8fa11b12020-01-28 08:31:04 -0800406 b = b[10:]
407 default:
Damien Neilcadb4ab2020-02-03 16:17:31 -0800408 return out, ValidationInvalid
Damien Neil8fa11b12020-01-28 08:31:04 -0800409 }
Damien Neilb0c26f12019-12-16 09:37:59 -0800410 }
Damien Neilb0c26f12019-12-16 09:37:59 -0800411 continue State
Damien Neil8fa11b12020-01-28 08:31:04 -0800412 case wire.BytesType:
413 var size uint64
Damien Neil6f297792020-01-29 15:55:53 -0800414 if len(b) >= 1 && b[0] < 0x80 {
Damien Neil8fa11b12020-01-28 08:31:04 -0800415 size = uint64(b[0])
416 b = b[1:]
417 } else if len(b) >= 2 && b[1] < 128 {
418 size = uint64(b[0]&0x7f) + uint64(b[1])<<7
419 b = b[2:]
420 } else {
421 var n int
422 size, n = wire.ConsumeVarint(b)
Damien Neilb0c26f12019-12-16 09:37:59 -0800423 if n < 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800424 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800425 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800426 b = b[n:]
Damien Neilb0c26f12019-12-16 09:37:59 -0800427 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800428 if size > uint64(len(b)) {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800429 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800430 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800431 v := b[:size]
432 b = b[size:]
433 switch vi.typ {
Damien Neilcb0bfd02020-01-28 09:11:12 -0800434 case validationTypeMessage:
435 if vi.mi == nil {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800436 return out, ValidationUnknown
Damien Neil8fa11b12020-01-28 08:31:04 -0800437 }
Damien Neilcb0bfd02020-01-28 09:11:12 -0800438 vi.mi.init()
439 fallthrough
440 case validationTypeMap:
Damien Neil4eefd772020-02-06 10:27:31 -0800441 if vi.mi != nil {
442 vi.mi.init()
443 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800444 states = append(states, validationState{
445 typ: vi.typ,
446 keyType: vi.keyType,
447 valType: vi.valType,
448 mi: vi.mi,
449 tail: b,
450 })
451 b = v
452 continue State
453 case validationTypeRepeatedVarint:
454 // Packed field.
455 for len(v) > 0 {
456 _, n := wire.ConsumeVarint(v)
457 if n < 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800458 return out, ValidationInvalid
Damien Neil8fa11b12020-01-28 08:31:04 -0800459 }
460 v = v[n:]
461 }
462 case validationTypeRepeatedFixed32:
463 // Packed field.
464 if len(v)%4 != 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800465 return out, ValidationInvalid
Damien Neil8fa11b12020-01-28 08:31:04 -0800466 }
467 case validationTypeRepeatedFixed64:
468 // Packed field.
469 if len(v)%8 != 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800470 return out, ValidationInvalid
Damien Neil8fa11b12020-01-28 08:31:04 -0800471 }
472 case validationTypeUTF8String:
473 if !utf8.Valid(v) {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800474 return out, ValidationInvalid
Damien Neil8fa11b12020-01-28 08:31:04 -0800475 }
Damien Neilb0c26f12019-12-16 09:37:59 -0800476 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800477 case wire.Fixed32Type:
478 if len(b) < 4 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800479 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800480 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800481 b = b[4:]
482 case wire.Fixed64Type:
483 if len(b) < 8 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800484 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800485 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800486 b = b[8:]
487 case wire.StartGroupType:
Damien Neil9afe9bb2020-02-07 10:06:53 -0800488 switch {
489 case vi.typ == validationTypeGroup:
Damien Neil8fa11b12020-01-28 08:31:04 -0800490 if vi.mi == nil {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800491 return out, ValidationUnknown
Damien Neil8fa11b12020-01-28 08:31:04 -0800492 }
Damien Neilcb0bfd02020-01-28 09:11:12 -0800493 vi.mi.init()
Damien Neil8fa11b12020-01-28 08:31:04 -0800494 states = append(states, validationState{
495 typ: validationTypeGroup,
496 mi: vi.mi,
497 endGroup: num,
498 })
499 continue State
Damien Neil9afe9bb2020-02-07 10:06:53 -0800500 case flags.ProtoLegacy && vi.typ == validationTypeMessageSetItem:
501 typeid, v, n, err := messageset.ConsumeFieldValue(b, false)
502 if err != nil {
503 return out, ValidationInvalid
504 }
505 xt, err := opts.Resolver.FindExtensionByNumber(st.mi.Desc.FullName(), typeid)
506 switch {
507 case err == preg.NotFound:
508 b = b[n:]
509 case err != nil:
510 return out, ValidationUnknown
511 default:
512 xvi := getExtensionFieldInfo(xt).validation
513 states = append(states, validationState{
514 typ: xvi.typ,
515 mi: xvi.mi,
516 tail: b[n:],
517 })
518 b = v
519 continue State
520 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800521 default:
522 n := wire.ConsumeFieldValue(num, wtyp, b)
523 if n < 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800524 return out, ValidationInvalid
Damien Neil8fa11b12020-01-28 08:31:04 -0800525 }
526 b = b[n:]
527 }
528 default:
Damien Neilcadb4ab2020-02-03 16:17:31 -0800529 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800530 }
Damien Neilb0c26f12019-12-16 09:37:59 -0800531 }
532 if st.endGroup != 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800533 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800534 }
535 if len(b) != 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800536 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800537 }
538 b = st.tail
539 PopState:
Damien Neil54a0a042020-01-08 17:53:16 -0800540 numRequiredFields := 0
Damien Neilb0c26f12019-12-16 09:37:59 -0800541 switch st.typ {
542 case validationTypeMessage, validationTypeGroup:
Damien Neil54a0a042020-01-08 17:53:16 -0800543 numRequiredFields = int(st.mi.numRequiredFields)
544 case validationTypeMap:
545 // If this is a map field with a message value that contains
546 // required fields, require that the value be present.
547 if st.mi != nil && st.mi.numRequiredFields > 0 {
548 numRequiredFields = 1
Damien Neilb0c26f12019-12-16 09:37:59 -0800549 }
550 }
Damien Neil54a0a042020-01-08 17:53:16 -0800551 // If there are more than 64 required fields, this check will
552 // always fail and we will report that the message is potentially
553 // uninitialized.
554 if numRequiredFields > 0 && bits.OnesCount64(st.requiredMask) != numRequiredFields {
555 initialized = false
556 }
Damien Neilb0c26f12019-12-16 09:37:59 -0800557 states = states[:len(states)-1]
558 }
Damien Neilcadb4ab2020-02-03 16:17:31 -0800559 out.n = start - len(b)
560 if initialized {
561 out.initialized = true
Damien Neilb0c26f12019-12-16 09:37:59 -0800562 }
Damien Neilcadb4ab2020-02-03 16:17:31 -0800563 return out, ValidationValid
Damien Neilb0c26f12019-12-16 09:37:59 -0800564}