blob: 08cfb6054b4318cdb22338fc558addef1e734c06 [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"
Joe Tsaie0b77db2020-05-26 11:21:59 -070017 "google.golang.org/protobuf/internal/genid"
Damien Neilb0c26f12019-12-16 09:37:59 -080018 "google.golang.org/protobuf/internal/strs"
19 pref "google.golang.org/protobuf/reflect/protoreflect"
20 preg "google.golang.org/protobuf/reflect/protoregistry"
21 piface "google.golang.org/protobuf/runtime/protoiface"
22)
23
24// ValidationStatus is the result of validating the wire-format encoding of a message.
25type ValidationStatus int
26
27const (
28 // ValidationUnknown indicates that unmarshaling the message might succeed or fail.
29 // The validator was unable to render a judgement.
30 //
31 // The only causes of this status are an aberrant message type appearing somewhere
32 // in the message or a failure in the extension resolver.
33 ValidationUnknown ValidationStatus = iota + 1
34
35 // ValidationInvalid indicates that unmarshaling the message will fail.
36 ValidationInvalid
37
Damien Neilcadb4ab2020-02-03 16:17:31 -080038 // ValidationValid indicates that unmarshaling the message will succeed.
39 ValidationValid
Damien Neilb0c26f12019-12-16 09:37:59 -080040)
41
42func (v ValidationStatus) String() string {
43 switch v {
44 case ValidationUnknown:
45 return "ValidationUnknown"
46 case ValidationInvalid:
47 return "ValidationInvalid"
Damien Neilcadb4ab2020-02-03 16:17:31 -080048 case ValidationValid:
49 return "ValidationValid"
Damien Neilb0c26f12019-12-16 09:37:59 -080050 default:
51 return fmt.Sprintf("ValidationStatus(%d)", int(v))
52 }
53}
54
55// Validate determines whether the contents of the buffer are a valid wire encoding
56// of the message type.
57//
58// This function is exposed for testing.
Damien Neil466dd772020-02-14 14:49:35 -080059func Validate(mt pref.MessageType, in piface.UnmarshalInput) (out piface.UnmarshalOutput, _ ValidationStatus) {
Damien Neilb0c26f12019-12-16 09:37:59 -080060 mi, ok := mt.(*MessageInfo)
61 if !ok {
Damien Neilcadb4ab2020-02-03 16:17:31 -080062 return out, ValidationUnknown
Damien Neilb0c26f12019-12-16 09:37:59 -080063 }
Damien Neil466dd772020-02-14 14:49:35 -080064 if in.Resolver == nil {
65 in.Resolver = preg.GlobalTypes
66 }
67 o, st := mi.validate(in.Buf, 0, unmarshalOptions{
68 flags: in.Flags,
69 resolver: in.Resolver,
70 })
71 if o.initialized {
72 out.Flags |= piface.UnmarshalInitialized
73 }
Damien Neilcadb4ab2020-02-03 16:17:31 -080074 return out, st
Damien Neilb0c26f12019-12-16 09:37:59 -080075}
76
77type validationInfo struct {
78 mi *MessageInfo
79 typ validationType
80 keyType, valType validationType
81
Damien Neil170b2bf2020-01-24 16:42:42 -080082 // For non-required fields, requiredBit is 0.
Damien Neilb0c26f12019-12-16 09:37:59 -080083 //
Damien Neil170b2bf2020-01-24 16:42:42 -080084 // For required fields, requiredBit's nth bit is set, where n is a
85 // unique index in the range [0, MessageInfo.numRequiredFields).
86 //
87 // If there are more than 64 required fields, requiredBit is 0.
88 requiredBit uint64
Damien Neilb0c26f12019-12-16 09:37:59 -080089}
90
91type validationType uint8
92
93const (
94 validationTypeOther validationType = iota
95 validationTypeMessage
96 validationTypeGroup
97 validationTypeMap
98 validationTypeRepeatedVarint
99 validationTypeRepeatedFixed32
100 validationTypeRepeatedFixed64
101 validationTypeVarint
102 validationTypeFixed32
103 validationTypeFixed64
104 validationTypeBytes
105 validationTypeUTF8String
Damien Neil9afe9bb2020-02-07 10:06:53 -0800106 validationTypeMessageSetItem
Damien Neilb0c26f12019-12-16 09:37:59 -0800107)
108
109func newFieldValidationInfo(mi *MessageInfo, si structInfo, fd pref.FieldDescriptor, ft reflect.Type) validationInfo {
110 var vi validationInfo
111 switch {
Joe Tsai387873d2020-04-28 14:44:38 -0700112 case fd.ContainingOneof() != nil && !fd.ContainingOneof().IsSynthetic():
Damien Neilb0c26f12019-12-16 09:37:59 -0800113 switch fd.Kind() {
114 case pref.MessageKind:
115 vi.typ = validationTypeMessage
116 if ot, ok := si.oneofWrappersByNumber[fd.Number()]; ok {
117 vi.mi = getMessageInfo(ot.Field(0).Type)
118 }
119 case pref.GroupKind:
120 vi.typ = validationTypeGroup
121 if ot, ok := si.oneofWrappersByNumber[fd.Number()]; ok {
122 vi.mi = getMessageInfo(ot.Field(0).Type)
123 }
124 case pref.StringKind:
125 if strs.EnforceUTF8(fd) {
126 vi.typ = validationTypeUTF8String
127 }
128 }
129 default:
130 vi = newValidationInfo(fd, ft)
131 }
132 if fd.Cardinality() == pref.Required {
133 // Avoid overflow. The required field check is done with a 64-bit mask, with
134 // any message containing more than 64 required fields always reported as
135 // potentially uninitialized, so it is not important to get a precise count
136 // of the required fields past 64.
137 if mi.numRequiredFields < math.MaxUint8 {
138 mi.numRequiredFields++
Damien Neil170b2bf2020-01-24 16:42:42 -0800139 vi.requiredBit = 1 << (mi.numRequiredFields - 1)
Damien Neilb0c26f12019-12-16 09:37:59 -0800140 }
141 }
142 return vi
143}
144
145func newValidationInfo(fd pref.FieldDescriptor, ft reflect.Type) validationInfo {
146 var vi validationInfo
147 switch {
148 case fd.IsList():
149 switch fd.Kind() {
150 case pref.MessageKind:
151 vi.typ = validationTypeMessage
152 if ft.Kind() == reflect.Slice {
153 vi.mi = getMessageInfo(ft.Elem())
154 }
155 case pref.GroupKind:
156 vi.typ = validationTypeGroup
157 if ft.Kind() == reflect.Slice {
158 vi.mi = getMessageInfo(ft.Elem())
159 }
160 case pref.StringKind:
161 vi.typ = validationTypeBytes
162 if strs.EnforceUTF8(fd) {
163 vi.typ = validationTypeUTF8String
164 }
165 default:
166 switch wireTypes[fd.Kind()] {
Joe Tsaicd108d02020-02-14 18:08:02 -0800167 case protowire.VarintType:
Damien Neilb0c26f12019-12-16 09:37:59 -0800168 vi.typ = validationTypeRepeatedVarint
Joe Tsaicd108d02020-02-14 18:08:02 -0800169 case protowire.Fixed32Type:
Damien Neilb0c26f12019-12-16 09:37:59 -0800170 vi.typ = validationTypeRepeatedFixed32
Joe Tsaicd108d02020-02-14 18:08:02 -0800171 case protowire.Fixed64Type:
Damien Neilb0c26f12019-12-16 09:37:59 -0800172 vi.typ = validationTypeRepeatedFixed64
173 }
174 }
175 case fd.IsMap():
176 vi.typ = validationTypeMap
177 switch fd.MapKey().Kind() {
178 case pref.StringKind:
179 if strs.EnforceUTF8(fd) {
180 vi.keyType = validationTypeUTF8String
181 }
182 }
183 switch fd.MapValue().Kind() {
184 case pref.MessageKind:
185 vi.valType = validationTypeMessage
186 if ft.Kind() == reflect.Map {
187 vi.mi = getMessageInfo(ft.Elem())
188 }
189 case pref.StringKind:
190 if strs.EnforceUTF8(fd) {
191 vi.valType = validationTypeUTF8String
192 }
193 }
194 default:
195 switch fd.Kind() {
196 case pref.MessageKind:
197 vi.typ = validationTypeMessage
198 if !fd.IsWeak() {
199 vi.mi = getMessageInfo(ft)
200 }
201 case pref.GroupKind:
202 vi.typ = validationTypeGroup
203 vi.mi = getMessageInfo(ft)
204 case pref.StringKind:
205 vi.typ = validationTypeBytes
206 if strs.EnforceUTF8(fd) {
207 vi.typ = validationTypeUTF8String
208 }
209 default:
210 switch wireTypes[fd.Kind()] {
Joe Tsaicd108d02020-02-14 18:08:02 -0800211 case protowire.VarintType:
Damien Neilb0c26f12019-12-16 09:37:59 -0800212 vi.typ = validationTypeVarint
Joe Tsaicd108d02020-02-14 18:08:02 -0800213 case protowire.Fixed32Type:
Damien Neilb0c26f12019-12-16 09:37:59 -0800214 vi.typ = validationTypeFixed32
Joe Tsaicd108d02020-02-14 18:08:02 -0800215 case protowire.Fixed64Type:
Damien Neilb0c26f12019-12-16 09:37:59 -0800216 vi.typ = validationTypeFixed64
Joe Tsaicd108d02020-02-14 18:08:02 -0800217 case protowire.BytesType:
Damien Neil6635e7d2020-01-15 15:08:57 -0800218 vi.typ = validationTypeBytes
Damien Neilb0c26f12019-12-16 09:37:59 -0800219 }
220 }
221 }
222 return vi
223}
224
Joe Tsaicd108d02020-02-14 18:08:02 -0800225func (mi *MessageInfo) validate(b []byte, groupTag protowire.Number, opts unmarshalOptions) (out unmarshalOutput, result ValidationStatus) {
Damien Neilcb0bfd02020-01-28 09:11:12 -0800226 mi.init()
Damien Neilb0c26f12019-12-16 09:37:59 -0800227 type validationState struct {
228 typ validationType
229 keyType, valType validationType
Joe Tsaicd108d02020-02-14 18:08:02 -0800230 endGroup protowire.Number
Damien Neilb0c26f12019-12-16 09:37:59 -0800231 mi *MessageInfo
232 tail []byte
233 requiredMask uint64
234 }
235
236 // Pre-allocate some slots to avoid repeated slice reallocation.
237 states := make([]validationState, 0, 16)
238 states = append(states, validationState{
239 typ: validationTypeMessage,
240 mi: mi,
241 })
242 if groupTag > 0 {
243 states[0].typ = validationTypeGroup
244 states[0].endGroup = groupTag
245 }
246 initialized := true
Damien Neilcadb4ab2020-02-03 16:17:31 -0800247 start := len(b)
Damien Neilb0c26f12019-12-16 09:37:59 -0800248State:
249 for len(states) > 0 {
250 st := &states[len(states)-1]
Damien Neilb0c26f12019-12-16 09:37:59 -0800251 for len(b) > 0 {
Damien Neil5d828832020-01-28 08:06:12 -0800252 // Parse the tag (field number and wire type).
253 var tag uint64
254 if b[0] < 0x80 {
255 tag = uint64(b[0])
256 b = b[1:]
257 } else if len(b) >= 2 && b[1] < 128 {
258 tag = uint64(b[0]&0x7f) + uint64(b[1])<<7
259 b = b[2:]
260 } else {
261 var n int
Joe Tsaicd108d02020-02-14 18:08:02 -0800262 tag, n = protowire.ConsumeVarint(b)
Damien Neil5d828832020-01-28 08:06:12 -0800263 if n < 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800264 return out, ValidationInvalid
Damien Neil5d828832020-01-28 08:06:12 -0800265 }
266 b = b[n:]
Damien Neilb0c26f12019-12-16 09:37:59 -0800267 }
Joe Tsaicd108d02020-02-14 18:08:02 -0800268 var num protowire.Number
269 if n := tag >> 3; n < uint64(protowire.MinValidNumber) || n > uint64(protowire.MaxValidNumber) {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800270 return out, ValidationInvalid
Damien Neil5d828832020-01-28 08:06:12 -0800271 } else {
Joe Tsaicd108d02020-02-14 18:08:02 -0800272 num = protowire.Number(n)
Damien Neilb0c26f12019-12-16 09:37:59 -0800273 }
Joe Tsaicd108d02020-02-14 18:08:02 -0800274 wtyp := protowire.Type(tag & 7)
Damien Neil5d828832020-01-28 08:06:12 -0800275
Joe Tsaicd108d02020-02-14 18:08:02 -0800276 if wtyp == protowire.EndGroupType {
Damien Neilb0c26f12019-12-16 09:37:59 -0800277 if st.endGroup == num {
278 goto PopState
279 }
Damien Neilcadb4ab2020-02-03 16:17:31 -0800280 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800281 }
282 var vi validationInfo
Damien Neil9afe9bb2020-02-07 10:06:53 -0800283 switch {
284 case st.typ == validationTypeMap:
Damien Neilb0c26f12019-12-16 09:37:59 -0800285 switch num {
Joe Tsaie0b77db2020-05-26 11:21:59 -0700286 case genid.MapEntry_Key_field_number:
Damien Neilb0c26f12019-12-16 09:37:59 -0800287 vi.typ = st.keyType
Joe Tsaie0b77db2020-05-26 11:21:59 -0700288 case genid.MapEntry_Value_field_number:
Damien Neilb0c26f12019-12-16 09:37:59 -0800289 vi.typ = st.valType
290 vi.mi = st.mi
Damien Neil170b2bf2020-01-24 16:42:42 -0800291 vi.requiredBit = 1
Damien Neilb0c26f12019-12-16 09:37:59 -0800292 }
Damien Neil9afe9bb2020-02-07 10:06:53 -0800293 case flags.ProtoLegacy && st.mi.isMessageSet:
294 switch num {
295 case messageset.FieldItem:
296 vi.typ = validationTypeMessageSetItem
297 }
Damien Neilb0c26f12019-12-16 09:37:59 -0800298 default:
299 var f *coderFieldInfo
300 if int(num) < len(st.mi.denseCoderFields) {
301 f = st.mi.denseCoderFields[num]
302 } else {
303 f = st.mi.coderFields[num]
304 }
305 if f != nil {
306 vi = f.validation
307 if vi.typ == validationTypeMessage && vi.mi == nil {
308 // Probable weak field.
309 //
310 // TODO: Consider storing the results of this lookup somewhere
311 // rather than recomputing it on every validation.
312 fd := st.mi.Desc.Fields().ByNumber(num)
313 if fd == nil || !fd.IsWeak() {
314 break
315 }
316 messageName := fd.Message().FullName()
317 messageType, err := preg.GlobalTypes.FindMessageByName(messageName)
318 switch err {
319 case nil:
320 vi.mi, _ = messageType.(*MessageInfo)
321 case preg.NotFound:
322 vi.typ = validationTypeBytes
323 default:
Damien Neilcadb4ab2020-02-03 16:17:31 -0800324 return out, ValidationUnknown
Damien Neilb0c26f12019-12-16 09:37:59 -0800325 }
326 }
327 break
328 }
329 // Possible extension field.
330 //
331 // TODO: We should return ValidationUnknown when:
332 // 1. The resolver is not frozen. (More extensions may be added to it.)
333 // 2. The resolver returns preg.NotFound.
334 // In this case, a type added to the resolver in the future could cause
335 // unmarshaling to begin failing. Supporting this requires some way to
336 // determine if the resolver is frozen.
Damien Neil466dd772020-02-14 14:49:35 -0800337 xt, err := opts.resolver.FindExtensionByNumber(st.mi.Desc.FullName(), num)
Damien Neilb0c26f12019-12-16 09:37:59 -0800338 if err != nil && err != preg.NotFound {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800339 return out, ValidationUnknown
Damien Neilb0c26f12019-12-16 09:37:59 -0800340 }
341 if err == nil {
342 vi = getExtensionFieldInfo(xt).validation
343 }
344 }
Damien Neil170b2bf2020-01-24 16:42:42 -0800345 if vi.requiredBit != 0 {
Damien Neilb0c26f12019-12-16 09:37:59 -0800346 // Check that the field has a compatible wire type.
347 // We only need to consider non-repeated field types,
348 // since repeated fields (and maps) can never be required.
349 ok := false
350 switch vi.typ {
351 case validationTypeVarint:
Joe Tsaicd108d02020-02-14 18:08:02 -0800352 ok = wtyp == protowire.VarintType
Damien Neilb0c26f12019-12-16 09:37:59 -0800353 case validationTypeFixed32:
Joe Tsaicd108d02020-02-14 18:08:02 -0800354 ok = wtyp == protowire.Fixed32Type
Damien Neilb0c26f12019-12-16 09:37:59 -0800355 case validationTypeFixed64:
Joe Tsaicd108d02020-02-14 18:08:02 -0800356 ok = wtyp == protowire.Fixed64Type
Damien Neilf9d4fdf2020-02-07 11:42:45 -0800357 case validationTypeBytes, validationTypeUTF8String, validationTypeMessage:
Joe Tsaicd108d02020-02-14 18:08:02 -0800358 ok = wtyp == protowire.BytesType
Damien Neilf9d4fdf2020-02-07 11:42:45 -0800359 case validationTypeGroup:
Joe Tsaicd108d02020-02-14 18:08:02 -0800360 ok = wtyp == protowire.StartGroupType
Damien Neilb0c26f12019-12-16 09:37:59 -0800361 }
362 if ok {
Damien Neil170b2bf2020-01-24 16:42:42 -0800363 st.requiredMask |= vi.requiredBit
Damien Neilb0c26f12019-12-16 09:37:59 -0800364 }
365 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800366
367 switch wtyp {
Joe Tsaicd108d02020-02-14 18:08:02 -0800368 case protowire.VarintType:
Damien Neil0f783d82020-02-05 07:34:41 -0800369 if len(b) >= 10 {
Damien Neil8fa11b12020-01-28 08:31:04 -0800370 switch {
371 case b[0] < 0x80:
372 b = b[1:]
373 case b[1] < 0x80:
374 b = b[2:]
375 case b[2] < 0x80:
376 b = b[3:]
377 case b[3] < 0x80:
378 b = b[4:]
379 case b[4] < 0x80:
380 b = b[5:]
381 case b[5] < 0x80:
382 b = b[6:]
383 case b[6] < 0x80:
384 b = b[7:]
385 case b[7] < 0x80:
386 b = b[8:]
387 case b[8] < 0x80:
388 b = b[9:]
Damien Neil4d918162020-02-01 10:39:11 -0800389 case b[9] < 0x80 && b[9] < 2:
Damien Neil8fa11b12020-01-28 08:31:04 -0800390 b = b[10:]
391 default:
Damien Neilcadb4ab2020-02-03 16:17:31 -0800392 return out, ValidationInvalid
Damien Neil8fa11b12020-01-28 08:31:04 -0800393 }
394 } else {
395 switch {
396 case len(b) > 0 && b[0] < 0x80:
397 b = b[1:]
398 case len(b) > 1 && b[1] < 0x80:
399 b = b[2:]
400 case len(b) > 2 && b[2] < 0x80:
401 b = b[3:]
402 case len(b) > 3 && b[3] < 0x80:
403 b = b[4:]
404 case len(b) > 4 && b[4] < 0x80:
405 b = b[5:]
406 case len(b) > 5 && b[5] < 0x80:
407 b = b[6:]
408 case len(b) > 6 && b[6] < 0x80:
409 b = b[7:]
410 case len(b) > 7 && b[7] < 0x80:
411 b = b[8:]
412 case len(b) > 8 && b[8] < 0x80:
413 b = b[9:]
Damien Neil4d918162020-02-01 10:39:11 -0800414 case len(b) > 9 && b[9] < 2:
Damien Neil8fa11b12020-01-28 08:31:04 -0800415 b = b[10:]
416 default:
Damien Neilcadb4ab2020-02-03 16:17:31 -0800417 return out, ValidationInvalid
Damien Neil8fa11b12020-01-28 08:31:04 -0800418 }
Damien Neilb0c26f12019-12-16 09:37:59 -0800419 }
Damien Neilb0c26f12019-12-16 09:37:59 -0800420 continue State
Joe Tsaicd108d02020-02-14 18:08:02 -0800421 case protowire.BytesType:
Damien Neil8fa11b12020-01-28 08:31:04 -0800422 var size uint64
Damien Neil6f297792020-01-29 15:55:53 -0800423 if len(b) >= 1 && b[0] < 0x80 {
Damien Neil8fa11b12020-01-28 08:31:04 -0800424 size = uint64(b[0])
425 b = b[1:]
426 } else if len(b) >= 2 && b[1] < 128 {
427 size = uint64(b[0]&0x7f) + uint64(b[1])<<7
428 b = b[2:]
429 } else {
430 var n int
Joe Tsaicd108d02020-02-14 18:08:02 -0800431 size, n = protowire.ConsumeVarint(b)
Damien Neilb0c26f12019-12-16 09:37:59 -0800432 if n < 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800433 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800434 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800435 b = b[n:]
Damien Neilb0c26f12019-12-16 09:37:59 -0800436 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800437 if size > uint64(len(b)) {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800438 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800439 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800440 v := b[:size]
441 b = b[size:]
442 switch vi.typ {
Damien Neilcb0bfd02020-01-28 09:11:12 -0800443 case validationTypeMessage:
444 if vi.mi == nil {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800445 return out, ValidationUnknown
Damien Neil8fa11b12020-01-28 08:31:04 -0800446 }
Damien Neilcb0bfd02020-01-28 09:11:12 -0800447 vi.mi.init()
448 fallthrough
449 case validationTypeMap:
Damien Neil4eefd772020-02-06 10:27:31 -0800450 if vi.mi != nil {
451 vi.mi.init()
452 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800453 states = append(states, validationState{
454 typ: vi.typ,
455 keyType: vi.keyType,
456 valType: vi.valType,
457 mi: vi.mi,
458 tail: b,
459 })
460 b = v
461 continue State
462 case validationTypeRepeatedVarint:
463 // Packed field.
464 for len(v) > 0 {
Joe Tsaicd108d02020-02-14 18:08:02 -0800465 _, n := protowire.ConsumeVarint(v)
Damien Neil8fa11b12020-01-28 08:31:04 -0800466 if n < 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800467 return out, ValidationInvalid
Damien Neil8fa11b12020-01-28 08:31:04 -0800468 }
469 v = v[n:]
470 }
471 case validationTypeRepeatedFixed32:
472 // Packed field.
473 if len(v)%4 != 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800474 return out, ValidationInvalid
Damien Neil8fa11b12020-01-28 08:31:04 -0800475 }
476 case validationTypeRepeatedFixed64:
477 // Packed field.
478 if len(v)%8 != 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800479 return out, ValidationInvalid
Damien Neil8fa11b12020-01-28 08:31:04 -0800480 }
481 case validationTypeUTF8String:
482 if !utf8.Valid(v) {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800483 return out, ValidationInvalid
Damien Neil8fa11b12020-01-28 08:31:04 -0800484 }
Damien Neilb0c26f12019-12-16 09:37:59 -0800485 }
Joe Tsaicd108d02020-02-14 18:08:02 -0800486 case protowire.Fixed32Type:
Damien Neil8fa11b12020-01-28 08:31:04 -0800487 if len(b) < 4 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800488 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800489 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800490 b = b[4:]
Joe Tsaicd108d02020-02-14 18:08:02 -0800491 case protowire.Fixed64Type:
Damien Neil8fa11b12020-01-28 08:31:04 -0800492 if len(b) < 8 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800493 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800494 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800495 b = b[8:]
Joe Tsaicd108d02020-02-14 18:08:02 -0800496 case protowire.StartGroupType:
Damien Neil9afe9bb2020-02-07 10:06:53 -0800497 switch {
498 case vi.typ == validationTypeGroup:
Damien Neil8fa11b12020-01-28 08:31:04 -0800499 if vi.mi == nil {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800500 return out, ValidationUnknown
Damien Neil8fa11b12020-01-28 08:31:04 -0800501 }
Damien Neilcb0bfd02020-01-28 09:11:12 -0800502 vi.mi.init()
Damien Neil8fa11b12020-01-28 08:31:04 -0800503 states = append(states, validationState{
504 typ: validationTypeGroup,
505 mi: vi.mi,
506 endGroup: num,
507 })
508 continue State
Damien Neil9afe9bb2020-02-07 10:06:53 -0800509 case flags.ProtoLegacy && vi.typ == validationTypeMessageSetItem:
510 typeid, v, n, err := messageset.ConsumeFieldValue(b, false)
511 if err != nil {
512 return out, ValidationInvalid
513 }
Damien Neil466dd772020-02-14 14:49:35 -0800514 xt, err := opts.resolver.FindExtensionByNumber(st.mi.Desc.FullName(), typeid)
Damien Neil9afe9bb2020-02-07 10:06:53 -0800515 switch {
516 case err == preg.NotFound:
517 b = b[n:]
518 case err != nil:
519 return out, ValidationUnknown
520 default:
521 xvi := getExtensionFieldInfo(xt).validation
Damien Neil5698f902020-02-26 08:35:54 -0800522 if xvi.mi != nil {
523 xvi.mi.init()
524 }
Damien Neil9afe9bb2020-02-07 10:06:53 -0800525 states = append(states, validationState{
526 typ: xvi.typ,
527 mi: xvi.mi,
528 tail: b[n:],
529 })
530 b = v
531 continue State
532 }
Damien Neil8fa11b12020-01-28 08:31:04 -0800533 default:
Joe Tsaicd108d02020-02-14 18:08:02 -0800534 n := protowire.ConsumeFieldValue(num, wtyp, b)
Damien Neil8fa11b12020-01-28 08:31:04 -0800535 if n < 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800536 return out, ValidationInvalid
Damien Neil8fa11b12020-01-28 08:31:04 -0800537 }
538 b = b[n:]
539 }
540 default:
Damien Neilcadb4ab2020-02-03 16:17:31 -0800541 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800542 }
Damien Neilb0c26f12019-12-16 09:37:59 -0800543 }
544 if st.endGroup != 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800545 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800546 }
547 if len(b) != 0 {
Damien Neilcadb4ab2020-02-03 16:17:31 -0800548 return out, ValidationInvalid
Damien Neilb0c26f12019-12-16 09:37:59 -0800549 }
550 b = st.tail
551 PopState:
Damien Neil54a0a042020-01-08 17:53:16 -0800552 numRequiredFields := 0
Damien Neilb0c26f12019-12-16 09:37:59 -0800553 switch st.typ {
554 case validationTypeMessage, validationTypeGroup:
Damien Neil54a0a042020-01-08 17:53:16 -0800555 numRequiredFields = int(st.mi.numRequiredFields)
556 case validationTypeMap:
557 // If this is a map field with a message value that contains
558 // required fields, require that the value be present.
559 if st.mi != nil && st.mi.numRequiredFields > 0 {
560 numRequiredFields = 1
Damien Neilb0c26f12019-12-16 09:37:59 -0800561 }
562 }
Damien Neil54a0a042020-01-08 17:53:16 -0800563 // If there are more than 64 required fields, this check will
564 // always fail and we will report that the message is potentially
565 // uninitialized.
566 if numRequiredFields > 0 && bits.OnesCount64(st.requiredMask) != numRequiredFields {
567 initialized = false
568 }
Damien Neilb0c26f12019-12-16 09:37:59 -0800569 states = states[:len(states)-1]
570 }
Damien Neilcadb4ab2020-02-03 16:17:31 -0800571 out.n = start - len(b)
572 if initialized {
573 out.initialized = true
Damien Neilb0c26f12019-12-16 09:37:59 -0800574 }
Damien Neilcadb4ab2020-02-03 16:17:31 -0800575 return out, ValidationValid
Damien Neilb0c26f12019-12-16 09:37:59 -0800576}