types.go 2.9 KB

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