blob: 06acc78805800dc177180218a03c11f233c32e68 [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
14 "google.golang.org/protobuf/internal/encoding/wire"
Damien Neil0bf97b72020-01-24 09:00:33 -080015 "google.golang.org/protobuf/internal/flags"
Damien Neilb0c26f12019-12-16 09:37:59 -080016 "google.golang.org/protobuf/internal/strs"
17 pref "google.golang.org/protobuf/reflect/protoreflect"
18 preg "google.golang.org/protobuf/reflect/protoregistry"
19 piface "google.golang.org/protobuf/runtime/protoiface"
20)
21
22// ValidationStatus is the result of validating the wire-format encoding of a message.
23type ValidationStatus int
24
25const (
26 // ValidationUnknown indicates that unmarshaling the message might succeed or fail.
27 // The validator was unable to render a judgement.
28 //
29 // The only causes of this status are an aberrant message type appearing somewhere
30 // in the message or a failure in the extension resolver.
31 ValidationUnknown ValidationStatus = iota + 1
32
33 // ValidationInvalid indicates that unmarshaling the message will fail.
34 ValidationInvalid
35
Damien Neilcadb4ab2020-02-03 16:17:31 -080036 // ValidationValid indicates that unmarshaling the message will succeed.
37 ValidationValid
Damien Neilb0c26f12019-12-16 09:37:59 -080038)
39
40func (v ValidationStatus) String() string {
41 switch v {
42 case ValidationUnknown:
43 return "ValidationUnknown"
44 case ValidationInvalid:
45 return "ValidationInvalid"
Damien Neilcadb4ab2020-02-03 16:17:31 -080046 case ValidationValid:
47 return "ValidationValid"
Damien Neilb0c26f12019-12-16 09:37:59 -080048 default:
49 return fmt.Sprintf("ValidationStatus(%d)", int(v))
50 }
51}
52
53// Validate determines whether the contents of the buffer are a valid wire encoding
54// of the message type.
55//
56// This function is exposed for testing.
Damien Neilcadb4ab2020-02-03 16:17:31 -080057func Validate(b []byte, mt pref.MessageType, opts piface.UnmarshalOptions) (out piface.UnmarshalOutput, _ ValidationStatus) {
Damien Neilb0c26f12019-12-16 09:37:59 -080058 mi, ok := mt.(*MessageInfo)
59 if !ok {
Damien Neilcadb4ab2020-02-03 16:17:31 -080060 return out, ValidationUnknown
Damien Neilb0c26f12019-12-16 09:37:59 -080061 }
Damien Neilcadb4ab2020-02-03 16:17:31 -080062 o, st := mi.validate(b, 0, unmarshalOptions(opts))
63 out.Initialized = o.initialized
64 return out, st
Damien Neilb0c26f12019-12-16 09:37:59 -080065}
66
67type validationInfo struct {
68 mi *MessageInfo
69 typ validationType
70 keyType, valType validationType
71
Damien Neil170b2bf2020-01-24 16:42:42 -080072 // For non-required fields, requiredBit is 0.
Damien Neilb0c26f12019-12-16 09:37:59 -080073 //
Damien Neil170b2bf2020-01-24 16:42:42 -080074 // For required fields, requiredBit's nth bit is set, where n is a
75 // unique index in the range [0, MessageInfo.numRequiredFields).
76 //
77 // If there are more than 64 required fields, requiredBit is 0.
78 requiredBit uint64
Damien Neilb0c26f12019-12-16 09:37:59 -080079}
80
81type validationType uint8
82
83const (
84 validationTypeOther validationType = iota
85 validationTypeMessage
86 validationTypeGroup
87 validationTypeMap
88 validationTypeRepeatedVarint
89 validationTypeRepeatedFixed32
90 validationTypeRepeatedFixed64
91 validationTypeVarint
92 validationTypeFixed32
93 validationTypeFixed64
94 validationTypeBytes
95 validationTypeUTF8String
96)
97
98func newFieldValidationInfo(mi *MessageInfo, si structInfo, fd pref.FieldDescriptor, ft reflect.Type) validationInfo {
99 var vi validationInfo
100 switch {
101 case fd.ContainingOneof() != nil:
102 switch fd.Kind() {
103 case pref.MessageKind:
104 vi.typ = validationTypeMessage
105 if ot, ok := si.oneofWrappersByNumber[fd.Number()]; ok {
106 vi.mi = getMessageInfo(ot.Field(0).Type)
107 }
108 case pref.GroupKind:
109 vi.typ = validationTypeGroup
110 if ot, ok := si.oneofWrappersByNumber[fd.Number()]; ok {
111 vi.mi = getMessageInfo(ot.Field(0).Type)
112 }
113 case pref.StringKind:
114 if strs.EnforceUTF8(fd) {
115 vi.typ = validationTypeUTF8String
116 }
117 }
118 default:
119 vi = newValidationInfo(fd, ft)
120 }
121 if fd.Cardinality() == pref.Required {
122 // Avoid overflow. The required field check is done with a 64-bit mask, with
123 // any message containing more than 64 required fields always reported as
124 // potentially uninitialized, so it is not important to get a precise count
125 // of the required fields past 64.
126 if mi.numRequiredFields < math.MaxUint8 {
127 mi.numRequiredFields++
Damien Neil170b2bf2020-01-24 16:42:42 -0800128 vi.requiredBit = 1 << (mi.numRequiredFields - 1)
Damien Neilb0c26f12019-12-16 09:37:59 -0800129 }
130 }
131 return vi
132}
133
134func newValidationInfo(fd pref.FieldDescriptor, ft reflect.Type) validationInfo {
135 var vi validationInfo
136 switch {
137 case fd.IsList():
138 switch fd.Kind() {
139 case pref.MessageKind:
140 vi.typ = validationTypeMessage
141 if ft.Kind() == reflect.Slice {
142 vi.mi = getMessageInfo(ft.Elem())
143 }
144 case pref.GroupKind:
145 vi.typ = validationTypeGroup
146 if ft.Kind() == reflect.Slice {
147 vi.mi = getMessageInfo(ft.Elem())
148 }
149 case pref.StringKind:
150 vi.typ = validationTypeBytes
151 if strs.EnforceUTF8(fd) {
152 vi.typ = validationTypeUTF8String
153 }
154 default:
155 switch wireTypes[fd.Kind()] {
156 case wire.VarintType:
157 vi.typ = validationTypeRepeatedVarint
158 case wire.Fixed32Type:
159 vi.typ = validationTypeRepeatedFixed32
160 case wire.Fixed64Type:
161 vi.typ = validationTypeRepeatedFixed64
162 }
163 }
164 case fd.IsMap():
165 vi.typ = validationTypeMap
166 switch fd.MapKey().Kind() {
167 case pref.StringKind:
168 if strs.EnforceUTF8(fd) {
169 vi.keyType = validationTypeUTF8String
170 }
171 }
172 switch fd.MapValue().Kind() {
173 case pref.MessageKind:
174 vi.valType = validationTypeMessage
175 if ft.Kind() == reflect.Map {
176 vi.mi = getMessageInfo(ft.Elem())
177 }
178 case pref.StringKind:
179 if strs.EnforceUTF8(fd) {
180 vi.valType = validationTypeUTF8String
181 }
182 }
183 default:
184 switch fd.Kind() {
185 case pref.MessageKind:
186 vi.typ = validationTypeMessage
187 if !fd.IsWeak() {
188 vi.mi = getMessageInfo(ft)
189 }
190 case pref.GroupKind:
191 vi.typ = validationTypeGroup
192 vi.mi = getMessageInfo(ft)
193 case pref.StringKind:
194 vi.typ = validationTypeBytes
195 if strs.EnforceUTF8(fd) {
196 vi.typ = validationTypeUTF8String
197 }
198 default:
199 switch wireTypes[fd.Kind()] {
200 case wire.VarintType:
201 vi.typ = validationTypeVarint
202 case wire.Fixed32Type:
203 vi.typ = validationTypeFixed32
204 case wire.Fixed64Type:
205 vi.typ = validationTypeFixed64
Damien Neil6635e7d2020-01-15 15:08:57 -0800206 case wire.BytesType:
207 vi.typ = validationTypeBytes
Damien Neilb0c26f12019-12-16 09:37:59 -0800208 }
209 }
210 }
211 return vi
212}
213
Damien Neilcadb4ab2020-02-03 16:17:31 -0800214func (mi *MessageInfo) validate(b []byte, groupTag wire.Number, opts unmarshalOptions) (out unmarshalOutput, result ValidationStatus) {
Damien Neilcb0bfd02020-01-28 09:11:12 -0800215 mi.init()
Damien Neilb0c26f12019-12-16 09:37:59 -0800216 type validationState struct {
217 typ validationType
218 keyType, valType validationType
219 endGroup wire.Number
220 mi *MessageInfo
221 tail []byte
222 requiredMask uint64
223 }
224
225 // Pre-allocate some slots to avoid repeated slice reallocation.
226 states := make([]validationState, 0, 16)
227 states = append(states, validationState{
228 typ: validationTypeMessage,
229 mi: mi,
230 })
231 if groupTag > 0 {
232 states[0].typ = validationTypeGroup
233 states[0].endGroup = groupTag
234 }
235 initialized := true
Damien Neilcadb4ab2020-02-03 16:17:31 -0800236 start := len(b)
Damien Neilb0c26f12019-12-16 09:37:59 -0800237State:
238 for len(states) > 0 {
239 st := &states[len(states)-1]
240 if st.mi != nil {
Damien Neil0bf97b72020-01-24 09:00:33 -0800241 if flags.ProtoLegacy && st.mi.isMessageSet {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800242 return out, ValidationUnknown
Damien Neil0bf97b72020-01-24 09:00:33 -0800243 }
Damien Neilb0c26f12019-12-16 09:37:59 -0800244 }
Damien Neilb0c26f12019-12-16 09:37:59 -0800245 for len(b) > 0 {
Damien Neil5d828832020-01-28 08:06:12 -0800246 // Parse the tag (field number and wire type).
247 var tag uint64
248 if b[0] < 0x80 {
249 tag = uint64(b[0])
250 b = b[1:]
251 } else if len(b) >= 2 && b[1] < 128 {
252 tag = uint64(b[0]&0x7f) + uint64(b[1])<<7
253 b = b[2:]
254 } else {
255 var n int
256 tag, n = wire.ConsumeVarint(b)
257 if n < 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800258 return out, ValidationInvalid
Damien Neil5d828832020-01-28 08:06:12 -0800259 }
260 b = b[n:]
Damien Neilb0c26f12019-12-16 09:37:59 -0800261 }
Damien Neil5d828832020-01-28 08:06:12 -0800262 var num wire.Number
263 if n := tag >> 3; n < uint64(wire.MinValidNumber) || n > uint64(wire.MaxValidNumber) {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800264 return out, ValidationInvalid
Damien Neil5d828832020-01-28 08:06:12 -0800265 } else {
266 num = wire.Number(n)
Damien Neilb0c26f12019-12-16 09:37:59 -0800267 }
Damien Neil5d828832020-01-28 08:06:12 -0800268 wtyp := wire.Type(tag & 7)
269
Damien Neilb0c26f12019-12-16 09:37:59 -0800270 if wtyp == wire.EndGroupType {
271 if st.endGroup == num {
272 goto PopState
273 }
Damien Neilcadb4ab2020-02-03 16:17:31 -0800274 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800275 }
276 var vi validationInfo
277 switch st.typ {
278 case validationTypeMap:
279 switch num {
280 case 1:
281 vi.typ = st.keyType
282 case 2:
283 vi.typ = st.valType
284 vi.mi = st.mi
Damien Neil170b2bf2020-01-24 16:42:42 -0800285 vi.requiredBit = 1
Damien Neilb0c26f12019-12-16 09:37:59 -0800286 }
287 default:
288 var f *coderFieldInfo
289 if int(num) < len(st.mi.denseCoderFields) {
290 f = st.mi.denseCoderFields[num]
291 } else {
292 f = st.mi.coderFields[num]
293 }
294 if f != nil {
295 vi = f.validation
296 if vi.typ == validationTypeMessage && vi.mi == nil {
297 // Probable weak field.
298 //
299 // TODO: Consider storing the results of this lookup somewhere
300 // rather than recomputing it on every validation.
301 fd := st.mi.Desc.Fields().ByNumber(num)
302 if fd == nil || !fd.IsWeak() {
303 break
304 }
305 messageName := fd.Message().FullName()
306 messageType, err := preg.GlobalTypes.FindMessageByName(messageName)
307 switch err {
308 case nil:
309 vi.mi, _ = messageType.(*MessageInfo)
310 case preg.NotFound:
311 vi.typ = validationTypeBytes
312 default:
Damien Neilcadb4ab2020-02-03 16:17:31 -0800313 return out, ValidationUnknown
Damien Neilb0c26f12019-12-16 09:37:59 -0800314 }
315 }
316 break
317 }
318 // Possible extension field.
319 //
320 // TODO: We should return ValidationUnknown when:
321 // 1. The resolver is not frozen. (More extensions may be added to it.)
322 // 2. The resolver returns preg.NotFound.
323 // In this case, a type added to the resolver in the future could cause
324 // unmarshaling to begin failing. Supporting this requires some way to
325 // determine if the resolver is frozen.
Damien Neil524c6062020-01-28 13:32:01 -0800326 xt, err := opts.Resolver.FindExtensionByNumber(st.mi.Desc.FullName(), num)
Damien Neilb0c26f12019-12-16 09:37:59 -0800327 if err != nil && err != preg.NotFound {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800328 return out, ValidationUnknown
Damien Neilb0c26f12019-12-16 09:37:59 -0800329 }
330 if err == nil {
331 vi = getExtensionFieldInfo(xt).validation
332 }
333 }
Damien Neil170b2bf2020-01-24 16:42:42 -0800334 if vi.requiredBit != 0 {
Damien Neilb0c26f12019-12-16 09:37:59 -0800335 // Check that the field has a compatible wire type.
336 // We only need to consider non-repeated field types,
337 // since repeated fields (and maps) can never be required.
338 ok := false
339 switch vi.typ {
340 case validationTypeVarint:
341 ok = wtyp == wire.VarintType
342 case validationTypeFixed32:
343 ok = wtyp == wire.Fixed32Type
344 case validationTypeFixed64:
345 ok = wtyp == wire.Fixed64Type
Damien Neilf9d4fdf2020-02-07 11:42:45 -0800346 case validationTypeBytes, validationTypeUTF8String, validationTypeMessage:
Damien Neilb0c26f12019-12-16 09:37:59 -0800347 ok = wtyp == wire.BytesType
Damien Neilf9d4fdf2020-02-07 11:42:45 -0800348 case validationTypeGroup:
349 ok = wtyp == wire.StartGroupType
Damien Neilb0c26f12019-12-16 09:37:59 -0800350 }
351 if ok {
Damien Neil170b2bf2020-01-24 16:42:42 -0800352 st.requiredMask |= vi.requiredBit
Damien Neilb0c26f12019-12-16 09:37:59 -0800353 }
354 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800355
356 switch wtyp {
357 case wire.VarintType:
Damien Neil0f783d82020-02-05 07:34:41 -0800358 if len(b) >= 10 {
Damien Neil8fa11b12020-01-28 08:31:04 -0800359 switch {
360 case b[0] < 0x80:
361 b = b[1:]
362 case b[1] < 0x80:
363 b = b[2:]
364 case b[2] < 0x80:
365 b = b[3:]
366 case b[3] < 0x80:
367 b = b[4:]
368 case b[4] < 0x80:
369 b = b[5:]
370 case b[5] < 0x80:
371 b = b[6:]
372 case b[6] < 0x80:
373 b = b[7:]
374 case b[7] < 0x80:
375 b = b[8:]
376 case b[8] < 0x80:
377 b = b[9:]
Damien Neil4d918162020-02-01 10:39:11 -0800378 case b[9] < 0x80 && b[9] < 2:
Damien Neil8fa11b12020-01-28 08:31:04 -0800379 b = b[10:]
380 default:
Damien Neilcadb4ab2020-02-03 16:17:31 -0800381 return out, ValidationInvalid
Damien Neil8fa11b12020-01-28 08:31:04 -0800382 }
383 } else {
384 switch {
385 case len(b) > 0 && b[0] < 0x80:
386 b = b[1:]
387 case len(b) > 1 && b[1] < 0x80:
388 b = b[2:]
389 case len(b) > 2 && b[2] < 0x80:
390 b = b[3:]
391 case len(b) > 3 && b[3] < 0x80:
392 b = b[4:]
393 case len(b) > 4 && b[4] < 0x80:
394 b = b[5:]
395 case len(b) > 5 && b[5] < 0x80:
396 b = b[6:]
397 case len(b) > 6 && b[6] < 0x80:
398 b = b[7:]
399 case len(b) > 7 && b[7] < 0x80:
400 b = b[8:]
401 case len(b) > 8 && b[8] < 0x80:
402 b = b[9:]
Damien Neil4d918162020-02-01 10:39:11 -0800403 case len(b) > 9 && b[9] < 2:
Damien Neil8fa11b12020-01-28 08:31:04 -0800404 b = b[10:]
405 default:
Damien Neilcadb4ab2020-02-03 16:17:31 -0800406 return out, ValidationInvalid
Damien Neil8fa11b12020-01-28 08:31:04 -0800407 }
Damien Neilb0c26f12019-12-16 09:37:59 -0800408 }
Damien Neilb0c26f12019-12-16 09:37:59 -0800409 continue State
Damien Neil8fa11b12020-01-28 08:31:04 -0800410 case wire.BytesType:
411 var size uint64
Damien Neil6f297792020-01-29 15:55:53 -0800412 if len(b) >= 1 && b[0] < 0x80 {
Damien Neil8fa11b12020-01-28 08:31:04 -0800413 size = uint64(b[0])
414 b = b[1:]
415 } else if len(b) >= 2 && b[1] < 128 {
416 size = uint64(b[0]&0x7f) + uint64(b[1])<<7
417 b = b[2:]
418 } else {
419 var n int
420 size, n = wire.ConsumeVarint(b)
Damien Neilb0c26f12019-12-16 09:37:59 -0800421 if n < 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800422 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800423 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800424 b = b[n:]
Damien Neilb0c26f12019-12-16 09:37:59 -0800425 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800426 if size > uint64(len(b)) {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800427 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800428 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800429 v := b[:size]
430 b = b[size:]
431 switch vi.typ {
Damien Neilcb0bfd02020-01-28 09:11:12 -0800432 case validationTypeMessage:
433 if vi.mi == nil {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800434 return out, ValidationUnknown
Damien Neil8fa11b12020-01-28 08:31:04 -0800435 }
Damien Neilcb0bfd02020-01-28 09:11:12 -0800436 vi.mi.init()
437 fallthrough
438 case validationTypeMap:
Damien Neil4eefd772020-02-06 10:27:31 -0800439 if vi.mi != nil {
440 vi.mi.init()
441 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800442 states = append(states, validationState{
443 typ: vi.typ,
444 keyType: vi.keyType,
445 valType: vi.valType,
446 mi: vi.mi,
447 tail: b,
448 })
449 b = v
450 continue State
451 case validationTypeRepeatedVarint:
452 // Packed field.
453 for len(v) > 0 {
454 _, n := wire.ConsumeVarint(v)
455 if n < 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800456 return out, ValidationInvalid
Damien Neil8fa11b12020-01-28 08:31:04 -0800457 }
458 v = v[n:]
459 }
460 case validationTypeRepeatedFixed32:
461 // Packed field.
462 if len(v)%4 != 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800463 return out, ValidationInvalid
Damien Neil8fa11b12020-01-28 08:31:04 -0800464 }
465 case validationTypeRepeatedFixed64:
466 // Packed field.
467 if len(v)%8 != 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800468 return out, ValidationInvalid
Damien Neil8fa11b12020-01-28 08:31:04 -0800469 }
470 case validationTypeUTF8String:
471 if !utf8.Valid(v) {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800472 return out, ValidationInvalid
Damien Neil8fa11b12020-01-28 08:31:04 -0800473 }
Damien Neilb0c26f12019-12-16 09:37:59 -0800474 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800475 case wire.Fixed32Type:
476 if len(b) < 4 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800477 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800478 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800479 b = b[4:]
480 case wire.Fixed64Type:
481 if len(b) < 8 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800482 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800483 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800484 b = b[8:]
485 case wire.StartGroupType:
486 switch vi.typ {
487 case validationTypeGroup:
488 if vi.mi == nil {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800489 return out, ValidationUnknown
Damien Neil8fa11b12020-01-28 08:31:04 -0800490 }
Damien Neilcb0bfd02020-01-28 09:11:12 -0800491 vi.mi.init()
Damien Neil8fa11b12020-01-28 08:31:04 -0800492 states = append(states, validationState{
493 typ: validationTypeGroup,
494 mi: vi.mi,
495 endGroup: num,
496 })
497 continue State
498 default:
499 n := wire.ConsumeFieldValue(num, wtyp, b)
500 if n < 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800501 return out, ValidationInvalid
Damien Neil8fa11b12020-01-28 08:31:04 -0800502 }
503 b = b[n:]
504 }
505 default:
Damien Neilcadb4ab2020-02-03 16:17:31 -0800506 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800507 }
Damien Neilb0c26f12019-12-16 09:37:59 -0800508 }
509 if st.endGroup != 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800510 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800511 }
512 if len(b) != 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800513 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800514 }
515 b = st.tail
516 PopState:
Damien Neil54a0a042020-01-08 17:53:16 -0800517 numRequiredFields := 0
Damien Neilb0c26f12019-12-16 09:37:59 -0800518 switch st.typ {
519 case validationTypeMessage, validationTypeGroup:
Damien Neil54a0a042020-01-08 17:53:16 -0800520 numRequiredFields = int(st.mi.numRequiredFields)
521 case validationTypeMap:
522 // If this is a map field with a message value that contains
523 // required fields, require that the value be present.
524 if st.mi != nil && st.mi.numRequiredFields > 0 {
525 numRequiredFields = 1
Damien Neilb0c26f12019-12-16 09:37:59 -0800526 }
527 }
Damien Neil54a0a042020-01-08 17:53:16 -0800528 // If there are more than 64 required fields, this check will
529 // always fail and we will report that the message is potentially
530 // uninitialized.
531 if numRequiredFields > 0 && bits.OnesCount64(st.requiredMask) != numRequiredFields {
532 initialized = false
533 }
Damien Neilb0c26f12019-12-16 09:37:59 -0800534 states = states[:len(states)-1]
535 }
Damien Neilcadb4ab2020-02-03 16:17:31 -0800536 out.n = start - len(b)
537 if initialized {
538 out.initialized = true
Damien Neilb0c26f12019-12-16 09:37:59 -0800539 }
Damien Neilcadb4ab2020-02-03 16:17:31 -0800540 return out, ValidationValid
Damien Neilb0c26f12019-12-16 09:37:59 -0800541}