| // run |
| |
| // Copyright 2018 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 return values are always scanned, when |
| // calling methods (+functions, TODO) with reflect. |
| |
| package main |
| |
| import ( |
| "reflect" |
| "runtime/debug" |
| "sync" |
| ) |
| |
| func main() { |
| debug.SetGCPercent(1) // run GC frequently |
| var wg sync.WaitGroup |
| for i := 0; i < 20; i++ { |
| wg.Add(1) |
| go func() { |
| defer wg.Done() |
| for i := 0; i < 2000; i++ { |
| _test() |
| } |
| }() |
| } |
| wg.Wait() |
| } |
| |
| type Stt struct { |
| Data interface{} |
| } |
| |
| type My struct { |
| b byte |
| } |
| |
| func (this *My) Run(rawData []byte) (Stt, error) { |
| var data string = "hello" |
| stt := Stt{ |
| Data: data, |
| } |
| return stt, nil |
| } |
| |
| func _test() (interface{}, error) { |
| f := reflect.ValueOf(&My{}).MethodByName("Run") |
| if method, ok := f.Interface().(func([]byte) (Stt, error)); ok { |
| s, e := method(nil) |
| // The bug in issue27695 happens here, during the return |
| // from the above call (at the end of reflect.callMethod |
| // when preparing to return). The result value that |
| // is assigned to s was not being scanned if GC happens |
| // to occur there. |
| i := interface{}(s) |
| return i, e |
| } |
| return nil, nil |
| } |