@@ -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,18 +337,126 @@ 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+ )
345353 }
346354}
347355
356+ abstract class Content extends TContent {
357+ abstract string toString ( ) ;
358+ }
359+
360+ private class VariantContent extends Content , TVariantContent {
361+ private CrateOriginOption crate ;
362+ private string path ;
363+ private string name ;
364+
365+ VariantContent ( ) { this = TVariantContent ( crate , path , name ) }
366+
367+ override string toString ( ) { result = name }
368+ }
369+
370+ abstract class ContentSet extends TContentSet {
371+ /** Gets a textual representation of this element. */
372+ abstract string toString ( ) ;
373+
374+ /** Gets a content that may be stored into when storing into this set. */
375+ abstract Content getAStoreContent ( ) ;
376+
377+ /** Gets a content that may be read from when reading from this set. */
378+ abstract Content getAReadContent ( ) ;
379+ }
380+
381+ private class SingletonContentSet extends ContentSet , TSingletonContentSet {
382+ private Content c ;
383+
384+ SingletonContentSet ( ) { this = TSingletonContentSet ( c ) }
385+
386+ Content getContent ( ) { result = c }
387+
388+ override string toString ( ) { result = c .toString ( ) }
389+
390+ override Content getAStoreContent ( ) { result = c }
391+
392+ override Content getAReadContent ( ) { result = c }
393+ }
394+
395+ private import codeql.util.Option
396+
397+ private class CrateOrigin extends string {
398+ CrateOrigin ( ) {
399+ this = [ any ( Item i ) .getCrateOrigin ( ) , any ( Resolvable r ) .getResolvedCrateOrigin ( ) ]
400+ }
401+ }
402+
403+ private class CrateOriginOption = Option< CrateOrigin > :: Option ;
404+
405+ pragma [ nomagic]
406+ private predicate hasExtendedCanonicalPath ( Item i , CrateOriginOption crate , string path ) {
407+ path = i .getExtendedCanonicalPath ( ) and
408+ (
409+ crate .asSome ( ) = i .getCrateOrigin ( )
410+ or
411+ crate .isNone ( ) and
412+ not i .hasCrateOrigin ( )
413+ )
414+ }
415+
416+ pragma [ nomagic]
417+ private predicate resolvesExtendedCanonicalPath ( Resolvable r , CrateOriginOption crate , string path ) {
418+ path = r .getResolvedPath ( ) and
419+ (
420+ crate .asSome ( ) = r .getResolvedCrateOrigin ( )
421+ or
422+ crate .isNone ( ) and
423+ not r .hasResolvedCrateOrigin ( )
424+ )
425+ }
426+
427+ pragma [ nomagic]
428+ private predicate callResolvesExtendedCanonicalPath (
429+ CallExprBase call , CrateOriginOption crate , string path
430+ ) {
431+ exists ( Resolvable r | resolvesExtendedCanonicalPath ( r , crate , path ) |
432+ r = call .( MethodCallExpr )
433+ or
434+ r = call .( CallExpr ) .getExpr ( ) .( PathExpr ) .getPath ( )
435+ )
436+ }
437+
438+ /** Holds if qualified path `p` resolves to variant `c`. */
439+ private predicate pathResolvesToVariant ( Path p , VariantContent c ) {
440+ exists ( CrateOriginOption crate , string path |
441+ resolvesExtendedCanonicalPath ( p .getQualifier ( ) , crate , path ) and
442+ c = TVariantContent ( crate , path , p .getPart ( ) .getNameRef ( ) .getText ( ) )
443+ )
444+ or
445+ // TODO: Remove once library types are extracted
446+ not p .hasQualifier ( ) and
447+ c = TVariantContent ( _, "crate::std::option::Option" , p .getPart ( ) .getNameRef ( ) .getText ( ) )
448+ }
449+
450+ /** Holds if `ce` constructs an enum value of type `c`. */
451+ private predicate variantConstructor ( CallExpr ce , VariantContent c ) {
452+ pathResolvesToVariant ( ce .getExpr ( ) .( PathExpr ) .getPath ( ) , c )
453+ }
454+
455+ /** Holds if `p` destructs an enum value of type `c`. */
456+ private predicate variantDestructor ( TupleStructPat p , VariantContent c ) {
457+ pathResolvesToVariant ( p .getPath ( ) , c )
458+ }
459+
348460private class DataFlowCallableAlias = DataFlowCallable ;
349461
350462private class ReturnKindAlias = ReturnKind ;
@@ -353,6 +465,10 @@ private class DataFlowCallAlias = DataFlowCall;
353465
354466private class ParameterPositionAlias = ParameterPosition ;
355467
468+ private class ContentAlias = Content ;
469+
470+ private class ContentSetAlias = ContentSet ;
471+
356472module RustDataFlow implements InputSig< Location > {
357473 /**
358474 * An element, viewed as a node in a data flow graph. Either an expression
@@ -399,55 +515,11 @@ module RustDataFlow implements InputSig<Location> {
399515
400516 final class ReturnKind = ReturnKindAlias ;
401517
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-
446518 /** Gets a viable implementation of the target of the given `Call`. */
447519 DataFlowCallable viableCallable ( DataFlowCall call ) {
448520 exists ( string path , CrateOriginOption crate |
449- hasExtendedCanonicalPath ( result , crate , path ) and
450- resolvesExtendedCanonicalPath ( call , crate , path )
521+ hasExtendedCanonicalPath ( result . asCfgScope ( ) , crate , path ) and
522+ callResolvesExtendedCanonicalPath ( call . asCallBaseExprCfgNode ( ) . getExpr ( ) , crate , path )
451523 )
452524 }
453525
@@ -469,24 +541,15 @@ module RustDataFlow implements InputSig<Location> {
469541
470542 predicate typeStrongerThan ( DataFlowType t1 , DataFlowType t2 ) { none ( ) }
471543
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" }
544+ class Content = ContentAlias ;
479545
480- /** Gets a content that may be stored into when storing into this set. */
481- Content getAStoreContent ( ) { none ( ) }
546+ class ContentSet = ContentSetAlias ;
482547
483- /** Gets a content that may be read from when reading from this set. */
484- Content getAReadContent ( ) { none ( ) }
485- }
548+ predicate forceHighPrecision ( Content c ) { none ( ) }
486549
487- final class ContentApprox = Void ;
550+ final class ContentApprox = Content ; // todo
488551
489- ContentApprox getContentApprox ( Content c ) { any ( ) }
552+ ContentApprox getContentApprox ( Content c ) { result = c }
490553
491554 class ParameterPosition = ParameterPositionAlias ;
492555
@@ -519,14 +582,27 @@ module RustDataFlow implements InputSig<Location> {
519582 * `node1` references an object with a content `c.getAReadContent()` whose
520583 * value ends up in `node2`.
521584 */
522- predicate readStep ( Node node1 , ContentSet c , Node node2 ) { none ( ) }
585+ predicate readStep ( Node node1 , ContentSet c , Node node2 ) {
586+ node1 .asPat ( ) =
587+ any ( TupleStructPatCfgNode pat |
588+ variantDestructor ( pat .getPat ( ) , c .( SingletonContentSet ) .getContent ( ) ) and
589+ node2 .asPat ( ) = pat .getField ( 0 )
590+ )
591+ }
523592
524593 /**
525594 * Holds if data can flow from `node1` to `node2` via a store into `c`. Thus,
526595 * `node2` references an object with a content `c.getAStoreContent()` that
527596 * contains the value of `node1`.
528597 */
529- predicate storeStep ( Node node1 , ContentSet c , Node node2 ) { none ( ) }
598+ predicate storeStep ( Node node1 , ContentSet c , Node node2 ) {
599+ // todo: use post-update
600+ node2 .asExpr ( ) =
601+ any ( CallExprCfgNode call |
602+ variantConstructor ( call .getCallExpr ( ) , c .( SingletonContentSet ) .getContent ( ) ) and
603+ node1 .asExpr ( ) = call .getArgument ( 0 )
604+ )
605+ }
530606
531607 /**
532608 * Holds if values stored inside content `c` are cleared at node `n`. For example,
@@ -593,8 +669,6 @@ module RustDataFlow implements InputSig<Location> {
593669 class DataFlowSecondLevelScope = Void ;
594670}
595671
596- final class ContentSet = RustDataFlow:: ContentSet ;
597-
598672import MakeImpl< Location , RustDataFlow >
599673
600674/** A collection of cached types and predicates to be evaluated in the same stage. */
@@ -612,14 +686,6 @@ private module Cached {
612686 cached
613687 newtype TDataFlowCall = TCall ( CallExprBaseCfgNode c )
614688
615- cached
616- newtype TOptionalContentSet =
617- TAnyElementContent ( ) or
618- TAnyContent ( )
619-
620- cached
621- class TContentSet = TAnyElementContent or TAnyContent ;
622-
623689 cached
624690 newtype TDataFlowCallable = TCfgScope ( CfgScope scope )
625691
@@ -635,6 +701,24 @@ private module Cached {
635701 i in [ 0 .. max ( [ any ( ParamList l ) .getNumberOfParams ( ) , any ( ArgList l ) .getNumberOfArgs ( ) ] ) - 1 ]
636702 } or
637703 TSelfParameterPosition ( )
704+
705+ cached
706+ newtype TContent =
707+ TVariantContent ( CrateOriginOption crate , string path , string name ) {
708+ exists ( Enum e |
709+ hasExtendedCanonicalPath ( e , crate , path ) and
710+ // s = e.getExtendedCanonicalPath() and
711+ name = e .getVariantList ( ) .getAVariant ( ) .getName ( ) .getText ( )
712+ )
713+ or
714+ // TODO: Remove once library types are extracted
715+ crate .isNone ( ) and
716+ path = "crate::std::option::Option" and
717+ name = [ "None" , "Some" ]
718+ }
719+
720+ cached
721+ newtype TContentSet = TSingletonContentSet ( Content c )
638722}
639723
640724import Cached
0 commit comments