-
Notifications
You must be signed in to change notification settings - Fork 17.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
x/tools/go/ssa/ssautil: Reachable: conservative approximation to reachable functions, runtime types #69291
Comments
Related Issues and Documentation (Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.) |
Change https://go.dev/cl/609281 mentions this issue: |
I guess you mean
Ditto? |
Change https://go.dev/cl/610939 mentions this issue: |
Change https://go.dev/cl/611535 mentions this issue: |
This change moves ssa.forEachReachable into internal/typesinternal.ForEachElement, simplifies the signature (by internalizing the type map part) and adds a test. There are two copies of this algorithm (the other in go/callgraph/rta), and we will need it again in ssautil.Reachable (see golang/go#69291). A follow-up change will make the copy in rta delegate to this one (small steps). Also, make ssa.Program.RuntimeTypes do the type analysis when it is called, instead of doing it eagerly each time we encounter a MakeInterface instruction. This should reduce eventually costs since RuntimeTypes shouldn't be needed: it was added for the pointer analysis (since deleted) and it used by ssautil.AllFunctions (to be replaced, see golang/go#69291), and in both cases it is the wrong tool for the job because: (a) it is more precise to accumulate runtime types in the subset of the program of interest, while doing some kind of reachability fixed-point computation; and (b) its use in AllFunctions is unsound because although it accounts for all (too many!) MakeInterface operations it does not account for types exposed through public API (see the proposed replacement, ssautil.Reachable) when analyzing incomplete programs. Updates golang/go#69291 Change-Id: Ib369278e50295b9287fe95c06169b81425193e90 Reviewed-on: https://go-review.googlesource.com/c/tools/+/610939 Reviewed-by: Tim King <taking@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This proposal has been added to the active column of the proposals project |
This seems reasonable. My main concern is that x/tools has traditionally had a slow accumulation of analysis cruft and I don't want this to also become more future cruft. The thing that seems most over-fit to the current needs is the way address-taken information is returned. I see the need for that, but worry that the map will be easy to use incorrectly. |
Yeah, we know. ;-) If it's any consolation, some of this cruft predated the Go command's support for
|
@adonovan , for the record, could you explain what would be updated to use this and what the effects would be? |
In the CL stack of https://go.dev/cl/609281 linked above, the CL https://go.dev/cl/609281 uses the new Reachable function to improve the performance and precision of CHA by producing a smaller set of candidate dynamic call targets (address-taken functions only), and thus a smaller and more precise call graph in less time. Since VTA uses CHA as a first step, this also improves the performance of VTA, though not its precision, since it eventually gets the same answer at the cost of more work (deleting spurious edges). Govulncheck uses VTA (indeed, it is the most expensive step), so this change makes the govulncheck tool much faster. Govulncheck lives in a different repo (x/vuln), which is why Reachable cannot be a mere internal function of x/tools (as it is in my current CL stack). And of course other external clients of VTA would also benefit. -- The proposed Reachable function is not just more precise, it is "more sound" (excuse the oxymoron), because it does the fixed point iteration of functions and dynamic types together. By contrast, the old implementation used for its set of dynamic types only the types encountered during SSA building, which doesn't include types from the public API of each importable package (when analyzing partial programs) nor types and functions created by generic instantiation during the fixed point iteration. I expect the "increased soundness" to be minor though. |
Have all remaining concerns about this proposal been addressed? The proposal is in #69291 (comment) |
Based on the discussion above, this proposal seems like a likely accept. The proposal is in #69291 (comment) |
No change in consensus, so accepted. 🎉 The proposal is in #69291 (comment) |
Background: The existing
ssautil.AllFunctions
helper performs a reachability analysis starting from all the packages in a Go SSA program, and returns the set of functions it encounters:Unfortunately it is poorly defined and its implementation is a bit of a historical mess; it is complicated and delivers results that are simultaneously "too much" (imprecise) and "too little" (unsound).
An example of imprecision is that it searches the body of every function in the ssa.Program for MakeInterface operations, when only those functions that are reachable from the entry points need be considered. Another example is that it uses all packages of the program as roots for reachability, even though typically the program consists of all dependencies of a few packages of interest.
An example of unsoundness is that it doesn't consider all of the types derivable from the public API of a package as potential dynamic call targets.
Furthermore, its traversal is a lost opportunity to to track information ("address-taken" status of functions) that would be useful to CHA and VTA.
Proposal: We propose to add a new function
ssautil.Reachable
that:We plan to redefine the existing
AllFunctions
as a shallow wrapper around the new function.@timothy-king @zpavlinovic
The text was updated successfully, but these errors were encountered: