]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: add a use of runtime.KeepAlive's argument
authorKeith Randall <khr@golang.org>
Fri, 11 Aug 2017 16:48:46 +0000 (09:48 -0700)
committerKeith Randall <khr@golang.org>
Mon, 14 Aug 2017 20:11:21 +0000 (20:11 +0000)
This makes sure that its argument is marked live on entry.
We need its arg to be live so defers of KeepAlive get
scanned correctly by the GC.

Fixes #21402

Change-Id: I906813e433d0e9726ca46483723303338da5b4d7
Reviewed-on: https://go-review.googlesource.com/55150
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/runtime/mfinal.go
src/runtime/mfinal_test.go

index a8729b1aa469a8f14312d1d7ee30e1b69bd9499d..c11a6f15a428b19d032ebb1c035ef5a43c420f89 100644 (file)
@@ -461,11 +461,7 @@ func findObject(v unsafe.Pointer) (s *mspan, x unsafe.Pointer, n uintptr) {
        return
 }
 
-// Mark KeepAlive as noinline so that the current compiler will ensure
-// that the argument is alive at the point of the function call.
-// If it were inlined, it would disappear, and there would be nothing
-// keeping the argument alive. Perhaps a future compiler will recognize
-// runtime.KeepAlive specially and do something more efficient.
+// Mark KeepAlive as noinline so that it is easily detectable as an intrinsic.
 //go:noinline
 
 // KeepAlive marks its argument as currently reachable.
@@ -487,4 +483,11 @@ func findObject(v unsafe.Pointer) (s *mspan, x unsafe.Pointer, n uintptr) {
 // Without the KeepAlive call, the finalizer could run at the start of
 // syscall.Read, closing the file descriptor before syscall.Read makes
 // the actual system call.
-func KeepAlive(interface{}) {}
+func KeepAlive(x interface{}) {
+       // Introduce a use of x that the compiler can't eliminate.
+       // This makes sure x is alive on entry. We need x to be alive
+       // on entry for "defer runtime.KeepAlive(x)"; see issue 21402.
+       if cgoAlwaysFalse {
+               println(x)
+       }
+}
index e9e3601de6c15bab95b4de73508d277e9e23f6d1..85a5f7acaef6b4ac25769ab81f426cde29e3f7e9 100644 (file)
@@ -241,3 +241,20 @@ var (
        Foo2 = &Object2{}
        Foo1 = &Object1{}
 )
+
+func TestDeferKeepAlive(t *testing.T) {
+       // See issue 21402.
+       t.Parallel()
+       type T *int // needs to be a pointer base type to avoid tinyalloc and its never-finalized behavior.
+       x := new(T)
+       finRun := false
+       runtime.SetFinalizer(x, func(x *T) {
+               finRun = true
+       })
+       defer runtime.KeepAlive(x)
+       runtime.GC()
+       time.Sleep(time.Second)
+       if finRun {
+               t.Errorf("finalizer ran prematurely")
+       }
+}