@@ -102,7 +102,67 @@ private predicate summarizedLocalStep(Node nodeFrom, Node nodeTo) {
102102}
103103
104104/** Holds if there is a level step from `nodeFrom` to `nodeTo`. */
105- predicate levelStep ( Node nodeFrom , Node nodeTo ) { summarizedLocalStep ( nodeFrom , nodeTo ) }
105+ predicate levelStep ( Node nodeFrom , Node nodeTo ) {
106+ summarizedLocalStep ( nodeFrom , nodeTo )
107+ or
108+ localFieldStep ( nodeFrom , nodeTo )
109+ }
110+
111+ /**
112+ * Gets a method of `mod`, with `instance` indicating if this is an instance method.
113+ *
114+ * Does not take inheritance or the various forms of inclusion into account.
115+ */
116+ pragma [ nomagic]
117+ private MethodBase getAMethod ( ModuleBase mod , boolean instance ) {
118+ not mod instanceof SingletonClass and
119+ result = mod .getAMethod ( ) and
120+ if result instanceof SingletonMethod then instance = false else instance = true
121+ or
122+ exists ( SingletonClass cls |
123+ cls .getValue ( ) .( SelfVariableAccess ) .getCfgScope ( ) = mod and
124+ result = cls .getAMethod ( ) .( Method ) and
125+ instance = false
126+ )
127+ }
128+
129+ /**
130+ * Gets a value flowing into `field` in `mod`, with `instance` indicating if it's
131+ * a field on an instance of `mod` (as opposed to the module object itself).
132+ */
133+ pragma [ nomagic]
134+ private Node fieldPredecessor ( ModuleBase mod , boolean instance , string field ) {
135+ exists ( InstanceVariableWriteAccess access , AssignExpr assign |
136+ access .getReceiver ( ) .getCfgScope ( ) = getAMethod ( mod , instance ) and
137+ field = access .getVariable ( ) .getName ( ) and
138+ assign .getLeftOperand ( ) = access and
139+ result .asExpr ( ) .getExpr ( ) = assign .getRightOperand ( )
140+ )
141+ }
142+
143+ /**
144+ * Gets a reference to `field` in `mod`, with `instance` indicating if it's
145+ * a field on an instance of `mod` (as opposed to the module object itself).
146+ */
147+ pragma [ nomagic]
148+ private Node fieldSuccessor ( ModuleBase mod , boolean instance , string field ) {
149+ exists ( InstanceVariableReadAccess access |
150+ access .getReceiver ( ) .getCfgScope ( ) = getAMethod ( mod , instance ) and
151+ result .asExpr ( ) .getExpr ( ) = access and
152+ field = access .getVariable ( ) .getName ( )
153+ )
154+ }
155+
156+ /**
157+ * Holds if `pred -> succ` should be used a level step, from a field assignment to
158+ * a read within the same class.
159+ */
160+ private predicate localFieldStep ( Node pred , Node succ ) {
161+ exists ( ModuleBase mod , boolean instance , string field |
162+ pred = fieldPredecessor ( mod , instance , field ) and
163+ succ = fieldSuccessor ( mod , instance , field )
164+ )
165+ }
106166
107167pragma [ noinline]
108168private predicate argumentPositionMatch (
@@ -325,9 +385,18 @@ private predicate hasStoreSummary(
325385 SummarizedCallable callable , DataFlow:: ContentSet contents , SummaryComponentStack input ,
326386 SummaryComponentStack output
327387) {
328- callable .propagatesFlow ( input , push ( SummaryComponent:: content ( contents ) , output ) , true ) and
329388 not isNonLocal ( input .head ( ) ) and
330- not isNonLocal ( output .head ( ) )
389+ not isNonLocal ( output .head ( ) ) and
390+ (
391+ callable .propagatesFlow ( input , push ( SummaryComponent:: content ( contents ) , output ) , true )
392+ or
393+ // Allow the input to start with an arbitrary WithoutContent[X].
394+ // Since type-tracking only tracks one content deep, and we're about to store into another content,
395+ // we're already preventing the input from being in a content.
396+ callable
397+ .propagatesFlow ( push ( SummaryComponent:: withoutContent ( _) , input ) ,
398+ push ( SummaryComponent:: content ( contents ) , output ) , true )
399+ )
331400}
332401
333402pragma [ nomagic]
@@ -460,6 +529,9 @@ private predicate dependsOnSummaryComponentStack(
460529 callable .propagatesFlow ( stack , _, true )
461530 or
462531 callable .propagatesFlow ( _, stack , true )
532+ or
533+ // include store summaries as they may skip an initial step at the input
534+ hasStoreSummary ( callable , _, stack , _)
463535 )
464536 or
465537 dependsOnSummaryComponentStackCons ( callable , _, stack )
0 commit comments