@@ -115,6 +115,11 @@ module Node {
115115 */
116116 ExprCfgNode asExpr ( ) { none ( ) }
117117
118+ /**
119+ * Gets the pattern that corresponds to this node, if any.
120+ */
121+ PatCfgNode asPat ( ) { none ( ) }
122+
118123 /** Gets the enclosing callable. */
119124 DataFlowCallable getEnclosingCallable ( ) { result = TCfgScope ( this .getCfgScope ( ) ) }
120125
@@ -177,8 +182,7 @@ module Node {
177182
178183 PatNode ( ) { this = TPatNode ( n ) }
179184
180- /** Gets the `PatCfgNode` in the CFG that this node corresponds to. */
181- PatCfgNode getPat ( ) { result = n }
185+ override PatCfgNode asPat ( ) { result = n }
182186 }
183187
184188 abstract class ParameterNode extends AstCfgFlowNode { }
@@ -333,27 +337,167 @@ module LocalFlow {
333337 nodeFrom .( Node:: AstCfgFlowNode ) .getCfgNode ( ) =
334338 nodeTo .( Node:: SsaNode ) .getDefinitionExt ( ) .( Ssa:: WriteDefinition ) .getControlFlowNode ( )
335339 or
336- nodeFrom .( Node:: PositionalParameterNode ) .getParameter ( ) .getPat ( ) =
337- nodeTo .( Node:: PatNode ) .getPat ( )
340+ nodeFrom .( Node:: PositionalParameterNode ) .getParameter ( ) .getPat ( ) = nodeTo .asPat ( )
338341 or
339342 SsaFlow:: localFlowStep ( _, nodeFrom , nodeTo , _)
340343 or
341344 exists ( AssignmentExprCfgNode a |
342345 a .getRhs ( ) = nodeFrom .getCfgNode ( ) and
343346 a .getLhs ( ) = nodeTo .getCfgNode ( )
344347 )
348+ or
349+ exists ( MatchExprCfgNode match |
350+ nodeFrom .asExpr ( ) = match .getExpr ( ) and
351+ nodeTo .asPat ( ) = match .getArmPat ( _)
352+ )
353+ or
354+ nodeFrom .asPat ( ) .( OrPatCfgNode ) .getAPat ( ) = nodeTo .asPat ( )
355+ }
356+ }
357+
358+ /**
359+ * A reference contained in an object. For example a field in a struct.
360+ */
361+ abstract class Content extends TContent {
362+ /** Gets a textual representation of this content. */
363+ abstract string toString ( ) ;
364+ }
365+
366+ /** A variant of an `enum`. */
367+ abstract private class VariantContent extends Content {
368+ string name ;
369+
370+ bindingset [ this , name]
371+ VariantContent ( ) { exists ( name ) }
372+ }
373+
374+ /** A tuple variant of an `enum`. */
375+ private class VariantTupleContent extends VariantContent , TVariantTupleContent {
376+ private CrateOriginOption crate ;
377+ private string path ;
378+ private int i ;
379+
380+ VariantTupleContent ( ) { this = TVariantTupleContent ( crate , path , name , i ) }
381+
382+ final override string toString ( ) {
383+ // only print indices when the arity is > 1
384+ if exists ( TVariantTupleContent ( crate , path , name , 1 ) )
385+ then result = name + "(" + i + ")"
386+ else result = name
345387 }
346388}
347389
348- private class DataFlowCallableAlias = DataFlowCallable ;
390+ /** A value that represents a set of `Content`s. */
391+ abstract class ContentSet extends TContentSet {
392+ /** Gets a textual representation of this element. */
393+ abstract string toString ( ) ;
394+
395+ /** Gets a content that may be stored into when storing into this set. */
396+ abstract Content getAStoreContent ( ) ;
397+
398+ /** Gets a content that may be read from when reading from this set. */
399+ abstract Content getAReadContent ( ) ;
400+ }
401+
402+ private class SingletonContentSet extends ContentSet , TSingletonContentSet {
403+ private Content c ;
404+
405+ SingletonContentSet ( ) { this = TSingletonContentSet ( c ) }
406+
407+ Content getContent ( ) { result = c }
408+
409+ override string toString ( ) { result = c .toString ( ) }
410+
411+ override Content getAStoreContent ( ) { result = c }
412+
413+ override Content getAReadContent ( ) { result = c }
414+ }
415+
416+ private import codeql.util.Option
417+
418+ private class CrateOrigin extends string {
419+ CrateOrigin ( ) {
420+ this = [ any ( Item i ) .getCrateOrigin ( ) , any ( Resolvable r ) .getResolvedCrateOrigin ( ) ]
421+ }
422+ }
423+
424+ private class CrateOriginOption = Option< CrateOrigin > :: Option ;
425+
426+ pragma [ nomagic]
427+ private predicate hasExtendedCanonicalPath ( Item i , CrateOriginOption crate , string path ) {
428+ path = i .getExtendedCanonicalPath ( ) and
429+ (
430+ crate .asSome ( ) = i .getCrateOrigin ( )
431+ or
432+ crate .isNone ( ) and
433+ not i .hasCrateOrigin ( )
434+ )
435+ }
436+
437+ pragma [ nomagic]
438+ private predicate resolvesExtendedCanonicalPath ( Resolvable r , CrateOriginOption crate , string path ) {
439+ path = r .getResolvedPath ( ) and
440+ (
441+ crate .asSome ( ) = r .getResolvedCrateOrigin ( )
442+ or
443+ crate .isNone ( ) and
444+ not r .hasResolvedCrateOrigin ( )
445+ )
446+ }
447+
448+ pragma [ nomagic]
449+ private predicate callResolvesExtendedCanonicalPath (
450+ CallExprBase call , CrateOriginOption crate , string path
451+ ) {
452+ exists ( Resolvable r | resolvesExtendedCanonicalPath ( r , crate , path ) |
453+ r = call .( MethodCallExpr )
454+ or
455+ r = call .( CallExpr ) .getExpr ( ) .( PathExpr ) .getPath ( )
456+ )
457+ }
458+
459+ /** Holds if qualified path `p` resolves to variant `c`. */
460+ private predicate pathResolvesToVariant ( Path p , VariantContent c , int i ) {
461+ exists ( CrateOriginOption crate , string path |
462+ resolvesExtendedCanonicalPath ( p .getQualifier ( ) , crate , path ) and
463+ c = TVariantTupleContent ( crate , path , p .getPart ( ) .getNameRef ( ) .getText ( ) , i )
464+ )
465+ or
466+ // TODO: Remove once library types are extracted
467+ not p .hasQualifier ( ) and
468+ c = TVariantTupleContent ( _, "crate::std::option::Option" , p .getPart ( ) .getNameRef ( ) .getText ( ) , i )
469+ }
470+
471+ /** Holds if `ce` constructs an enum value of type `c`. */
472+ pragma [ nomagic]
473+ private predicate variantConstructor ( CallExpr ce , VariantContent c , int i ) {
474+ pathResolvesToVariant ( ce .getExpr ( ) .( PathExpr ) .getPath ( ) , c , i )
475+ }
476+
477+ /** Holds if `p` destructs an enum value of type `c`. */
478+ pragma [ nomagic]
479+ private predicate variantDestructor ( TupleStructPat p , VariantContent c , int i ) {
480+ pathResolvesToVariant ( p .getPath ( ) , c , i )
481+ }
482+
483+ // Defines a set of aliases needed for the `RustDataFlow` module
484+ private module Aliases {
485+ class DataFlowCallableAlias = DataFlowCallable ;
349486
350- private class ReturnKindAlias = ReturnKind ;
487+ class ReturnKindAlias = ReturnKind ;
351488
352- private class DataFlowCallAlias = DataFlowCall ;
489+ class DataFlowCallAlias = DataFlowCall ;
353490
354- private class ParameterPositionAlias = ParameterPosition ;
491+ class ParameterPositionAlias = ParameterPosition ;
492+
493+ class ContentAlias = Content ;
494+
495+ class ContentSetAlias = ContentSet ;
496+ }
355497
356498module RustDataFlow implements InputSig< Location > {
499+ private import Aliases
500+
357501 /**
358502 * An element, viewed as a node in a data flow graph. Either an expression
359503 * (`ExprNode`) or a parameter (`ParameterNode`).
@@ -399,55 +543,11 @@ module RustDataFlow implements InputSig<Location> {
399543
400544 final class ReturnKind = ReturnKindAlias ;
401545
402- private import codeql.util.Option
403-
404- private class CrateOrigin extends string {
405- CrateOrigin ( ) {
406- this = [ any ( Item i ) .getCrateOrigin ( ) , any ( Resolvable r ) .getResolvedCrateOrigin ( ) ]
407- }
408- }
409-
410- private class CrateOriginOption = Option< CrateOrigin > :: Option ;
411-
412- pragma [ nomagic]
413- private predicate hasExtendedCanonicalPath (
414- DataFlowCallable c , CrateOriginOption crate , string path
415- ) {
416- exists ( Item i |
417- i = c .asCfgScope ( ) and
418- path = i .getExtendedCanonicalPath ( )
419- |
420- crate .asSome ( ) = i .getCrateOrigin ( )
421- or
422- crate .isNone ( ) and
423- not i .hasCrateOrigin ( )
424- )
425- }
426-
427- pragma [ nomagic]
428- private predicate resolvesExtendedCanonicalPath (
429- DataFlowCall c , CrateOriginOption crate , string path
430- ) {
431- exists ( Resolvable r |
432- path = r .getResolvedPath ( ) and
433- (
434- r = c .asMethodCallExprCfgNode ( ) .getExpr ( )
435- or
436- r = c .asCallExprCfgNode ( ) .getExpr ( ) .( PathExprCfgNode ) .getPath ( )
437- )
438- |
439- crate .asSome ( ) = r .getResolvedCrateOrigin ( )
440- or
441- crate .isNone ( ) and
442- not r .hasResolvedCrateOrigin ( )
443- )
444- }
445-
446546 /** Gets a viable implementation of the target of the given `Call`. */
447547 DataFlowCallable viableCallable ( DataFlowCall call ) {
448548 exists ( string path , CrateOriginOption crate |
449- hasExtendedCanonicalPath ( result , crate , path ) and
450- resolvesExtendedCanonicalPath ( call , crate , path )
549+ hasExtendedCanonicalPath ( result . asCfgScope ( ) , crate , path ) and
550+ callResolvesExtendedCanonicalPath ( call . asCallBaseExprCfgNode ( ) . getExpr ( ) , crate , path )
451551 )
452552 }
453553
@@ -469,24 +569,15 @@ module RustDataFlow implements InputSig<Location> {
469569
470570 predicate typeStrongerThan ( DataFlowType t1 , DataFlowType t2 ) { none ( ) }
471571
472- final class Content = Void ;
473-
474- predicate forceHighPrecision ( Content c ) { none ( ) }
475-
476- class ContentSet extends TContentSet {
477- /** Gets a textual representation of this element. */
478- string toString ( ) { result = "ContentSet" }
572+ class Content = ContentAlias ;
479573
480- /** Gets a content that may be stored into when storing into this set. */
481- Content getAStoreContent ( ) { none ( ) }
574+ class ContentSet = ContentSetAlias ;
482575
483- /** Gets a content that may be read from when reading from this set. */
484- Content getAReadContent ( ) { none ( ) }
485- }
576+ predicate forceHighPrecision ( Content c ) { none ( ) }
486577
487- final class ContentApprox = Void ;
578+ final class ContentApprox = Content ; // todo
488579
489- ContentApprox getContentApprox ( Content c ) { any ( ) }
580+ ContentApprox getContentApprox ( Content c ) { result = c }
490581
491582 class ParameterPosition = ParameterPositionAlias ;
492583
@@ -519,14 +610,34 @@ module RustDataFlow implements InputSig<Location> {
519610 * `node1` references an object with a content `c.getAReadContent()` whose
520611 * value ends up in `node2`.
521612 */
522- predicate readStep ( Node node1 , ContentSet c , Node node2 ) { none ( ) }
613+ predicate readStep ( Node node1 , ContentSet cs , Node node2 ) {
614+ exists ( Content c | c = cs .( SingletonContentSet ) .getContent ( ) |
615+ node1 .asPat ( ) =
616+ any ( TupleStructPatCfgNode pat , int i |
617+ variantDestructor ( pat .getPat ( ) , c , i ) and
618+ node2 .asPat ( ) = pat .getField ( i )
619+ |
620+ pat
621+ )
622+ )
623+ }
523624
524625 /**
525626 * Holds if data can flow from `node1` to `node2` via a store into `c`. Thus,
526627 * `node2` references an object with a content `c.getAStoreContent()` that
527628 * contains the value of `node1`.
528629 */
529- predicate storeStep ( Node node1 , ContentSet c , Node node2 ) { none ( ) }
630+ predicate storeStep ( Node node1 , ContentSet cs , Node node2 ) {
631+ exists ( Content c | c = cs .( SingletonContentSet ) .getContent ( ) |
632+ node2 .asExpr ( ) =
633+ any ( CallExprCfgNode call , int i |
634+ variantConstructor ( call .getCallExpr ( ) , c , i ) and
635+ node1 .asExpr ( ) = call .getArgument ( i )
636+ |
637+ call
638+ )
639+ )
640+ }
530641
531642 /**
532643 * Holds if values stored inside content `c` are cleared at node `n`. For example,
@@ -593,8 +704,6 @@ module RustDataFlow implements InputSig<Location> {
593704 class DataFlowSecondLevelScope = Void ;
594705}
595706
596- final class ContentSet = RustDataFlow:: ContentSet ;
597-
598707import MakeImpl< Location , RustDataFlow >
599708
600709/** A collection of cached types and predicates to be evaluated in the same stage. */
@@ -612,14 +721,6 @@ private module Cached {
612721 cached
613722 newtype TDataFlowCall = TCall ( CallExprBaseCfgNode c )
614723
615- cached
616- newtype TOptionalContentSet =
617- TAnyElementContent ( ) or
618- TAnyContent ( )
619-
620- cached
621- class TContentSet = TAnyElementContent or TAnyContent ;
622-
623724 cached
624725 newtype TDataFlowCallable = TCfgScope ( CfgScope scope )
625726
@@ -635,6 +736,27 @@ private module Cached {
635736 i in [ 0 .. max ( [ any ( ParamList l ) .getNumberOfParams ( ) , any ( ArgList l ) .getNumberOfArgs ( ) ] ) - 1 ]
636737 } or
637738 TSelfParameterPosition ( )
739+
740+ cached
741+ newtype TContent =
742+ TVariantTupleContent ( CrateOriginOption crate , string path , string name , int i ) {
743+ exists ( Enum e , Variant v |
744+ hasExtendedCanonicalPath ( e , crate , path ) and
745+ v = e .getVariantList ( ) .getAVariant ( ) and
746+ name = v .getName ( ) .getText ( ) and
747+ i in [ 0 .. v .getFieldList ( ) .( TupleFieldList ) .getNumberOfFields ( ) - 1 ]
748+ )
749+ or
750+ // TODO: Remove once library types are extracted
751+ crate .isNone ( ) and
752+ path = "crate::std::option::Option" and
753+ name = "Some" and
754+ i = 0
755+ }
756+
757+ // todo: add TVariantRecordContent
758+ cached
759+ newtype TContentSet = TSingletonContentSet ( Content c )
638760}
639761
640762import Cached
0 commit comments