4
4
5
5
private import codeql.util.Void
6
6
private import codeql.util.Unit
7
+ private import codeql.util.Boolean
7
8
private import codeql.dataflow.DataFlow
8
9
private import codeql.dataflow.internal.DataFlowImpl
9
10
private import rust
@@ -96,6 +97,8 @@ final class ParameterPosition extends TParameterPosition {
96
97
/** Gets the underlying integer position, if any. */
97
98
int getPosition ( ) { this = TPositionalParameterPosition ( result ) }
98
99
100
+ predicate hasPosition ( ) { exists ( this .getPosition ( ) ) }
101
+
99
102
/** Holds if this position represents the `self` position. */
100
103
predicate isSelf ( ) { this = TSelfParameterPosition ( ) }
101
104
@@ -130,21 +133,21 @@ private predicate callToMethod(CallExpr call) {
130
133
)
131
134
}
132
135
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
+ */
134
142
private predicate isArgumentForCall ( ExprCfgNode arg , CallExprBaseCfgNode call , ParameterPosition pos ) {
135
143
if callToMethod ( call .( CallExprCfgNode ) .getCallExpr ( ) )
136
- then (
144
+ then
137
145
// The first argument is for the `self` parameter
138
146
arg = call .getArgument ( 0 ) and pos .isSelf ( )
139
147
or
140
148
// Succeeding arguments are shifted left
141
149
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 ( ) )
148
151
}
149
152
150
153
/**
@@ -374,6 +377,30 @@ module Node {
374
377
}
375
378
}
376
379
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
+
377
404
final class SummaryArgumentNode extends FlowSummaryNode , ArgumentNode {
378
405
private FlowSummaryImpl:: Private:: SummaryNode receiver ;
379
406
private RustDataFlow:: ArgumentPosition pos_ ;
@@ -519,6 +546,18 @@ module Node {
519
546
override Location getLocation ( ) { result = n .getLocation ( ) }
520
547
}
521
548
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
+
522
561
final class SummaryPostUpdateNode extends FlowSummaryNode , PostUpdateNode {
523
562
private FlowSummaryNode pre ;
524
563
@@ -648,6 +687,14 @@ module LocalFlow {
648
687
)
649
688
or
650
689
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 ( )
651
698
}
652
699
}
653
700
@@ -998,6 +1045,23 @@ predicate lambdaCallExpr(CallExprCfgNode call, LambdaCallKind kind, ExprCfgNode
998
1045
exists ( kind )
999
1046
}
1000
1047
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
+
1001
1065
// Defines a set of aliases needed for the `RustDataFlow` module
1002
1066
private module Aliases {
1003
1067
class DataFlowCallableAlias = DataFlowCallable ;
@@ -1054,13 +1118,12 @@ module RustDataFlow implements InputSig<Location> {
1054
1118
DataFlowType getNodeType ( Node node ) { any ( ) }
1055
1119
1056
1120
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
1064
1127
}
1065
1128
1066
1129
predicate neverSkipInPathGraph ( Node node ) {
@@ -1169,6 +1232,28 @@ module RustDataFlow implements InputSig<Location> {
1169
1232
node2 .( Node:: FlowSummaryNode ) .getSummaryNode ( ) )
1170
1233
}
1171
1234
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
+
1172
1257
/**
1173
1258
* Holds if data can flow from `node1` to `node2` via a read of `c`. Thus,
1174
1259
* `node1` references an object with a content `c.getAReadContent()` whose
@@ -1251,6 +1336,17 @@ module RustDataFlow implements InputSig<Location> {
1251
1336
node2 .asExpr ( ) = await
1252
1337
)
1253
1338
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
1254
1350
VariableCapture:: readStep ( node1 , c , node2 )
1255
1351
)
1256
1352
or
@@ -1327,11 +1423,7 @@ module RustDataFlow implements InputSig<Location> {
1327
1423
node2 .( PostUpdateNode ) .getPreUpdateNode ( ) .asExpr ( ) = index .getBase ( )
1328
1424
)
1329
1425
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 )
1335
1427
or
1336
1428
// Store in function argument
1337
1429
exists ( DataFlowCall call , int i |
@@ -1341,6 +1433,10 @@ module RustDataFlow implements InputSig<Location> {
1341
1433
)
1342
1434
or
1343
1435
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 )
1344
1440
}
1345
1441
1346
1442
/**
@@ -1612,17 +1708,25 @@ private module Cached {
1612
1708
TPatNode ( PatCfgNode p ) or
1613
1709
TNameNode ( NameCfgNode n ) { n .getName ( ) = any ( Variable v ) .getName ( ) } or
1614
1710
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
1618
1721
e =
1619
1722
[
1620
1723
any ( IndexExprCfgNode i ) .getBase ( ) , any ( FieldExprCfgNode access ) .getExpr ( ) ,
1621
1724
any ( TryExprCfgNode try ) .getExpr ( ) ,
1622
1725
any ( PrefixExprCfgNode pe | pe .getOperatorName ( ) = "*" ) .getExpr ( ) ,
1623
- any ( AwaitExprCfgNode a ) .getExpr ( )
1726
+ any ( AwaitExprCfgNode a ) .getExpr ( ) , any ( MethodCallExprCfgNode mc ) . getReceiver ( )
1624
1727
]
1625
1728
} or
1729
+ TReceiverNode ( MethodCallExprCfgNode mc , Boolean isPost ) or
1626
1730
TSsaNode ( SsaImpl:: DataFlowIntegration:: SsaNode node ) or
1627
1731
TFlowSummaryNode ( FlowSummaryImpl:: Private:: SummaryNode sn ) or
1628
1732
TClosureSelfReferenceNode ( CfgScope c ) { lambdaCreationExpr ( c , _) } or
0 commit comments