@@ -14,7 +14,6 @@ private import codeql.rust.controlflow.CfgNodes
14
14
private import codeql.rust.dataflow.Ssa
15
15
private import codeql.rust.dataflow.FlowSummary
16
16
private import FlowSummaryImpl as FlowSummaryImpl
17
- private import codeql.rust.elements.internal.PathResolution as PathResolution
18
17
19
18
/**
20
19
* A return kind. A return kind describes how a value can be returned from a
@@ -661,7 +660,7 @@ private module VariantInLib {
661
660
}
662
661
663
662
/** A tuple variant from library code. */
664
- class VariantInLibTupleFieldContent extends VariantContent , TVariantInLibTupleFieldContent {
663
+ class VariantInLibTupleFieldContent extends Content , TVariantInLibTupleFieldContent {
665
664
private VariantInLib:: VariantInLib v ;
666
665
private int pos_ ;
667
666
@@ -740,82 +739,73 @@ abstract class Content extends TContent {
740
739
abstract Location getLocation ( ) ;
741
740
}
742
741
743
- /**
744
- * A variant of an `enum`. In addition to the variant itself, this also includes the
745
- * position (for tuple variants) or the field name (for record variants).
746
- */
747
- abstract class VariantContent extends Content { }
748
-
749
- private TupleField getVariantTupleField ( Variant v , int i ) {
750
- result = v .getFieldList ( ) .( TupleFieldList ) .getField ( i )
742
+ /** A field belonging to either a variant or a struct. */
743
+ abstract class FieldContent extends Content {
744
+ /** Gets an access to this field. */
745
+ pragma [ nomagic]
746
+ abstract FieldExprCfgNode getAnAccess ( ) ;
751
747
}
752
748
753
- /** A tuple variant. */
754
- private class VariantTupleFieldContent extends VariantContent , TVariantTupleFieldContent {
755
- private Variant v ;
756
- private int pos_ ;
749
+ /** A tuple field belonging to either a variant or a struct. */
750
+ class TupleFieldContent extends FieldContent , TTupleFieldContent {
751
+ private TupleField field ;
752
+
753
+ TupleFieldContent ( ) { this = TTupleFieldContent ( field ) }
754
+
755
+ predicate isVariantField ( Variant v , int pos ) { field .isVariantField ( v , pos ) }
757
756
758
- VariantTupleFieldContent ( ) { this = TVariantTupleFieldContent ( v , pos_ ) }
757
+ predicate isStructField ( Struct s , int pos ) { field . isStructField ( s , pos ) }
759
758
760
- Variant getVariant ( int pos ) { result = v and pos = pos_ }
759
+ override FieldExprCfgNode getAnAccess ( ) { none ( ) } // TODO
761
760
762
761
final override string toString ( ) {
763
- exists ( string name |
764
- name = v .getName ( ) .getText ( ) and
762
+ exists ( Variant v , int pos , string vname |
763
+ this .isVariantField ( v , pos ) and
764
+ vname = v .getName ( ) .getText ( ) and
765
765
// only print indices when the arity is > 1
766
- if exists ( getVariantTupleField ( v , 1 ) ) then result = name + "(" + pos_ + ")" else result = name
766
+ if exists ( v .getTupleField ( 1 ) ) then result = vname + "(" + pos + ")" else result = vname
767
+ )
768
+ or
769
+ exists ( Struct s , int pos , string sname |
770
+ this .isStructField ( s , pos ) and
771
+ sname = s .getName ( ) .getText ( ) and
772
+ // only print indices when the arity is > 1
773
+ if exists ( s .getTupleField ( 1 ) ) then result = sname + "(" + pos + ")" else result = sname
767
774
)
768
775
}
769
776
770
- final override Location getLocation ( ) { result = getVariantTupleField ( v , pos_ ) .getLocation ( ) }
777
+ final override Location getLocation ( ) { result = field .getLocation ( ) }
771
778
}
772
779
773
- private RecordField getVariantRecordField ( Variant v , string field ) {
774
- result = v .getFieldList ( ) .( RecordFieldList ) .getAField ( ) and
775
- field = result .getName ( ) .getText ( )
776
- }
780
+ /** A record field belonging to either a variant or a struct. */
781
+ class RecordFieldContent extends FieldContent , TRecordFieldContent {
782
+ private RecordField field ;
783
+
784
+ RecordFieldContent ( ) { this = TRecordFieldContent ( field ) }
777
785
778
- /** A record variant. */
779
- private class VariantRecordFieldContent extends VariantContent , TVariantRecordFieldContent {
780
- private Variant v ;
781
- private string field_ ;
786
+ predicate isVariantField ( Variant v , string name ) { field .isVariantField ( v , name ) }
782
787
783
- VariantRecordFieldContent ( ) { this = TVariantRecordFieldContent ( v , field_ ) }
788
+ predicate isStructField ( Struct s , string name ) { field . isStructField ( s , name ) }
784
789
785
- Variant getVariant ( string field ) { result = v and field = field_ }
790
+ override FieldExprCfgNode getAnAccess ( ) { none ( ) } // TODO
786
791
787
792
final override string toString ( ) {
788
- exists ( string name |
789
- name = v .getName ( ) .getText ( ) and
793
+ exists ( Variant v , string name , string vname |
794
+ this .isVariantField ( v , name ) and
795
+ vname = v .getName ( ) .getText ( ) and
790
796
// only print field when the arity is > 1
791
- if strictcount ( string f | exists ( getVariantRecordField ( v , f ) ) ) > 1
792
- then result = name + "{" + field_ + "}"
793
- else result = name
797
+ if strictcount ( v .getRecordField ( _) ) > 1 then result = vname + "." + name else result = vname
794
798
)
795
- }
796
-
797
- final override Location getLocation ( ) {
798
- result = getVariantRecordField ( v , field_ ) .getName ( ) .getLocation ( )
799
- }
800
- }
801
-
802
- /** Content stored in a field on a struct. */
803
- class StructFieldContent extends Content , TStructFieldContent {
804
- private Struct s ;
805
- private string field_ ;
806
-
807
- StructFieldContent ( ) { this = TStructFieldContent ( s , field_ ) }
808
-
809
- Struct getStruct ( string field ) { result = s and field = field_ }
810
-
811
- override string toString ( ) { result = s .getName ( ) .getText ( ) + "." + field_ .toString ( ) }
812
-
813
- override Location getLocation ( ) {
814
- exists ( Name f | f = s .getFieldList ( ) .( RecordFieldList ) .getAField ( ) .getName ( ) |
815
- f .getText ( ) = field_ and
816
- result = f .getLocation ( )
799
+ or
800
+ exists ( Struct s , string name , string sname |
801
+ this .isStructField ( s , name ) and
802
+ sname = s .getName ( ) .getText ( ) and
803
+ // only print field when the arity is > 1
804
+ if strictcount ( s .getRecordField ( _) ) > 1 then result = sname + "." + name else result = sname
817
805
)
818
806
}
807
+
808
+ final override Location getLocation ( ) { result = field .getLocation ( ) }
819
809
}
820
810
821
811
/** A captured variable. */
@@ -859,13 +849,18 @@ final class ElementContent extends Content, TElementContent {
859
849
* NOTE: Unlike `struct`s and `enum`s tuples are structural and not nominal,
860
850
* hence we don't store a canonical path for them.
861
851
*/
862
- final class TuplePositionContent extends Content , TTuplePositionContent {
852
+ final class TuplePositionContent extends FieldContent , TTuplePositionContent {
863
853
private int pos ;
864
854
865
855
TuplePositionContent ( ) { this = TTuplePositionContent ( pos ) }
866
856
867
857
int getPosition ( ) { result = pos }
868
858
859
+ override FieldExprCfgNode getAnAccess ( ) {
860
+ // TODO: limit to tuple types
861
+ result .getNameRef ( ) .getText ( ) .toInt ( ) = pos
862
+ }
863
+
869
864
override string toString ( ) { result = "tuple." + pos .toString ( ) }
870
865
871
866
override Location getLocation ( ) { result instanceof EmptyLocation }
@@ -901,11 +896,6 @@ final class FunctionCallReturnContent extends Content, TFunctionCallReturnConten
901
896
override Location getLocation ( ) { result instanceof EmptyLocation }
902
897
}
903
898
904
- /** Holds if `access` indexes a tuple at an index corresponding to `c`. */
905
- private predicate fieldTuplePositionContent ( FieldExprCfgNode access , TuplePositionContent c ) {
906
- access .getNameRef ( ) .getText ( ) .toInt ( ) = c .getPosition ( )
907
- }
908
-
909
899
/** A value that represents a set of `Content`s. */
910
900
abstract class ContentSet extends TContentSet {
911
901
/** Gets a textual representation of this element. */
@@ -1128,23 +1118,6 @@ module RustDataFlow implements InputSig<Location> {
1128
1118
node2 .( Node:: FlowSummaryNode ) .getSummaryNode ( ) )
1129
1119
}
1130
1120
1131
- /** Gets the item that `p` resolves to, if any. */
1132
- private PathResolution:: ItemNode resolvePath ( PathAstNode p ) {
1133
- result = PathResolution:: resolvePath ( p .getPath ( ) )
1134
- }
1135
-
1136
- /** Holds if `p` destructs an enum variant `v`. */
1137
- pragma [ nomagic]
1138
- private predicate tupleVariantDestruction ( TupleStructPat p , Variant v ) { v = resolvePath ( p ) }
1139
-
1140
- /** Holds if `p` destructs an enum variant `v`. */
1141
- pragma [ nomagic]
1142
- private predicate recordVariantDestruction ( RecordPat p , Variant v ) { v = resolvePath ( p ) }
1143
-
1144
- /** Holds if `p` destructs a struct `s`. */
1145
- pragma [ nomagic]
1146
- private predicate structDestruction ( RecordPat p , Struct s ) { s = resolvePath ( p ) }
1147
-
1148
1121
/**
1149
1122
* Holds if data can flow from `node1` to `node2` via a read of `c`. Thus,
1150
1123
* `node1` references an object with a content `c.getAReadContent()` whose
@@ -1156,7 +1129,7 @@ module RustDataFlow implements InputSig<Location> {
1156
1129
pat = node1 .asPat ( ) and
1157
1130
node2 .asPat ( ) = pat .getField ( pos )
1158
1131
|
1159
- tupleVariantDestruction ( pat .getPat ( ) , c . ( VariantTupleFieldContent ) . getVariant ( pos ) )
1132
+ c = TTupleFieldContent ( pat .getTupleStructPat ( ) . getTupleField ( pos ) )
1160
1133
or
1161
1134
VariantInLib:: tupleVariantCanonicalDestruction ( pat .getPat ( ) , c , pos )
1162
1135
)
@@ -1169,25 +1142,17 @@ module RustDataFlow implements InputSig<Location> {
1169
1142
or
1170
1143
exists ( RecordPatCfgNode pat , string field |
1171
1144
pat = node1 .asPat ( ) and
1172
- (
1173
- // Pattern destructs a struct-like variant.
1174
- recordVariantDestruction ( pat .getPat ( ) , c .( VariantRecordFieldContent ) .getVariant ( field ) )
1175
- or
1176
- // Pattern destructs a struct.
1177
- structDestruction ( pat .getPat ( ) , c .( StructFieldContent ) .getStruct ( field ) )
1178
- ) and
1145
+ c = TRecordFieldContent ( pat .getRecordPat ( ) .getRecordField ( field ) ) and
1179
1146
node2 .asPat ( ) = pat .getFieldPat ( field )
1180
1147
)
1181
1148
or
1182
1149
c instanceof ReferenceContent and
1183
1150
node1 .asPat ( ) .( RefPatCfgNode ) .getPat ( ) = node2 .asPat ( )
1184
1151
or
1185
1152
exists ( FieldExprCfgNode access |
1186
- // Read of a tuple entry
1187
- fieldTuplePositionContent ( access , c ) and
1188
- // TODO: Handle read of a struct field.
1189
1153
node1 .asExpr ( ) = access .getExpr ( ) and
1190
- node2 .asExpr ( ) = access
1154
+ node2 .asExpr ( ) = access and
1155
+ access = c .( FieldContent ) .getAnAccess ( )
1191
1156
)
1192
1157
or
1193
1158
exists ( IndexExprCfgNode arr |
@@ -1236,49 +1201,29 @@ module RustDataFlow implements InputSig<Location> {
1236
1201
cs , node2 .( Node:: FlowSummaryNode ) .getSummaryNode ( ) )
1237
1202
}
1238
1203
1239
- /** Holds if `ce` constructs an enum value of type `v`. */
1240
- pragma [ nomagic]
1241
- private predicate tupleVariantConstruction ( CallExpr ce , Variant v ) {
1242
- v = resolvePath ( ce .getFunction ( ) .( PathExpr ) )
1243
- }
1244
-
1245
- /** Holds if `re` constructs an enum value of type `v`. */
1246
1204
pragma [ nomagic]
1247
- private predicate recordVariantConstruction ( RecordExpr re , Variant v ) { v = resolvePath ( re ) }
1248
-
1249
- /** Holds if `re` constructs a struct value of type `s`. */
1250
- pragma [ nomagic]
1251
- private predicate structConstruction ( RecordExpr re , Struct s ) { s = resolvePath ( re ) }
1252
-
1253
- private predicate tupleAssignment ( Node node1 , Node node2 , TuplePositionContent c ) {
1205
+ private predicate fieldAssignment ( Node node1 , Node node2 , FieldContent c ) {
1254
1206
exists ( AssignmentExprCfgNode assignment , FieldExprCfgNode access |
1255
1207
assignment .getLhs ( ) = access and
1256
- fieldTuplePositionContent ( access , c ) and
1257
1208
node1 .asExpr ( ) = assignment .getRhs ( ) and
1258
- node2 .asExpr ( ) = access .getExpr ( )
1209
+ node2 .asExpr ( ) = access .getExpr ( ) and
1210
+ access = c .getAnAccess ( )
1259
1211
)
1260
1212
}
1261
1213
1262
1214
pragma [ nomagic]
1263
1215
private predicate storeContentStep ( Node node1 , Content c , Node node2 ) {
1264
1216
exists ( CallExprCfgNode call , int pos |
1265
- node1 .asExpr ( ) = call .getArgument ( pos ) and
1217
+ node1 .asExpr ( ) = call .getArgument ( pragma [ only_bind_into ] ( pos ) ) and
1266
1218
node2 .asExpr ( ) = call
1267
1219
|
1268
- tupleVariantConstruction ( call .getCallExpr ( ) , c . ( VariantTupleFieldContent ) . getVariant ( pos ) )
1220
+ c = TTupleFieldContent ( call .getCallExpr ( ) . getTupleField ( pragma [ only_bind_into ] ( pos ) ) )
1269
1221
or
1270
1222
VariantInLib:: tupleVariantCanonicalConstruction ( call .getCallExpr ( ) , c , pos )
1271
1223
)
1272
1224
or
1273
1225
exists ( RecordExprCfgNode re , string field |
1274
- (
1275
- // Expression is for a struct-like enum variant.
1276
- recordVariantConstruction ( re .getRecordExpr ( ) ,
1277
- c .( VariantRecordFieldContent ) .getVariant ( field ) )
1278
- or
1279
- // Expression is for a struct.
1280
- structConstruction ( re .getRecordExpr ( ) , c .( StructFieldContent ) .getStruct ( field ) )
1281
- ) and
1226
+ c = TRecordFieldContent ( re .getRecordExpr ( ) .getRecordField ( field ) ) and
1282
1227
node1 .asExpr ( ) = re .getFieldExpr ( field ) and
1283
1228
node2 .asExpr ( ) = re
1284
1229
)
@@ -1295,7 +1240,7 @@ module RustDataFlow implements InputSig<Location> {
1295
1240
node2 .asExpr ( ) .( ArrayListExprCfgNode ) .getAnExpr ( )
1296
1241
]
1297
1242
or
1298
- tupleAssignment ( node1 , node2 .( PostUpdateNode ) .getPreUpdateNode ( ) , c )
1243
+ fieldAssignment ( node1 , node2 .( PostUpdateNode ) .getPreUpdateNode ( ) , c )
1299
1244
or
1300
1245
exists ( AssignmentExprCfgNode assignment , IndexExprCfgNode index |
1301
1246
c instanceof ElementContent and
@@ -1338,7 +1283,7 @@ module RustDataFlow implements InputSig<Location> {
1338
1283
* in `x.f = newValue`.
1339
1284
*/
1340
1285
predicate clearsContent ( Node n , ContentSet cs ) {
1341
- tupleAssignment ( _, n , cs .( SingletonContentSet ) .getContent ( ) )
1286
+ fieldAssignment ( _, n , cs .( SingletonContentSet ) .getContent ( ) )
1342
1287
or
1343
1288
FlowSummaryImpl:: Private:: Steps:: summaryClearsContent ( n .( Node:: FlowSummaryNode ) .getSummaryNode ( ) ,
1344
1289
cs )
@@ -1644,10 +1589,10 @@ private module Cached {
1644
1589
1645
1590
cached
1646
1591
newtype TContent =
1647
- TVariantTupleFieldContent ( Variant v , int pos ) { exists ( getVariantTupleField ( v , pos ) ) } or
1592
+ TTupleFieldContent ( TupleField field ) or
1593
+ TRecordFieldContent ( RecordField field ) or
1648
1594
// TODO: Remove once library types are extracted
1649
1595
TVariantInLibTupleFieldContent ( VariantInLib:: VariantInLib v , int pos ) { pos = v .getAPosition ( ) } or
1650
- TVariantRecordFieldContent ( Variant v , string field ) { exists ( getVariantRecordField ( v , field ) ) } or
1651
1596
TElementContent ( ) or
1652
1597
TTuplePositionContent ( int pos ) {
1653
1598
pos in [ 0 .. max ( [
@@ -1656,9 +1601,6 @@ private module Cached {
1656
1601
]
1657
1602
) ]
1658
1603
} or
1659
- TStructFieldContent ( Struct s , string field ) {
1660
- field = s .getFieldList ( ) .( RecordFieldList ) .getAField ( ) .getName ( ) .getText ( )
1661
- } or
1662
1604
TFunctionCallReturnContent ( ) or
1663
1605
TFunctionCallArgumentContent ( int pos ) {
1664
1606
pos in [ 0 .. any ( CallExpr c ) .getArgList ( ) .getNumberOfArgs ( ) - 1 ]
0 commit comments