@@ -14,7 +14,6 @@ private import codeql.rust.controlflow.CfgNodes
1414private import codeql.rust.dataflow.Ssa
1515private import codeql.rust.dataflow.FlowSummary
1616private import FlowSummaryImpl as FlowSummaryImpl
17- private import codeql.rust.elements.internal.PathResolution as PathResolution
1817
1918/**
2019 * A return kind. A return kind describes how a value can be returned from a
@@ -661,7 +660,7 @@ private module VariantInLib {
661660 }
662661
663662 /** A tuple variant from library code. */
664- class VariantInLibTupleFieldContent extends VariantContent , TVariantInLibTupleFieldContent {
663+ class VariantInLibTupleFieldContent extends Content , TVariantInLibTupleFieldContent {
665664 private VariantInLib:: VariantInLib v ;
666665 private int pos_ ;
667666
@@ -740,82 +739,73 @@ abstract class Content extends TContent {
740739 abstract Location getLocation ( ) ;
741740}
742741
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 ( ) ;
751747}
752748
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 ) }
757756
758- VariantTupleFieldContent ( ) { this = TVariantTupleFieldContent ( v , pos_ ) }
757+ predicate isStructField ( Struct s , int pos ) { field . isStructField ( s , pos ) }
759758
760- Variant getVariant ( int pos ) { result = v and pos = pos_ }
759+ override FieldExprCfgNode getAnAccess ( ) { none ( ) } // TODO
761760
762761 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
765765 // 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
767774 )
768775 }
769776
770- final override Location getLocation ( ) { result = getVariantTupleField ( v , pos_ ) .getLocation ( ) }
777+ final override Location getLocation ( ) { result = field .getLocation ( ) }
771778}
772779
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 ) }
777785
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 ) }
782787
783- VariantRecordFieldContent ( ) { this = TVariantRecordFieldContent ( v , field_ ) }
788+ predicate isStructField ( Struct s , string name ) { field . isStructField ( s , name ) }
784789
785- Variant getVariant ( string field ) { result = v and field = field_ }
790+ override FieldExprCfgNode getAnAccess ( ) { none ( ) } // TODO
786791
787792 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
790796 // 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
794798 )
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
817805 )
818806 }
807+
808+ final override Location getLocation ( ) { result = field .getLocation ( ) }
819809}
820810
821811/** A captured variable. */
@@ -859,13 +849,18 @@ final class ElementContent extends Content, TElementContent {
859849 * NOTE: Unlike `struct`s and `enum`s tuples are structural and not nominal,
860850 * hence we don't store a canonical path for them.
861851 */
862- final class TuplePositionContent extends Content , TTuplePositionContent {
852+ final class TuplePositionContent extends FieldContent , TTuplePositionContent {
863853 private int pos ;
864854
865855 TuplePositionContent ( ) { this = TTuplePositionContent ( pos ) }
866856
867857 int getPosition ( ) { result = pos }
868858
859+ override FieldExprCfgNode getAnAccess ( ) {
860+ // TODO: limit to tuple types
861+ result .getNameRef ( ) .getText ( ) .toInt ( ) = pos
862+ }
863+
869864 override string toString ( ) { result = "tuple." + pos .toString ( ) }
870865
871866 override Location getLocation ( ) { result instanceof EmptyLocation }
@@ -901,11 +896,6 @@ final class FunctionCallReturnContent extends Content, TFunctionCallReturnConten
901896 override Location getLocation ( ) { result instanceof EmptyLocation }
902897}
903898
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-
909899/** A value that represents a set of `Content`s. */
910900abstract class ContentSet extends TContentSet {
911901 /** Gets a textual representation of this element. */
@@ -1128,23 +1118,6 @@ module RustDataFlow implements InputSig<Location> {
11281118 node2 .( Node:: FlowSummaryNode ) .getSummaryNode ( ) )
11291119 }
11301120
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-
11481121 /**
11491122 * Holds if data can flow from `node1` to `node2` via a read of `c`. Thus,
11501123 * `node1` references an object with a content `c.getAReadContent()` whose
@@ -1156,7 +1129,7 @@ module RustDataFlow implements InputSig<Location> {
11561129 pat = node1 .asPat ( ) and
11571130 node2 .asPat ( ) = pat .getField ( pos )
11581131 |
1159- tupleVariantDestruction ( pat .getPat ( ) , c . ( VariantTupleFieldContent ) . getVariant ( pos ) )
1132+ c = TTupleFieldContent ( pat .getTupleStructPat ( ) . getTupleField ( pos ) )
11601133 or
11611134 VariantInLib:: tupleVariantCanonicalDestruction ( pat .getPat ( ) , c , pos )
11621135 )
@@ -1169,25 +1142,17 @@ module RustDataFlow implements InputSig<Location> {
11691142 or
11701143 exists ( RecordPatCfgNode pat , string field |
11711144 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
11791146 node2 .asPat ( ) = pat .getFieldPat ( field )
11801147 )
11811148 or
11821149 c instanceof ReferenceContent and
11831150 node1 .asPat ( ) .( RefPatCfgNode ) .getPat ( ) = node2 .asPat ( )
11841151 or
11851152 exists ( FieldExprCfgNode access |
1186- // Read of a tuple entry
1187- fieldTuplePositionContent ( access , c ) and
1188- // TODO: Handle read of a struct field.
11891153 node1 .asExpr ( ) = access .getExpr ( ) and
1190- node2 .asExpr ( ) = access
1154+ node2 .asExpr ( ) = access and
1155+ access = c .( FieldContent ) .getAnAccess ( )
11911156 )
11921157 or
11931158 exists ( IndexExprCfgNode arr |
@@ -1236,49 +1201,29 @@ module RustDataFlow implements InputSig<Location> {
12361201 cs , node2 .( Node:: FlowSummaryNode ) .getSummaryNode ( ) )
12371202 }
12381203
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`. */
12461204 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 ) {
12541206 exists ( AssignmentExprCfgNode assignment , FieldExprCfgNode access |
12551207 assignment .getLhs ( ) = access and
1256- fieldTuplePositionContent ( access , c ) and
12571208 node1 .asExpr ( ) = assignment .getRhs ( ) and
1258- node2 .asExpr ( ) = access .getExpr ( )
1209+ node2 .asExpr ( ) = access .getExpr ( ) and
1210+ access = c .getAnAccess ( )
12591211 )
12601212 }
12611213
12621214 pragma [ nomagic]
12631215 private predicate storeContentStep ( Node node1 , Content c , Node node2 ) {
12641216 exists ( CallExprCfgNode call , int pos |
1265- node1 .asExpr ( ) = call .getArgument ( pos ) and
1217+ node1 .asExpr ( ) = call .getArgument ( pragma [ only_bind_into ] ( pos ) ) and
12661218 node2 .asExpr ( ) = call
12671219 |
1268- tupleVariantConstruction ( call .getCallExpr ( ) , c . ( VariantTupleFieldContent ) . getVariant ( pos ) )
1220+ c = TTupleFieldContent ( call .getCallExpr ( ) . getTupleField ( pragma [ only_bind_into ] ( pos ) ) )
12691221 or
12701222 VariantInLib:: tupleVariantCanonicalConstruction ( call .getCallExpr ( ) , c , pos )
12711223 )
12721224 or
12731225 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
12821227 node1 .asExpr ( ) = re .getFieldExpr ( field ) and
12831228 node2 .asExpr ( ) = re
12841229 )
@@ -1295,7 +1240,7 @@ module RustDataFlow implements InputSig<Location> {
12951240 node2 .asExpr ( ) .( ArrayListExprCfgNode ) .getAnExpr ( )
12961241 ]
12971242 or
1298- tupleAssignment ( node1 , node2 .( PostUpdateNode ) .getPreUpdateNode ( ) , c )
1243+ fieldAssignment ( node1 , node2 .( PostUpdateNode ) .getPreUpdateNode ( ) , c )
12991244 or
13001245 exists ( AssignmentExprCfgNode assignment , IndexExprCfgNode index |
13011246 c instanceof ElementContent and
@@ -1338,7 +1283,7 @@ module RustDataFlow implements InputSig<Location> {
13381283 * in `x.f = newValue`.
13391284 */
13401285 predicate clearsContent ( Node n , ContentSet cs ) {
1341- tupleAssignment ( _, n , cs .( SingletonContentSet ) .getContent ( ) )
1286+ fieldAssignment ( _, n , cs .( SingletonContentSet ) .getContent ( ) )
13421287 or
13431288 FlowSummaryImpl:: Private:: Steps:: summaryClearsContent ( n .( Node:: FlowSummaryNode ) .getSummaryNode ( ) ,
13441289 cs )
@@ -1644,10 +1589,10 @@ private module Cached {
16441589
16451590 cached
16461591 newtype TContent =
1647- TVariantTupleFieldContent ( Variant v , int pos ) { exists ( getVariantTupleField ( v , pos ) ) } or
1592+ TTupleFieldContent ( TupleField field ) or
1593+ TRecordFieldContent ( RecordField field ) or
16481594 // TODO: Remove once library types are extracted
16491595 TVariantInLibTupleFieldContent ( VariantInLib:: VariantInLib v , int pos ) { pos = v .getAPosition ( ) } or
1650- TVariantRecordFieldContent ( Variant v , string field ) { exists ( getVariantRecordField ( v , field ) ) } or
16511596 TElementContent ( ) or
16521597 TTuplePositionContent ( int pos ) {
16531598 pos in [ 0 .. max ( [
@@ -1656,9 +1601,6 @@ private module Cached {
16561601 ]
16571602 ) ]
16581603 } or
1659- TStructFieldContent ( Struct s , string field ) {
1660- field = s .getFieldList ( ) .( RecordFieldList ) .getAField ( ) .getName ( ) .getText ( )
1661- } or
16621604 TFunctionCallReturnContent ( ) or
16631605 TFunctionCallArgumentContent ( int pos ) {
16641606 pos in [ 0 .. any ( CallExpr c ) .getArgList ( ) .getNumberOfArgs ( ) - 1 ]
0 commit comments