blob: 57de9cc85b13586f433647ac9f760655d9fb220f [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
Joe Tsaicd108d02020-02-14 18:08:02 -080014 "google.golang.org/protobuf/encoding/protowire"
Damien Neil9afe9bb2020-02-07 10:06:53 -080015 "google.golang.org/protobuf/internal/encoding/messageset"
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 Neil466dd772020-02-14 14:49:35 -080058func Validate(mt pref.MessageType, in piface.UnmarshalInput) (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 Neil466dd772020-02-14 14:49:35 -080063 if in.Resolver == nil {
64 in.Resolver = preg.GlobalTypes
65 }
66 o, st := mi.validate(in.Buf, 0, unmarshalOptions{
67 flags: in.Flags,
68 resolver: in.Resolver,
69 })
70 if o.initialized {
71 out.Flags |= piface.UnmarshalInitialized
72 }
Damien Neilcadb4ab2020-02-03 16:17:31 -080073 return out, st
Damien Neilb0c26f12019-12-16 09:37:59 -080074}
75
76type validationInfo struct {
77 mi *MessageInfo
78 typ validationType
79 keyType, valType validationType
80
Damien Neil170b2bf2020-01-24 16:42:42 -080081 // For non-required fields, requiredBit is 0.
Damien Neilb0c26f12019-12-16 09:37:59 -080082 //
Damien Neil170b2bf2020-01-24 16:42:42 -080083 // For required fields, requiredBit's nth bit is set, where n is a
84 // unique index in the range [0, MessageInfo.numRequiredFields).
85 //
86 // If there are more than 64 required fields, requiredBit is 0.
87 requiredBit uint64
Damien Neilb0c26f12019-12-16 09:37:59 -080088}
89
90type validationType uint8
91
92const (
93 validationTypeOther validationType = iota
94 validationTypeMessage
95 validationTypeGroup
96 validationTypeMap
97 validationTypeRepeatedVarint
98 validationTypeRepeatedFixed32
99 validationTypeRepeatedFixed64
100 validationTypeVarint
101 validationTypeFixed32
102 validationTypeFixed64
103 validationTypeBytes
104 validationTypeUTF8String
Damien Neil9afe9bb2020-02-07 10:06:53 -0800105 validationTypeMessageSetItem
Damien Neilb0c26f12019-12-16 09:37:59 -0800106)
107
108func newFieldValidationInfo(mi *MessageInfo, si structInfo, fd pref.FieldDescriptor, ft reflect.Type) validationInfo {
109 var vi validationInfo
110 switch {
Joe Tsai387873d2020-04-28 14:44:38 -0700111 case fd.ContainingOneof() != nil && !fd.ContainingOneof().IsSynthetic():
Damien Neilb0c26f12019-12-16 09:37:59 -0800112 switch fd.Kind() {
113 case pref.MessageKind:
114 vi.typ = validationTypeMessage
115 if ot, ok := si.oneofWrappersByNumber[fd.Number()]; ok {
116 vi.mi = getMessageInfo(ot.Field(0).Type)
117 }
118 case pref.GroupKind:
119 vi.typ = validationTypeGroup
120 if ot, ok := si.oneofWrappersByNumber[fd.Number()]; ok {
121 vi.mi = getMessageInfo(ot.Field(0).Type)
122 }
123 case pref.StringKind:
124 if strs.EnforceUTF8(fd) {
125 vi.typ = validationTypeUTF8String
126 }
127 }
128 default:
129 vi = newValidationInfo(fd, ft)
130 }
131 if fd.Cardinality() == pref.Required {
132 // Avoid overflow. The required field check is done with a 64-bit mask, with
133 // any message containing more than 64 required fields always reported as
134 // potentially uninitialized, so it is not important to get a precise count
135 // of the required fields past 64.
136 if mi.numRequiredFields < math.MaxUint8 {
137 mi.numRequiredFields++
Damien Neil170b2bf2020-01-24 16:42:42 -0800138 vi.requiredBit = 1 << (mi.numRequiredFields - 1)
Damien Neilb0c26f12019-12-16 09:37:59 -0800139 }
140 }
141 return vi
142}
143
144func newValidationInfo(fd pref.FieldDescriptor, ft reflect.Type) validationInfo {
145 var vi validationInfo
146 switch {
147 case fd.IsList():
148 switch fd.Kind() {
149 case pref.MessageKind:
150 vi.typ = validationTypeMessage
151 if ft.Kind() == reflect.Slice {
152 vi.mi = getMessageInfo(ft.Elem())
153 }
154 case pref.GroupKind:
155 vi.typ = validationTypeGroup
156 if ft.Kind() == reflect.Slice {
157 vi.mi = getMessageInfo(ft.Elem())
158 }
159 case pref.StringKind:
160 vi.typ = validationTypeBytes
161 if strs.EnforceUTF8(fd) {
162 vi.typ = validationTypeUTF8String
163 }
164 default:
165 switch wireTypes[fd.Kind()] {
Joe Tsaicd108d02020-02-14 18:08:02 -0800166 case protowire.VarintType:
Damien Neilb0c26f12019-12-16 09:37:59 -0800167 vi.typ = validationTypeRepeatedVarint
Joe Tsaicd108d02020-02-14 18:08:02 -0800168 case protowire.Fixed32Type:
Damien Neilb0c26f12019-12-16 09:37:59 -0800169 vi.typ = validationTypeRepeatedFixed32
Joe Tsaicd108d02020-02-14 18:08:02 -0800170 case protowire.Fixed64Type:
Damien Neilb0c26f12019-12-16 09:37:59 -0800171 vi.typ = validationTypeRepeatedFixed64
172 }
173 }
174 case fd.IsMap():
175 vi.typ = validationTypeMap
176 switch fd.MapKey().Kind() {
177 case pref.StringKind:
178 if strs.EnforceUTF8(fd) {
179 vi.keyType = validationTypeUTF8String
180 }
181 }
182 switch fd.MapValue().Kind() {
183 case pref.MessageKind:
184 vi.valType = validationTypeMessage
185 if ft.Kind() == reflect.Map {
186 vi.mi = getMessageInfo(ft.Elem())
187 }
188 case pref.StringKind:
189 if strs.EnforceUTF8(fd) {
190 vi.valType = validationTypeUTF8String
191 }
192 }
193 default:
194 switch fd.Kind() {
195 case pref.MessageKind:
196 vi.typ = validationTypeMessage
197 if !fd.IsWeak() {
198 vi.mi = getMessageInfo(ft)
199 }
200 case pref.GroupKind:
201 vi.typ = validationTypeGroup
202 vi.mi = getMessageInfo(ft)
203 case pref.StringKind:
204 vi.typ = validationTypeBytes
205 if strs.EnforceUTF8(fd) {
206 vi.typ = validationTypeUTF8String
207 }
208 default:
209 switch wireTypes[fd.Kind()] {
Joe Tsaicd108d02020-02-14 18:08:02 -0800210 case protowire.VarintType:
Damien Neilb0c26f12019-12-16 09:37:59 -0800211 vi.typ = validationTypeVarint
Joe Tsaicd108d02020-02-14 18:08:02 -0800212 case protowire.Fixed32Type:
Damien Neilb0c26f12019-12-16 09:37:59 -0800213 vi.typ = validationTypeFixed32
Joe Tsaicd108d02020-02-14 18:08:02 -0800214 case protowire.Fixed64Type:
Damien Neilb0c26f12019-12-16 09:37:59 -0800215 vi.typ = validationTypeFixed64
Joe Tsaicd108d02020-02-14 18:08:02 -0800216 case protowire.BytesType:
Damien Neil6635e7d2020-01-15 15:08:57 -0800217 vi.typ = validationTypeBytes
Damien Neilb0c26f12019-12-16 09:37:59 -0800218 }
219 }
220 }
221 return vi
222}
223
Joe Tsaicd108d02020-02-14 18:08:02 -0800224func (mi *MessageInfo) validate(b []byte, groupTag protowire.Number, opts unmarshalOptions) (out unmarshalOutput, result ValidationStatus) {
Damien Neilcb0bfd02020-01-28 09:11:12 -0800225 mi.init()
Damien Neilb0c26f12019-12-16 09:37:59 -0800226 type validationState struct {
227 typ validationType
228 keyType, valType validationType
Joe Tsaicd108d02020-02-14 18:08:02 -0800229 endGroup protowire.Number
Damien Neilb0c26f12019-12-16 09:37:59 -0800230 mi *MessageInfo
231 tail []byte
232 requiredMask uint64
233 }
234
235 // Pre-allocate some slots to avoid repeated slice reallocation.
236 states := make([]validationState, 0, 16)
237 states = append(states, validationState{
238 typ: validationTypeMessage,
239 mi: mi,
240 })
241 if groupTag > 0 {
242 states[0].typ = validationTypeGroup
243 states[0].endGroup = groupTag
244 }
245 initialized := true
Damien Neilcadb4ab2020-02-03 16:17:31 -0800246 start := len(b)
Damien Neilb0c26f12019-12-16 09:37:59 -0800247State:
248 for len(states) > 0 {
249 st := &states[len(states)-1]
Damien Neilb0c26f12019-12-16 09:37:59 -0800250 for len(b) > 0 {
Damien Neil5d828832020-01-28 08:06:12 -0800251 // Parse the tag (field number and wire type).
252 var tag uint64
253 if b[0] < 0x80 {
254 tag = uint64(b[0])
255 b = b[1:]
256 } else if len(b) >= 2 && b[1] < 128 {
257 tag = uint64(b[0]&0x7f) + uint64(b[1])<<7
258 b = b[2:]
259 } else {
260 var n int
Joe Tsaicd108d02020-02-14 18:08:02 -0800261 tag, n = protowire.ConsumeVarint(b)
Damien Neil5d828832020-01-28 08:06:12 -0800262 if n < 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800263 return out, ValidationInvalid
Damien Neil5d828832020-01-28 08:06:12 -0800264 }
265 b = b[n:]
Damien Neilb0c26f12019-12-16 09:37:59 -0800266 }
Joe Tsaicd108d02020-02-14 18:08:02 -0800267 var num protowire.Number
268 if n := tag >> 3; n < uint64(protowire.MinValidNumber) || n > uint64(protowire.MaxValidNumber) {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800269 return out, ValidationInvalid
Damien Neil5d828832020-01-28 08:06:12 -0800270 } else {
Joe Tsaicd108d02020-02-14 18:08:02 -0800271 num = protowire.Number(n)
Damien Neilb0c26f12019-12-16 09:37:59 -0800272 }
Joe Tsaicd108d02020-02-14 18:08:02 -0800273 wtyp := protowire.Type(tag & 7)
Damien Neil5d828832020-01-28 08:06:12 -0800274
Joe Tsaicd108d02020-02-14 18:08:02 -0800275 if wtyp == protowire.EndGroupType {
Damien Neilb0c26f12019-12-16 09:37:59 -0800276 if st.endGroup == num {
277 goto PopState
278 }
Damien Neilcadb4ab2020-02-03 16:17:31 -0800279 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800280 }
281 var vi validationInfo
Damien Neil9afe9bb2020-02-07 10:06:53 -0800282 switch {
283 case st.typ == validationTypeMap:
Damien Neilb0c26f12019-12-16 09:37:59 -0800284 switch num {
285 case 1:
286 vi.typ = st.keyType
287 case 2:
288 vi.typ = st.valType
289 vi.mi = st.mi
Damien Neil170b2bf2020-01-24 16:42:42 -0800290 vi.requiredBit = 1
Damien Neilb0c26f12019-12-16 09:37:59 -0800291 }
Damien Neil9afe9bb2020-02-07 10:06:53 -0800292 case flags.ProtoLegacy && st.mi.isMessageSet:
293 switch num {
294 case messageset.FieldItem:
295 vi.typ = validationTypeMessageSetItem
296 }
Damien Neilb0c26f12019-12-16 09:37:59 -0800297 default:
298 var f *coderFieldInfo
299 if int(num) < len(st.mi.denseCoderFields) {
300 f = st.mi.denseCoderFields[num]
301 } else {
302 f = st.mi.coderFields[num]
303 }
304 if f != nil {
305 vi = f.validation
306 if vi.typ == validationTypeMessage && vi.mi == nil {
307 // Probable weak field.
308 //
309 // TODO: Consider storing the results of this lookup somewhere
310 // rather than recomputing it on every validation.
311 fd := st.mi.Desc.Fields().ByNumber(num)
312 if fd == nil || !fd.IsWeak() {
313 break
314 }
315 messageName := fd.Message().FullName()
316 messageType, err := preg.GlobalTypes.FindMessageByName(messageName)
317 switch err {
318 case nil:
319 vi.mi, _ = messageType.(*MessageInfo)
320 case preg.NotFound:
321 vi.typ = validationTypeBytes
322 default:
Damien Neilcadb4ab2020-02-03 16:17:31 -0800323 return out, ValidationUnknown
Damien Neilb0c26f12019-12-16 09:37:59 -0800324 }
325 }
326 break
327 }
328 // Possible extension field.
329 //
330 // TODO: We should return ValidationUnknown when:
331 // 1. The resolver is not frozen. (More extensions may be added to it.)
332 // 2. The resolver returns preg.NotFound.
333 // In this case, a type added to the resolver in the future could cause
334 // unmarshaling to begin failing. Supporting this requires some way to
335 // determine if the resolver is frozen.
Damien Neil466dd772020-02-14 14:49:35 -0800336 xt, err := opts.resolver.FindExtensionByNumber(st.mi.Desc.FullName(), num)
Damien Neilb0c26f12019-12-16 09:37:59 -0800337 if err != nil && err != preg.NotFound {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800338 return out, ValidationUnknown
Damien Neilb0c26f12019-12-16 09:37:59 -0800339 }
340 if err == nil {
341 vi = getExtensionFieldInfo(xt).validation
342 }
343 }
Damien Neil170b2bf2020-01-24 16:42:42 -0800344 if vi.requiredBit != 0 {
Damien Neilb0c26f12019-12-16 09:37:59 -0800345 // Check that the field has a compatible wire type.
346 // We only need to consider non-repeated field types,
347 // since repeated fields (and maps) can never be required.
348 ok := false
349 switch vi.typ {
350 case validationTypeVarint:
Joe Tsaicd108d02020-02-14 18:08:02 -0800351 ok = wtyp == protowire.VarintType
Damien Neilb0c26f12019-12-16 09:37:59 -0800352 case validationTypeFixed32:
Joe Tsaicd108d02020-02-14 18:08:02 -0800353 ok = wtyp == protowire.Fixed32Type
Damien Neilb0c26f12019-12-16 09:37:59 -0800354 case validationTypeFixed64:
Joe Tsaicd108d02020-02-14 18:08:02 -0800355 ok = wtyp == protowire.Fixed64Type
Damien Neilf9d4fdf2020-02-07 11:42:45 -0800356 case validationTypeBytes, validationTypeUTF8String, validationTypeMessage:
Joe Tsaicd108d02020-02-14 18:08:02 -0800357 ok = wtyp == protowire.BytesType
Damien Neilf9d4fdf2020-02-07 11:42:45 -0800358 case validationTypeGroup:
Joe Tsaicd108d02020-02-14 18:08:02 -0800359 ok = wtyp == protowire.StartGroupType
Damien Neilb0c26f12019-12-16 09:37:59 -0800360 }
361 if ok {
Damien Neil170b2bf2020-01-24 16:42:42 -0800362 st.requiredMask |= vi.requiredBit
Damien Neilb0c26f12019-12-16 09:37:59 -0800363 }
364 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800365
366 switch wtyp {
Joe Tsaicd108d02020-02-14 18:08:02 -0800367 case protowire.VarintType:
Damien Neil0f783d82020-02-05 07:34:41 -0800368 if len(b) >= 10 {
Damien Neil8fa11b12020-01-28 08:31:04 -0800369 switch {
370 case b[0] < 0x80:
371 b = b[1:]
372 case b[1] < 0x80:
373 b = b[2:]
374 case b[2] < 0x80:
375 b = b[3:]
376 case b[3] < 0x80:
377 b = b[4:]
378 case b[4] < 0x80:
379 b = b[5:]
380 case b[5] < 0x80:
381 b = b[6:]
382 case b[6] < 0x80:
383 b = b[7:]
384 case b[7] < 0x80:
385 b = b[8:]
386 case b[8] < 0x80:
387 b = b[9:]
Damien Neil4d918162020-02-01 10:39:11 -0800388 case b[9] < 0x80 && b[9] < 2:
Damien Neil8fa11b12020-01-28 08:31:04 -0800389 b = b[10:]
390 default:
Damien Neilcadb4ab2020-02-03 16:17:31 -0800391 return out, ValidationInvalid
Damien Neil8fa11b12020-01-28 08:31:04 -0800392 }
393 } else {
394 switch {
395 case len(b) > 0 && b[0] < 0x80:
396 b = b[1:]
397 case len(b) > 1 && b[1] < 0x80:
398 b = b[2:]
399 case len(b) > 2 && b[2] < 0x80:
400 b = b[3:]
401 case len(b) > 3 && b[3] < 0x80:
402 b = b[4:]
403 case len(b) > 4 && b[4] < 0x80:
404 b = b[5:]
405 case len(b) > 5 && b[5] < 0x80:
406 b = b[6:]
407 case len(b) > 6 && b[6] < 0x80:
408 b = b[7:]
409 case len(b) > 7 && b[7] < 0x80:
410 b = b[8:]
411 case len(b) > 8 && b[8] < 0x80:
412 b = b[9:]
Damien Neil4d918162020-02-01 10:39:11 -0800413 case len(b) > 9 && b[9] < 2:
Damien Neil8fa11b12020-01-28 08:31:04 -0800414 b = b[10:]
415 default:
Damien Neilcadb4ab2020-02-03 16:17:31 -0800416 return out, ValidationInvalid
Damien Neil8fa11b12020-01-28 08:31:04 -0800417 }
Damien Neilb0c26f12019-12-16 09:37:59 -0800418 }
Damien Neilb0c26f12019-12-16 09:37:59 -0800419 continue State
Joe Tsaicd108d02020-02-14 18:08:02 -0800420 case protowire.BytesType:
Damien Neil8fa11b12020-01-28 08:31:04 -0800421 var size uint64
Damien Neil6f297792020-01-29 15:55:53 -0800422 if len(b) >= 1 && b[0] < 0x80 {
Damien Neil8fa11b12020-01-28 08:31:04 -0800423 size = uint64(b[0])
424 b = b[1:]
425 } else if len(b) >= 2 && b[1] < 128 {
426 size = uint64(b[0]&0x7f) + uint64(b[1])<<7
427 b = b[2:]
428 } else {
429 var n int
Joe Tsaicd108d02020-02-14 18:08:02 -0800430 size, n = protowire.ConsumeVarint(b)
Damien Neilb0c26f12019-12-16 09:37:59 -0800431 if n < 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800432 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800433 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800434 b = b[n:]
Damien Neilb0c26f12019-12-16 09:37:59 -0800435 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800436 if size > uint64(len(b)) {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800437 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800438 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800439 v := b[:size]
440 b = b[size:]
441 switch vi.typ {
Damien Neilcb0bfd02020-01-28 09:11:12 -0800442 case validationTypeMessage:
443 if vi.mi == nil {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800444 return out, ValidationUnknown
Damien Neil8fa11b12020-01-28 08:31:04 -0800445 }
Damien Neilcb0bfd02020-01-28 09:11:12 -0800446 vi.mi.init()
447 fallthrough
448 case validationTypeMap:
Damien Neil4eefd772020-02-06 10:27:31 -0800449 if vi.mi != nil {
450 vi.mi.init()
451 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800452 states = append(states, validationState{
453 typ: vi.typ,
454 keyType: vi.keyType,
455 valType: vi.valType,
456 mi: vi.mi,
457 tail: b,
458 })
459 b = v
460 continue State
461 case validationTypeRepeatedVarint:
462 // Packed field.
463 for len(v) > 0 {
Joe Tsaicd108d02020-02-14 18:08:02 -0800464 _, n := protowire.ConsumeVarint(v)
Damien Neil8fa11b12020-01-28 08:31:04 -0800465 if n < 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800466 return out, ValidationInvalid
Damien Neil8fa11b12020-01-28 08:31:04 -0800467 }
468 v = v[n:]
469 }
470 case validationTypeRepeatedFixed32:
471 // Packed field.
472 if len(v)%4 != 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800473 return out, ValidationInvalid
Damien Neil8fa11b12020-01-28 08:31:04 -0800474 }
475 case validationTypeRepeatedFixed64:
476 // Packed field.
477 if len(v)%8 != 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800478 return out, ValidationInvalid
Damien Neil8fa11b12020-01-28 08:31:04 -0800479 }
480 case validationTypeUTF8String:
481 if !utf8.Valid(v) {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800482 return out, ValidationInvalid
Damien Neil8fa11b12020-01-28 08:31:04 -0800483 }
Damien Neilb0c26f12019-12-16 09:37:59 -0800484 }
Joe Tsaicd108d02020-02-14 18:08:02 -0800485 case protowire.Fixed32Type:
Damien Neil8fa11b12020-01-28 08:31:04 -0800486 if len(b) < 4 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800487 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800488 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800489 b = b[4:]
Joe Tsaicd108d02020-02-14 18:08:02 -0800490 case protowire.Fixed64Type:
Damien Neil8fa11b12020-01-28 08:31:04 -0800491 if len(b) < 8 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800492 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800493 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800494 b = b[8:]
Joe Tsaicd108d02020-02-14 18:08:02 -0800495 case protowire.StartGroupType:
Damien Neil9afe9bb2020-02-07 10:06:53 -0800496 switch {
497 case vi.typ == validationTypeGroup:
Damien Neil8fa11b12020-01-28 08:31:04 -0800498 if vi.mi == nil {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800499 return out, ValidationUnknown
Damien Neil8fa11b12020-01-28 08:31:04 -0800500 }
Damien Neilcb0bfd02020-01-28 09:11:12 -0800501 vi.mi.init()
Damien Neil8fa11b12020-01-28 08:31:04 -0800502 states = append(states, validationState{
503 typ: validationTypeGroup,
504 mi: vi.mi,
505 endGroup: num,
506 })
507 continue State
Damien Neil9afe9bb2020-02-07 10:06:53 -0800508 case flags.ProtoLegacy && vi.typ == validationTypeMessageSetItem:
509 typeid, v, n, err := messageset.ConsumeFieldValue(b, false)
510 if err != nil {
511 return out, ValidationInvalid
512 }
Damien Neil466dd772020-02-14 14:49:35 -0800513 xt, err := opts.resolver.FindExtensionByNumber(st.mi.Desc.FullName(), typeid)
Damien Neil9afe9bb2020-02-07 10:06:53 -0800514 switch {
515 case err == preg.NotFound:
516 b = b[n:]
517 case err != nil:
518 return out, ValidationUnknown
519 default:
520 xvi := getExtensionFieldInfo(xt).validation
Damien Neil5698f902020-02-26 08:35:54 -0800521 if xvi.mi != nil {
522 xvi.mi.init()
523 }
Damien Neil9afe9bb2020-02-07 10:06:53 -0800524 states = append(states, validationState{
525 typ: xvi.typ,
526 mi: xvi.mi,
527 tail: b[n:],
528 })
529 b = v
530 continue State
531 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800532 default:
Joe Tsaicd108d02020-02-14 18:08:02 -0800533 n := protowire.ConsumeFieldValue(num, wtyp, b)
Damien Neil8fa11b12020-01-28 08:31:04 -0800534 if n < 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800535 return out, ValidationInvalid
Damien Neil8fa11b12020-01-28 08:31:04 -0800536 }
537 b = b[n:]
538 }
539 default:
Damien Neilcadb4ab2020-02-03 16:17:31 -0800540 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800541 }
Damien Neilb0c26f12019-12-16 09:37:59 -0800542 }
543 if st.endGroup != 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800544 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800545 }
546 if len(b) != 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800547 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800548 }
549 b = st.tail
550 PopState:
Damien Neil54a0a042020-01-08 17:53:16 -0800551 numRequiredFields := 0
Damien Neilb0c26f12019-12-16 09:37:59 -0800552 switch st.typ {
553 case validationTypeMessage, validationTypeGroup:
Damien Neil54a0a042020-01-08 17:53:16 -0800554 numRequiredFields = int(st.mi.numRequiredFields)
555 case validationTypeMap:
556 // If this is a map field with a message value that contains
557 // required fields, require that the value be present.
558 if st.mi != nil && st.mi.numRequiredFields > 0 {
559 numRequiredFields = 1
Damien Neilb0c26f12019-12-16 09:37:59 -0800560 }
561 }
Damien Neil54a0a042020-01-08 17:53:16 -0800562 // If there are more than 64 required fields, this check will
563 // always fail and we will report that the message is potentially
564 // uninitialized.
565 if numRequiredFields > 0 && bits.OnesCount64(st.requiredMask) != numRequiredFields {
566 initialized = false
567 }
Damien Neilb0c26f12019-12-16 09:37:59 -0800568 states = states[:len(states)-1]
569 }
Damien Neilcadb4ab2020-02-03 16:17:31 -0800570 out.n = start - len(b)
571 if initialized {
572 out.initialized = true
Damien Neilb0c26f12019-12-16 09:37:59 -0800573 }
Damien Neilcadb4ab2020-02-03 16:17:31 -0800574 return out, ValidationValid
Damien Neilb0c26f12019-12-16 09:37:59 -0800575}