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
@@ -367,13 +370,41 @@ module Node {
367
370
private CallExprBaseCfgNode call_ ;
368
371
private RustDataFlow:: ArgumentPosition pos_ ;
369
372
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
+ }
371
378
372
379
override predicate isArgumentOf ( DataFlowCall call , RustDataFlow:: ArgumentPosition pos ) {
373
380
call .asCallBaseExprCfgNode ( ) = call_ and pos = pos_
374
381
}
375
382
}
376
383
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
+
377
408
final class SummaryArgumentNode extends FlowSummaryNode , ArgumentNode {
378
409
private FlowSummaryImpl:: Private:: SummaryNode receiver ;
379
410
private RustDataFlow:: ArgumentPosition pos_ ;
@@ -519,6 +550,18 @@ module Node {
519
550
override Location getLocation ( ) { result = n .getLocation ( ) }
520
551
}
521
552
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
+
522
565
final class SummaryPostUpdateNode extends FlowSummaryNode , PostUpdateNode {
523
566
private FlowSummaryNode pre ;
524
567
@@ -648,6 +691,14 @@ module LocalFlow {
648
691
)
649
692
or
650
693
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 ( )
651
702
}
652
703
}
653
704
@@ -998,6 +1049,23 @@ predicate lambdaCallExpr(CallExprCfgNode call, LambdaCallKind kind, ExprCfgNode
998
1049
exists ( kind )
999
1050
}
1000
1051
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
+
1001
1069
// Defines a set of aliases needed for the `RustDataFlow` module
1002
1070
private module Aliases {
1003
1071
class DataFlowCallableAlias = DataFlowCallable ;
@@ -1054,13 +1122,12 @@ module RustDataFlow implements InputSig<Location> {
1054
1122
DataFlowType getNodeType ( Node node ) { any ( ) }
1055
1123
1056
1124
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
1064
1131
}
1065
1132
1066
1133
predicate neverSkipInPathGraph ( Node node ) {
@@ -1169,6 +1236,28 @@ module RustDataFlow implements InputSig<Location> {
1169
1236
node2 .( Node:: FlowSummaryNode ) .getSummaryNode ( ) )
1170
1237
}
1171
1238
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
+
1172
1261
/**
1173
1262
* Holds if data can flow from `node1` to `node2` via a read of `c`. Thus,
1174
1263
* `node1` references an object with a content `c.getAReadContent()` whose
@@ -1251,6 +1340,17 @@ module RustDataFlow implements InputSig<Location> {
1251
1340
node2 .asExpr ( ) = await
1252
1341
)
1253
1342
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
1254
1354
VariableCapture:: readStep ( node1 , c , node2 )
1255
1355
)
1256
1356
or
@@ -1327,11 +1427,7 @@ module RustDataFlow implements InputSig<Location> {
1327
1427
node2 .( PostUpdateNode ) .getPreUpdateNode ( ) .asExpr ( ) = index .getBase ( )
1328
1428
)
1329
1429
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 )
1335
1431
or
1336
1432
// Store in function argument
1337
1433
exists ( DataFlowCall call , int i |
@@ -1341,6 +1437,10 @@ module RustDataFlow implements InputSig<Location> {
1341
1437
)
1342
1438
or
1343
1439
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 )
1344
1444
}
1345
1445
1346
1446
/**
@@ -1612,9 +1712,16 @@ private module Cached {
1612
1712
TPatNode ( PatCfgNode p ) or
1613
1713
TNameNode ( NameCfgNode n ) { n .getName ( ) = any ( Variable v ) .getName ( ) } or
1614
1714
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
1618
1725
e =
1619
1726
[
1620
1727
any ( IndexExprCfgNode i ) .getBase ( ) , any ( FieldExprCfgNode access ) .getExpr ( ) ,
@@ -1623,6 +1730,7 @@ private module Cached {
1623
1730
any ( AwaitExprCfgNode a ) .getExpr ( )
1624
1731
]
1625
1732
} or
1733
+ TReceiverNode ( MethodCallExprCfgNode mc , Boolean isPost ) or
1626
1734
TSsaNode ( SsaImpl:: DataFlowIntegration:: SsaNode node ) or
1627
1735
TFlowSummaryNode ( FlowSummaryImpl:: Private:: SummaryNode sn ) or
1628
1736
TClosureSelfReferenceNode ( CfgScope c ) { lambdaCreationExpr ( c , _) } or
0 commit comments