@@ -95,9 +95,6 @@ signature module InputSig {
9595 /** Gets the variable that is the target of this write. */
9696 CapturedVariable getVariable ( ) ;
9797
98- /** Gets the expression that is the source of this write. */
99- Expr getSource ( ) ;
100-
10198 /** Gets the location of this write. */
10299 Location getLocation ( ) ;
103100
@@ -210,6 +207,22 @@ signature module OutputSig<InputSig I> {
210207 I:: ClosureExpr getClosureExpr ( ) ;
211208 }
212209
210+ /**
211+ * A node representing the incoming value about to be written at the given assignment.
212+ *
213+ * The captured-variable library will generate flows out of this node, and assume that other
214+ * parts of the language implementation produce the relevant data flows into this node.
215+ *
216+ * For ordinary assignments, this could be mapped to the right-hand side of the assignment.
217+ *
218+ * For more general cases, where an lvalue has no direct corresponding rvalue, this can be mapped
219+ * to a data-flow node that wraps the lvalue, with language-specific incoming data flows.
220+ */
221+ class VariableWriteSourceNode extends ClosureNode {
222+ /** Gets the variable write for which this node is the incoming value being written to the variable. */
223+ I:: VariableWrite getVariableWrite ( ) ;
224+ }
225+
213226 /** Holds if `post` is a `PostUpdateNode` for `pre`. */
214227 predicate capturePostUpdateNode ( SynthesizedCaptureNode post , SynthesizedCaptureNode pre ) ;
215228
@@ -239,7 +252,6 @@ module Flow<InputSig Input> implements OutputSig<Input> {
239252 private class RelevantExpr extends FinalExpr {
240253 RelevantExpr ( ) {
241254 this instanceof VariableRead or
242- any ( VariableWrite vw ) .getSource ( ) = this or
243255 this instanceof ClosureExpr or
244256 any ( ClosureExpr ce ) .hasAliasedAccess ( this )
245257 }
@@ -353,14 +365,6 @@ module Flow<InputSig Input> implements OutputSig<Input> {
353365
354366 query predicate uniqueWriteTarget ( string msg ) { uniqueWriteTarget ( _, msg ) }
355367
356- private predicate uniqueWriteSource ( VariableWrite vw , string msg ) {
357- msg = "VariableWrite has no source expression" and not exists ( vw .getSource ( ) )
358- or
359- msg = "VariableWrite has multiple source expressions" and 2 <= strictcount ( vw .getSource ( ) )
360- }
361-
362- query predicate uniqueWriteSource ( string msg ) { uniqueWriteSource ( _, msg ) }
363-
364368 private predicate uniqueWriteCfgNode ( VariableWrite vw , string msg ) {
365369 msg = "VariableWrite has no cfg node" and not vw .hasCfgNode ( _, _)
366370 or
@@ -370,17 +374,6 @@ module Flow<InputSig Input> implements OutputSig<Input> {
370374
371375 query predicate uniqueWriteCfgNode ( string msg ) { uniqueWriteCfgNode ( _, msg ) }
372376
373- private predicate localWriteStep ( VariableWrite vw , string msg ) {
374- exists ( BasicBlock bb1 , BasicBlock bb2 |
375- vw .hasCfgNode ( bb1 , _) and
376- vw .getSource ( ) .hasCfgNode ( bb2 , _) and
377- bb1 .getEnclosingCallable ( ) != bb2 .getEnclosingCallable ( ) and
378- msg = "VariableWrite is not a local step"
379- )
380- }
381-
382- query predicate localWriteStep ( string msg ) { localWriteStep ( _, msg ) }
383-
384377 query predicate uniqueReadVariable ( VariableRead vr , string msg ) {
385378 msg = "VariableRead has no source variable" and not exists ( vr .getVariable ( ) )
386379 or
@@ -435,9 +428,7 @@ module Flow<InputSig Input> implements OutputSig<Input> {
435428 n = strictcount ( Expr e | uniqueLocation ( e , msg ) ) or
436429 n = strictcount ( Expr e | uniqueCfgNode ( e , msg ) ) or
437430 n = strictcount ( VariableWrite vw | uniqueWriteTarget ( vw , msg ) ) or
438- n = strictcount ( VariableWrite vw | uniqueWriteSource ( vw , msg ) ) or
439431 n = strictcount ( VariableWrite vw | uniqueWriteCfgNode ( vw , msg ) ) or
440- n = strictcount ( VariableWrite vw | localWriteStep ( vw , msg ) ) or
441432 n = strictcount ( VariableRead vr | uniqueReadVariable ( vr , msg ) ) or
442433 n = strictcount ( ClosureExpr ce | closureMustHaveBody ( ce , msg ) ) or
443434 n = strictcount ( ClosureExpr ce , Expr access | closureAliasMustBeLocal ( ce , access , msg ) ) or
@@ -689,13 +680,12 @@ module Flow<InputSig Input> implements OutputSig<Input> {
689680 TExprNode ( Expr expr , boolean isPost ) {
690681 expr instanceof VariableRead and isPost = [ false , true ]
691682 or
692- exists ( VariableWrite vw | expr = vw .getSource ( ) and isPost = false )
693- or
694683 synthRead ( _, _, _, _, expr ) and isPost = [ false , true ]
695684 } or
696685 TParamNode ( CapturedParameter p ) or
697686 TThisParamNode ( Callable c ) { captureAccess ( _, c ) } or
698- TMallocNode ( ClosureExpr ce ) { hasConstructorCapture ( ce , _) }
687+ TMallocNode ( ClosureExpr ce ) { hasConstructorCapture ( ce , _) } or
688+ TVariableWriteSourceNode ( VariableWrite write )
699689
700690 class ClosureNode extends TClosureNode {
701691 /** Gets a textual representation of this node. */
@@ -721,6 +711,11 @@ module Flow<InputSig Input> implements OutputSig<Input> {
721711 result = "this" and this = TThisParamNode ( _)
722712 or
723713 result = "malloc" and this = TMallocNode ( _)
714+ or
715+ exists ( VariableWrite write |
716+ this = TVariableWriteSourceNode ( write ) and
717+ result = "Source of write to " + write .getVariable ( ) .toString ( )
718+ )
724719 }
725720
726721 /** Gets the location of this node. */
@@ -748,6 +743,10 @@ module Flow<InputSig Input> implements OutputSig<Input> {
748743 exists ( Callable c | this = TThisParamNode ( c ) and result = c .getLocation ( ) )
749744 or
750745 exists ( ClosureExpr ce | this = TMallocNode ( ce ) and result = ce .getLocation ( ) )
746+ or
747+ exists ( VariableWrite write |
748+ this = TVariableWriteSourceNode ( write ) and result = write .getLocation ( )
749+ )
751750 }
752751 }
753752
@@ -807,6 +806,10 @@ module Flow<InputSig Input> implements OutputSig<Input> {
807806 ClosureExpr getClosureExpr ( ) { this = TMallocNode ( result ) }
808807 }
809808
809+ class VariableWriteSourceNode extends ClosureNode , TVariableWriteSourceNode {
810+ VariableWrite getVariableWrite ( ) { this = TVariableWriteSourceNode ( result ) }
811+ }
812+
810813 predicate capturePostUpdateNode ( SynthesizedCaptureNode post , SynthesizedCaptureNode pre ) {
811814 exists ( CapturedVariable v , BasicBlock bb , int i |
812815 pre = TSynthRead ( v , bb , i , false ) and post = TSynthRead ( v , bb , i , true )
@@ -851,7 +854,7 @@ module Flow<InputSig Input> implements OutputSig<Input> {
851854 or
852855 exists ( VariableWrite vw , CapturedVariable v |
853856 captureWrite ( v , bb , i , true , vw ) and
854- n = TExprNode ( vw . getSource ( ) , false ) and
857+ n = TVariableWriteSourceNode ( vw ) and
855858 isPost = false and
856859 cc = TVariable ( v )
857860 )
@@ -898,7 +901,7 @@ module Flow<InputSig Input> implements OutputSig<Input> {
898901 // write to v inside the closure body
899902 exists ( BasicBlock bb , int i , VariableWrite vw |
900903 captureWrite ( v , bb , i , false , vw ) and
901- node1 = TExprNode ( vw . getSource ( ) , false ) and
904+ node1 = TVariableWriteSourceNode ( vw ) and
902905 node2 = TSynthThisQualifier ( bb , i , true )
903906 )
904907 }
0 commit comments