]> Cypherpunks repositories - gostls13.git/commitdiff
reflect: keep pointer register results alive in callMethod
authorCherry Zhang <cherryyz@google.com>
Wed, 14 Apr 2021 03:41:45 +0000 (23:41 -0400)
committerCherry Zhang <cherryyz@google.com>
Wed, 14 Apr 2021 16:37:06 +0000 (16:37 +0000)
When callMethod calls the underlying method, after reflectcall
it gets the result registers in "Ints" slots but not in "Ptrs"
slots. If the GC runs at this point, it may lose track of those
pointers and free the memory they point to.

To make sure the GC sees the pointer results, copy "Ints" to
"Ptrs", and keep them alive until we return to the caller.

This fixes test/fixedbugs/issue27695.go with register ABI.

Change-Id: I4092c91bcbd6954683740a12d91d689900446875
Reviewed-on: https://go-review.googlesource.com/c/go/+/309909
Trust: Cherry Zhang <cherryyz@google.com>
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
src/reflect/abi.go
src/reflect/value.go

index caa770fcb0f3d2a5d45b36fa5a8000668000c338..17b79a8394fad5b5f12afd581356a6c354cfa0b4 100644 (file)
@@ -366,6 +366,22 @@ func (a *abiDesc) dump() {
        println("stackCallArgsSize", a.stackCallArgsSize)
        println("retOffset", a.retOffset)
        println("spill", a.spill)
+       print("inRegPtrs:")
+       dumpPtrBitMap(a.inRegPtrs)
+       println()
+       print("outRegPtrs:")
+       dumpPtrBitMap(a.outRegPtrs)
+       println()
+}
+
+func dumpPtrBitMap(b abi.IntArgRegBitmap) {
+       for i := 0; i < intArgRegs; i++ {
+               x := 0
+               if b.Get(i) {
+                       x = 1
+               }
+               print(" ", x)
+       }
 }
 
 func newAbiDesc(t *funcType, rcvr *rtype) abiDesc {
index 7890c125d81b0f5e75d3b9b1ea6b764fa8dc6189..6f1a3c02d68e4bde47515728931d09373aff56c4 100644 (file)
@@ -1023,6 +1023,9 @@ func callMethod(ctxt *methodValue, frame unsafe.Pointer, retValid *bool, regs *a
        methodFrameSize = align(methodFrameSize, ptrSize)
        methodFrameSize += methodABI.spill
 
+       // Mark pointers in registers for the return path.
+       methodRegs.ReturnIsPtr = methodABI.outRegPtrs
+
        // Call.
        // Call copies the arguments from scratch to the stack, calls fn,
        // and then copies the results back into scratch.
@@ -1059,6 +1062,11 @@ func callMethod(ctxt *methodValue, frame unsafe.Pointer, retValid *bool, regs *a
 
        // See the comment in callReflect.
        runtime.KeepAlive(ctxt)
+
+       // Keep valueRegs alive because it may hold live pointer results.
+       // The caller (methodValueCall) has it as a stack object, which is only
+       // scanned when there is a reference to it.
+       runtime.KeepAlive(valueRegs)
 }
 
 // funcName returns the name of f, for use in error messages.