aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/traceback.go
diff options
context:
space:
mode:
authorKeith Randall <khr@google.com>2018-09-25 15:54:11 -0700
committerKeith Randall <khr@golang.org>2018-09-29 20:25:24 +0000
commitef5037398385ff52b17af325a0ad82017bd65820 (patch)
treeb828c15a770de9607a9bf7b9d7dd3cb4167641b3 /src/runtime/traceback.go
parenta0e7f12771c2e84e626dcf5e30da5d62a3b1adf6 (diff)
downloadgo-ef5037398385ff52b17af325a0ad82017bd65820.tar.gz
go-ef5037398385ff52b17af325a0ad82017bd65820.zip
reflect: ensure correct scanning of return values
During a call to a reflect-generated function or method (via makeFuncStub or methodValueCall), when should we scan the return values? When we're starting a reflect call, the space on the stack for the return values is not initialized yet, as it contains whatever junk was on the stack of the caller at the time. The return space must not be scanned during a GC. When we're finishing a reflect call, the return values are initialized, and must be scanned during a GC to make sure that any pointers in the return values are found and their referents retained. When the GC stack walk comes across a reflect call in progress on the stack, it needs to know whether to scan the results or not. It doesn't know the progress of the reflect call, so it can't decide by itself. The reflect package needs to tell it. This CL adds another slot in the frame of makeFuncStub and methodValueCall so we can put a boolean in there which tells the runtime whether to scan the results or not. This CL also adds the args length to reflectMethodValue so the runtime can restrict its scanning to only the args section (not the results) if the reflect package says the results aren't ready yet. Do a delicate dance in the reflect package to set the "results are valid" bit. We need to make sure we set the bit only after we've copied the results back to the stack. But we must set the bit before we drop reflect's copy of the results. Otherwise, we might have a state where (temporarily) no one has a live copy of the results. That's the state we were observing in issue #27695 before this CL. The bitmap used by the runtime currently contains only the args. (Actually, it contains all the bits, but the size is set so we use only the args portion.) This is safe for early in a reflect call, but unsafe late in a reflect call. The test issue27695.go demonstrates this unsafety. We change the bitmap to always include both args and results, and decide at runtime which portion to use. issue27695.go only has a test for method calls. Function calls were ok because there wasn't a safepoint between when reflect dropped its copy of the return values and when the caller is resumed. This may change when we introduce safepoints everywhere. This truncate-to-only-the-args was part of CL 9888 (in 2015). That part of the CL fixed the problem demonstrated in issue27695b.go but introduced the problem demonstrated in issue27695.go. TODO, in another CL: simplify FuncLayout and its test. stack return value is now identical to frametype.ptrdata + frametype.gcdata. Fixes #27695 Change-Id: I2d49b34e34a82c6328b34f02610587a291b25c5f Reviewed-on: https://go-review.googlesource.com/137440 Run-TryBot: Keith Randall <khr@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Austin Clements <austin@google.com>
Diffstat (limited to 'src/runtime/traceback.go')
-rw-r--r--src/runtime/traceback.go13
1 files changed, 11 insertions, 2 deletions
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go
index 4c2010493a..8e104ae89e 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -571,8 +571,9 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
// reflectMethodValue is a partial duplicate of reflect.makeFuncImpl
// and reflect.methodValue.
type reflectMethodValue struct {
- fn uintptr
- stack *bitvector // args bitmap
+ fn uintptr
+ stack *bitvector // ptrmap for both args and results
+ argLen uintptr // just args
}
// getArgInfoFast returns the argument frame information for a call to f.
@@ -601,6 +602,7 @@ func getArgInfo(frame *stkframe, f funcInfo, needArgMap bool, ctxt *funcval) (ar
// These take a *reflect.methodValue as their
// context register.
var mv *reflectMethodValue
+ var retValid bool
if ctxt != nil {
// This is not an actual call, but a
// deferred call. The function value
@@ -614,6 +616,10 @@ func getArgInfo(frame *stkframe, f funcInfo, needArgMap bool, ctxt *funcval) (ar
// 0(SP).
arg0 := frame.sp + sys.MinFrameSize
mv = *(**reflectMethodValue)(unsafe.Pointer(arg0))
+ // Figure out whether the return values are valid.
+ // Reflect will update this value after it copies
+ // in the return values.
+ retValid = *(*bool)(unsafe.Pointer(arg0 + 3*sys.PtrSize))
}
if mv.fn != f.entry {
print("runtime: confused by ", funcname(f), "\n")
@@ -621,6 +627,9 @@ func getArgInfo(frame *stkframe, f funcInfo, needArgMap bool, ctxt *funcval) (ar
}
bv := mv.stack
arglen = uintptr(bv.n * sys.PtrSize)
+ if !retValid {
+ arglen = uintptr(mv.argLen) &^ (sys.PtrSize - 1)
+ }
argmap = bv
}
}