summaryrefslogtreecommitdiffhomepage
path: root/util/deephash
diff options
context:
space:
mode:
Diffstat (limited to 'util/deephash')
-rw-r--r--util/deephash/debug.go74
-rw-r--r--util/deephash/pointer.go228
-rw-r--r--util/deephash/pointer_norace.go26
-rw-r--r--util/deephash/pointer_race.go198
-rw-r--r--util/deephash/testtype/testtype.go30
5 files changed, 278 insertions, 278 deletions
diff --git a/util/deephash/debug.go b/util/deephash/debug.go
index 50b3d5605..ff417e583 100644
--- a/util/deephash/debug.go
+++ b/util/deephash/debug.go
@@ -1,37 +1,37 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-//go:build deephash_debug
-
-package deephash
-
-import "fmt"
-
-func (h *hasher) HashBytes(b []byte) {
- fmt.Printf("B(%q)+", b)
- h.Block512.HashBytes(b)
-}
-func (h *hasher) HashString(s string) {
- fmt.Printf("S(%q)+", s)
- h.Block512.HashString(s)
-}
-func (h *hasher) HashUint8(n uint8) {
- fmt.Printf("U8(%d)+", n)
- h.Block512.HashUint8(n)
-}
-func (h *hasher) HashUint16(n uint16) {
- fmt.Printf("U16(%d)+", n)
- h.Block512.HashUint16(n)
-}
-func (h *hasher) HashUint32(n uint32) {
- fmt.Printf("U32(%d)+", n)
- h.Block512.HashUint32(n)
-}
-func (h *hasher) HashUint64(n uint64) {
- fmt.Printf("U64(%d)+", n)
- h.Block512.HashUint64(n)
-}
-func (h *hasher) Sum(b []byte) []byte {
- fmt.Println("FIN")
- return h.Block512.Sum(b)
-}
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+//go:build deephash_debug
+
+package deephash
+
+import "fmt"
+
+func (h *hasher) HashBytes(b []byte) {
+ fmt.Printf("B(%q)+", b)
+ h.Block512.HashBytes(b)
+}
+func (h *hasher) HashString(s string) {
+ fmt.Printf("S(%q)+", s)
+ h.Block512.HashString(s)
+}
+func (h *hasher) HashUint8(n uint8) {
+ fmt.Printf("U8(%d)+", n)
+ h.Block512.HashUint8(n)
+}
+func (h *hasher) HashUint16(n uint16) {
+ fmt.Printf("U16(%d)+", n)
+ h.Block512.HashUint16(n)
+}
+func (h *hasher) HashUint32(n uint32) {
+ fmt.Printf("U32(%d)+", n)
+ h.Block512.HashUint32(n)
+}
+func (h *hasher) HashUint64(n uint64) {
+ fmt.Printf("U64(%d)+", n)
+ h.Block512.HashUint64(n)
+}
+func (h *hasher) Sum(b []byte) []byte {
+ fmt.Println("FIN")
+ return h.Block512.Sum(b)
+}
diff --git a/util/deephash/pointer.go b/util/deephash/pointer.go
index aafae47a2..71b11d7ff 100644
--- a/util/deephash/pointer.go
+++ b/util/deephash/pointer.go
@@ -1,114 +1,114 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-package deephash
-
-import (
- "net/netip"
- "reflect"
- "time"
- "unsafe"
-)
-
-// unsafePointer is an untyped pointer.
-// It is the caller's responsibility to call operations on the correct type.
-//
-// This pointer only ever points to a small set of kinds or types:
-// time.Time, netip.Addr, string, array, slice, struct, map, pointer, interface,
-// or a pointer to memory that is directly hashable.
-//
-// Arrays are represented as pointers to the first element.
-// Structs are represented as pointers to the first field.
-// Slices are represented as pointers to a slice header.
-// Pointers are represented as pointers to a pointer.
-//
-// We do not support direct operations on maps and interfaces, and instead
-// rely on pointer.asValue to convert the pointer back to a reflect.Value.
-// Conversion of an unsafe.Pointer to reflect.Value guarantees that the
-// read-only flag in the reflect.Value is unpopulated, avoiding panics that may
-// otherwise have occurred since the value was obtained from an unexported field.
-type unsafePointer struct{ p unsafe.Pointer }
-
-func unsafePointerOf(v reflect.Value) unsafePointer {
- return unsafePointer{v.UnsafePointer()}
-}
-func (p unsafePointer) isNil() bool {
- return p.p == nil
-}
-
-// pointerElem dereferences a pointer.
-// p must point to a pointer.
-func (p unsafePointer) pointerElem() unsafePointer {
- return unsafePointer{*(*unsafe.Pointer)(p.p)}
-}
-
-// sliceLen returns the slice length.
-// p must point to a slice.
-func (p unsafePointer) sliceLen() int {
- return (*reflect.SliceHeader)(p.p).Len
-}
-
-// sliceArray returns a pointer to the underlying slice array.
-// p must point to a slice.
-func (p unsafePointer) sliceArray() unsafePointer {
- return unsafePointer{unsafe.Pointer((*reflect.SliceHeader)(p.p).Data)}
-}
-
-// arrayIndex returns a pointer to an element in the array.
-// p must point to an array.
-func (p unsafePointer) arrayIndex(index int, size uintptr) unsafePointer {
- return unsafePointer{unsafe.Add(p.p, uintptr(index)*size)}
-}
-
-// structField returns a pointer to a field in a struct.
-// p must pointer to a struct.
-func (p unsafePointer) structField(index int, offset, size uintptr) unsafePointer {
- return unsafePointer{unsafe.Add(p.p, offset)}
-}
-
-// asString casts p as a *string.
-func (p unsafePointer) asString() *string {
- return (*string)(p.p)
-}
-
-// asTime casts p as a *time.Time.
-func (p unsafePointer) asTime() *time.Time {
- return (*time.Time)(p.p)
-}
-
-// asAddr casts p as a *netip.Addr.
-func (p unsafePointer) asAddr() *netip.Addr {
- return (*netip.Addr)(p.p)
-}
-
-// asValue casts p as a reflect.Value containing a pointer to value of t.
-func (p unsafePointer) asValue(typ reflect.Type) reflect.Value {
- return reflect.NewAt(typ, p.p)
-}
-
-// asMemory returns the memory pointer at by p for a specified size.
-func (p unsafePointer) asMemory(size uintptr) []byte {
- return unsafe.Slice((*byte)(p.p), size)
-}
-
-// visitStack is a stack of pointers visited.
-// Pointers are pushed onto the stack when visited, and popped when leaving.
-// The integer value is the depth at which the pointer was visited.
-// The length of this stack should be zero after every hashing operation.
-type visitStack map[unsafe.Pointer]int
-
-func (v visitStack) seen(p unsafe.Pointer) (int, bool) {
- idx, ok := v[p]
- return idx, ok
-}
-
-func (v *visitStack) push(p unsafe.Pointer) {
- if *v == nil {
- *v = make(map[unsafe.Pointer]int)
- }
- (*v)[p] = len(*v)
-}
-
-func (v visitStack) pop(p unsafe.Pointer) {
- delete(v, p)
-}
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+package deephash
+
+import (
+ "net/netip"
+ "reflect"
+ "time"
+ "unsafe"
+)
+
+// unsafePointer is an untyped pointer.
+// It is the caller's responsibility to call operations on the correct type.
+//
+// This pointer only ever points to a small set of kinds or types:
+// time.Time, netip.Addr, string, array, slice, struct, map, pointer, interface,
+// or a pointer to memory that is directly hashable.
+//
+// Arrays are represented as pointers to the first element.
+// Structs are represented as pointers to the first field.
+// Slices are represented as pointers to a slice header.
+// Pointers are represented as pointers to a pointer.
+//
+// We do not support direct operations on maps and interfaces, and instead
+// rely on pointer.asValue to convert the pointer back to a reflect.Value.
+// Conversion of an unsafe.Pointer to reflect.Value guarantees that the
+// read-only flag in the reflect.Value is unpopulated, avoiding panics that may
+// otherwise have occurred since the value was obtained from an unexported field.
+type unsafePointer struct{ p unsafe.Pointer }
+
+func unsafePointerOf(v reflect.Value) unsafePointer {
+ return unsafePointer{v.UnsafePointer()}
+}
+func (p unsafePointer) isNil() bool {
+ return p.p == nil
+}
+
+// pointerElem dereferences a pointer.
+// p must point to a pointer.
+func (p unsafePointer) pointerElem() unsafePointer {
+ return unsafePointer{*(*unsafe.Pointer)(p.p)}
+}
+
+// sliceLen returns the slice length.
+// p must point to a slice.
+func (p unsafePointer) sliceLen() int {
+ return (*reflect.SliceHeader)(p.p).Len
+}
+
+// sliceArray returns a pointer to the underlying slice array.
+// p must point to a slice.
+func (p unsafePointer) sliceArray() unsafePointer {
+ return unsafePointer{unsafe.Pointer((*reflect.SliceHeader)(p.p).Data)}
+}
+
+// arrayIndex returns a pointer to an element in the array.
+// p must point to an array.
+func (p unsafePointer) arrayIndex(index int, size uintptr) unsafePointer {
+ return unsafePointer{unsafe.Add(p.p, uintptr(index)*size)}
+}
+
+// structField returns a pointer to a field in a struct.
+// p must pointer to a struct.
+func (p unsafePointer) structField(index int, offset, size uintptr) unsafePointer {
+ return unsafePointer{unsafe.Add(p.p, offset)}
+}
+
+// asString casts p as a *string.
+func (p unsafePointer) asString() *string {
+ return (*string)(p.p)
+}
+
+// asTime casts p as a *time.Time.
+func (p unsafePointer) asTime() *time.Time {
+ return (*time.Time)(p.p)
+}
+
+// asAddr casts p as a *netip.Addr.
+func (p unsafePointer) asAddr() *netip.Addr {
+ return (*netip.Addr)(p.p)
+}
+
+// asValue casts p as a reflect.Value containing a pointer to value of t.
+func (p unsafePointer) asValue(typ reflect.Type) reflect.Value {
+ return reflect.NewAt(typ, p.p)
+}
+
+// asMemory returns the memory pointer at by p for a specified size.
+func (p unsafePointer) asMemory(size uintptr) []byte {
+ return unsafe.Slice((*byte)(p.p), size)
+}
+
+// visitStack is a stack of pointers visited.
+// Pointers are pushed onto the stack when visited, and popped when leaving.
+// The integer value is the depth at which the pointer was visited.
+// The length of this stack should be zero after every hashing operation.
+type visitStack map[unsafe.Pointer]int
+
+func (v visitStack) seen(p unsafe.Pointer) (int, bool) {
+ idx, ok := v[p]
+ return idx, ok
+}
+
+func (v *visitStack) push(p unsafe.Pointer) {
+ if *v == nil {
+ *v = make(map[unsafe.Pointer]int)
+ }
+ (*v)[p] = len(*v)
+}
+
+func (v visitStack) pop(p unsafe.Pointer) {
+ delete(v, p)
+}
diff --git a/util/deephash/pointer_norace.go b/util/deephash/pointer_norace.go
index f98a70f6a..499372000 100644
--- a/util/deephash/pointer_norace.go
+++ b/util/deephash/pointer_norace.go
@@ -1,13 +1,13 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-//go:build !race
-
-package deephash
-
-import "reflect"
-
-type pointer = unsafePointer
-
-// pointerOf returns a pointer from v, which must be a reflect.Pointer.
-func pointerOf(v reflect.Value) pointer { return unsafePointerOf(v) }
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+//go:build !race
+
+package deephash
+
+import "reflect"
+
+type pointer = unsafePointer
+
+// pointerOf returns a pointer from v, which must be a reflect.Pointer.
+func pointerOf(v reflect.Value) pointer { return unsafePointerOf(v) }
diff --git a/util/deephash/pointer_race.go b/util/deephash/pointer_race.go
index c638c7d39..93a358b6d 100644
--- a/util/deephash/pointer_race.go
+++ b/util/deephash/pointer_race.go
@@ -1,99 +1,99 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-//go:build race
-
-package deephash
-
-import (
- "fmt"
- "net/netip"
- "reflect"
- "time"
-)
-
-// pointer is a typed pointer that performs safety checks for every operation.
-type pointer struct {
- unsafePointer
- t reflect.Type // type of pointed-at value; may be nil
- n uintptr // size of valid memory after p
-}
-
-// pointerOf returns a pointer from v, which must be a reflect.Pointer.
-func pointerOf(v reflect.Value) pointer {
- assert(v.Kind() == reflect.Pointer, "got %v, want pointer", v.Kind())
- te := v.Type().Elem()
- return pointer{unsafePointerOf(v), te, te.Size()}
-}
-
-func (p pointer) pointerElem() pointer {
- assert(p.t.Kind() == reflect.Pointer, "got %v, want pointer", p.t.Kind())
- te := p.t.Elem()
- return pointer{p.unsafePointer.pointerElem(), te, te.Size()}
-}
-
-func (p pointer) sliceLen() int {
- assert(p.t.Kind() == reflect.Slice, "got %v, want slice", p.t.Kind())
- return p.unsafePointer.sliceLen()
-}
-
-func (p pointer) sliceArray() pointer {
- assert(p.t.Kind() == reflect.Slice, "got %v, want slice", p.t.Kind())
- n := p.sliceLen()
- assert(n >= 0, "got negative slice length %d", n)
- ta := reflect.ArrayOf(n, p.t.Elem())
- return pointer{p.unsafePointer.sliceArray(), ta, ta.Size()}
-}
-
-func (p pointer) arrayIndex(index int, size uintptr) pointer {
- assert(p.t.Kind() == reflect.Array, "got %v, want array", p.t.Kind())
- assert(0 <= index && index < p.t.Len(), "got array of size %d, want to access element %d", p.t.Len(), index)
- assert(p.t.Elem().Size() == size, "got element size of %d, want %d", p.t.Elem().Size(), size)
- te := p.t.Elem()
- return pointer{p.unsafePointer.arrayIndex(index, size), te, te.Size()}
-}
-
-func (p pointer) structField(index int, offset, size uintptr) pointer {
- assert(p.t.Kind() == reflect.Struct, "got %v, want struct", p.t.Kind())
- assert(p.n >= offset, "got size of %d, want excessive start offset of %d", p.n, offset)
- assert(p.n >= offset+size, "got size of %d, want excessive end offset of %d", p.n, offset+size)
- if index < 0 {
- return pointer{p.unsafePointer.structField(index, offset, size), nil, size}
- }
- sf := p.t.Field(index)
- t := sf.Type
- assert(sf.Offset == offset, "got offset of %d, want offset %d", sf.Offset, offset)
- assert(t.Size() == size, "got size of %d, want size %d", t.Size(), size)
- return pointer{p.unsafePointer.structField(index, offset, size), t, t.Size()}
-}
-
-func (p pointer) asString() *string {
- assert(p.t.Kind() == reflect.String, "got %v, want string", p.t)
- return p.unsafePointer.asString()
-}
-
-func (p pointer) asTime() *time.Time {
- assert(p.t == timeTimeType, "got %v, want %v", p.t, timeTimeType)
- return p.unsafePointer.asTime()
-}
-
-func (p pointer) asAddr() *netip.Addr {
- assert(p.t == netipAddrType, "got %v, want %v", p.t, netipAddrType)
- return p.unsafePointer.asAddr()
-}
-
-func (p pointer) asValue(typ reflect.Type) reflect.Value {
- assert(p.t == typ, "got %v, want %v", p.t, typ)
- return p.unsafePointer.asValue(typ)
-}
-
-func (p pointer) asMemory(size uintptr) []byte {
- assert(p.n >= size, "got size of %d, want excessive size of %d", p.n, size)
- return p.unsafePointer.asMemory(size)
-}
-
-func assert(b bool, f string, a ...any) {
- if !b {
- panic(fmt.Sprintf(f, a...))
- }
-}
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+//go:build race
+
+package deephash
+
+import (
+ "fmt"
+ "net/netip"
+ "reflect"
+ "time"
+)
+
+// pointer is a typed pointer that performs safety checks for every operation.
+type pointer struct {
+ unsafePointer
+ t reflect.Type // type of pointed-at value; may be nil
+ n uintptr // size of valid memory after p
+}
+
+// pointerOf returns a pointer from v, which must be a reflect.Pointer.
+func pointerOf(v reflect.Value) pointer {
+ assert(v.Kind() == reflect.Pointer, "got %v, want pointer", v.Kind())
+ te := v.Type().Elem()
+ return pointer{unsafePointerOf(v), te, te.Size()}
+}
+
+func (p pointer) pointerElem() pointer {
+ assert(p.t.Kind() == reflect.Pointer, "got %v, want pointer", p.t.Kind())
+ te := p.t.Elem()
+ return pointer{p.unsafePointer.pointerElem(), te, te.Size()}
+}
+
+func (p pointer) sliceLen() int {
+ assert(p.t.Kind() == reflect.Slice, "got %v, want slice", p.t.Kind())
+ return p.unsafePointer.sliceLen()
+}
+
+func (p pointer) sliceArray() pointer {
+ assert(p.t.Kind() == reflect.Slice, "got %v, want slice", p.t.Kind())
+ n := p.sliceLen()
+ assert(n >= 0, "got negative slice length %d", n)
+ ta := reflect.ArrayOf(n, p.t.Elem())
+ return pointer{p.unsafePointer.sliceArray(), ta, ta.Size()}
+}
+
+func (p pointer) arrayIndex(index int, size uintptr) pointer {
+ assert(p.t.Kind() == reflect.Array, "got %v, want array", p.t.Kind())
+ assert(0 <= index && index < p.t.Len(), "got array of size %d, want to access element %d", p.t.Len(), index)
+ assert(p.t.Elem().Size() == size, "got element size of %d, want %d", p.t.Elem().Size(), size)
+ te := p.t.Elem()
+ return pointer{p.unsafePointer.arrayIndex(index, size), te, te.Size()}
+}
+
+func (p pointer) structField(index int, offset, size uintptr) pointer {
+ assert(p.t.Kind() == reflect.Struct, "got %v, want struct", p.t.Kind())
+ assert(p.n >= offset, "got size of %d, want excessive start offset of %d", p.n, offset)
+ assert(p.n >= offset+size, "got size of %d, want excessive end offset of %d", p.n, offset+size)
+ if index < 0 {
+ return pointer{p.unsafePointer.structField(index, offset, size), nil, size}
+ }
+ sf := p.t.Field(index)
+ t := sf.Type
+ assert(sf.Offset == offset, "got offset of %d, want offset %d", sf.Offset, offset)
+ assert(t.Size() == size, "got size of %d, want size %d", t.Size(), size)
+ return pointer{p.unsafePointer.structField(index, offset, size), t, t.Size()}
+}
+
+func (p pointer) asString() *string {
+ assert(p.t.Kind() == reflect.String, "got %v, want string", p.t)
+ return p.unsafePointer.asString()
+}
+
+func (p pointer) asTime() *time.Time {
+ assert(p.t == timeTimeType, "got %v, want %v", p.t, timeTimeType)
+ return p.unsafePointer.asTime()
+}
+
+func (p pointer) asAddr() *netip.Addr {
+ assert(p.t == netipAddrType, "got %v, want %v", p.t, netipAddrType)
+ return p.unsafePointer.asAddr()
+}
+
+func (p pointer) asValue(typ reflect.Type) reflect.Value {
+ assert(p.t == typ, "got %v, want %v", p.t, typ)
+ return p.unsafePointer.asValue(typ)
+}
+
+func (p pointer) asMemory(size uintptr) []byte {
+ assert(p.n >= size, "got size of %d, want excessive size of %d", p.n, size)
+ return p.unsafePointer.asMemory(size)
+}
+
+func assert(b bool, f string, a ...any) {
+ if !b {
+ panic(fmt.Sprintf(f, a...))
+ }
+}
diff --git a/util/deephash/testtype/testtype.go b/util/deephash/testtype/testtype.go
index 3c90053d6..2df38da87 100644
--- a/util/deephash/testtype/testtype.go
+++ b/util/deephash/testtype/testtype.go
@@ -1,15 +1,15 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-// Package testtype contains types for testing deephash.
-package testtype
-
-import "time"
-
-type UnexportedAddressableTime struct {
- t time.Time
-}
-
-func NewUnexportedAddressableTime(t time.Time) *UnexportedAddressableTime {
- return &UnexportedAddressableTime{t: t}
-}
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+// Package testtype contains types for testing deephash.
+package testtype
+
+import "time"
+
+type UnexportedAddressableTime struct {
+ t time.Time
+}
+
+func NewUnexportedAddressableTime(t time.Time) *UnexportedAddressableTime {
+ return &UnexportedAddressableTime{t: t}
+}