types.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package deephash
  4. import (
  5. "net/netip"
  6. "reflect"
  7. "time"
  8. )
  9. var (
  10. timeTimeType = reflect.TypeFor[time.Time]()
  11. netipAddrType = reflect.TypeFor[netip.Addr]()
  12. selfHasherType = reflect.TypeFor[SelfHasher]()
  13. )
  14. // typeIsSpecialized reports whether this type has specialized hashing.
  15. // These are never memory hashable and never considered recursive.
  16. func typeIsSpecialized(t reflect.Type) bool {
  17. switch t {
  18. case timeTimeType, netipAddrType:
  19. return true
  20. default:
  21. if t.Kind() != reflect.Pointer && t.Kind() != reflect.Interface {
  22. if t.Implements(selfHasherType) || reflect.PointerTo(t).Implements(selfHasherType) {
  23. return true
  24. }
  25. }
  26. return false
  27. }
  28. }
  29. // typeIsMemHashable reports whether t can be hashed by directly hashing its
  30. // contiguous bytes in memory (e.g. structs with gaps are not mem-hashable).
  31. func typeIsMemHashable(t reflect.Type) bool {
  32. if typeIsSpecialized(t) {
  33. return false
  34. }
  35. if t.Size() == 0 {
  36. return true
  37. }
  38. switch t.Kind() {
  39. case reflect.Bool,
  40. reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
  41. reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
  42. reflect.Float32, reflect.Float64,
  43. reflect.Complex64, reflect.Complex128:
  44. return true
  45. case reflect.Array:
  46. return typeIsMemHashable(t.Elem())
  47. case reflect.Struct:
  48. var sumFieldSize uintptr
  49. for i, numField := 0, t.NumField(); i < numField; i++ {
  50. sf := t.Field(i)
  51. if !typeIsMemHashable(sf.Type) {
  52. return false
  53. }
  54. sumFieldSize += sf.Type.Size()
  55. }
  56. return sumFieldSize == t.Size() // ensure no gaps
  57. }
  58. return false
  59. }
  60. // typeIsRecursive reports whether t has a path back to itself.
  61. // For interfaces, it currently always reports true.
  62. func typeIsRecursive(t reflect.Type) bool {
  63. inStack := map[reflect.Type]bool{}
  64. var visitType func(t reflect.Type) (isRecursiveSoFar bool)
  65. visitType = func(t reflect.Type) (isRecursiveSoFar bool) {
  66. // Check whether we have seen this type before.
  67. if inStack[t] {
  68. return true
  69. }
  70. inStack[t] = true
  71. defer func() {
  72. delete(inStack, t)
  73. }()
  74. // Types with specialized hashing are never considered recursive.
  75. if typeIsSpecialized(t) {
  76. return false
  77. }
  78. // Any type that is memory hashable must not be recursive since
  79. // cycles can only occur if pointers are involved.
  80. if typeIsMemHashable(t) {
  81. return false
  82. }
  83. // Recursively check types that may contain pointers.
  84. switch t.Kind() {
  85. default:
  86. panic("unhandled kind " + t.Kind().String())
  87. case reflect.String, reflect.UnsafePointer, reflect.Func:
  88. return false
  89. case reflect.Interface:
  90. // Assume the worst for now. TODO(bradfitz): in some cases
  91. // we should be able to prove that it's not recursive. Not worth
  92. // it for now.
  93. return true
  94. case reflect.Array, reflect.Chan, reflect.Pointer, reflect.Slice:
  95. return visitType(t.Elem())
  96. case reflect.Map:
  97. return visitType(t.Key()) || visitType(t.Elem())
  98. case reflect.Struct:
  99. for i, numField := 0, t.NumField(); i < numField; i++ {
  100. if visitType(t.Field(i).Type) {
  101. return true
  102. }
  103. }
  104. return false
  105. }
  106. }
  107. return visitType(t)
  108. }