@@ -48,11 +48,11 @@ class StepSummary extends TStepSummary {
4848module StepSummary {
4949 cached
5050 predicate step ( Node pred , Node succ , StepSummary summary ) {
51- exists ( Node mid | simpleLocalFlowStep ( pred , mid ) and smallstep ( mid , succ , summary ) )
51+ exists ( Node mid | EssaFlow :: essaFlowStep * ( pred , mid ) and smallstep ( mid , succ , summary ) )
5252 }
5353
5454 predicate smallstep ( Node pred , Node succ , StepSummary summary ) {
55- simpleLocalFlowStep ( pred , succ ) and
55+ EssaFlow :: essaFlowStep ( pred , succ ) and
5656 summary = LevelStep ( )
5757 or
5858 callStep ( pred , succ ) and summary = CallStep ( )
@@ -69,22 +69,61 @@ module StepSummary {
6969 }
7070}
7171
72+ /** Holds if `pred` steps to `succ` by being passed as a parameter in a call. */
7273predicate callStep ( ArgumentNode pred , ParameterNode succ ) {
74+ // TODO: Support special methods?
7375 exists ( DataFlowCall call , int i |
7476 pred .argumentOf ( call , i ) and succ .isParameterOf ( call .getCallable ( ) , i )
7577 )
7678}
7779
80+ /** Holds if `pred` steps to `succ` by being returned from a call. */
7881predicate returnStep ( ReturnNode pred , Node succ ) {
7982 exists ( DataFlowCall call |
80- pred .getEnclosingCallable ( ) = call .getCallable ( ) and succ = TCfgNode ( call )
83+ pred .getEnclosingCallable ( ) = call .getCallable ( ) and succ = TCfgNode ( call . getNode ( ) )
8184 )
8285}
8386
84- /** TODO: Implement these. */
85- predicate basicStoreStep ( Node pred , Node succ , string attr ) { none ( ) }
87+ /**
88+ * Holds if `pred` is being written to the `attr` attribute of the object in `succ`.
89+ *
90+ * Note that the choice of `succ` does not have to make sense "chronologically".
91+ * All we care about is whether the `attr` attribute of `succ` can have a specific type,
92+ * and the assumption is that if a specific type appears here, then any access of that
93+ * particular attribute can yield something of that particular type.
94+ *
95+ * Thus, in an example such as
96+ *
97+ * ```python
98+ * def foo(y):
99+ * x = Foo()
100+ * bar(x)
101+ * x.attr = y
102+ * baz(x)
103+ *
104+ * def bar(x):
105+ * z = x.attr
106+ * ```
107+ * for the attribute write `x.attr = y`, we will have `attr` being the literal string `"attr"`,
108+ * `pred` will be `y`, and `succ` will be the object `Foo()` created on the first line of the
109+ * function. This means we will track the fact that `x.attr` can have the type of `y` into the
110+ * assignment to `z` inside `bar`, even though this attribute write happens _after_ `bar` is called.
111+ */
112+ predicate basicStoreStep ( Node pred , Node succ , string attr ) {
113+ exists ( AttributeAssignment a , Node var |
114+ a .getName ( ) = attr and
115+ EssaFlow:: essaFlowStep * ( succ , var ) and
116+ var .asVar ( ) = a .getInput ( ) and
117+ pred .asCfgNode ( ) = a .getValue ( )
118+ )
119+ }
86120
87- predicate basicLoadStep ( Node pred , Node succ , string attr ) { none ( ) }
121+ /**
122+ * Holds if `succ` is the result of accessing the `attr` attribute of `pred`.
123+ */
124+ predicate basicLoadStep ( Node pred , Node succ , string attr ) {
125+ exists ( AttrNode s | succ .asCfgNode ( ) = s and s .getObject ( attr ) = pred .asCfgNode ( ) )
126+ }
88127
89128/**
90129 * A utility class that is equivalent to `boolean` but does not require type joining.
@@ -180,6 +219,13 @@ class TypeTracker extends TTypeTracker {
180219 */
181220 boolean hasCall ( ) { result = hasCall }
182221
222+ /**
223+ * INTERNAL. DO NOT USE.
224+ *
225+ * Gets the property associated with this type tracker.
226+ */
227+ string getProp ( ) { result = prop }
228+
183229 /**
184230 * Gets a type tracker that starts where this one has left off to allow continued
185231 * tracking.
@@ -231,7 +277,7 @@ class TypeTracker extends TTypeTracker {
231277 result = this .append ( summary )
232278 )
233279 or
234- simpleLocalFlowStep ( pred , succ ) and
280+ EssaFlow :: essaFlowStep ( pred , succ ) and
235281 result = this
236282 }
237283}
0 commit comments