@@ -63,17 +63,26 @@ private module Cached {
63
63
newtype TNode =
64
64
TExprNode ( CfgNode n , Expr e ) { hasExprNode ( n , e ) } or
65
65
TSsaDefinitionNode ( Ssa:: Definition def ) or
66
- TInoutReturnNode ( ParamDecl param ) { param .isInout ( ) } or
67
- TInOutUpdateNode ( Argument arg ) { arg .getExpr ( ) instanceof InOutExpr } or
68
- TSummaryNode ( FlowSummary:: SummarizedCallable c , FlowSummaryImpl:: Private:: SummaryNodeState state )
69
-
70
- private predicate hasExprNode ( CfgNode n , Expr e ) {
71
- n .( ExprCfgNode ) .getExpr ( ) = e
72
- or
73
- n .( PropertyGetterCfgNode ) .getRef ( ) = e
74
- or
75
- n .( PropertySetterCfgNode ) .getAssignExpr ( ) = e
76
- }
66
+ TInoutReturnNode ( ParamDecl param ) { modifiableParam ( param ) } or
67
+ TSummaryNode ( FlowSummary:: SummarizedCallable c , FlowSummaryImpl:: Private:: SummaryNodeState state ) or
68
+ TExprPostUpdateNode ( CfgNode n ) {
69
+ // Obviously, the base of setters needs a post-update node
70
+ n = any ( PropertySetterCfgNode setter ) .getBase ( )
71
+ or
72
+ // The base of getters and observers needs a post-update node to support reverse reads.
73
+ n = any ( PropertyGetterCfgNode getter ) .getBase ( )
74
+ or
75
+ n = any ( PropertyObserverCfgNode getter ) .getBase ( )
76
+ or
77
+ // Arguments that are `inout` expressions needs a post-update node,
78
+ // as well as any class-like argument (since a field can be modified).
79
+ // Finally, qualifiers and bases of member reference need post-update nodes to support reverse reads.
80
+ hasExprNode ( n ,
81
+ [
82
+ any ( Argument arg | modifiable ( arg ) ) .getExpr ( ) , any ( MemberRefExpr ref ) .getBase ( ) ,
83
+ any ( ApplyExpr apply ) .getQualifier ( )
84
+ ] )
85
+ }
77
86
78
87
private predicate localSsaFlowStepUseUse ( Ssa:: Definition def , Node nodeFrom , Node nodeTo ) {
79
88
def .adjacentReadPair ( nodeFrom .getCfgNode ( ) , nodeTo .getCfgNode ( ) ) and
@@ -102,18 +111,12 @@ private module Cached {
102
111
// use-use flow
103
112
localSsaFlowStepUseUse ( def , nodeFrom , nodeTo )
104
113
or
105
- // localSsaFlowStepUseUse(def, nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo)
106
- // or
114
+ localSsaFlowStepUseUse ( def , nodeFrom .( PostUpdateNode ) .getPreUpdateNode ( ) , nodeTo )
115
+ or
107
116
// step from previous read to Phi node
108
117
localFlowSsaInput ( nodeFrom , def , nodeTo .asDefinition ( ) )
109
118
)
110
119
or
111
- // flow through writes to inout parameters
112
- exists ( ParamReturnKind kind , ExprCfgNode arg |
113
- arg = nodeFrom .( InOutUpdateNode ) .getCall ( kind ) .asCall ( ) .getArgument ( kind .getIndex ( ) ) and
114
- nodeTo .asDefinition ( ) .( Ssa:: WriteDefinition ) .isInoutDef ( arg )
115
- )
116
- or
117
120
// flow through `&` (inout argument)
118
121
nodeFrom .asExpr ( ) = nodeTo .asExpr ( ) .( InOutExpr ) .getSubExpr ( )
119
122
or
@@ -138,10 +141,36 @@ private module Cached {
138
141
predicate localFlowStepImpl ( Node nodeFrom , Node nodeTo ) { localFlowStepCommon ( nodeFrom , nodeTo ) }
139
142
140
143
cached
141
- newtype TContentSet = TODO_TContentSet ( )
144
+ newtype TContentSet = TSingletonContent ( Content c )
142
145
143
146
cached
144
- newtype TContent = TODO_Content ( )
147
+ newtype TContent = TFieldContent ( FieldDecl f )
148
+ }
149
+
150
+ /**
151
+ * Holds if `arg` can be modified (by overwriting the content completely),
152
+ * or if any of its fields can be overwritten by a function call.
153
+ */
154
+ private predicate modifiable ( Argument arg ) {
155
+ arg .getExpr ( ) instanceof InOutExpr
156
+ or
157
+ arg .getExpr ( ) .getType ( ) instanceof NominalType
158
+ }
159
+
160
+ predicate modifiableParam ( ParamDecl param ) {
161
+ param .isInout ( )
162
+ or
163
+ param instanceof SelfParamDecl
164
+ }
165
+
166
+ private predicate hasExprNode ( CfgNode n , Expr e ) {
167
+ n .( ExprCfgNode ) .getExpr ( ) = e
168
+ or
169
+ n .( PropertyGetterCfgNode ) .getRef ( ) = e
170
+ or
171
+ n .( PropertySetterCfgNode ) .getAssignExpr ( ) = e
172
+ or
173
+ n .( PropertyObserverCfgNode ) .getAssignExpr ( ) = e
145
174
}
146
175
147
176
import Cached
@@ -341,40 +370,92 @@ private module OutNodes {
341
370
}
342
371
}
343
372
344
- class InOutUpdateNode extends OutNode , TInOutUpdateNode , NodeImpl {
373
+ class InOutUpdateArgNode extends OutNode , ExprPostUpdateNode {
345
374
Argument arg ;
346
375
347
- InOutUpdateNode ( ) { this = TInOutUpdateNode ( arg ) }
376
+ InOutUpdateArgNode ( ) {
377
+ modifiable ( arg ) and
378
+ hasExprNode ( n , arg .getExpr ( ) )
379
+ }
348
380
349
381
override DataFlowCall getCall ( ReturnKind kind ) {
350
- result .asCall ( ) . getExpr ( ) = arg . getApplyExpr ( ) and
382
+ result .getAnArgument ( ) = n and
351
383
kind .( ParamReturnKind ) .getIndex ( ) = arg .getIndex ( )
352
384
}
385
+ }
353
386
354
- override DataFlowCallable getEnclosingCallable ( ) {
355
- result = this .getCall ( _) .getEnclosingCallable ( )
387
+ class InOutUpdateQualifierNode extends OutNode , ExprPostUpdateNode {
388
+ InOutUpdateQualifierNode ( ) { hasExprNode ( n , any ( ApplyExpr apply ) .getQualifier ( ) ) }
389
+
390
+ override DataFlowCall getCall ( ReturnKind kind ) {
391
+ result .getAnArgument ( ) = n and
392
+ kind .( ParamReturnKind ) .getIndex ( ) = - 1
356
393
}
394
+ }
395
+
396
+ class PropertySetterOutNode extends OutNode , ExprNodeImpl {
397
+ PropertySetterCfgNode setter ;
357
398
358
- override Location getLocationImpl ( ) { result = arg . getLocation ( ) }
399
+ PropertySetterOutNode ( ) { setter = this . getCfgNode ( ) }
359
400
360
- override string toStringImpl ( ) { result = arg .toString ( ) }
401
+ override DataFlowCall getCall ( ReturnKind kind ) {
402
+ result .( PropertySetterCall ) .getSetter ( ) = setter and kind .( ParamReturnKind ) .getIndex ( ) = - 1
403
+ }
404
+ }
405
+
406
+ class PropertyGetterOutNode extends OutNode , ExprNodeImpl {
407
+ PropertyGetterCfgNode getter ;
408
+
409
+ PropertyGetterOutNode ( ) { getter = this .getCfgNode ( ) }
410
+
411
+ override DataFlowCall getCall ( ReturnKind kind ) {
412
+ result .( PropertyGetterCall ) .getGetter ( ) = getter and kind instanceof NormalReturnKind
413
+ }
414
+ }
415
+
416
+ class PropertyObserverOutNode extends OutNode , ExprNodeImpl {
417
+ PropertyObserverCfgNode observer ;
418
+
419
+ PropertyObserverOutNode ( ) { observer = this .getCfgNode ( ) }
420
+
421
+ override DataFlowCall getCall ( ReturnKind kind ) {
422
+ result .( PropertyGetterCall ) .getGetter ( ) = observer and kind .( ParamReturnKind ) .getIndex ( ) = - 1
423
+ }
361
424
}
362
425
}
363
426
364
427
import OutNodes
365
428
366
429
predicate jumpStep ( Node pred , Node succ ) { none ( ) }
367
430
368
- predicate storeStep ( Node node1 , ContentSet c , Node node2 ) { none ( ) }
431
+ predicate storeStep ( Node node1 , ContentSet c , Node node2 ) {
432
+ exists ( MemberRefExpr ref , AssignExpr assign |
433
+ ref = assign .getDest ( ) and
434
+ node1 .asExpr ( ) = assign .getSource ( ) and
435
+ node2 .( PostUpdateNode ) .getPreUpdateNode ( ) .asExpr ( ) = ref .getBase ( ) and
436
+ c .isSingleton ( any ( Content:: FieldContent ct | ct .getField ( ) = ref .getMember ( ) ) )
437
+ )
438
+ }
369
439
370
- predicate readStep ( Node node1 , ContentSet c , Node node2 ) { none ( ) }
440
+ predicate isLValue ( Expr e ) { any ( AssignExpr assign ) .getDest ( ) = e }
441
+
442
+ predicate readStep ( Node node1 , ContentSet c , Node node2 ) {
443
+ exists ( MemberRefExpr ref |
444
+ not isLValue ( ref ) and
445
+ node1 .asExpr ( ) = ref .getBase ( ) and
446
+ node2 .asExpr ( ) = ref and
447
+ c .isSingleton ( any ( Content:: FieldContent ct | ct .getField ( ) = ref .getMember ( ) ) )
448
+ )
449
+ }
371
450
372
451
/**
373
452
* Holds if values stored inside content `c` are cleared at node `n`. For example,
374
453
* any value stored inside `f` is cleared at the pre-update node associated with `x`
375
454
* in `x.f = newValue`.
376
455
*/
377
- predicate clearsContent ( Node n , ContentSet c ) { none ( ) }
456
+ predicate clearsContent ( Node n , ContentSet c ) {
457
+ n = any ( PostUpdateNode pun | storeStep ( _, c , pun ) ) .getPreUpdateNode ( )
458
+ }
378
459
379
460
/**
380
461
* Holds if the value that is being tracked is expected to be stored inside content `c`
@@ -408,7 +489,21 @@ abstract class PostUpdateNodeImpl extends Node {
408
489
abstract Node getPreUpdateNode ( ) ;
409
490
}
410
491
411
- private module PostUpdateNodes { }
492
+ private module PostUpdateNodes {
493
+ class ExprPostUpdateNode extends PostUpdateNodeImpl , NodeImpl , TExprPostUpdateNode {
494
+ CfgNode n ;
495
+
496
+ ExprPostUpdateNode ( ) { this = TExprPostUpdateNode ( n ) }
497
+
498
+ override ExprNode getPreUpdateNode ( ) { n = result .getCfgNode ( ) }
499
+
500
+ override Location getLocationImpl ( ) { result = n .getLocation ( ) }
501
+
502
+ override string toStringImpl ( ) { result = "[post] " + n .toString ( ) }
503
+
504
+ override DataFlowCallable getEnclosingCallable ( ) { result = TDataFlowFunc ( n .getScope ( ) ) }
505
+ }
506
+ }
412
507
413
508
private import PostUpdateNodes
414
509
0 commit comments