isinit.go 3.2 KB

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