Skip to content

Commit 4158477

Browse files
committed
Rust: Use type inference to insert implicit borrows and derefs
1 parent 2c95f00 commit 4158477

3 files changed

Lines changed: 27 additions & 29 deletions

File tree

rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ private import rust
1111
private import SsaImpl as SsaImpl
1212
private import codeql.rust.controlflow.internal.Scope as Scope
1313
private import codeql.rust.internal.PathResolution
14+
private import codeql.rust.internal.TypeInference as TypeInference
1415
private import codeql.rust.controlflow.ControlFlowGraph
1516
private import codeql.rust.controlflow.CfgNodes
1617
private import codeql.rust.dataflow.Ssa
@@ -321,23 +322,6 @@ predicate lambdaCallExpr(CallExprCfgNode call, LambdaCallKind kind, ExprCfgNode
321322
exists(kind)
322323
}
323324

324-
/** Holds if `mc` implicitly borrows its receiver. */
325-
private predicate implicitBorrow(MethodCallExpr mc) {
326-
// Determining whether an implicit borrow happens depends on the type of the
327-
// receiever as well as the target. As a heuristic we simply check if the
328-
// target takes `self` as a borrow and limit the approximation to cases where
329-
// the receiver is a simple variable.
330-
mc.getReceiver() instanceof VariableAccess and
331-
mc.getStaticTarget().getParamList().getSelfParam().isRef()
332-
}
333-
334-
/** Holds if `mc` implicitly dereferences its receiver. */
335-
private predicate implicitDeref(MethodCallExpr mc) {
336-
// Similarly to `implicitBorrow` this is an approximation.
337-
mc.getReceiver() instanceof VariableAccess and
338-
not mc.getStaticTarget().getParamList().getSelfParam().isRef()
339-
}
340-
341325
// Defines a set of aliases needed for the `RustDataFlow` module
342326
private module Aliases {
343327
class DataFlowCallableAlias = DataFlowCallable;
@@ -520,15 +504,15 @@ module RustDataFlow implements InputSig<Location> {
520504

521505
pragma[nomagic]
522506
private predicate implicitDerefToReceiver(Node node1, ReceiverNode node2, ReferenceContent c) {
507+
TypeInference::receiverHasImplicitDeref(node1.asExpr().getExpr()) and
523508
node1.asExpr() = node2.getReceiver() and
524-
implicitDeref(node2.getMethodCall().getMethodCallExpr()) and
525509
exists(c)
526510
}
527511

528512
pragma[nomagic]
529513
private predicate implicitBorrowToReceiver(Node node1, ReceiverNode node2, ReferenceContent c) {
514+
TypeInference::receiverHasImplicitBorrow(node1.asExpr().getExpr()) and
530515
node1.asExpr() = node2.getReceiver() and
531-
implicitBorrow(node2.getMethodCall().getMethodCallExpr()) and
532516
exists(c)
533517
}
534518

rust/ql/lib/codeql/rust/internal/TypeInference.qll

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,7 @@ private Type inferCallExprBaseType(AstNode n, TypePath path) {
690690
|
691691
if apos.isSelf()
692692
then
693-
exists(Type receiverType | receiverType = CallExprBaseMatchingInput::inferReceiverType(n) |
693+
exists(Type receiverType | receiverType = inferType(n) |
694694
if receiverType = TRefType()
695695
then
696696
path = path0 and
@@ -840,7 +840,7 @@ private Type inferFieldExprType(AstNode n, TypePath path) {
840840
|
841841
if apos.isSelf()
842842
then
843-
exists(Type receiverType | receiverType = FieldExprMatchingInput::inferReceiverType(n) |
843+
exists(Type receiverType | receiverType = inferType(n) |
844844
if receiverType = TRefType()
845845
then
846846
// adjust for implicit deref
@@ -895,6 +895,28 @@ cached
895895
private module Cached {
896896
private import codeql.rust.internal.CachedStages
897897

898+
/** Holds if `receiver` is the receiver of a method call with an implicit dereference. */
899+
cached
900+
predicate receiverHasImplicitDeref(AstNode receiver) {
901+
exists(CallExprBaseMatchingInput::Access a, CallExprBaseMatchingInput::AccessPosition apos |
902+
apos.isSelf() and
903+
receiver = a.getNodeAt(apos) and
904+
inferType(receiver) = TRefType() and
905+
CallExprBaseMatching::inferAccessType(a, apos, TypePath::nil()) != TRefType()
906+
)
907+
}
908+
909+
/** Holds if `receiver` is the receiver of a method call with an implicit borrow. */
910+
cached
911+
predicate receiverHasImplicitBorrow(AstNode receiver) {
912+
exists(CallExprBaseMatchingInput::Access a, CallExprBaseMatchingInput::AccessPosition apos |
913+
apos.isSelf() and
914+
receiver = a.getNodeAt(apos) and
915+
CallExprBaseMatching::inferAccessType(a, apos, TypePath::nil()) = TRefType() and
916+
inferType(receiver) != TRefType()
917+
)
918+
}
919+
898920
pragma[inline]
899921
private Type getLookupType(AstNode n) {
900922
exists(Type t |
Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,4 @@
11
unexpectedModel
22
| Unexpected summary found: repo::test;<crate::option::MyOption as crate::clone::Clone>::clone;Argument[self].Field[crate::option::MyOption::MySome(0)].Reference;ReturnValue.Field[crate::option::MyOption::MySome(0)];value;dfc-generated |
3-
| Unexpected summary found: repo::test;<crate::option::MyOption as crate::convert::From>::from;Argument[0].Field[crate::option::MyOption::MySome(0)];ReturnValue.Field[crate::option::MyOption::MySome(0)].Reference;value;dfc-generated |
43
| Unexpected summary found: repo::test;<crate::option::MyOption>::cloned;Argument[self].Field[crate::option::MyOption::MySome(0)].Reference;ReturnValue.Field[crate::option::MyOption::MySome(0)];value;dfc-generated |
5-
| Unexpected summary found: repo::test;<crate::option::MyOption>::get_or_insert;Argument[0];Argument[self].Field[crate::option::MyOption::MySome(0)];value;dfc-generated |
6-
| Unexpected summary found: repo::test;<crate::option::MyOption>::get_or_insert;Argument[self].Field[crate::option::MyOption::MySome(0)];ReturnValue.Reference;value;dfc-generated |
7-
| Unexpected summary found: repo::test;<crate::option::MyOption>::get_or_insert_default;Argument[self].Field[crate::option::MyOption::MySome(0)];ReturnValue.Reference;value;dfc-generated |
8-
| Unexpected summary found: repo::test;<crate::option::MyOption>::get_or_insert_with;Argument[self].Field[crate::option::MyOption::MySome(0)];ReturnValue.Reference;value;dfc-generated |
9-
| Unexpected summary found: repo::test;<crate::option::MyOption>::insert;Argument[self].Field[crate::option::MyOption::MySome(0)];ReturnValue.Reference;value;dfc-generated |
104
expectedModel
11-
| Expected summary missing: repo::test;<crate::option::MyOption>::take_if;Argument[self].Reference.Field[crate::option::MyOption::MySome(0)];Argument[0].Parameter[0].Reference;value;dfc-generated |
12-
| Expected summary missing: repo::test;<crate::option::MyOption>::take_if;Argument[self].Reference;ReturnValue;value;dfc-generated |

0 commit comments

Comments
 (0)