Skip to content

Commit 2307df4

Browse files
authored
Merge pull request github#18010 from paldepind/rust-df-viable-callable
Rust: Include method calls in DataFlowCall and implement simple call target resolution
2 parents ef9f383 + 86672b7 commit 2307df4

File tree

5 files changed

+159
-27
lines changed

5 files changed

+159
-27
lines changed

rust/ql/lib/codeql/rust/controlflow/CfgNodes.qll

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,19 @@ class ExprCfgNode extends AstCfgNode {
3131
}
3232

3333
/** A CFG node that corresponds to a call in the AST. */
34-
class CallCfgNode extends ExprCfgNode {
34+
class CallExprCfgNode extends ExprCfgNode {
3535
override CallExpr node;
36+
37+
/** Gets the underlying `CallExpr`. */
38+
CallExpr getCallExpr() { result = node }
39+
}
40+
41+
/** A CFG node that corresponds to a call in the AST. */
42+
class MethodCallExprCfgNode extends ExprCfgNode {
43+
override MethodCallExpr node;
44+
45+
/** Gets the underlying `MethodCallExpr`. */
46+
MethodCallExpr getMethodCallExpr() { result = node }
3647
}
3748

3849
final class ExitCfgNode = ExitNode;

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

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -42,35 +42,23 @@ final class DataFlowCallable extends TDataFlowCallable {
4242
Location getLocation() { result = this.asCfgScope().getLocation() }
4343
}
4444

45-
abstract class DataFlowCall extends TDataFlowCall {
46-
/** Gets the enclosing callable. */
47-
abstract DataFlowCallable getEnclosingCallable();
48-
49-
/** Gets the underlying source code call, if any. */
50-
abstract CallCfgNode asCall();
51-
52-
/** Gets a textual representation of this call. */
53-
abstract string toString();
54-
55-
/** Gets the location of this call. */
56-
abstract Location getLocation();
57-
}
58-
59-
final class NormalCall extends DataFlowCall, TNormalCall {
60-
private CallCfgNode c;
45+
final class DataFlowCall extends TDataFlowCall {
46+
/** Gets the underlying call in the CFG, if any. */
47+
CallExprCfgNode asCallExprCfgNode() { this = TNormalCall(result) }
6148

62-
NormalCall() { this = TNormalCall(c) }
49+
MethodCallExprCfgNode asMethodCallExprCfgNode() { this = TMethodCall(result) }
6350

64-
/** Gets the underlying call in the CFG, if any. */
65-
override CallCfgNode asCall() { result = c }
51+
ExprCfgNode asExprCfgNode() {
52+
result = this.asCallExprCfgNode() or result = this.asMethodCallExprCfgNode()
53+
}
6654

67-
override DataFlowCallable getEnclosingCallable() {
68-
result = TCfgScope(c.getExpr().getEnclosingCfgScope())
55+
DataFlowCallable getEnclosingCallable() {
56+
result = TCfgScope(this.asExprCfgNode().getExpr().getEnclosingCfgScope())
6957
}
7058

71-
override string toString() { result = c.toString() }
59+
string toString() { result = this.asExprCfgNode().toString() }
7260

73-
override Location getLocation() { result = c.getLocation() }
61+
Location getLocation() { result = this.asExprCfgNode().getLocation() }
7462
}
7563

7664
module Node {
@@ -204,7 +192,7 @@ module Node {
204192
ExprOutNode() { this.asExpr() instanceof CallExpr }
205193

206194
/** Gets the underlying call CFG node that includes this out node. */
207-
override DataFlowCall getCall() { result.(NormalCall).asCall() = this.getCfgNode() }
195+
override DataFlowCall getCall() { result.asExprCfgNode() = this.getCfgNode() }
208196
}
209197

210198
/**
@@ -331,7 +319,15 @@ module RustDataFlow implements InputSig<Location> {
331319
final class ReturnKind = ReturnKindAlias;
332320

333321
/** Gets a viable implementation of the target of the given `Call`. */
334-
DataFlowCallable viableCallable(DataFlowCall c) { none() }
322+
DataFlowCallable viableCallable(DataFlowCall c) {
323+
exists(Function f, string name | result.asCfgScope() = f and name = f.getName().toString() |
324+
if f.getParamList().hasSelfParam()
325+
then name = c.asMethodCallExprCfgNode().getMethodCallExpr().getNameRef().getText()
326+
else
327+
name =
328+
c.asCallExprCfgNode().getCallExpr().getExpr().(PathExpr).getPath().getPart().toString()
329+
)
330+
}
335331

336332
/**
337333
* Gets a node that can read the value returned from `call` with return kind
@@ -488,7 +484,9 @@ private module Cached {
488484
TSsaNode(SsaImpl::DataFlowIntegration::SsaNode node)
489485

490486
cached
491-
newtype TDataFlowCall = TNormalCall(CallCfgNode c)
487+
newtype TDataFlowCall =
488+
TNormalCall(CallExprCfgNode c) or
489+
TMethodCall(MethodCallExprCfgNode c)
492490

493491
cached
494492
newtype TOptionalContentSet =
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
fn source(i: i64) -> i64 {
2+
1000 + i
3+
}
4+
5+
fn sink(s: i64) {
6+
println!("{}", s);
7+
}
8+
9+
// -----------------------------------------------------------------------------
10+
// Data flow in, out, and through functions.
11+
12+
fn get_data(n: i64) -> i64 {
13+
source(n)
14+
}
15+
16+
fn data_out_of_call() {
17+
let a = get_data(7);
18+
sink(a); // $ hasValueFlow=n
19+
}
20+
21+
fn data_in(n: i64) {
22+
sink(n + 7); // $ hasValueFlow
23+
}
24+
25+
fn data_in_to_call() {
26+
let a = source(3);
27+
data_in(a);
28+
}
29+
30+
fn pass_through(i: i64) -> i64 {
31+
i
32+
}
33+
34+
fn data_through_call() {
35+
let a = source(1);
36+
let b = pass_through(a);
37+
sink(b); // $ hasValueFlow=1
38+
}
39+
40+
// -----------------------------------------------------------------------------
41+
// Data flow in, out, and through method.
42+
43+
struct MyFlag {
44+
flag: bool,
45+
}
46+
47+
impl MyFlag {
48+
fn data_in(&self, n: i64) {
49+
sink(n); // $ hasValueFlow=1
50+
}
51+
fn get_data(&self) -> i64 {
52+
if self.flag {
53+
0
54+
} else {
55+
source(2)
56+
}
57+
}
58+
fn data_through(&self, n: i64) -> i64 {
59+
if self.flag {
60+
0
61+
} else {
62+
n
63+
}
64+
}
65+
}
66+
67+
fn data_out_of_method() {
68+
let mn = MyFlag { flag: true };
69+
let a = mn.get_data();
70+
sink(a);
71+
}
72+
73+
fn data_in_to_method_call() {
74+
let mn = MyFlag { flag: true };
75+
let a = source(1);
76+
mn.data_in(a)
77+
}
78+
79+
fn data_through_method() {
80+
let mn = MyFlag { flag: true };
81+
let a = source(4);
82+
mn.data_through(a);
83+
sink(a); // $ hasValueFlow=4
84+
}
85+
86+
fn main() {
87+
data_out_of_call();
88+
data_in_to_call();
89+
data_through_call();
90+
91+
data_out_of_method();
92+
data_in_to_method_call();
93+
data_through_method();
94+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
| main.rs:13:5:13:13 | CallExpr | main.rs:1:1:3:1 | source |
2+
| main.rs:17:13:17:23 | CallExpr | main.rs:12:1:14:1 | get_data |
3+
| main.rs:18:5:18:11 | CallExpr | main.rs:5:1:7:1 | sink |
4+
| main.rs:22:5:22:15 | CallExpr | main.rs:5:1:7:1 | sink |
5+
| main.rs:26:13:26:21 | CallExpr | main.rs:1:1:3:1 | source |
6+
| main.rs:27:5:27:14 | CallExpr | main.rs:21:1:23:1 | data_in |
7+
| main.rs:35:13:35:21 | CallExpr | main.rs:1:1:3:1 | source |
8+
| main.rs:36:13:36:27 | CallExpr | main.rs:30:1:32:1 | pass_through |
9+
| main.rs:37:5:37:11 | CallExpr | main.rs:5:1:7:1 | sink |
10+
| main.rs:49:9:49:15 | CallExpr | main.rs:5:1:7:1 | sink |
11+
| main.rs:55:13:55:21 | CallExpr | main.rs:1:1:3:1 | source |
12+
| main.rs:69:13:69:25 | ... .get_data(...) | main.rs:51:5:57:5 | get_data |
13+
| main.rs:70:5:70:11 | CallExpr | main.rs:5:1:7:1 | sink |
14+
| main.rs:75:13:75:21 | CallExpr | main.rs:1:1:3:1 | source |
15+
| main.rs:76:5:76:17 | ... .data_in(...) | main.rs:48:5:50:5 | data_in |
16+
| main.rs:81:13:81:21 | CallExpr | main.rs:1:1:3:1 | source |
17+
| main.rs:82:5:82:22 | ... .data_through(...) | main.rs:58:5:64:5 | data_through |
18+
| main.rs:83:5:83:11 | CallExpr | main.rs:5:1:7:1 | sink |
19+
| main.rs:87:5:87:22 | CallExpr | main.rs:16:1:19:1 | data_out_of_call |
20+
| main.rs:88:5:88:21 | CallExpr | main.rs:25:1:28:1 | data_in_to_call |
21+
| main.rs:89:5:89:23 | CallExpr | main.rs:34:1:38:1 | data_through_call |
22+
| main.rs:91:5:91:24 | CallExpr | main.rs:67:1:71:1 | data_out_of_method |
23+
| main.rs:92:5:92:28 | CallExpr | main.rs:73:1:77:1 | data_in_to_method_call |
24+
| main.rs:93:5:93:25 | CallExpr | main.rs:79:1:84:1 | data_through_method |
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import codeql.rust.dataflow.internal.DataFlowImpl
2+
3+
query predicate viableCallable(DataFlowCall call, DataFlowCallable callee) {
4+
RustDataFlow::viableCallable(call) = callee
5+
}

0 commit comments

Comments
 (0)