Skip to content

Commit f2569c4

Browse files
authored
Merge pull request github#17921 from paldepind/rust-df-enclosing-callable
Rust: Implement enclosing callable
2 parents 39b2d2c + 22835c2 commit f2569c4

File tree

16 files changed

+120
-152
lines changed

16 files changed

+120
-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: 112 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,65 @@ 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+
/** 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;
61+
62+
NormalCall() { this = TNormalCall(c) }
63+
64+
/** Gets the underlying call in the CFG, if any. */
65+
override CallCfgNode asCall() { result = c }
66+
67+
override DataFlowCallable getEnclosingCallable() { none() }
68+
69+
override string toString() { result = c.toString() }
70+
71+
override Location getLocation() { result = c.getLocation() }
72+
}
73+
1574
module Node {
1675
/**
1776
* An element, viewed as a node in a data flow graph. Either an expression
@@ -29,6 +88,12 @@ module Node {
2988
*/
3089
Expr asExpr() { none() }
3190

91+
/** Gets the enclosing callable. */
92+
DataFlowCallable getEnclosingCallable() { result = TCfgScope(this.getCfgScope()) }
93+
94+
/** Do not call: use `getEnclosingCallable()` instead. */
95+
abstract CfgScope getCfgScope();
96+
3297
/**
3398
* Gets the control flow node that corresponds to this data flow node.
3499
*/
@@ -49,6 +114,8 @@ module Node {
49114
final class NaNode extends Node {
50115
NaNode() { none() }
51116

117+
override CfgScope getCfgScope() { none() }
118+
52119
override string toString() { result = "N/A" }
53120

54121
override Location getLocation() { none() }
@@ -62,11 +129,13 @@ module Node {
62129
* to multiple `ExprNode`s, just like it may correspond to multiple
63130
* `ControlFlow::Node`s.
64131
*/
65-
final class ExprNode extends Node, TExprNode {
132+
class ExprNode extends Node, TExprNode {
66133
ExprCfgNode n;
67134

68135
ExprNode() { this = TExprNode(n) }
69136

137+
override CfgScope getCfgScope() { result = this.asExpr().getEnclosingCallable() }
138+
70139
override Location getLocation() { result = n.getExpr().getLocation() }
71140

72141
override string toString() { result = n.getExpr().toString() }
@@ -85,6 +154,8 @@ module Node {
85154

86155
ParameterNode() { this = TParameterNode(parameter) }
87156

157+
override CfgScope getCfgScope() { result = parameter.getEnclosingCallable() }
158+
88159
override Location getLocation() { result = parameter.getLocation() }
89160

90161
override string toString() { result = parameter.toString() }
@@ -105,6 +176,8 @@ module Node {
105176
def = node.getDefinitionExt()
106177
}
107178

179+
override CfgScope getCfgScope() { result = def.getBasicBlock().getScope() }
180+
108181
SsaImpl::DefinitionExt getDefinitionExt() { result = def }
109182

110183
/** Holds if this node should be hidden from path explanations. */
@@ -115,11 +188,25 @@ module Node {
115188
override string toString() { result = node.toString() }
116189
}
117190

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

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

124211
/**
125212
* A node associated with an object after an operation that might have
@@ -198,6 +285,12 @@ module LocalFlow {
198285
}
199286
}
200287

288+
private class DataFlowCallableAlias = DataFlowCallable;
289+
290+
private class ReturnKindAlias = ReturnKind;
291+
292+
private class DataFlowCallAlias = DataFlowCall;
293+
201294
module RustDataFlow implements InputSig<Location> {
202295
/**
203296
* An element, viewed as a node in a data flow graph. Either an expression
@@ -221,7 +314,7 @@ module RustDataFlow implements InputSig<Location> {
221314

222315
predicate isArgumentNode(ArgumentNode n, DataFlowCall call, ArgumentPosition pos) { none() }
223316

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

226319
DataFlowType getNodeType(Node node) { any() }
227320

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

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-
}
328+
final class DataFlowCall = DataFlowCallAlias;
246329

247-
final class DataFlowCallable = CfgScope;
330+
final class DataFlowCallable = DataFlowCallableAlias;
248331

249-
final class ReturnKind = Void;
332+
final class ReturnKind = ReturnKindAlias;
250333

251334
/** Gets a viable implementation of the target of the given `Call`. */
252335
DataFlowCallable viableCallable(DataFlowCall c) { none() }
253336

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

256345
// NOTE: For now we use the type `Unit` and do not benefit from type
257346
// information in the data flow analysis.
@@ -400,7 +489,7 @@ private module Cached {
400489
TSsaNode(SsaImpl::DataFlowIntegration::SsaNode node)
401490

402491
cached
403-
newtype TDataFlowCall = TNormalCall(CallExpr c)
492+
newtype TDataFlowCall = TNormalCall(CallCfgNode c)
404493

405494
cached
406495
newtype TOptionalContentSet =
@@ -410,6 +499,9 @@ private module Cached {
410499
cached
411500
class TContentSet = TAnyElementContent or TAnyContent;
412501

502+
cached
503+
newtype TDataFlowCallable = TCfgScope(CfgScope scope)
504+
413505
/** This is the local flow predicate that is exposed. */
414506
cached
415507
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. |

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

Lines changed: 0 additions & 7 deletions
This file was deleted.
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. |

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

Lines changed: 0 additions & 2 deletions
This file was deleted.
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. |

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

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

0 commit comments

Comments
 (0)