weak: prevent unsafe conversions using weak pointers

Prevent conversions between Pointer types,
like we do for sync/atomic.Pointer.

Fixes #71583

Change-Id: I20e83106d8a27996f221e6cd9d52637b0442cea4
Reviewed-on: https://go-review.googlesource.com/c/go/+/647195
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
This commit is contained in:
thepudds 2025-02-06 08:07:38 -05:00 committed by Gopher Robot
parent 478ad013f9
commit 8163ea1458
3 changed files with 38 additions and 1 deletions

View File

@ -56,6 +56,9 @@ import (
// referenced object. Typically, this batching only happens for tiny // referenced object. Typically, this batching only happens for tiny
// (on the order of 16 bytes or less) and pointer-free objects. // (on the order of 16 bytes or less) and pointer-free objects.
type Pointer[T any] struct { type Pointer[T any] struct {
// Mention T in the type definition to prevent conversions
// between Pointer types, like we do for sync/atomic.Pointer.
_ [0]*T
u unsafe.Pointer u unsafe.Pointer
} }
@ -69,7 +72,7 @@ func Make[T any](ptr *T) Pointer[T] {
u = runtime_registerWeakPointer(unsafe.Pointer(ptr)) u = runtime_registerWeakPointer(unsafe.Pointer(ptr))
} }
runtime.KeepAlive(ptr) runtime.KeepAlive(ptr)
return Pointer[T]{u} return Pointer[T]{u: u}
} }
// Value returns the original pointer used to create the weak pointer. // Value returns the original pointer used to create the weak pointer.

View File

@ -6,10 +6,12 @@ package weak_test
import ( import (
"context" "context"
"internal/goarch"
"runtime" "runtime"
"sync" "sync"
"testing" "testing"
"time" "time"
"unsafe"
"weak" "weak"
) )
@ -155,6 +157,14 @@ func TestPointerFinalizer(t *testing.T) {
} }
} }
func TestPointerSize(t *testing.T) {
var p weak.Pointer[T]
size := unsafe.Sizeof(p)
if size != goarch.PtrSize {
t.Errorf("weak.Pointer[T] size = %d, want %d", size, goarch.PtrSize)
}
}
// Regression test for issue 69210. // Regression test for issue 69210.
// //
// Weak-to-strong conversions must shade the new strong pointer, otherwise // Weak-to-strong conversions must shade the new strong pointer, otherwise

24
test/weak.go Normal file
View File

@ -0,0 +1,24 @@
// errorcheck
// Copyright 2025 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Test weak pointers.
package p
import (
"runtime"
"weak"
)
// Adapted from example in https://github.com/golang/go/issues/67552#issuecomment-2639661220
func conversion() {
p := "hello"
a := weak.Make(&p)
b := (weak.Pointer[*byte])(a) // ERROR "cannot convert a \(variable of struct type weak\.Pointer\[string\]\) to type weak.Pointer\[\*byte\]"
c := b.Value()
println(**c)
runtime.KeepAlive(p)
}