Skip to content

Commit dadc605

Browse files
committed
Rust: Implement enclosing callable
1 parent ff80b24 commit dadc605

File tree

16 files changed

+119
-152
lines changed

16 files changed

+119
-152
lines changed

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
private import rust
77
private import ControlFlowGraph
8+
private import internal.ControlFlowGraphImpl
89

910
/** A CFG node that corresponds to an element in the AST. */
1011
class AstCfgNode extends CfgNode {
@@ -20,3 +21,10 @@ class ExprCfgNode extends AstCfgNode {
2021
/** Gets the underlying expression. */
2122
Expr getExpr() { result = node }
2223
}
24+
25+
/** A CFG node that corresponds to a call in the AST. */
26+
class CallCfgNode extends ExprCfgNode {
27+
override CallExpr node;
28+
}
29+
30+
final class ExitCfgNode = ExitNode;

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

Lines changed: 111 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,64 @@ private import codeql.rust.controlflow.ControlFlowGraph
1212
private import codeql.rust.controlflow.CfgNodes
1313
private import codeql.rust.dataflow.Ssa
1414

15+
private newtype TReturnKind = TNormalReturnKind()
16+
17+
/**
18+
* A return kind. A return kind describes how a value can be returned from a
19+
* callable.
20+
*
21+
* The only return kind is a "normal" return from a `return` statement or an
22+
* expression body.
23+
*/
24+
final class ReturnKind extends TNormalReturnKind {
25+
string toString() { result = "return" }
26+
}
27+
28+
/**
29+
* A callable. This includes callables from source code, as well as callables
30+
* defined in library code.
31+
*/
32+
final class DataFlowCallable extends TDataFlowCallable {
33+
/**
34+
* Gets the underlying CFG scope, if any.
35+
*/
36+
CfgScope asCfgScope() { this = TCfgScope(result) }
37+
38+
/** Gets a textual representation of this callable. */
39+
string toString() { result = this.asCfgScope().toString() }
40+
41+
/** Gets the location of this callable. */
42+
Location getLocation() { result = this.asCfgScope().getLocation() }
43+
}
44+
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+
abstract string toString();
53+
54+
/** Gets the location of this call. */
55+
abstract Location getLocation();
56+
}
57+
58+
final class NormalCall extends DataFlowCall, TNormalCall {
59+
private CallCfgNode c;
60+
61+
NormalCall() { this = TNormalCall(c) }
62+
63+
/** Gets the underlying call in the CFG, if any. */
64+
override CallCfgNode asCall() { result = c }
65+
66+
override DataFlowCallable getEnclosingCallable() { none() }
67+
68+
override string toString() { result = c.toString() }
69+
70+
override Location getLocation() { result = c.getLocation() }
71+
}
72+
1573
module Node {
1674
/**
1775
* An element, viewed as a node in a data flow graph. Either an expression
@@ -29,6 +87,12 @@ module Node {
2987
*/
3088
Expr asExpr() { none() }
3189

90+
/** Gets the enclosing callable. */
91+
DataFlowCallable getEnclosingCallable() { result = TCfgScope(this.getCfgScope()) }
92+
93+
/** Do not call: use `getEnclosingCallable()` instead. */
94+
abstract CfgScope getCfgScope();
95+
3296
/**
3397
* Gets the control flow node that corresponds to this data flow node.
3498
*/
@@ -49,6 +113,8 @@ module Node {
49113
final class NaNode extends Node {
50114
NaNode() { none() }
51115

116+
override CfgScope getCfgScope() { none() }
117+
52118
override string toString() { result = "N/A" }
53119

54120
override Location getLocation() { none() }
@@ -62,11 +128,13 @@ module Node {
62128
* to multiple `ExprNode`s, just like it may correspond to multiple
63129
* `ControlFlow::Node`s.
64130
*/
65-
final class ExprNode extends Node, TExprNode {
131+
class ExprNode extends Node, TExprNode {
66132
ExprCfgNode n;
67133

68134
ExprNode() { this = TExprNode(n) }
69135

136+
override CfgScope getCfgScope() { result = this.asExpr().getEnclosingCallable() }
137+
70138
override Location getLocation() { result = n.getExpr().getLocation() }
71139

72140
override string toString() { result = n.getExpr().toString() }
@@ -85,6 +153,8 @@ module Node {
85153

86154
ParameterNode() { this = TParameterNode(parameter) }
87155

156+
override CfgScope getCfgScope() { result = parameter.getEnclosingCallable() }
157+
88158
override Location getLocation() { result = parameter.getLocation() }
89159

90160
override string toString() { result = parameter.toString() }
@@ -105,6 +175,8 @@ module Node {
105175
def = node.getDefinitionExt()
106176
}
107177

178+
override CfgScope getCfgScope() { result = def.getBasicBlock().getScope() }
179+
108180
SsaImpl::DefinitionExt getDefinitionExt() { result = def }
109181

110182
/** Holds if this node should be hidden from path explanations. */
@@ -115,11 +187,25 @@ module Node {
115187
override string toString() { result = node.toString() }
116188
}
117189

118-
final class ReturnNode extends NaNode {
119-
RustDataFlow::ReturnKind getKind() { none() }
190+
/** A data flow node that represents a value returned by a callable. */
191+
final class ReturnNode extends ExprNode {
192+
ReturnNode() { this.getCfgNode().getASuccessor() instanceof ExitCfgNode }
193+
194+
ReturnKind getKind() { any() }
195+
}
196+
197+
/** A data-flow node that represents the output of a call. */
198+
abstract class OutNode extends Node, ExprNode {
199+
/** Gets the underlying call, where this node is a corresponding output of kind `kind`. */
200+
abstract DataFlowCall getCall();
120201
}
121202

122-
final class OutNode = NaNode;
203+
final private class ExprOutNode extends OutNode {
204+
ExprOutNode() { this.asExpr() instanceof CallExpr }
205+
206+
/** Gets the underlying call CFG node that includes this out node. */
207+
override DataFlowCall getCall() { result.(NormalCall).asCall() = this.getCfgNode() }
208+
}
123209

124210
/**
125211
* A node associated with an object after an operation that might have
@@ -198,6 +284,12 @@ module LocalFlow {
198284
}
199285
}
200286

287+
class DataFlowCallableAlias = DataFlowCallable;
288+
289+
class ReturnKindAlias = ReturnKind;
290+
291+
class DataFlowCallAlias = DataFlowCall;
292+
201293
module RustDataFlow implements InputSig<Location> {
202294
/**
203295
* An element, viewed as a node in a data flow graph. Either an expression
@@ -221,7 +313,7 @@ module RustDataFlow implements InputSig<Location> {
221313

222314
predicate isArgumentNode(ArgumentNode n, DataFlowCall call, ArgumentPosition pos) { none() }
223315

224-
DataFlowCallable nodeGetEnclosingCallable(Node node) { none() }
316+
DataFlowCallable nodeGetEnclosingCallable(Node node) { result = node.getEnclosingCallable() }
225317

226318
DataFlowType getNodeType(Node node) { any() }
227319

@@ -232,26 +324,22 @@ module RustDataFlow implements InputSig<Location> {
232324
/** Gets the node corresponding to `e`. */
233325
Node exprNode(DataFlowExpr e) { result.getCfgNode() = e }
234326

235-
final class DataFlowCall extends TNormalCall {
236-
private CallExpr c;
237-
238-
DataFlowCall() { this = TNormalCall(c) }
239-
240-
DataFlowCallable getEnclosingCallable() { none() }
241-
242-
string toString() { result = c.toString() }
243-
244-
Location getLocation() { result = c.getLocation() }
245-
}
327+
final class DataFlowCall = DataFlowCallAlias;
246328

247-
final class DataFlowCallable = CfgScope;
329+
final class DataFlowCallable = DataFlowCallableAlias;
248330

249-
final class ReturnKind = Void;
331+
final class ReturnKind = ReturnKindAlias;
250332

251333
/** Gets a viable implementation of the target of the given `Call`. */
252334
DataFlowCallable viableCallable(DataFlowCall c) { none() }
253335

254-
OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { none() }
336+
/**
337+
* Gets a node that can read the value returned from `call` with return kind
338+
* `kind`.
339+
*/
340+
OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) {
341+
call = result.getCall() and exists(kind)
342+
}
255343

256344
// NOTE: For now we use the type `Unit` and do not benefit from type
257345
// information in the data flow analysis.
@@ -400,7 +488,7 @@ private module Cached {
400488
TSsaNode(SsaImpl::DataFlowIntegration::SsaNode node)
401489

402490
cached
403-
newtype TDataFlowCall = TNormalCall(CallExpr c)
491+
newtype TDataFlowCall = TNormalCall(CallCfgNode c)
404492

405493
cached
406494
newtype TOptionalContentSet =
@@ -410,6 +498,9 @@ private module Cached {
410498
cached
411499
class TContentSet = TAnyElementContent or TAnyContent;
412500

501+
cached
502+
newtype TDataFlowCallable = TCfgScope(CfgScope scope)
503+
413504
/** This is the local flow predicate that is exposed. */
414505
cached
415506
predicate localFlowStepImpl(Node::Node nodeFrom, Node::Node nodeTo) {
Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,2 @@
1-
uniqueEnclosingCallable
2-
| gen_become_expr.rs:4:11:4:16 | Param | Node should have one enclosing callable but has 0. |
3-
| gen_become_expr.rs:4:19:4:24 | Param | Node should have one enclosing callable but has 0. |
41
uniqueCallEnclosingCallable
52
| gen_become_expr.rs:8:17:8:36 | CallExpr | Call should have one enclosing callable but has 0. |
Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +0,0 @@
1-
uniqueEnclosingCallable
2-
| gen_closure_expr.rs:5:6:5:6 | Param | Node should have one enclosing callable but has 0. |
3-
| gen_closure_expr.rs:6:11:6:16 | Param | Node should have one enclosing callable but has 0. |
4-
| gen_closure_expr.rs:7:12:7:17 | Param | Node should have one enclosing callable but has 0. |
5-
| gen_closure_expr.rs:7:20:7:20 | Param | Node should have one enclosing callable but has 0. |
6-
| gen_closure_expr.rs:9:6:9:6 | Param | Node should have one enclosing callable but has 0. |
7-
| gen_closure_expr.rs:11:14:11:14 | Param | Node should have one enclosing callable but has 0. |
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
uniqueCallEnclosingCallable
22
| gen_continue_expr.rs:6:12:6:22 | CallExpr | Call should have one enclosing callable but has 0. |
3-
| gen_continue_expr.rs:11:12:11:22 | CallExpr | Call should have one enclosing callable but has 0. |
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +0,0 @@
1-
uniqueEnclosingCallable
2-
| gen_function.rs:4:8:4:13 | Param | Node should have one enclosing callable but has 0. |
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,2 @@
1-
uniqueEnclosingCallable
2-
| gen_let_expr.rs:3:18:3:43 | Param | Node should have one enclosing callable but has 0. |
31
uniqueCallEnclosingCallable
42
| gen_let_expr.rs:6:18:6:24 | CallExpr | Call should have one enclosing callable but has 0. |
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
uniqueCallEnclosingCallable
22
| gen_loop_expr.rs:6:18:6:40 | CallExpr | Call should have one enclosing callable but has 0. |
3-
| gen_loop_expr.rs:9:18:9:39 | CallExpr | Call should have one enclosing callable but has 0. |

rust/ql/test/extractor-tests/generated/MacroItems/CONSISTENCY/DataFlowConsistency.expected

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
uniqueEnclosingCallable
2-
| common_definitions.rs:3:15:3:25 | Param | Node should have one enclosing callable but has 0. |
3-
| file://:0:0:0:0 | Param | Node should have one enclosing callable but has 0. |
41
uniqueNodeLocation
52
| file://:0:0:0:0 | BlockExpr | Node should have one location but has 0. |
63
| file://:0:0:0:0 | MethodCallExpr | Node should have one location but has 0. |
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +0,0 @@
1-
uniqueEnclosingCallable
2-
| gen_match_arm.rs:3:19:3:24 | Param | Node should have one enclosing callable but has 0. |

0 commit comments

Comments
 (0)