You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The RTA package should support an option to soundly handle reflective calls of reflectively generated function signatures.
After stumbling across some dead code in x/tools, I spent some time trying to build a dead-code detection tool based on RTA, which seems like the ideal analysis for the job. It is mostly sound with respect to dynamic calls because any time a value of a non-interface type is converted to an interface (ssa.MakeInterface), our RTA implementation assumes that not only are all the methods of the concrete type reachable through interface dynamic calls, but additionally all the types that can be obtained from the interface value through the reflect package are also "live", so their methods are in turn treated as candidates for dynamic calls.
However, there are gaps. Consider the program below, which prints "hello":
package main
import "reflect"
type T int
type U int
func (T) hello(U) { println("hello") }
func main() {
reflect.ValueOf(T(0).hello).Call([]reflect.Value{reflect.ValueOf(U(0))})
}
To the RTA algorithm, there exist no dynamic call sites using the signature func(U). (That's the reason for the type U in the example, to avoid T.hello from coincidentally having a signature that is used for dynamic calls elsewhere, such as in the reflect package.) So, the fact that the method T.hello has its address taken in the first call to ValueOf doesn't result in any call graph edges, nor in T.hello being considered reachable.
But as we can see from the dynamic behavior, the reflective Call operator can potentially act as a call to any address-taken function or method. Calls such as this are common: they are how template expressions call back into Go through template.FuncMap, and in x/tools they are how the packagestest Expect function calls back into test code such as the methods of gopls' tests.Data. Unfortunately the invisibility of such calls to RTA causes significant portions of the application and/or tests to be considered dead code when it is very much alive.
The solution is to conservatively assume that reflect.Value.Call acts like a dynamic call to any function signature.
The text was updated successfully, but these errors were encountered:
The RTA package should support an option to soundly handle reflective calls of reflectively generated function signatures.
After stumbling across some dead code in x/tools, I spent some time trying to build a dead-code detection tool based on RTA, which seems like the ideal analysis for the job. It is mostly sound with respect to dynamic calls because any time a value of a non-interface type is converted to an interface (ssa.MakeInterface), our RTA implementation assumes that not only are all the methods of the concrete type reachable through interface dynamic calls, but additionally all the types that can be obtained from the interface value through the reflect package are also "live", so their methods are in turn treated as candidates for dynamic calls.
However, there are gaps. Consider the program below, which prints "hello":
To the RTA algorithm, there exist no dynamic call sites using the signature
func(U)
. (That's the reason for the type U in the example, to avoid T.hello from coincidentally having a signature that is used for dynamic calls elsewhere, such as in the reflect package.) So, the fact that the method T.hello has its address taken in the first call to ValueOf doesn't result in any call graph edges, nor in T.hello being considered reachable.But as we can see from the dynamic behavior, the reflective
Call
operator can potentially act as a call to any address-taken function or method. Calls such as this are common: they are how template expressions call back into Go through template.FuncMap, and in x/tools they are how the packagestest Expect function calls back into test code such as the methods of gopls' tests.Data. Unfortunately the invisibility of such calls to RTA causes significant portions of the application and/or tests to be considered dead code when it is very much alive.The solution is to conservatively assume that reflect.Value.Call acts like a dynamic call to any function signature.
The text was updated successfully, but these errors were encountered: