]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: when marking REFLECTMETHOD, check for reflect package itself
authorCherry Zhang <cherryyz@google.com>
Sat, 18 Apr 2020 21:47:54 +0000 (17:47 -0400)
committerCherry Zhang <cherryyz@google.com>
Sun, 19 Apr 2020 03:12:32 +0000 (03:12 +0000)
reflect.Type.Method (and MethodByName) can be used to obtain a
reference of a method by reflection. The linker needs to know
if reflect.Type.Method is called, and retain all exported methods
accordingly. This is handled by the compiler, which marks the
caller of reflect.Type.Method with REFLECTMETHOD attribute. The
current code failed to handle the reflect package itself, so the
method wrapper reflect.Type.Method is not marked. This CL fixes
it.

Fixes #38515.

Change-Id: I12904d23eda664cf1794bc3676152f3218fb762b
Reviewed-on: https://go-review.googlesource.com/c/go/+/228880
Run-TryBot: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/cmd/compile/internal/gc/walk.go
test/reflectmethod5.go [new file with mode: 0644]
test/reflectmethod6.go [new file with mode: 0644]

index 06910450ff772fe6934ad4869982313a6096c725..8ad7f6ace8d123a1c9eaad6d95180e1ad902c027 100644 (file)
@@ -3658,7 +3658,8 @@ func usemethod(n *Node) {
 
        // Note: Don't rely on res0.Type.String() since its formatting depends on multiple factors
        //       (including global variables such as numImports - was issue #19028).
-       if s := res0.Type.Sym; s != nil && s.Name == "Method" && s.Pkg != nil && s.Pkg.Path == "reflect" {
+       // Also need to check for reflect package itself (see Issue #38515).
+       if s := res0.Type.Sym; s != nil && s.Name == "Method" && s.Pkg != nil && (s.Pkg.Path == "reflect" || s.Pkg == localpkg && myimportpath == "reflect") {
                Curfn.Func.SetReflectMethod(true)
        }
 }
diff --git a/test/reflectmethod5.go b/test/reflectmethod5.go
new file mode 100644 (file)
index 0000000..a3fdaa2
--- /dev/null
@@ -0,0 +1,30 @@
+// run
+
+// Copyright 2020 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.
+
+// Issue 38515: failed to mark the method wrapper
+// reflect.Type.Method itself as REFLECTMETHOD.
+
+package main
+
+import "reflect"
+
+var called bool
+
+type foo struct{}
+
+func (foo) X() { called = true }
+
+var h = reflect.Type.Method
+
+func main() {
+       v := reflect.ValueOf(foo{})
+       m := h(v.Type(), 0)
+       f := m.Func.Interface().(func(foo))
+       f(foo{})
+       if !called {
+               panic("FAIL")
+       }
+}
diff --git a/test/reflectmethod6.go b/test/reflectmethod6.go
new file mode 100644 (file)
index 0000000..004ea30
--- /dev/null
@@ -0,0 +1,32 @@
+// run
+
+// Copyright 2020 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.
+
+// Similar to reflectmethod5.go, but for reflect.Type.MethodByName.
+
+package main
+
+import "reflect"
+
+var called bool
+
+type foo struct{}
+
+func (foo) X() { called = true }
+
+var h = reflect.Type.MethodByName
+
+func main() {
+       v := reflect.ValueOf(foo{})
+       m, ok := h(v.Type(), "X")
+       if !ok {
+               panic("FAIL")
+       }
+       f := m.Func.Interface().(func(foo))
+       f(foo{})
+       if !called {
+               panic("FAIL")
+       }
+}