aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/runtime/pinner.go29
-rw-r--r--src/runtime/pinner_test.go16
2 files changed, 32 insertions, 13 deletions
diff --git a/src/runtime/pinner.go b/src/runtime/pinner.go
index 8bb351eb8f..eb62a0fd53 100644
--- a/src/runtime/pinner.go
+++ b/src/runtime/pinner.go
@@ -25,10 +25,8 @@ type Pinner struct {
// objects, these objects must be pinned separately if they are going to be
// accessed from C code.
//
-// The argument must be a pointer of any type or an
-// unsafe.Pointer. It must be the result of calling new,
-// taking the address of a composite literal, or taking the address of a
-// local variable. If one of these conditions is not met, Pin will panic.
+// The argument must be a pointer of any type or an unsafe.Pointer.
+// It's safe to call Pin on non-Go pointers, in which case Pin will do nothing.
func (p *Pinner) Pin(pointer any) {
if p.pinner == nil {
// Check the pinner cache first.
@@ -59,8 +57,9 @@ func (p *Pinner) Pin(pointer any) {
}
}
ptr := pinnerGetPtr(&pointer)
- setPinned(ptr, true)
- p.refs = append(p.refs, ptr)
+ if setPinned(ptr, true) {
+ p.refs = append(p.refs, ptr)
+ }
}
// Unpin unpins all pinned objects of the Pinner.
@@ -143,15 +142,19 @@ func isPinned(ptr unsafe.Pointer) bool {
return pinState.isPinned()
}
-// setPinned marks or unmarks a Go pointer as pinned.
-func setPinned(ptr unsafe.Pointer, pin bool) {
+// setPinned marks or unmarks a Go pointer as pinned, when the ptr is a Go pointer.
+// It will be ignored while try to pin a non-Go pointer,
+// and it will be panic while try to unpin a non-Go pointer,
+// which should not happen in normal usage.
+func setPinned(ptr unsafe.Pointer, pin bool) bool {
span := spanOfHeap(uintptr(ptr))
if span == nil {
- if isGoPointerWithoutSpan(ptr) {
- // this is a linker-allocated or zero size object, nothing to do.
- return
+ if !pin {
+ panic(errorString("tried to unpin non-Go pointer"))
}
- panic(errorString("runtime.Pinner.Pin: argument is not a Go pointer"))
+ // This is a linker-allocated, zero size object or other object,
+ // nothing to do, silently ignore it.
+ return false
}
// ensure that the span is swept, b/c sweeping accesses the specials list
@@ -209,7 +212,7 @@ func setPinned(ptr unsafe.Pointer, pin bool) {
}
unlock(&span.speciallock)
releasem(mp)
- return
+ return true
}
type pinState struct {
diff --git a/src/runtime/pinner_test.go b/src/runtime/pinner_test.go
index 88ead7c946..ef8500cd35 100644
--- a/src/runtime/pinner_test.go
+++ b/src/runtime/pinner_test.go
@@ -522,3 +522,19 @@ func BenchmarkPinnerIsPinnedOnUnpinnedParallel(b *testing.B) {
}
})
}
+
+// const string data is not in span.
+func TestPinnerConstStringData(t *testing.T) {
+ var pinner runtime.Pinner
+ str := "test-const-string"
+ p := unsafe.StringData(str)
+ addr := unsafe.Pointer(p)
+ if !runtime.IsPinned(addr) {
+ t.Fatal("not marked as pinned")
+ }
+ pinner.Pin(p)
+ pinner.Unpin()
+ if !runtime.IsPinned(addr) {
+ t.Fatal("not marked as pinned")
+ }
+}