// The pointer to the object must be valid.
if ptr == nil {
- throw("runtime.AddCleanup: ptr is nil")
+ panic("runtime.AddCleanup: ptr is nil")
}
usptr := uintptr(unsafe.Pointer(ptr))
// Check that arg is not equal to ptr.
- // TODO(67535) this does not cover the case where T and *S are the same
- // type and ptr and arg are equal.
- if unsafe.Pointer(&arg) == unsafe.Pointer(ptr) {
- throw("runtime.AddCleanup: ptr is equal to arg, cleanup will never run")
+ if kind := abi.TypeOf(arg).Kind(); kind == abi.Pointer || kind == abi.UnsafePointer {
+ if unsafe.Pointer(ptr) == *((*unsafe.Pointer)(unsafe.Pointer(&arg))) {
+ panic("runtime.AddCleanup: ptr is equal to arg, cleanup will never run")
+ }
}
if inUserArenaChunk(usptr) {
// Arena-allocated objects are not eligible for cleanup.
- throw("runtime.AddCleanup: ptr is arena-allocated")
+ panic("runtime.AddCleanup: ptr is arena-allocated")
}
if debug.sbrk != 0 {
// debug.sbrk never frees memory, so no cleanup will ever run
// Cleanup is a noop.
return Cleanup{}
}
- throw("runtime.AddCleanup: ptr not in allocated block")
+ panic("runtime.AddCleanup: ptr not in allocated block")
}
// Ensure we have a finalizer processing goroutine running.
<-ch
stop()
}
+
+func TestCleanupPointerEqualsArg(t *testing.T) {
+ // See go.dev/issue/71316
+ defer func() {
+ want := "runtime.AddCleanup: ptr is equal to arg, cleanup will never run"
+ if r := recover(); r == nil {
+ t.Error("want panic, test did not panic")
+ } else if r == want {
+ // do nothing
+ } else {
+ t.Errorf("wrong panic: want=%q, got=%q", want, r)
+ }
+ }()
+
+ // allocate struct with pointer to avoid hitting tinyalloc.
+ // Otherwise we can't be sure when the allocation will
+ // be freed.
+ type T struct {
+ v int
+ p unsafe.Pointer
+ }
+ v := &new(T).v
+ *v = 97531
+ runtime.AddCleanup(v, func(x *int) {}, v)
+ v = nil
+ runtime.GC()
+}