isinit.go 3.3 KB

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