@@ -252,10 +252,10 @@ module Node {
252
252
* Nodes corresponding to AST elements, for example `ExprNode`, usually refer
253
253
* to the value before the update.
254
254
*/
255
- final class PostUpdateNode extends Node , TArgumentPostUpdateNode {
255
+ final class PostUpdateNode extends Node , TExprPostUpdateNode {
256
256
private ExprCfgNode n ;
257
257
258
- PostUpdateNode ( ) { this = TArgumentPostUpdateNode ( n ) }
258
+ PostUpdateNode ( ) { this = TExprPostUpdateNode ( n ) }
259
259
260
260
/** Gets the node before the state update. */
261
261
Node getPreUpdateNode ( ) { result = TExprNode ( n ) }
@@ -264,7 +264,7 @@ module Node {
264
264
265
265
final override Location getLocation ( ) { result = n .getLocation ( ) }
266
266
267
- final override string toString ( ) { result = n .toString ( ) }
267
+ final override string toString ( ) { result = "[post] " + n .toString ( ) }
268
268
}
269
269
270
270
final class CastNode = NaNode ;
@@ -286,6 +286,9 @@ module SsaFlow {
286
286
or
287
287
result .( SsaFlow:: ExprNode ) .getExpr ( ) = n .asExpr ( )
288
288
or
289
+ result .( SsaFlow:: ExprPostUpdateNode ) .getExpr ( ) =
290
+ n .( Node:: PostUpdateNode ) .getPreUpdateNode ( ) .asExpr ( )
291
+ or
289
292
n = toParameterNode ( result .( SsaFlow:: ParameterNode ) .getParameter ( ) )
290
293
}
291
294
@@ -449,6 +452,54 @@ private class VariantFieldContent extends VariantContent, TVariantFieldContent {
449
452
}
450
453
}
451
454
455
+ /** A canonical path pointing to a struct. */
456
+ private class StructCanonicalPath extends MkStructCanonicalPath {
457
+ CrateOriginOption crate ;
458
+ string path ;
459
+
460
+ StructCanonicalPath ( ) { this = MkStructCanonicalPath ( crate , path ) }
461
+
462
+ /** Gets the underlying struct. */
463
+ Struct getStruct ( ) { hasExtendedCanonicalPath ( result , crate , path ) }
464
+
465
+ string toString ( ) { result = this .getStruct ( ) .getName ( ) .getText ( ) }
466
+
467
+ Location getLocation ( ) { result = this .getStruct ( ) .getLocation ( ) }
468
+ }
469
+
470
+ /** Content stored in a field on a struct. */
471
+ private class StructFieldContent extends Content , TStructFieldContent {
472
+ private StructCanonicalPath s ;
473
+ private string field_ ;
474
+
475
+ StructFieldContent ( ) { this = TStructFieldContent ( s , field_ ) }
476
+
477
+ StructCanonicalPath getStructCanonicalPath ( string field ) { result = s and field = field_ }
478
+
479
+ override string toString ( ) { result = s .toString ( ) + "." + field_ .toString ( ) }
480
+ }
481
+
482
+ /**
483
+ * Content stored at a position in a tuple.
484
+ *
485
+ * NOTE: Unlike `struct`s and `enum`s tuples are structural and not nominal,
486
+ * hence we don't store a canonical path for them.
487
+ */
488
+ private class TuplePositionContent extends Content , TTuplePositionContent {
489
+ private int pos ;
490
+
491
+ TuplePositionContent ( ) { this = TTuplePositionContent ( pos ) }
492
+
493
+ int getPosition ( ) { result = pos }
494
+
495
+ override string toString ( ) { result = "tuple." + pos .toString ( ) }
496
+ }
497
+
498
+ /** Holds if `access` indexes a tuple at an index corresponding to `c`. */
499
+ private predicate fieldTuplePositionContent ( FieldExprCfgNode access , TuplePositionContent c ) {
500
+ access .getNameRef ( ) .getText ( ) .toInt ( ) = c .getPosition ( )
501
+ }
502
+
452
503
/** A value that represents a set of `Content`s. */
453
504
abstract class ContentSet extends TContentSet {
454
505
/** Gets a textual representation of this element. */
@@ -597,6 +648,14 @@ module RustDataFlow implements InputSig<Location> {
597
648
*/
598
649
predicate jumpStep ( Node node1 , Node node2 ) { none ( ) }
599
650
651
+ /** Holds if path `p` resolves to struct `s`. */
652
+ private predicate pathResolveToStructCanonicalPath ( Path p , StructCanonicalPath s ) {
653
+ exists ( CrateOriginOption crate , string path |
654
+ resolveExtendedCanonicalPath ( p , crate , path ) and
655
+ s = MkStructCanonicalPath ( crate , path )
656
+ )
657
+ }
658
+
600
659
/** Holds if path `p` resolves to variant `v`. */
601
660
private predicate pathResolveToVariantCanonicalPath ( Path p , VariantCanonicalPath v ) {
602
661
exists ( CrateOriginOption crate , string path |
@@ -625,6 +684,12 @@ module RustDataFlow implements InputSig<Location> {
625
684
pathResolveToVariantCanonicalPath ( p .getPath ( ) , v )
626
685
}
627
686
687
+ /** Holds if `p` destructs a struct `s`. */
688
+ pragma [ nomagic]
689
+ private predicate structDestruction ( RecordPat p , StructCanonicalPath s ) {
690
+ pathResolveToStructCanonicalPath ( p .getPath ( ) , s )
691
+ }
692
+
628
693
/**
629
694
* Holds if data can flow from `node1` to `node2` via a read of `c`. Thus,
630
695
* `node1` references an object with a content `c.getAReadContent()` whose
@@ -641,10 +706,24 @@ module RustDataFlow implements InputSig<Location> {
641
706
or
642
707
exists ( RecordPatCfgNode pat , string field |
643
708
pat = node1 .asPat ( ) and
644
- recordVariantDestruction ( pat .getPat ( ) ,
645
- c .( VariantFieldContent ) .getVariantCanonicalPath ( field ) ) and
709
+ (
710
+ // Pattern destructs a struct-like variant.
711
+ recordVariantDestruction ( pat .getPat ( ) ,
712
+ c .( VariantFieldContent ) .getVariantCanonicalPath ( field ) )
713
+ or
714
+ // Pattern destructs a struct.
715
+ structDestruction ( pat .getPat ( ) , c .( StructFieldContent ) .getStructCanonicalPath ( field ) )
716
+ ) and
646
717
node2 .asPat ( ) = pat .getFieldPat ( field )
647
718
)
719
+ or
720
+ exists ( FieldExprCfgNode access |
721
+ // Read of a tuple entry
722
+ fieldTuplePositionContent ( access , c ) and
723
+ // TODO: Handle read of a struct field.
724
+ node1 .asExpr ( ) = access .getExpr ( ) and
725
+ node2 .asExpr ( ) = access
726
+ )
648
727
)
649
728
}
650
729
@@ -660,30 +739,55 @@ module RustDataFlow implements InputSig<Location> {
660
739
pathResolveToVariantCanonicalPath ( re .getPath ( ) , v )
661
740
}
662
741
742
+ /** Holds if `re` constructs a struct value of type `s`. */
743
+ pragma [ nomagic]
744
+ private predicate structConstruction ( RecordExpr re , StructCanonicalPath s ) {
745
+ pathResolveToStructCanonicalPath ( re .getPath ( ) , s )
746
+ }
747
+
748
+ private predicate tupleAssignment ( Node node1 , Node node2 , TuplePositionContent c ) {
749
+ exists ( AssignmentExprCfgNode assignment , FieldExprCfgNode access |
750
+ assignment .getLhs ( ) = access and
751
+ fieldTuplePositionContent ( access , c ) and
752
+ node1 .asExpr ( ) = assignment .getRhs ( ) and
753
+ node2 .asExpr ( ) = access .getExpr ( )
754
+ )
755
+ }
756
+
663
757
/**
664
758
* Holds if data can flow from `node1` to `node2` via a store into `c`. Thus,
665
759
* `node2` references an object with a content `c.getAStoreContent()` that
666
760
* contains the value of `node1`.
667
761
*/
668
762
predicate storeStep ( Node node1 , ContentSet cs , Node node2 ) {
669
763
exists ( Content c | c = cs .( SingletonContentSet ) .getContent ( ) |
670
- node2 .asExpr ( ) =
671
- any ( CallExprCfgNode call , int pos |
672
- tupleVariantConstruction ( call .getCallExpr ( ) ,
673
- c .( VariantPositionContent ) .getVariantCanonicalPath ( pos ) ) and
674
- node1 .asExpr ( ) = call .getArgument ( pos )
675
- |
676
- call
677
- )
764
+ exists ( CallExprCfgNode call , int pos |
765
+ tupleVariantConstruction ( call .getCallExpr ( ) ,
766
+ c .( VariantPositionContent ) .getVariantCanonicalPath ( pos ) ) and
767
+ node1 .asExpr ( ) = call .getArgument ( pos ) and
768
+ node2 .asExpr ( ) = call
769
+ )
678
770
or
679
- node2 .asExpr ( ) =
680
- any ( RecordExprCfgNode re , string field |
771
+ exists ( RecordExprCfgNode re , string field |
772
+ (
773
+ // Expression is for a struct-like enum variant.
681
774
recordVariantConstruction ( re .getRecordExpr ( ) ,
682
- c .( VariantFieldContent ) .getVariantCanonicalPath ( field ) ) and
683
- node1 .asExpr ( ) = re .getFieldExpr ( field )
684
- |
685
- re
686
- )
775
+ c .( VariantFieldContent ) .getVariantCanonicalPath ( field ) )
776
+ or
777
+ // Expression is for a struct.
778
+ structConstruction ( re .getRecordExpr ( ) ,
779
+ c .( StructFieldContent ) .getStructCanonicalPath ( field ) )
780
+ ) and
781
+ node1 .asExpr ( ) = re .getFieldExpr ( field ) and
782
+ node2 .asExpr ( ) = re
783
+ )
784
+ or
785
+ exists ( TupleExprCfgNode tuple |
786
+ node1 .asExpr ( ) = tuple .getField ( c .( TuplePositionContent ) .getPosition ( ) ) and
787
+ node2 .asExpr ( ) = tuple
788
+ )
789
+ or
790
+ tupleAssignment ( node1 , node2 .( PostUpdateNode ) .getPreUpdateNode ( ) , c )
687
791
)
688
792
}
689
793
@@ -692,7 +796,9 @@ module RustDataFlow implements InputSig<Location> {
692
796
* any value stored inside `f` is cleared at the pre-update node associated with `x`
693
797
* in `x.f = newValue`.
694
798
*/
695
- predicate clearsContent ( Node n , ContentSet c ) { none ( ) }
799
+ predicate clearsContent ( Node n , ContentSet cs ) {
800
+ tupleAssignment ( _, n , cs .( SingletonContentSet ) .getContent ( ) )
801
+ }
696
802
697
803
/**
698
804
* Holds if the value that is being tracked is expected to be stored inside content `c`
@@ -762,7 +868,9 @@ private module Cached {
762
868
TExprNode ( ExprCfgNode n ) or
763
869
TParameterNode ( ParamBaseCfgNode p ) or
764
870
TPatNode ( PatCfgNode p ) or
765
- TArgumentPostUpdateNode ( ExprCfgNode e ) { isArgumentForCall ( e , _, _) } or
871
+ TExprPostUpdateNode ( ExprCfgNode e ) {
872
+ isArgumentForCall ( e , _, _) or e = any ( FieldExprCfgNode access ) .getExpr ( )
873
+ } or
766
874
TSsaNode ( SsaImpl:: DataFlowIntegration:: SsaNode node )
767
875
768
876
cached
@@ -800,6 +908,12 @@ private module Cached {
800
908
name = [ "Ok" , "Err" ]
801
909
}
802
910
911
+ cached
912
+ newtype TStructCanonicalPath =
913
+ MkStructCanonicalPath ( CrateOriginOption crate , string path ) {
914
+ exists ( Struct s | hasExtendedCanonicalPath ( s , crate , path ) )
915
+ }
916
+
803
917
cached
804
918
newtype TContent =
805
919
TVariantPositionContent ( VariantCanonicalPath v , int pos ) {
@@ -815,6 +929,16 @@ private module Cached {
815
929
} or
816
930
TVariantFieldContent ( VariantCanonicalPath v , string field ) {
817
931
field = v .getVariant ( ) .getFieldList ( ) .( RecordFieldList ) .getAField ( ) .getName ( ) .getText ( )
932
+ } or
933
+ TTuplePositionContent ( int pos ) {
934
+ pos in [ 0 .. max ( [
935
+ any ( TuplePat pat ) .getNumberOfFields ( ) ,
936
+ any ( FieldExpr access ) .getNameRef ( ) .getText ( ) .toInt ( )
937
+ ]
938
+ ) ]
939
+ } or
940
+ TStructFieldContent ( StructCanonicalPath s , string field ) {
941
+ field = s .getStruct ( ) .getFieldList ( ) .( RecordFieldList ) .getAField ( ) .getName ( ) .getText ( )
818
942
}
819
943
820
944
cached
0 commit comments