Skip to content

Commit c2ad6f9

Browse files
committed
wip
1 parent 0bddecd commit c2ad6f9

File tree

17 files changed

+177
-83
lines changed

17 files changed

+177
-83
lines changed

rust/ql/lib/codeql/rust/elements/internal/CallExprBaseImpl.qll

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,7 @@ module Impl {
2828
*/
2929
class CallExprBase extends Generated::CallExprBase {
3030
/** Gets the static target of this call, if any. */
31-
final Callable getStaticTarget() {
32-
result = TypeInference::resolveMethodCallTarget(this)
33-
or
34-
result = TypeInference::resolveCallTarget(this)
35-
}
31+
final Function getStaticTarget() { result = TypeInference::resolveCallTarget(this) }
3632

3733
override Expr getArg(int index) { result = this.getArgList().getArg(index) }
3834
}

rust/ql/lib/codeql/rust/elements/internal/CallImpl.qll

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,7 @@ module Impl {
5959
Expr getReceiver() { result = this.getArgument(TSelfArgumentPosition()) }
6060

6161
/** Gets the static target of this call, if any. */
62-
Function getStaticTarget() {
63-
result = TypeInference::resolveMethodCallTarget(this)
64-
or
65-
result = this.(CallExpr).getStaticTarget()
66-
}
62+
Function getStaticTarget() { result = TypeInference::resolveCallTarget(this) }
6763

6864
/** Gets a runtime target of this call, if any. */
6965
pragma[nomagic]
@@ -78,18 +74,21 @@ module Impl {
7874
}
7975

8076
/** Holds if the call expression dispatches to a method. */
81-
private predicate callIsMethodCall(CallExpr call, Path qualifier, string methodName) {
77+
private predicate callIsMethodCall(CallExpr call, Path qualifier, string methodName, boolean isRef) {
8278
exists(Path path, Function f |
8379
path = call.getFunction().(PathExpr).getPath() and
8480
f = resolvePath(path) and
85-
f.getParamList().hasSelfParam() and
8681
qualifier = path.getQualifier() and
87-
path.getSegment().getIdentifier().getText() = methodName
82+
path.getSegment().getIdentifier().getText() = methodName and
83+
exists(SelfParam self |
84+
self = f.getParamList().getSelfParam() and
85+
if self.isRef() then isRef = true else isRef = false
86+
)
8887
)
8988
}
9089

9190
private class CallExprCall extends Call instanceof CallExpr {
92-
CallExprCall() { not callIsMethodCall(this, _, _) }
91+
CallExprCall() { not callIsMethodCall(this, _, _, _) }
9392

9493
override string getMethodName() { none() }
9594

@@ -102,11 +101,19 @@ module Impl {
102101
}
103102
}
104103

105-
private class CallExprMethodCall extends Call instanceof CallExpr {
104+
class CallExprMethodCall extends Call instanceof CallExpr {
106105
Path qualifier;
107106
string methodName;
107+
boolean isRef;
108+
109+
CallExprMethodCall() { callIsMethodCall(this, qualifier, methodName, isRef) }
108110

109-
CallExprMethodCall() { callIsMethodCall(this, qualifier, methodName) }
111+
/**
112+
* Holds if this call has an explicit borrow for the `self` argument,
113+
* which is needed for `&self` parameters when method are called using
114+
* function call syntax.
115+
*/
116+
predicate hasExplicitSelfBorrow() { isRef = true }
110117

111118
override string getMethodName() { result = methodName }
112119

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

Lines changed: 65 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -770,9 +770,7 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
770770
Declaration getTarget() {
771771
result = resolveMethodCallTarget(this) // mutual recursion; resolving method calls requires resolving types and vice versa
772772
or
773-
result = resolveCallTargetSimple(this)
774-
or
775-
result = resolveCallTargetComplex(this) // mutual recursion
773+
result = resolveFunctionCallTarget(this) // potential mutual recursion; resolving some associated function calls requires resolving types
776774
}
777775
}
778776

@@ -1224,12 +1222,22 @@ private Type inferForLoopExprType(AstNode n, TypePath path) {
12241222
final class MethodCall extends Call {
12251223
MethodCall() { exists(this.getReceiver()) }
12261224

1225+
private Type getReceiverTypeAt(TypePath path) {
1226+
result = inferType(super.getReceiver(), path)
1227+
or
1228+
exists(PathExpr pe, TypeMention tm |
1229+
pe = this.(CallExpr).getFunction() and
1230+
tm = pe.getPath().getQualifier() and
1231+
result = tm.resolveTypeAt(path)
1232+
)
1233+
}
1234+
12271235
/** Gets the type of the receiver of the method call at `path`. */
12281236
Type getTypeAt(TypePath path) {
12291237
if this.receiverImplicitlyBorrowed()
12301238
then
12311239
exists(TypePath path0, Type t0 |
1232-
t0 = inferType(super.getReceiver(), path0) and
1240+
t0 = this.getReceiverTypeAt(path0) and
12331241
(
12341242
path0.isCons(TRefTypeParameter(), path)
12351243
or
@@ -1257,10 +1265,21 @@ final class MethodCall extends Call {
12571265
t0.(StructType).asItemNode() instanceof StringStruct and
12581266
result.(StructType).asItemNode() instanceof Builtins::Str
12591267
)
1260-
else result = inferType(super.getReceiver(), path)
1268+
else
1269+
if this.(CallImpl::CallExprMethodCall).hasExplicitSelfBorrow()
1270+
then
1271+
exists(TypePath path0 |
1272+
result = this.getReceiverTypeAt(path0) and
1273+
path0.isCons(TRefTypeParameter(), path)
1274+
)
1275+
else result = this.getReceiverTypeAt(path)
12611276
}
12621277
}
12631278

1279+
final private class FunctionCallExpr extends CallExpr {
1280+
FunctionCallExpr() { not this instanceof MethodCall }
1281+
}
1282+
12641283
/**
12651284
* Holds if a method for `type` with the name `name` and the arity `arity`
12661285
* exists in `impl`.
@@ -1500,15 +1519,28 @@ private Function getTraitMethod(ImplTraitReturnType trait, string name) {
15001519
result = getMethodSuccessor(trait.getImplTraitTypeRepr(), name)
15011520
}
15021521

1522+
pragma[nomagic]
1523+
private Function resolveMethodCallTarget(MethodCall mc) {
1524+
// The method comes from an `impl` block targeting the type of the receiver.
1525+
result = getMethodFromImpl(mc)
1526+
or
1527+
// The type of the receiver is a type parameter and the method comes from a
1528+
// trait bound on the type parameter.
1529+
result = getTypeParameterMethod(mc.getTypeAt(TypePath::nil()), mc.getMethodName())
1530+
or
1531+
// The type of the receiver is an `impl Trait` type.
1532+
result = getTraitMethod(mc.getTypeAt(TypePath::nil()), mc.getMethodName())
1533+
}
1534+
15031535
pragma[nomagic]
15041536
private predicate assocFuncResolutionDependsOnArgument(Function f, Impl impl, int pos) {
15051537
methodResolutionDependsOnArgument(impl, _, f, pos, _, _)
15061538
}
15071539

1508-
private class AssocFuncCallExpr extends CallExpr {
1540+
private class AssocFunctionCallExpr extends FunctionCallExpr {
15091541
private int pos;
15101542

1511-
AssocFuncCallExpr() {
1543+
AssocFunctionCallExpr() {
15121544
assocFuncResolutionDependsOnArgument(CallExprImpl::getResolvedFunction(this), _, pos)
15131545
}
15141546

@@ -1524,11 +1556,11 @@ private class AssocFuncCallExpr extends CallExpr {
15241556
}
15251557

15261558
private module AssocFuncIsInstantiationOfInput implements
1527-
IsInstantiationOfInputSig<AssocFuncCallExpr>
1559+
IsInstantiationOfInputSig<AssocFunctionCallExpr>
15281560
{
15291561
pragma[nomagic]
15301562
predicate potentialInstantiationOf(
1531-
AssocFuncCallExpr ce, TypeAbstraction impl, TypeMention constraint
1563+
AssocFunctionCallExpr ce, TypeAbstraction impl, TypeMention constraint
15321564
) {
15331565
exists(Function cand |
15341566
cand = ce.getACandidate(impl) and
@@ -1537,21 +1569,34 @@ private module AssocFuncIsInstantiationOfInput implements
15371569
}
15381570
}
15391571

1572+
/**
1573+
* Gets the target of `call`, where resolution does not rely on type inference.
1574+
*/
15401575
pragma[nomagic]
1541-
ItemNode resolveCallTargetSimple(CallExpr ce) {
1542-
result = CallExprImpl::getResolvedFunction(ce) and
1576+
private ItemNode resolveFunctionCallTargetSimple(FunctionCallExpr call) {
1577+
result = CallExprImpl::getResolvedFunction(call) and
15431578
not assocFuncResolutionDependsOnArgument(result, _, _)
15441579
}
15451580

1581+
/**
1582+
* Gets the target of `call`, where resolution relies on type inference.
1583+
*/
15461584
pragma[nomagic]
1547-
Function resolveCallTargetComplex(AssocFuncCallExpr ce) {
1585+
private Function resolveFunctionCallTargetComplex(AssocFunctionCallExpr call) {
15481586
exists(Impl impl |
1549-
IsInstantiationOf<AssocFuncCallExpr, AssocFuncIsInstantiationOfInput>::isInstantiationOf(ce,
1587+
IsInstantiationOf<AssocFunctionCallExpr, AssocFuncIsInstantiationOfInput>::isInstantiationOf(call,
15501588
impl, _) and
1551-
result = getMethodSuccessor(impl, ce.getACandidate(_).getName().getText())
1589+
result = getMethodSuccessor(impl, call.getACandidate(_).getName().getText())
15521590
)
15531591
}
15541592

1593+
pragma[inline]
1594+
private ItemNode resolveFunctionCallTarget(FunctionCallExpr call) {
1595+
result = resolveFunctionCallTargetSimple(call)
1596+
or
1597+
result = resolveFunctionCallTargetComplex(call)
1598+
}
1599+
15551600
cached
15561601
private module Cached {
15571602
private import codeql.rust.internal.CachedStages
@@ -1580,26 +1625,12 @@ private module Cached {
15801625
)
15811626
}
15821627

1583-
/** Gets a method that the method call `mc` resolves to, if any. */
1584-
cached
1585-
Function resolveMethodCallTarget(MethodCall mc) {
1586-
// The method comes from an `impl` block targeting the type of the receiver.
1587-
result = getMethodFromImpl(mc)
1588-
or
1589-
// The type of the receiver is a type parameter and the method comes from a
1590-
// trait bound on the type parameter.
1591-
result = getTypeParameterMethod(mc.getTypeAt(TypePath::nil()), mc.getMethodName())
1592-
or
1593-
// The type of the receiver is an `impl Trait` type.
1594-
result = getTraitMethod(mc.getTypeAt(TypePath::nil()), mc.getMethodName())
1595-
}
1596-
1597-
/** Gets a method that the method call `mc` resolves to, if any. */
1628+
/** Gets a function that `call` resolves to, if any. */
15981629
cached
1599-
Function resolveCallTarget(CallExpr ce) {
1600-
result = resolveCallTargetSimple(ce)
1630+
Function resolveCallTarget(Call call) {
1631+
result = resolveMethodCallTarget(call)
16011632
or
1602-
result = resolveCallTargetComplex(ce)
1633+
result = resolveFunctionCallTarget(call)
16031634
}
16041635

16051636
pragma[inline]
@@ -1736,8 +1767,8 @@ private module Debug {
17361767
private Locatable getRelevantLocatable() {
17371768
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
17381769
result.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
1739-
filepath.matches("%/sqlx.rs") and
1740-
startline = [56 .. 60]
1770+
filepath.matches("%/main.rs") and
1771+
startline = 120
17411772
)
17421773
}
17431774

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
11
multipleCallTargets
22
| proc_macro.rs:15:5:17:5 | ...::new(...) |
3-
| proc_macro.rs:16:12:16:16 | ...::to_tokens(...) |
43
| proc_macro.rs:25:5:28:5 | ...::new(...) |
5-
| proc_macro.rs:26:10:26:12 | ...::to_tokens(...) |
6-
| proc_macro.rs:27:10:27:16 | ...::to_tokens(...) |
74
| proc_macro.rs:41:5:49:5 | ...::new(...) |
85
| proc_macro.rs:41:5:49:5 | ...::new(...) |
96
| proc_macro.rs:41:5:49:5 | ...::new(...) |
107
| proc_macro.rs:41:5:49:5 | ...::new(...) |
11-
| proc_macro.rs:42:16:42:26 | ...::to_tokens(...) |
128
| proc_macro.rs:44:27:44:30 | ...::to_tokens(...) |
13-
| proc_macro.rs:46:18:46:28 | ...::to_tokens(...) |
149
multiplePathResolutions
1510
| macro_expansion.rs:1:5:1:14 | proc_macro |

rust/ql/test/library-tests/dataflow/global/CONSISTENCY/PathResolutionConsistency.expected

Lines changed: 0 additions & 5 deletions
This file was deleted.

rust/ql/test/library-tests/dataflow/sources/CONSISTENCY/PathResolutionConsistency.expected

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
multipleCallTargets
22
| test.rs:98:14:98:43 | ...::_print(...) |
33
| test.rs:109:14:109:33 | ...::_print(...) |
4+
| test.rs:112:62:112:77 | ...::from(...) |
5+
| test.rs:119:58:119:73 | ...::from(...) |
46
| test.rs:135:22:135:43 | ...::_print(...) |
57
| test.rs:140:22:140:43 | ...::_print(...) |
68
| test.rs:144:22:144:44 | ...::_print(...) |
@@ -30,6 +32,8 @@ multipleCallTargets
3032
| test.rs:737:30:737:43 | ...::_print(...) |
3133
| test.rs:752:14:752:43 | ...::_print(...) |
3234
| test.rs:766:14:766:34 | ...::_print(...) |
35+
| test.rs:806:50:806:66 | ...::from(...) |
36+
| test.rs:806:50:806:66 | ...::from(...) |
3337
| test.rs:808:14:808:31 | ...::_print(...) |
3438
| test.rs:811:14:811:31 | ...::_print(...) |
3539
| test.rs:814:14:814:31 | ...::_print(...) |
@@ -75,13 +79,5 @@ multipleCallTargets
7579
| test_futures_io.rs:93:26:93:63 | pinned.poll_read(...) |
7680
| test_futures_io.rs:116:22:116:50 | pinned.poll_fill_buf(...) |
7781
| test_futures_io.rs:145:26:145:49 | ...::with_capacity(...) |
78-
| web_frameworks.rs:40:5:40:26 | ...::next_key::<...>(...) |
79-
| web_frameworks.rs:40:5:40:26 | ...::next_value::<...>(...) |
80-
| web_frameworks.rs:40:5:40:26 | ...::write_str(...) |
81-
| web_frameworks.rs:40:5:40:26 | ...::write_str(...) |
82-
| web_frameworks.rs:42:9:42:17 | ...::next_element::<...>(...) |
83-
| web_frameworks.rs:42:9:42:17 | ...::next_value::<...>(...) |
84-
| web_frameworks.rs:43:9:43:17 | ...::next_element::<...>(...) |
85-
| web_frameworks.rs:43:9:43:17 | ...::next_value::<...>(...) |
8682
| web_frameworks.rs:101:14:101:23 | a.as_str() |
8783
| web_frameworks.rs:102:14:102:25 | a.as_bytes() |
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| test_futures_io.rs:46:40:46:60 | //... | Missing result: hasTaintFlow=url |
2+
| test_futures_io.rs:104:40:104:60 | //... | Missing result: hasTaintFlow=url |

rust/ql/test/library-tests/path-resolution/CONSISTENCY/PathResolutionConsistency.expected

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
multipleCallTargets
22
| main.rs:118:9:118:11 | f(...) |
33
| proc_macro.rs:9:5:11:5 | ...::new(...) |
4-
| proc_macro.rs:10:10:10:12 | ...::to_tokens(...) |
54
multiplePathResolutions
65
| main.rs:626:3:626:12 | proc_macro |
76
| main.rs:632:7:632:16 | proc_macro |
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
multipleCallTargets
22
| dereference.rs:61:15:61:24 | e1.deref() |
3-
| main.rs:120:17:120:40 | ...::trait_method(...) |
3+
| main.rs:2145:13:2145:31 | ...::from(...) |
4+
| main.rs:2146:13:2146:31 | ...::from(...) |
5+
| main.rs:2147:13:2147:31 | ...::from(...) |
6+
| main.rs:2153:13:2153:31 | ...::from(...) |
7+
| main.rs:2154:13:2154:31 | ...::from(...) |
8+
| main.rs:2155:13:2155:31 | ...::from(...) |

rust/ql/test/library-tests/type-inference/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ mod trait_impl {
117117
let a = x.trait_method(); // $ type=a:bool method=MyThing::trait_method
118118

119119
let y = MyThing { field: false };
120-
let b = MyTrait::trait_method(y); // $ type=b:bool method=MyThing::trait_method $ SPURIOUS: method=trait_method
120+
let b = MyTrait::trait_method(y); // $ type=b:bool method=MyThing::trait_method
121121
}
122122
}
123123

0 commit comments

Comments
 (0)