This PR introduces a new algorithm for tracing dataflow from bound variables to closure bodies that improves precision.
When a bound variable is tainted (either a directly bound variable with BoundVarNode or alias with BoundLabelNode) the dataflow visitor goes to the makeclosure node and changes is "tracing" mode to closure tracing. The visitor maintains the identity of the closure being traced, and when the closure is called, it has the correct call stack, which allows it to be more context aware.
The case of multiple closures is handled by maintaining a stack of closure identities (the current closure identity in ClosureTracingInfo maintains a pointer to the previous closure identity, or nil).
Other changes include:
using InstantiateGenerics so that reachability information is properly computed. This was causing a soundness issue, for example: when using user-defined generics like Map[T any, R any](a []T, f func(T) R){...} , the parameter function f would not be marked as reachable even if called in the body of Map, and when Map is called.
adding a Sync function for the inter-procedural flow graph (IPFG) that only contains the function in BuildGraph that is necessary when updating the IPFG.
This PR introduces a new algorithm for tracing dataflow from bound variables to closure bodies that improves precision. When a bound variable is tainted (either a directly bound variable with
BoundVarNode
or alias withBoundLabelNode
) the dataflow visitor goes to the makeclosure node and changes is "tracing" mode to closure tracing. The visitor maintains the identity of the closure being traced, and when the closure is called, it has the correct call stack, which allows it to be more context aware.The case of multiple closures is handled by maintaining a stack of closure identities (the current closure identity in
ClosureTracingInfo
maintains a pointer to the previous closure identity, or nil).Other changes include:
InstantiateGenerics
so that reachability information is properly computed. This was causing a soundness issue, for example: when using user-defined generics likeMap[T any, R any](a []T, f func(T) R){...}
, the parameter functionf
would not be marked as reachable even if called in the body ofMap
, and whenMap
is called.Sync
function for the inter-procedural flow graph (IPFG) that only contains the function inBuildGraph
that is necessary when updating the IPFG.