}
level, _, _ := gotraceback()
+ var ctxt *funcval // Context pointer for unstarted goroutines. See issue #25897.
+
if pc0 == ^uintptr(0) && sp0 == ^uintptr(0) { // Signal to fetch saved values from gp.
if gp.syscallsp != 0 {
pc0 = gp.syscallpc
if usesLR {
lr0 = gp.sched.lr
}
+ ctxt = (*funcval)(gp.sched.ctxt)
}
}
var ok bool
frame.arglen, frame.argmap, ok = getArgInfoFast(f, callback != nil)
if !ok {
- frame.arglen, frame.argmap = getArgInfo(&frame, f, callback != nil, nil)
+ frame.arglen, frame.argmap = getArgInfo(&frame, f, callback != nil, ctxt)
}
}
+ ctxt = nil // ctxt is only needed to get arg maps for the topmost frame
// Determine frame's 'continuation PC', where it can continue.
// Normally this is the return address on the stack, but if sigpanic
// with call frame frame.
//
// This is used for both actual calls with active stack frames and for
-// deferred calls that are not yet executing. If this is an actual
+// deferred calls or goroutines that are not yet executing. If this is an actual
// call, ctxt must be nil (getArgInfo will retrieve what it needs from
-// the active stack frame). If this is a deferred call, ctxt must be
-// the function object that was deferred.
+// the active stack frame). If this is a deferred call or unstarted goroutine,
+// ctxt must be the function object that was deferred or go'd.
func getArgInfo(frame *stkframe, f funcInfo, needArgMap bool, ctxt *funcval) (arglen uintptr, argmap *bitvector) {
arglen = uintptr(f.args)
if needArgMap && f.args == _ArgsSizeUnknown {
var retValid bool
if ctxt != nil {
// This is not an actual call, but a
- // deferred call. The function value
- // is itself the *reflect.methodValue.
+ // deferred call or an unstarted goroutine.
+ // The function value is itself the *reflect.methodValue.
mv = (*reflectMethodValue)(unsafe.Pointer(ctxt))
} else {
// This is a real call that took the
--- /dev/null
+// run
+
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Make sure the runtime can scan args of an unstarted goroutine
+// which starts with a reflect-generated function.
+
+package main
+
+import (
+ "reflect"
+ "runtime"
+)
+
+const N = 100
+
+func main() {
+ runtime.GOMAXPROCS(1)
+ c := make(chan bool, N)
+ for i := 0; i < N; i++ {
+ f := reflect.MakeFunc(reflect.TypeOf(((func(*int))(nil))),
+ func(args []reflect.Value) []reflect.Value {
+ c <- true
+ return nil
+ }).Interface().(func(*int))
+ go f(nil)
+ }
+ runtime.GC()
+ for i := 0; i < N; i++ {
+ <-c
+ }
+}
--- /dev/null
+// run
+
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Make sure the runtime can scan args of an unstarted goroutine
+// which starts with a reflect-generated function.
+
+package main
+
+import (
+ "reflect"
+ "runtime"
+)
+
+const N = 100
+
+type T struct {
+}
+
+func (t *T) Foo(c chan bool) {
+ c <- true
+}
+
+func main() {
+ t := &T{}
+ runtime.GOMAXPROCS(1)
+ c := make(chan bool, N)
+ for i := 0; i < N; i++ {
+ f := reflect.ValueOf(t).MethodByName("Foo").Interface().(func(chan bool))
+ go f(c)
+ }
+ runtime.GC()
+ for i := 0; i < N; i++ {
+ <-c
+ }
+}