isinit.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. // 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. package impl
  5. import (
  6. "sync"
  7. "google.golang.org/protobuf/proto"
  8. pref "google.golang.org/protobuf/reflect/protoreflect"
  9. )
  10. type errRequiredNotSet struct{}
  11. func (errRequiredNotSet) Error() string { return "proto: required field not set" }
  12. func (errRequiredNotSet) RequiredNotSet() bool { return true }
  13. func (mi *MessageInfo) isInitialized(msg proto.Message) error {
  14. return mi.isInitializedPointer(pointerOfIface(msg))
  15. }
  16. func (mi *MessageInfo) isInitializedPointer(p pointer) error {
  17. mi.init()
  18. if !mi.needsInitCheck {
  19. return nil
  20. }
  21. if p.IsNil() {
  22. return errRequiredNotSet{}
  23. }
  24. if mi.extensionOffset.IsValid() {
  25. e := p.Apply(mi.extensionOffset).Extensions()
  26. if err := mi.isInitExtensions(e); err != nil {
  27. return err
  28. }
  29. }
  30. for _, f := range mi.orderedCoderFields {
  31. if !f.isRequired && f.funcs.isInit == nil {
  32. continue
  33. }
  34. fptr := p.Apply(f.offset)
  35. if f.isPointer && fptr.Elem().IsNil() {
  36. if f.isRequired {
  37. return errRequiredNotSet{}
  38. }
  39. continue
  40. }
  41. if f.funcs.isInit == nil {
  42. continue
  43. }
  44. if err := f.funcs.isInit(fptr); err != nil {
  45. return err
  46. }
  47. }
  48. return nil
  49. }
  50. func (mi *MessageInfo) isInitExtensions(ext *map[int32]ExtensionField) error {
  51. if ext == nil {
  52. return nil
  53. }
  54. for _, x := range *ext {
  55. ei := mi.extensionFieldInfo(x.GetType())
  56. if ei.funcs.isInit == nil {
  57. continue
  58. }
  59. v := x.GetValue()
  60. if v == nil {
  61. continue
  62. }
  63. if err := ei.funcs.isInit(v); err != nil {
  64. return err
  65. }
  66. }
  67. return nil
  68. }
  69. var (
  70. needsInitCheckMu sync.Mutex
  71. needsInitCheckMap sync.Map
  72. )
  73. // needsInitCheck reports whether a message needs to be checked for partial initialization.
  74. //
  75. // It returns true if the message transitively includes any required or extension fields.
  76. func needsInitCheck(md pref.MessageDescriptor) bool {
  77. if v, ok := needsInitCheckMap.Load(md); ok {
  78. if has, ok := v.(bool); ok {
  79. return has
  80. }
  81. }
  82. needsInitCheckMu.Lock()
  83. defer needsInitCheckMu.Unlock()
  84. return needsInitCheckLocked(md)
  85. }
  86. func needsInitCheckLocked(md pref.MessageDescriptor) (has bool) {
  87. if v, ok := needsInitCheckMap.Load(md); ok {
  88. // If has is true, we've previously determined that this message
  89. // needs init checks.
  90. //
  91. // If has is false, we've previously determined that it can never
  92. // be uninitialized.
  93. //
  94. // If has is not a bool, we've just encountered a cycle in the
  95. // message graph. In this case, it is safe to return false: If
  96. // the message does have required fields, we'll detect them later
  97. // in the graph traversal.
  98. has, ok := v.(bool)
  99. return ok && has
  100. }
  101. needsInitCheckMap.Store(md, struct{}{}) // avoid cycles while descending into this message
  102. defer func() {
  103. needsInitCheckMap.Store(md, has)
  104. }()
  105. if md.RequiredNumbers().Len() > 0 {
  106. return true
  107. }
  108. if md.ExtensionRanges().Len() > 0 {
  109. return true
  110. }
  111. for i := 0; i < md.Fields().Len(); i++ {
  112. fd := md.Fields().Get(i)
  113. // Map keys are never messages, so just consider the map value.
  114. if fd.IsMap() {
  115. fd = fd.MapValue()
  116. }
  117. fmd := fd.Message()
  118. if fmd != nil && needsInitCheckLocked(fmd) {
  119. return true
  120. }
  121. }
  122. return false
  123. }