pointer_race.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. //go:build race
  4. package deephash
  5. import (
  6. "fmt"
  7. "net/netip"
  8. "reflect"
  9. "time"
  10. )
  11. // pointer is a typed pointer that performs safety checks for every operation.
  12. type pointer struct {
  13. unsafePointer
  14. t reflect.Type // type of pointed-at value; may be nil
  15. n uintptr // size of valid memory after p
  16. }
  17. // pointerOf returns a pointer from v, which must be a reflect.Pointer.
  18. func pointerOf(v reflect.Value) pointer {
  19. assert(v.Kind() == reflect.Pointer, "got %v, want pointer", v.Kind())
  20. te := v.Type().Elem()
  21. return pointer{unsafePointerOf(v), te, te.Size()}
  22. }
  23. func (p pointer) pointerElem() pointer {
  24. assert(p.t.Kind() == reflect.Pointer, "got %v, want pointer", p.t.Kind())
  25. te := p.t.Elem()
  26. return pointer{p.unsafePointer.pointerElem(), te, te.Size()}
  27. }
  28. func (p pointer) sliceLen() int {
  29. assert(p.t.Kind() == reflect.Slice, "got %v, want slice", p.t.Kind())
  30. return p.unsafePointer.sliceLen()
  31. }
  32. func (p pointer) sliceArray() pointer {
  33. assert(p.t.Kind() == reflect.Slice, "got %v, want slice", p.t.Kind())
  34. n := p.sliceLen()
  35. assert(n >= 0, "got negative slice length %d", n)
  36. ta := reflect.ArrayOf(n, p.t.Elem())
  37. return pointer{p.unsafePointer.sliceArray(), ta, ta.Size()}
  38. }
  39. func (p pointer) arrayIndex(index int, size uintptr) pointer {
  40. assert(p.t.Kind() == reflect.Array, "got %v, want array", p.t.Kind())
  41. assert(0 <= index && index < p.t.Len(), "got array of size %d, want to access element %d", p.t.Len(), index)
  42. assert(p.t.Elem().Size() == size, "got element size of %d, want %d", p.t.Elem().Size(), size)
  43. te := p.t.Elem()
  44. return pointer{p.unsafePointer.arrayIndex(index, size), te, te.Size()}
  45. }
  46. func (p pointer) structField(index int, offset, size uintptr) pointer {
  47. assert(p.t.Kind() == reflect.Struct, "got %v, want struct", p.t.Kind())
  48. assert(p.n >= offset, "got size of %d, want excessive start offset of %d", p.n, offset)
  49. assert(p.n >= offset+size, "got size of %d, want excessive end offset of %d", p.n, offset+size)
  50. if index < 0 {
  51. return pointer{p.unsafePointer.structField(index, offset, size), nil, size}
  52. }
  53. sf := p.t.Field(index)
  54. t := sf.Type
  55. assert(sf.Offset == offset, "got offset of %d, want offset %d", sf.Offset, offset)
  56. assert(t.Size() == size, "got size of %d, want size %d", t.Size(), size)
  57. return pointer{p.unsafePointer.structField(index, offset, size), t, t.Size()}
  58. }
  59. func (p pointer) asString() *string {
  60. assert(p.t.Kind() == reflect.String, "got %v, want string", p.t)
  61. return p.unsafePointer.asString()
  62. }
  63. func (p pointer) asTime() *time.Time {
  64. assert(p.t == timeTimeType, "got %v, want %v", p.t, timeTimeType)
  65. return p.unsafePointer.asTime()
  66. }
  67. func (p pointer) asAddr() *netip.Addr {
  68. assert(p.t == netipAddrType, "got %v, want %v", p.t, netipAddrType)
  69. return p.unsafePointer.asAddr()
  70. }
  71. func (p pointer) asValue(typ reflect.Type) reflect.Value {
  72. assert(p.t == typ, "got %v, want %v", p.t, typ)
  73. return p.unsafePointer.asValue(typ)
  74. }
  75. func (p pointer) asMemory(size uintptr) []byte {
  76. assert(p.n >= size, "got size of %d, want excessive size of %d", p.n, size)
  77. return p.unsafePointer.asMemory(size)
  78. }
  79. func assert(b bool, f string, a ...any) {
  80. if !b {
  81. panic(fmt.Sprintf(f, a...))
  82. }
  83. }