1// Copyright 2018 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 "reflect" 10 "strings" 11 "sync" 12 13 "google.golang.org/protobuf/internal/descopts" 14 ptag "google.golang.org/protobuf/internal/encoding/tag" 15 "google.golang.org/protobuf/internal/errors" 16 "google.golang.org/protobuf/internal/filedesc" 17 "google.golang.org/protobuf/internal/strs" 18 "google.golang.org/protobuf/reflect/protoreflect" 19 pref "google.golang.org/protobuf/reflect/protoreflect" 20 "google.golang.org/protobuf/runtime/protoiface" 21 piface "google.golang.org/protobuf/runtime/protoiface" 22) 23 24// legacyWrapMessage wraps v as a protoreflect.Message, 25// where v must be a *struct kind and not implement the v2 API already. 26func legacyWrapMessage(v reflect.Value) pref.Message { 27 t := v.Type() 28 if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct { 29 return aberrantMessage{v: v} 30 } 31 mt := legacyLoadMessageInfo(t, "") 32 return mt.MessageOf(v.Interface()) 33} 34 35// legacyLoadMessageType dynamically loads a protoreflect.Type for t, 36// where t must be not implement the v2 API already. 37// The provided name is used if it cannot be determined from the message. 38func legacyLoadMessageType(t reflect.Type, name pref.FullName) protoreflect.MessageType { 39 if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct { 40 return aberrantMessageType{t} 41 } 42 return legacyLoadMessageInfo(t, name) 43} 44 45var legacyMessageTypeCache sync.Map // map[reflect.Type]*MessageInfo 46 47// legacyLoadMessageInfo dynamically loads a *MessageInfo for t, 48// where t must be a *struct kind and not implement the v2 API already. 49// The provided name is used if it cannot be determined from the message. 50func legacyLoadMessageInfo(t reflect.Type, name pref.FullName) *MessageInfo { 51 // Fast-path: check if a MessageInfo is cached for this concrete type. 52 if mt, ok := legacyMessageTypeCache.Load(t); ok { 53 return mt.(*MessageInfo) 54 } 55 56 // Slow-path: derive message descriptor and initialize MessageInfo. 57 mi := &MessageInfo{ 58 Desc: legacyLoadMessageDesc(t, name), 59 GoReflectType: t, 60 } 61 62 var hasMarshal, hasUnmarshal bool 63 v := reflect.Zero(t).Interface() 64 if _, hasMarshal = v.(legacyMarshaler); hasMarshal { 65 mi.methods.Marshal = legacyMarshal 66 67 // We have no way to tell whether the type's Marshal method 68 // supports deterministic serialization or not, but this 69 // preserves the v1 implementation's behavior of always 70 // calling Marshal methods when present. 71 mi.methods.Flags |= piface.SupportMarshalDeterministic 72 } 73 if _, hasUnmarshal = v.(legacyUnmarshaler); hasUnmarshal { 74 mi.methods.Unmarshal = legacyUnmarshal 75 } 76 if _, hasMerge := v.(legacyMerger); hasMerge || (hasMarshal && hasUnmarshal) { 77 mi.methods.Merge = legacyMerge 78 } 79 80 if mi, ok := legacyMessageTypeCache.LoadOrStore(t, mi); ok { 81 return mi.(*MessageInfo) 82 } 83 return mi 84} 85 86var legacyMessageDescCache sync.Map // map[reflect.Type]protoreflect.MessageDescriptor 87 88// LegacyLoadMessageDesc returns an MessageDescriptor derived from the Go type, 89// which should be a *struct kind and must not implement the v2 API already. 90// 91// This is exported for testing purposes. 92func LegacyLoadMessageDesc(t reflect.Type) pref.MessageDescriptor { 93 return legacyLoadMessageDesc(t, "") 94} 95func legacyLoadMessageDesc(t reflect.Type, name pref.FullName) pref.MessageDescriptor { 96 // Fast-path: check if a MessageDescriptor is cached for this concrete type. 97 if mi, ok := legacyMessageDescCache.Load(t); ok { 98 return mi.(pref.MessageDescriptor) 99 } 100 101 // Slow-path: initialize MessageDescriptor from the raw descriptor. 102 mv := reflect.Zero(t).Interface() 103 if _, ok := mv.(pref.ProtoMessage); ok { 104 panic(fmt.Sprintf("%v already implements proto.Message", t)) 105 } 106 mdV1, ok := mv.(messageV1) 107 if !ok { 108 return aberrantLoadMessageDesc(t, name) 109 } 110 111 // If this is a dynamic message type where there isn't a 1-1 mapping between 112 // Go and protobuf types, calling the Descriptor method on the zero value of 113 // the message type isn't likely to work. If it panics, swallow the panic and 114 // continue as if the Descriptor method wasn't present. 115 b, idxs := func() ([]byte, []int) { 116 defer func() { 117 recover() 118 }() 119 return mdV1.Descriptor() 120 }() 121 if b == nil { 122 return aberrantLoadMessageDesc(t, name) 123 } 124 125 // If the Go type has no fields, then this might be a proto3 empty message 126 // from before the size cache was added. If there are any fields, check to 127 // see that at least one of them looks like something we generated. 128 if t.Elem().Kind() == reflect.Struct { 129 if nfield := t.Elem().NumField(); nfield > 0 { 130 hasProtoField := false 131 for i := 0; i < nfield; i++ { 132 f := t.Elem().Field(i) 133 if f.Tag.Get("protobuf") != "" || f.Tag.Get("protobuf_oneof") != "" || strings.HasPrefix(f.Name, "XXX_") { 134 hasProtoField = true 135 break 136 } 137 } 138 if !hasProtoField { 139 return aberrantLoadMessageDesc(t, name) 140 } 141 } 142 } 143 144 md := legacyLoadFileDesc(b).Messages().Get(idxs[0]) 145 for _, i := range idxs[1:] { 146 md = md.Messages().Get(i) 147 } 148 if name != "" && md.FullName() != name { 149 panic(fmt.Sprintf("mismatching message name: got %v, want %v", md.FullName(), name)) 150 } 151 if md, ok := legacyMessageDescCache.LoadOrStore(t, md); ok { 152 return md.(protoreflect.MessageDescriptor) 153 } 154 return md 155} 156 157var ( 158 aberrantMessageDescLock sync.Mutex 159 aberrantMessageDescCache map[reflect.Type]protoreflect.MessageDescriptor 160) 161 162// aberrantLoadMessageDesc returns an MessageDescriptor derived from the Go type, 163// which must not implement protoreflect.ProtoMessage or messageV1. 164// 165// This is a best-effort derivation of the message descriptor using the protobuf 166// tags on the struct fields. 167func aberrantLoadMessageDesc(t reflect.Type, name pref.FullName) pref.MessageDescriptor { 168 aberrantMessageDescLock.Lock() 169 defer aberrantMessageDescLock.Unlock() 170 if aberrantMessageDescCache == nil { 171 aberrantMessageDescCache = make(map[reflect.Type]protoreflect.MessageDescriptor) 172 } 173 return aberrantLoadMessageDescReentrant(t, name) 174} 175func aberrantLoadMessageDescReentrant(t reflect.Type, name pref.FullName) pref.MessageDescriptor { 176 // Fast-path: check if an MessageDescriptor is cached for this concrete type. 177 if md, ok := aberrantMessageDescCache[t]; ok { 178 return md 179 } 180 181 // Slow-path: construct a descriptor from the Go struct type (best-effort). 182 // Cache the MessageDescriptor early on so that we can resolve internal 183 // cyclic references. 184 md := &filedesc.Message{L2: new(filedesc.MessageL2)} 185 md.L0.FullName = aberrantDeriveMessageName(t, name) 186 md.L0.ParentFile = filedesc.SurrogateProto2 187 aberrantMessageDescCache[t] = md 188 189 if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct { 190 return md 191 } 192 193 // Try to determine if the message is using proto3 by checking scalars. 194 for i := 0; i < t.Elem().NumField(); i++ { 195 f := t.Elem().Field(i) 196 if tag := f.Tag.Get("protobuf"); tag != "" { 197 switch f.Type.Kind() { 198 case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String: 199 md.L0.ParentFile = filedesc.SurrogateProto3 200 } 201 for _, s := range strings.Split(tag, ",") { 202 if s == "proto3" { 203 md.L0.ParentFile = filedesc.SurrogateProto3 204 } 205 } 206 } 207 } 208 209 // Obtain a list of oneof wrapper types. 210 var oneofWrappers []reflect.Type 211 for _, method := range []string{"XXX_OneofFuncs", "XXX_OneofWrappers"} { 212 if fn, ok := t.MethodByName(method); ok { 213 for _, v := range fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))}) { 214 if vs, ok := v.Interface().([]interface{}); ok { 215 for _, v := range vs { 216 oneofWrappers = append(oneofWrappers, reflect.TypeOf(v)) 217 } 218 } 219 } 220 } 221 } 222 223 // Obtain a list of the extension ranges. 224 if fn, ok := t.MethodByName("ExtensionRangeArray"); ok { 225 vs := fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[0] 226 for i := 0; i < vs.Len(); i++ { 227 v := vs.Index(i) 228 md.L2.ExtensionRanges.List = append(md.L2.ExtensionRanges.List, [2]pref.FieldNumber{ 229 pref.FieldNumber(v.FieldByName("Start").Int()), 230 pref.FieldNumber(v.FieldByName("End").Int() + 1), 231 }) 232 md.L2.ExtensionRangeOptions = append(md.L2.ExtensionRangeOptions, nil) 233 } 234 } 235 236 // Derive the message fields by inspecting the struct fields. 237 for i := 0; i < t.Elem().NumField(); i++ { 238 f := t.Elem().Field(i) 239 if tag := f.Tag.Get("protobuf"); tag != "" { 240 tagKey := f.Tag.Get("protobuf_key") 241 tagVal := f.Tag.Get("protobuf_val") 242 aberrantAppendField(md, f.Type, tag, tagKey, tagVal) 243 } 244 if tag := f.Tag.Get("protobuf_oneof"); tag != "" { 245 n := len(md.L2.Oneofs.List) 246 md.L2.Oneofs.List = append(md.L2.Oneofs.List, filedesc.Oneof{}) 247 od := &md.L2.Oneofs.List[n] 248 od.L0.FullName = md.FullName().Append(pref.Name(tag)) 249 od.L0.ParentFile = md.L0.ParentFile 250 od.L0.Parent = md 251 od.L0.Index = n 252 253 for _, t := range oneofWrappers { 254 if t.Implements(f.Type) { 255 f := t.Elem().Field(0) 256 if tag := f.Tag.Get("protobuf"); tag != "" { 257 aberrantAppendField(md, f.Type, tag, "", "") 258 fd := &md.L2.Fields.List[len(md.L2.Fields.List)-1] 259 fd.L1.ContainingOneof = od 260 od.L1.Fields.List = append(od.L1.Fields.List, fd) 261 } 262 } 263 } 264 } 265 } 266 267 return md 268} 269 270func aberrantDeriveMessageName(t reflect.Type, name pref.FullName) pref.FullName { 271 if name.IsValid() { 272 return name 273 } 274 func() { 275 defer func() { recover() }() // swallow possible nil panics 276 if m, ok := reflect.Zero(t).Interface().(interface{ XXX_MessageName() string }); ok { 277 name = pref.FullName(m.XXX_MessageName()) 278 } 279 }() 280 if name.IsValid() { 281 return name 282 } 283 if t.Kind() == reflect.Ptr { 284 t = t.Elem() 285 } 286 return AberrantDeriveFullName(t) 287} 288 289func aberrantAppendField(md *filedesc.Message, goType reflect.Type, tag, tagKey, tagVal string) { 290 t := goType 291 isOptional := t.Kind() == reflect.Ptr && t.Elem().Kind() != reflect.Struct 292 isRepeated := t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 293 if isOptional || isRepeated { 294 t = t.Elem() 295 } 296 fd := ptag.Unmarshal(tag, t, placeholderEnumValues{}).(*filedesc.Field) 297 298 // Append field descriptor to the message. 299 n := len(md.L2.Fields.List) 300 md.L2.Fields.List = append(md.L2.Fields.List, *fd) 301 fd = &md.L2.Fields.List[n] 302 fd.L0.FullName = md.FullName().Append(fd.Name()) 303 fd.L0.ParentFile = md.L0.ParentFile 304 fd.L0.Parent = md 305 fd.L0.Index = n 306 307 if fd.L1.IsWeak || fd.L1.HasPacked { 308 fd.L1.Options = func() pref.ProtoMessage { 309 opts := descopts.Field.ProtoReflect().New() 310 if fd.L1.IsWeak { 311 opts.Set(opts.Descriptor().Fields().ByName("weak"), protoreflect.ValueOfBool(true)) 312 } 313 if fd.L1.HasPacked { 314 opts.Set(opts.Descriptor().Fields().ByName("packed"), protoreflect.ValueOfBool(fd.L1.IsPacked)) 315 } 316 return opts.Interface() 317 } 318 } 319 320 // Populate Enum and Message. 321 if fd.Enum() == nil && fd.Kind() == pref.EnumKind { 322 switch v := reflect.Zero(t).Interface().(type) { 323 case pref.Enum: 324 fd.L1.Enum = v.Descriptor() 325 default: 326 fd.L1.Enum = LegacyLoadEnumDesc(t) 327 } 328 } 329 if fd.Message() == nil && (fd.Kind() == pref.MessageKind || fd.Kind() == pref.GroupKind) { 330 switch v := reflect.Zero(t).Interface().(type) { 331 case pref.ProtoMessage: 332 fd.L1.Message = v.ProtoReflect().Descriptor() 333 case messageV1: 334 fd.L1.Message = LegacyLoadMessageDesc(t) 335 default: 336 if t.Kind() == reflect.Map { 337 n := len(md.L1.Messages.List) 338 md.L1.Messages.List = append(md.L1.Messages.List, filedesc.Message{L2: new(filedesc.MessageL2)}) 339 md2 := &md.L1.Messages.List[n] 340 md2.L0.FullName = md.FullName().Append(pref.Name(strs.MapEntryName(string(fd.Name())))) 341 md2.L0.ParentFile = md.L0.ParentFile 342 md2.L0.Parent = md 343 md2.L0.Index = n 344 345 md2.L1.IsMapEntry = true 346 md2.L2.Options = func() pref.ProtoMessage { 347 opts := descopts.Message.ProtoReflect().New() 348 opts.Set(opts.Descriptor().Fields().ByName("map_entry"), protoreflect.ValueOfBool(true)) 349 return opts.Interface() 350 } 351 352 aberrantAppendField(md2, t.Key(), tagKey, "", "") 353 aberrantAppendField(md2, t.Elem(), tagVal, "", "") 354 355 fd.L1.Message = md2 356 break 357 } 358 fd.L1.Message = aberrantLoadMessageDescReentrant(t, "") 359 } 360 } 361} 362 363type placeholderEnumValues struct { 364 protoreflect.EnumValueDescriptors 365} 366 367func (placeholderEnumValues) ByNumber(n pref.EnumNumber) pref.EnumValueDescriptor { 368 return filedesc.PlaceholderEnumValue(pref.FullName(fmt.Sprintf("UNKNOWN_%d", n))) 369} 370 371// legacyMarshaler is the proto.Marshaler interface superseded by protoiface.Methoder. 372type legacyMarshaler interface { 373 Marshal() ([]byte, error) 374} 375 376// legacyUnmarshaler is the proto.Unmarshaler interface superseded by protoiface.Methoder. 377type legacyUnmarshaler interface { 378 Unmarshal([]byte) error 379} 380 381// legacyMerger is the proto.Merger interface superseded by protoiface.Methoder. 382type legacyMerger interface { 383 Merge(protoiface.MessageV1) 384} 385 386var aberrantProtoMethods = &piface.Methods{ 387 Marshal: legacyMarshal, 388 Unmarshal: legacyUnmarshal, 389 Merge: legacyMerge, 390 391 // We have no way to tell whether the type's Marshal method 392 // supports deterministic serialization or not, but this 393 // preserves the v1 implementation's behavior of always 394 // calling Marshal methods when present. 395 Flags: piface.SupportMarshalDeterministic, 396} 397 398func legacyMarshal(in piface.MarshalInput) (piface.MarshalOutput, error) { 399 v := in.Message.(unwrapper).protoUnwrap() 400 marshaler, ok := v.(legacyMarshaler) 401 if !ok { 402 return piface.MarshalOutput{}, errors.New("%T does not implement Marshal", v) 403 } 404 out, err := marshaler.Marshal() 405 if in.Buf != nil { 406 out = append(in.Buf, out...) 407 } 408 return piface.MarshalOutput{ 409 Buf: out, 410 }, err 411} 412 413func legacyUnmarshal(in piface.UnmarshalInput) (piface.UnmarshalOutput, error) { 414 v := in.Message.(unwrapper).protoUnwrap() 415 unmarshaler, ok := v.(legacyUnmarshaler) 416 if !ok { 417 return piface.UnmarshalOutput{}, errors.New("%T does not implement Unmarshal", v) 418 } 419 return piface.UnmarshalOutput{}, unmarshaler.Unmarshal(in.Buf) 420} 421 422func legacyMerge(in piface.MergeInput) piface.MergeOutput { 423 // Check whether this supports the legacy merger. 424 dstv := in.Destination.(unwrapper).protoUnwrap() 425 merger, ok := dstv.(legacyMerger) 426 if ok { 427 merger.Merge(Export{}.ProtoMessageV1Of(in.Source)) 428 return piface.MergeOutput{Flags: piface.MergeComplete} 429 } 430 431 // If legacy merger is unavailable, implement merge in terms of 432 // a marshal and unmarshal operation. 433 srcv := in.Source.(unwrapper).protoUnwrap() 434 marshaler, ok := srcv.(legacyMarshaler) 435 if !ok { 436 return piface.MergeOutput{} 437 } 438 dstv = in.Destination.(unwrapper).protoUnwrap() 439 unmarshaler, ok := dstv.(legacyUnmarshaler) 440 if !ok { 441 return piface.MergeOutput{} 442 } 443 b, err := marshaler.Marshal() 444 if err != nil { 445 return piface.MergeOutput{} 446 } 447 err = unmarshaler.Unmarshal(b) 448 if err != nil { 449 return piface.MergeOutput{} 450 } 451 return piface.MergeOutput{Flags: piface.MergeComplete} 452} 453 454// aberrantMessageType implements MessageType for all types other than pointer-to-struct. 455type aberrantMessageType struct { 456 t reflect.Type 457} 458 459func (mt aberrantMessageType) New() pref.Message { 460 if mt.t.Kind() == reflect.Ptr { 461 return aberrantMessage{reflect.New(mt.t.Elem())} 462 } 463 return aberrantMessage{reflect.Zero(mt.t)} 464} 465func (mt aberrantMessageType) Zero() pref.Message { 466 return aberrantMessage{reflect.Zero(mt.t)} 467} 468func (mt aberrantMessageType) GoType() reflect.Type { 469 return mt.t 470} 471func (mt aberrantMessageType) Descriptor() pref.MessageDescriptor { 472 return LegacyLoadMessageDesc(mt.t) 473} 474 475// aberrantMessage implements Message for all types other than pointer-to-struct. 476// 477// When the underlying type implements legacyMarshaler or legacyUnmarshaler, 478// the aberrant Message can be marshaled or unmarshaled. Otherwise, there is 479// not much that can be done with values of this type. 480type aberrantMessage struct { 481 v reflect.Value 482} 483 484// Reset implements the v1 proto.Message.Reset method. 485func (m aberrantMessage) Reset() { 486 if mr, ok := m.v.Interface().(interface{ Reset() }); ok { 487 mr.Reset() 488 return 489 } 490 if m.v.Kind() == reflect.Ptr && !m.v.IsNil() { 491 m.v.Elem().Set(reflect.Zero(m.v.Type().Elem())) 492 } 493} 494 495func (m aberrantMessage) ProtoReflect() pref.Message { 496 return m 497} 498 499func (m aberrantMessage) Descriptor() pref.MessageDescriptor { 500 return LegacyLoadMessageDesc(m.v.Type()) 501} 502func (m aberrantMessage) Type() pref.MessageType { 503 return aberrantMessageType{m.v.Type()} 504} 505func (m aberrantMessage) New() pref.Message { 506 if m.v.Type().Kind() == reflect.Ptr { 507 return aberrantMessage{reflect.New(m.v.Type().Elem())} 508 } 509 return aberrantMessage{reflect.Zero(m.v.Type())} 510} 511func (m aberrantMessage) Interface() pref.ProtoMessage { 512 return m 513} 514func (m aberrantMessage) Range(f func(pref.FieldDescriptor, pref.Value) bool) { 515 return 516} 517func (m aberrantMessage) Has(pref.FieldDescriptor) bool { 518 return false 519} 520func (m aberrantMessage) Clear(pref.FieldDescriptor) { 521 panic("invalid Message.Clear on " + string(m.Descriptor().FullName())) 522} 523func (m aberrantMessage) Get(fd pref.FieldDescriptor) pref.Value { 524 if fd.Default().IsValid() { 525 return fd.Default() 526 } 527 panic("invalid Message.Get on " + string(m.Descriptor().FullName())) 528} 529func (m aberrantMessage) Set(pref.FieldDescriptor, pref.Value) { 530 panic("invalid Message.Set on " + string(m.Descriptor().FullName())) 531} 532func (m aberrantMessage) Mutable(pref.FieldDescriptor) pref.Value { 533 panic("invalid Message.Mutable on " + string(m.Descriptor().FullName())) 534} 535func (m aberrantMessage) NewField(pref.FieldDescriptor) pref.Value { 536 panic("invalid Message.NewField on " + string(m.Descriptor().FullName())) 537} 538func (m aberrantMessage) WhichOneof(pref.OneofDescriptor) pref.FieldDescriptor { 539 panic("invalid Message.WhichOneof descriptor on " + string(m.Descriptor().FullName())) 540} 541func (m aberrantMessage) GetUnknown() pref.RawFields { 542 return nil 543} 544func (m aberrantMessage) SetUnknown(pref.RawFields) { 545 // SetUnknown discards its input on messages which don't support unknown field storage. 546} 547func (m aberrantMessage) IsValid() bool { 548 if m.v.Kind() == reflect.Ptr { 549 return !m.v.IsNil() 550 } 551 return false 552} 553func (m aberrantMessage) ProtoMethods() *piface.Methods { 554 return aberrantProtoMethods 555} 556func (m aberrantMessage) protoUnwrap() interface{} { 557 return m.v.Interface() 558} 559