Skip to content

Commit

Permalink
unique: handle zero-size types
Browse files Browse the repository at this point in the history
Fixes #69458

Change-Id: Ic7fda7f556522780b2819138dfc1277137398692
Reviewed-on: https://go-review.googlesource.com/c/go/+/613397
Reviewed-by: Carlos Amedee <[email protected]>
LUCI-TryBot-Result: Go LUCI <[email protected]>
Auto-Submit: Cuong Manh Le <[email protected]>
Reviewed-by: Michael Knyszek <[email protected]>
  • Loading branch information
cuonglm authored and gopherbot committed Sep 16, 2024
1 parent aa06c94 commit 2927aa1
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 3 deletions.
7 changes: 6 additions & 1 deletion src/unique/handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ import (
"internal/weak"
"runtime"
"sync"
_ "unsafe"
"unsafe"
)

var zero uintptr

// Handle is a globally unique identity for some value of type T.
//
// Two handles compare equal exactly if the two values used to create the handles
Expand All @@ -32,6 +34,9 @@ func (h Handle[T]) Value() T {
func Make[T comparable](value T) Handle[T] {
// Find the map for type T.
typ := abi.TypeFor[T]()
if typ.Size() == 0 {
return Handle[T]{(*T)(unsafe.Pointer(&zero))}
}
ma, ok := uniqueMaps.Load(typ)
if !ok {
// This is a good time to initialize cleanup, since we must go through
Expand Down
10 changes: 8 additions & 2 deletions src/unique/handle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type testStruct struct {
z float64
b string
}
type testZeroSize struct{}

func TestHandle(t *testing.T) {
testHandle(t, testString("foo"))
Expand All @@ -45,6 +46,7 @@ func TestHandle(t *testing.T) {
})
testHandle(t, testStruct{0.5, "184"})
testHandle(t, testEface("hello"))
testHandle(t, testZeroSize(struct{}{}))
}

func testHandle[T comparable](t *testing.T, value T) {
Expand All @@ -65,15 +67,19 @@ func testHandle[T comparable](t *testing.T, value T) {
t.Error("v0 != v1")
}

drainMaps(t)
drainMaps[T](t)
checkMapsFor(t, value)
})
}

// drainMaps ensures that the internal maps are drained.
func drainMaps(t *testing.T) {
func drainMaps[T comparable](t *testing.T) {
t.Helper()

if unsafe.Sizeof(*(new(T))) == 0 {
return // zero-size types are not inserted.
}

wait := make(chan struct{}, 1)

// Set up a one-time notification for the next time the cleanup runs.
Expand Down

0 comments on commit 2927aa1

Please sign in to comment.