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
@@ -130,21 +133,21 @@ private predicate callToMethod(CallExpr call) {
130133 )
131134}
132135
133- /** Holds if `arg` is an argument of `call` at the position `pos`. */
136+ /**
137+ * Holds if `arg` is an argument of `call` at the position `pos`.
138+ *
139+ * Note that this does not hold for the receiever expression of a method call
140+ * as the synthetic `ReceiverNode` is the argument for the `self` parameter.
141+ */
134142private predicate isArgumentForCall ( ExprCfgNode arg , CallExprBaseCfgNode call , ParameterPosition pos ) {
135143 if callToMethod ( call .( CallExprCfgNode ) .getCallExpr ( ) )
136- then (
144+ then
137145 // The first argument is for the `self` parameter
138146 arg = call .getArgument ( 0 ) and pos .isSelf ( )
139147 or
140148 // Succeeding arguments are shifted left
141149 arg = call .getArgument ( pos .getPosition ( ) + 1 )
142- ) else (
143- // The self argument in a method call.
144- arg = call .( MethodCallExprCfgNode ) .getReceiver ( ) and pos .isSelf ( )
145- or
146- arg = call .getArgument ( pos .getPosition ( ) )
147- )
150+ else arg = call .getArgument ( pos .getPosition ( ) )
148151}
149152
150153/**
@@ -374,6 +377,30 @@ module Node {
374377 }
375378 }
376379
380+ /**
381+ * The receiver of a method call _after_ any implicit borrow or dereferencing
382+ * has taken place.
383+ */
384+ final class ReceiverNode extends ArgumentNode , TReceiverNode {
385+ private MethodCallExprCfgNode n ;
386+
387+ ReceiverNode ( ) { this = TReceiverNode ( n , false ) }
388+
389+ ExprCfgNode getReceiver ( ) { result = n .getReceiver ( ) }
390+
391+ MethodCallExprCfgNode getMethodCall ( ) { result = n }
392+
393+ override predicate isArgumentOf ( DataFlowCall call , RustDataFlow:: ArgumentPosition pos ) {
394+ call .asMethodCallExprCfgNode ( ) = n and pos = TSelfParameterPosition ( )
395+ }
396+
397+ override CfgScope getCfgScope ( ) { result = n .getAstNode ( ) .getEnclosingCfgScope ( ) }
398+
399+ override Location getLocation ( ) { result = this .getReceiver ( ) .getLocation ( ) }
400+
401+ override string toString ( ) { result = "receiver for " + this .getReceiver ( ) }
402+ }
403+
377404 final class SummaryArgumentNode extends FlowSummaryNode , ArgumentNode {
378405 private FlowSummaryImpl:: Private:: SummaryNode receiver ;
379406 private RustDataFlow:: ArgumentPosition pos_ ;
@@ -519,6 +546,18 @@ module Node {
519546 override Location getLocation ( ) { result = n .getLocation ( ) }
520547 }
521548
549+ final class ReceiverPostUpdateNode extends PostUpdateNode , TReceiverNode {
550+ private MethodCallExprCfgNode n ;
551+
552+ ReceiverPostUpdateNode ( ) { this = TReceiverNode ( n , true ) }
553+
554+ override Node getPreUpdateNode ( ) { result = TReceiverNode ( n , false ) }
555+
556+ override CfgScope getCfgScope ( ) { result = n .getAstNode ( ) .getEnclosingCfgScope ( ) }
557+
558+ override Location getLocation ( ) { result = n .getReceiver ( ) .getLocation ( ) }
559+ }
560+
522561 final class SummaryPostUpdateNode extends FlowSummaryNode , PostUpdateNode {
523562 private FlowSummaryNode pre ;
524563
@@ -648,6 +687,14 @@ module LocalFlow {
648687 )
649688 or
650689 nodeFrom .asPat ( ) .( OrPatCfgNode ) .getAPat ( ) = nodeTo .asPat ( )
690+ or
691+ // Simple value step from receiver expression to receiver node, in case
692+ // there is no implicit deref or borrow operation.
693+ nodeFrom .asExpr ( ) = nodeTo .( Node:: ReceiverNode ) .getReceiver ( )
694+ or
695+ // The dual step of the above, for the post-update nodes.
696+ nodeFrom .( Node:: PostUpdateNode ) .getPreUpdateNode ( ) .( Node:: ReceiverNode ) .getReceiver ( ) =
697+ nodeTo .( Node:: PostUpdateNode ) .getPreUpdateNode ( ) .asExpr ( )
651698 }
652699}
653700
@@ -998,6 +1045,23 @@ predicate lambdaCallExpr(CallExprCfgNode call, LambdaCallKind kind, ExprCfgNode
9981045 exists ( kind )
9991046}
10001047
1048+ /** Holds if `mc` implicitly borrows its receiver. */
1049+ private predicate implicitBorrow ( MethodCallExpr mc ) {
1050+ // Determining whether an implicit borrow happens depends on the type of the
1051+ // receiever as well as the target. As a heuristic we simply check if the
1052+ // target takes `self` as a borrow and limit the approximation to cases where
1053+ // the receiver is a simple variable.
1054+ mc .getReceiver ( ) instanceof VariableAccess and
1055+ mc .getStaticTarget ( ) .getParamList ( ) .getSelfParam ( ) .isRef ( )
1056+ }
1057+
1058+ /** Holds if `mc` implicitly dereferences its receiver. */
1059+ private predicate implicitDeref ( MethodCallExpr mc ) {
1060+ // Similarly to `implicitBorrow` this is an approximation.
1061+ mc .getReceiver ( ) instanceof VariableAccess and
1062+ not mc .getStaticTarget ( ) .getParamList ( ) .getSelfParam ( ) .isRef ( )
1063+ }
1064+
10011065// Defines a set of aliases needed for the `RustDataFlow` module
10021066private module Aliases {
10031067 class DataFlowCallableAlias = DataFlowCallable ;
@@ -1054,13 +1118,12 @@ module RustDataFlow implements InputSig<Location> {
10541118 DataFlowType getNodeType ( Node node ) { any ( ) }
10551119
10561120 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
1121+ node instanceof Node:: SsaNode or
1122+ node .( Node:: FlowSummaryNode ) .getSummaryNode ( ) .isHidden ( ) or
1123+ node instanceof Node:: CaptureNode or
1124+ node instanceof Node:: ClosureParameterNode or
1125+ node instanceof Node:: ReceiverNode or
1126+ node instanceof Node:: ReceiverPostUpdateNode
10641127 }
10651128
10661129 predicate neverSkipInPathGraph ( Node node ) {
@@ -1169,6 +1232,28 @@ module RustDataFlow implements InputSig<Location> {
11691232 node2 .( Node:: FlowSummaryNode ) .getSummaryNode ( ) )
11701233 }
11711234
1235+ pragma [ nomagic]
1236+ private predicate implicitDerefToReceiver ( Node node1 , Node:: ReceiverNode node2 , ReferenceContent c ) {
1237+ node1 .asExpr ( ) = node2 .getReceiver ( ) and
1238+ implicitDeref ( node2 .getMethodCall ( ) .getMethodCallExpr ( ) ) and
1239+ exists ( c )
1240+ }
1241+
1242+ pragma [ nomagic]
1243+ private predicate implicitBorrowToReceiver (
1244+ Node node1 , Node:: ReceiverNode node2 , ReferenceContent c
1245+ ) {
1246+ node1 .asExpr ( ) = node2 .getReceiver ( ) and
1247+ implicitBorrow ( node2 .getMethodCall ( ) .getMethodCallExpr ( ) ) and
1248+ exists ( c )
1249+ }
1250+
1251+ pragma [ nomagic]
1252+ private predicate referenceExprToExpr ( Node node1 , Node node2 , ReferenceContent c ) {
1253+ node1 .asExpr ( ) = node2 .asExpr ( ) .( RefExprCfgNode ) .getExpr ( ) and
1254+ exists ( c )
1255+ }
1256+
11721257 /**
11731258 * Holds if data can flow from `node1` to `node2` via a read of `c`. Thus,
11741259 * `node1` references an object with a content `c.getAReadContent()` whose
@@ -1251,6 +1336,17 @@ module RustDataFlow implements InputSig<Location> {
12511336 node2 .asExpr ( ) = await
12521337 )
12531338 or
1339+ referenceExprToExpr ( node2 .( PostUpdateNode ) .getPreUpdateNode ( ) ,
1340+ node1 .( PostUpdateNode ) .getPreUpdateNode ( ) , c )
1341+ or
1342+ // Step from receiver expression to receiver node, in case of an implicit
1343+ // dereference.
1344+ implicitDerefToReceiver ( node1 , node2 , c )
1345+ or
1346+ // A read step dual to the store step for implicit borrows.
1347+ implicitBorrowToReceiver ( node2 .( PostUpdateNode ) .getPreUpdateNode ( ) ,
1348+ node1 .( PostUpdateNode ) .getPreUpdateNode ( ) , c )
1349+ or
12541350 VariableCapture:: readStep ( node1 , c , node2 )
12551351 )
12561352 or
@@ -1327,11 +1423,7 @@ module RustDataFlow implements InputSig<Location> {
13271423 node2 .( PostUpdateNode ) .getPreUpdateNode ( ) .asExpr ( ) = index .getBase ( )
13281424 )
13291425 or
1330- exists ( RefExprCfgNode ref |
1331- c instanceof ReferenceContent and
1332- node1 .asExpr ( ) = ref .getExpr ( ) and
1333- node2 .asExpr ( ) = ref
1334- )
1426+ referenceExprToExpr ( node1 , node2 , c )
13351427 or
13361428 // Store in function argument
13371429 exists ( DataFlowCall call , int i |
@@ -1341,6 +1433,10 @@ module RustDataFlow implements InputSig<Location> {
13411433 )
13421434 or
13431435 VariableCapture:: storeStep ( node1 , c , node2 )
1436+ or
1437+ // Step from receiver expression to receiver node, in case of an implicit
1438+ // borrow.
1439+ implicitBorrowToReceiver ( node1 , node2 , c )
13441440 }
13451441
13461442 /**
@@ -1612,17 +1708,25 @@ private module Cached {
16121708 TPatNode ( PatCfgNode p ) or
16131709 TNameNode ( NameCfgNode n ) { n .getName ( ) = any ( Variable v ) .getName ( ) } or
16141710 TExprPostUpdateNode ( ExprCfgNode e ) {
1615- isArgumentForCall ( e , _, _) or
1616- lambdaCallExpr ( _, _, e ) or
1617- lambdaCreationExpr ( e .getExpr ( ) , _) or
1711+ isArgumentForCall ( e , _, _)
1712+ or
1713+ lambdaCallExpr ( _, _, e )
1714+ or
1715+ lambdaCreationExpr ( e .getExpr ( ) , _)
1716+ or
1717+ // Whenever `&mut e` has a post-update node we also create one for `e`.
1718+ // E.g., for `e` in `f(..., &mut e, ...)` or `*(&mut e) = ...`.
1719+ e = any ( RefExprCfgNode ref | ref .isMut ( ) and exists ( TExprPostUpdateNode ( ref ) ) ) .getExpr ( )
1720+ or
16181721 e =
16191722 [
16201723 any ( IndexExprCfgNode i ) .getBase ( ) , any ( FieldExprCfgNode access ) .getExpr ( ) ,
16211724 any ( TryExprCfgNode try ) .getExpr ( ) ,
16221725 any ( PrefixExprCfgNode pe | pe .getOperatorName ( ) = "*" ) .getExpr ( ) ,
1623- any ( AwaitExprCfgNode a ) .getExpr ( )
1726+ any ( AwaitExprCfgNode a ) .getExpr ( ) , any ( MethodCallExprCfgNode mc ) . getReceiver ( )
16241727 ]
16251728 } or
1729+ TReceiverNode ( MethodCallExprCfgNode mc , Boolean isPost ) or
16261730 TSsaNode ( SsaImpl:: DataFlowIntegration:: SsaNode node ) or
16271731 TFlowSummaryNode ( FlowSummaryImpl:: Private:: SummaryNode sn ) or
16281732 TClosureSelfReferenceNode ( CfgScope c ) { lambdaCreationExpr ( c , _) } or
0 commit comments