44
55private import codeql.util.Void
66private import codeql.util.Unit
7+ private import codeql.util.Boolean
78private import codeql.dataflow.DataFlow
89private import codeql.dataflow.internal.DataFlowImpl
910private import rust
@@ -96,6 +97,8 @@ final class ParameterPosition extends TParameterPosition {
9697 /** Gets the underlying integer position, if any. */
9798 int getPosition ( ) { this = TPositionalParameterPosition ( result ) }
9899
100+ predicate hasPosition ( ) { exists ( this .getPosition ( ) ) }
101+
99102 /** Holds if this position represents the `self` position. */
100103 predicate isSelf ( ) { this = TSelfParameterPosition ( ) }
101104
@@ -367,13 +370,41 @@ module Node {
367370 private CallExprBaseCfgNode call_ ;
368371 private RustDataFlow:: ArgumentPosition pos_ ;
369372
370- ExprArgumentNode ( ) { isArgumentForCall ( n , call_ , pos_ ) }
373+ ExprArgumentNode ( ) {
374+ isArgumentForCall ( n , call_ , pos_ ) and
375+ // For receivers in method calls the `ReceiverNode` is the argument.
376+ not call_ .( MethodCallExprCfgNode ) .getReceiver ( ) = n
377+ }
371378
372379 override predicate isArgumentOf ( DataFlowCall call , RustDataFlow:: ArgumentPosition pos ) {
373380 call .asCallBaseExprCfgNode ( ) = call_ and pos = pos_
374381 }
375382 }
376383
384+ /**
385+ * The receiver of a method call _after_ any implicit borrow or dereferences
386+ * has taken place.
387+ */
388+ final class ReceiverNode extends ArgumentNode , TReceiverNode {
389+ private MethodCallExprCfgNode n ;
390+
391+ ReceiverNode ( ) { this = TReceiverNode ( n , false ) }
392+
393+ ExprCfgNode getReceiver ( ) { result = n .getReceiver ( ) }
394+
395+ MethodCallExprCfgNode getMethodCall ( ) { result = n }
396+
397+ override predicate isArgumentOf ( DataFlowCall call , RustDataFlow:: ArgumentPosition pos ) {
398+ call .asMethodCallExprCfgNode ( ) = n and pos = TSelfParameterPosition ( )
399+ }
400+
401+ override CfgScope getCfgScope ( ) { result = n .getAstNode ( ) .getEnclosingCfgScope ( ) }
402+
403+ override Location getLocation ( ) { result = n .getLocation ( ) }
404+
405+ override string toString ( ) { result = "receiver for " + this .getReceiver ( ) }
406+ }
407+
377408 final class SummaryArgumentNode extends FlowSummaryNode , ArgumentNode {
378409 private FlowSummaryImpl:: Private:: SummaryNode receiver ;
379410 private RustDataFlow:: ArgumentPosition pos_ ;
@@ -519,6 +550,18 @@ module Node {
519550 override Location getLocation ( ) { result = n .getLocation ( ) }
520551 }
521552
553+ final class ReceiverPostUpdateNode extends PostUpdateNode , TReceiverNode {
554+ private MethodCallExprCfgNode n ;
555+
556+ ReceiverPostUpdateNode ( ) { this = TReceiverNode ( n , true ) }
557+
558+ override Node getPreUpdateNode ( ) { result = TReceiverNode ( n , false ) }
559+
560+ override CfgScope getCfgScope ( ) { result = n .getAstNode ( ) .getEnclosingCfgScope ( ) }
561+
562+ override Location getLocation ( ) { result = n .getLocation ( ) }
563+ }
564+
522565 final class SummaryPostUpdateNode extends FlowSummaryNode , PostUpdateNode {
523566 private FlowSummaryNode pre ;
524567
@@ -648,6 +691,14 @@ module LocalFlow {
648691 )
649692 or
650693 nodeFrom .asPat ( ) .( OrPatCfgNode ) .getAPat ( ) = nodeTo .asPat ( )
694+ or
695+ // Simple value step from receiver expression to receiver node, in case
696+ // there is no implicit deref or borrow operation.
697+ nodeFrom .asExpr ( ) = nodeTo .( Node:: ReceiverNode ) .getReceiver ( )
698+ or
699+ // The dual step of the above, for the post-update nodes.
700+ nodeFrom .( Node:: PostUpdateNode ) .getPreUpdateNode ( ) .( Node:: ReceiverNode ) .getReceiver ( ) =
701+ nodeTo .( Node:: PostUpdateNode ) .getPreUpdateNode ( ) .asExpr ( )
651702 }
652703}
653704
@@ -998,6 +1049,23 @@ predicate lambdaCallExpr(CallExprCfgNode call, LambdaCallKind kind, ExprCfgNode
9981049 exists ( kind )
9991050}
10001051
1052+ /** Holds if `mc` implicitly borrows its receiver. */
1053+ predicate implicitBorrow ( MethodCallExpr mc ) {
1054+ // Determining whether an implicit borrow happens depends on the type of the
1055+ // receiever as well as the target. As a heuristic we simply check if the
1056+ // target takes `self` as a borrow and limit the approximation to cases where
1057+ // the receiver is a simple variable.
1058+ mc .getReceiver ( ) instanceof VariableAccess and
1059+ mc .getStaticTarget ( ) .getParamList ( ) .getSelfParam ( ) .isRef ( )
1060+ }
1061+
1062+ /** Holds if `mc` implicitly dereferences its receiver. */
1063+ predicate implicitDeref ( MethodCallExpr mc ) {
1064+ // Similarly to `implicitBorrow` this is an approximation.
1065+ mc .getReceiver ( ) instanceof VariableAccess and
1066+ not mc .getStaticTarget ( ) .getParamList ( ) .getSelfParam ( ) .isRef ( )
1067+ }
1068+
10011069// Defines a set of aliases needed for the `RustDataFlow` module
10021070private module Aliases {
10031071 class DataFlowCallableAlias = DataFlowCallable ;
@@ -1054,13 +1122,12 @@ module RustDataFlow implements InputSig<Location> {
10541122 DataFlowType getNodeType ( Node node ) { any ( ) }
10551123
10561124 predicate nodeIsHidden ( Node node ) {
1057- node instanceof Node:: SsaNode
1058- or
1059- node .( Node:: FlowSummaryNode ) .getSummaryNode ( ) .isHidden ( )
1060- or
1061- node instanceof Node:: CaptureNode
1062- or
1063- node instanceof Node:: ClosureParameterNode
1125+ node instanceof Node:: SsaNode or
1126+ node .( Node:: FlowSummaryNode ) .getSummaryNode ( ) .isHidden ( ) or
1127+ node instanceof Node:: CaptureNode or
1128+ node instanceof Node:: ClosureParameterNode or
1129+ node instanceof Node:: ReceiverNode or
1130+ node instanceof Node:: ReceiverPostUpdateNode
10641131 }
10651132
10661133 predicate neverSkipInPathGraph ( Node node ) {
@@ -1169,6 +1236,28 @@ module RustDataFlow implements InputSig<Location> {
11691236 node2 .( Node:: FlowSummaryNode ) .getSummaryNode ( ) )
11701237 }
11711238
1239+ pragma [ nomagic]
1240+ private predicate implicitDerefToReceiver ( Node node1 , Node:: ReceiverNode node2 , ReferenceContent c ) {
1241+ node1 .asExpr ( ) = node2 .getReceiver ( ) and
1242+ implicitDeref ( node2 .getMethodCall ( ) .getMethodCallExpr ( ) ) and
1243+ exists ( c )
1244+ }
1245+
1246+ pragma [ nomagic]
1247+ private predicate implicitBorrowToReceiver (
1248+ Node node1 , Node:: ReceiverNode node2 , ReferenceContent c
1249+ ) {
1250+ node1 .asExpr ( ) = node2 .getReceiver ( ) and
1251+ implicitBorrow ( node2 .getMethodCall ( ) .getMethodCallExpr ( ) ) and
1252+ exists ( c )
1253+ }
1254+
1255+ pragma [ nomagic]
1256+ private predicate referenceExprToExpr ( Node node1 , Node node2 , ReferenceContent c ) {
1257+ node1 .asExpr ( ) = node2 .asExpr ( ) .( RefExprCfgNode ) .getExpr ( ) and
1258+ exists ( c )
1259+ }
1260+
11721261 /**
11731262 * Holds if data can flow from `node1` to `node2` via a read of `c`. Thus,
11741263 * `node1` references an object with a content `c.getAReadContent()` whose
@@ -1251,6 +1340,17 @@ module RustDataFlow implements InputSig<Location> {
12511340 node2 .asExpr ( ) = await
12521341 )
12531342 or
1343+ referenceExprToExpr ( node2 .( PostUpdateNode ) .getPreUpdateNode ( ) ,
1344+ node1 .( PostUpdateNode ) .getPreUpdateNode ( ) , c )
1345+ or
1346+ // Step from receiver expression to receiver node, in case of an implicit
1347+ // dereference.
1348+ implicitDerefToReceiver ( node1 , node2 , c )
1349+ or
1350+ // A read step dual to the store step for implicit borrows.
1351+ implicitBorrowToReceiver ( node2 .( PostUpdateNode ) .getPreUpdateNode ( ) ,
1352+ node1 .( PostUpdateNode ) .getPreUpdateNode ( ) , c )
1353+ or
12541354 VariableCapture:: readStep ( node1 , c , node2 )
12551355 )
12561356 or
@@ -1327,11 +1427,7 @@ module RustDataFlow implements InputSig<Location> {
13271427 node2 .( PostUpdateNode ) .getPreUpdateNode ( ) .asExpr ( ) = index .getBase ( )
13281428 )
13291429 or
1330- exists ( RefExprCfgNode ref |
1331- c instanceof ReferenceContent and
1332- node1 .asExpr ( ) = ref .getExpr ( ) and
1333- node2 .asExpr ( ) = ref
1334- )
1430+ referenceExprToExpr ( node1 , node2 , c )
13351431 or
13361432 // Store in function argument
13371433 exists ( DataFlowCall call , int i |
@@ -1341,6 +1437,10 @@ module RustDataFlow implements InputSig<Location> {
13411437 )
13421438 or
13431439 VariableCapture:: storeStep ( node1 , c , node2 )
1440+ or
1441+ // Step from receiver expression to receiver node, in case of an implicit
1442+ // borrow.
1443+ implicitBorrowToReceiver ( node1 , node2 , c )
13441444 }
13451445
13461446 /**
@@ -1612,9 +1712,16 @@ private module Cached {
16121712 TPatNode ( PatCfgNode p ) or
16131713 TNameNode ( NameCfgNode n ) { n .getName ( ) = any ( Variable v ) .getName ( ) } or
16141714 TExprPostUpdateNode ( ExprCfgNode e ) {
1615- isArgumentForCall ( e , _, _) or
1616- lambdaCallExpr ( _, _, e ) or
1617- lambdaCreationExpr ( e .getExpr ( ) , _) or
1715+ isArgumentForCall ( e , _, _)
1716+ or
1717+ lambdaCallExpr ( _, _, e )
1718+ or
1719+ lambdaCreationExpr ( e .getExpr ( ) , _)
1720+ or
1721+ // Whenever `&mut e` has a post-update node we also create one for `e`.
1722+ // E.g., for `e` in `f(..., &mut e, ...)` or `*(&mut e) = ...`.
1723+ e = any ( RefExprCfgNode ref | ref .isMut ( ) and exists ( TExprPostUpdateNode ( ref ) ) ) .getExpr ( )
1724+ or
16181725 e =
16191726 [
16201727 any ( IndexExprCfgNode i ) .getBase ( ) , any ( FieldExprCfgNode access ) .getExpr ( ) ,
@@ -1623,6 +1730,7 @@ private module Cached {
16231730 any ( AwaitExprCfgNode a ) .getExpr ( )
16241731 ]
16251732 } or
1733+ TReceiverNode ( MethodCallExprCfgNode mc , Boolean isPost ) or
16261734 TSsaNode ( SsaImpl:: DataFlowIntegration:: SsaNode node ) or
16271735 TFlowSummaryNode ( FlowSummaryImpl:: Private:: SummaryNode sn ) or
16281736 TClosureSelfReferenceNode ( CfgScope c ) { lambdaCreationExpr ( c , _) } or
0 commit comments