Skip to content

Commit 7f1898b

Browse files
committed
Rust: Use nodes from CfgNodes.qll in DataFlowImpl.qll
1 parent 5db0ea8 commit 7f1898b

File tree

5 files changed

+214
-55
lines changed

5 files changed

+214
-55
lines changed

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

Lines changed: 149 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,161 @@ class AstCfgNode extends CfgNode {
1616
AstCfgNode() { node = this.getAstNode() }
1717
}
1818

19-
/** A CFG node that corresponds to a parameter in the AST. */
20-
class ParamCfgNode extends AstCfgNode {
21-
override Param node;
19+
/**
20+
* An assignment expression, for example
21+
*
22+
* ```rust
23+
* x = y;
24+
* ```
25+
*/
26+
final class AssignmentExprCfgNode extends BinaryExprCfgNode {
27+
AssignmentExpr a;
28+
29+
AssignmentExprCfgNode() { a = this.getBinaryExpr() }
30+
31+
/** Gets the underlying `AssignmentExpr`. */
32+
AssignmentExpr getAssignmentExpr() { result = a }
33+
}
34+
35+
/**
36+
* A match expression. For example:
37+
* ```rust
38+
* match x {
39+
* Option::Some(y) => y,
40+
* Option::None => 0,
41+
* }
42+
* ```
43+
* ```rust
44+
* match x {
45+
* Some(y) if y != 0 => 1 / y,
46+
* _ => 0,
47+
* }
48+
* ```
49+
*/
50+
final class MatchExprCfgNode extends Nodes::MatchExprCfgNode {
51+
private MatchExpr node;
52+
53+
MatchExprCfgNode() { node = this.getMatchExpr() }
54+
55+
/**
56+
* Gets the pattern of the `i`th match arm, if it exists.
57+
*/
58+
PatCfgNode getArmPat(int i) {
59+
any(ChildMapping mapping).hasCfgChild(node, node.getArm(i).getPat(), this, result)
60+
}
61+
62+
/**
63+
* Gets the guard of the `i`th match arm, if it exists.
64+
*/
65+
ExprCfgNode getArmGuard(int i) {
66+
any(ChildMapping mapping)
67+
.hasCfgChild(node, node.getArm(i).getGuard().getCondition(), this, result)
68+
}
69+
70+
/**
71+
* Gets the expression of the `i`th match arm, if it exists.
72+
*/
73+
ExprCfgNode getArmExpr(int i) {
74+
any(ChildMapping mapping).hasCfgChild(node, node.getArm(i).getExpr(), this, result)
75+
}
76+
}
77+
78+
/**
79+
* A block expression. For example:
80+
* ```rust
81+
* {
82+
* let x = 42;
83+
* }
84+
* ```
85+
* ```rust
86+
* 'label: {
87+
* let x = 42;
88+
* x
89+
* }
90+
* ```
91+
*/
92+
final class BlockExprCfgNode extends Nodes::BlockExprCfgNode {
93+
private BlockExprChildMapping node;
2294

23-
/** Gets the underlying parameter. */
24-
Param getParam() { result = node }
95+
BlockExprCfgNode() { node = this.getAstNode() }
96+
97+
/**
98+
* Gets the tail expression of this block, if it exists.
99+
*/
100+
ExprCfgNode getTailExpr() {
101+
any(ChildMapping mapping).hasCfgChild(node, node.getStmtList().getTailExpr(), this, result)
102+
}
103+
}
104+
105+
/**
106+
* A break expression. For example:
107+
* ```rust
108+
* loop {
109+
* if not_ready() {
110+
* break;
111+
* }
112+
* }
113+
* ```
114+
* ```rust
115+
* let x = 'label: loop {
116+
* if done() {
117+
* break 'label 42;
118+
* }
119+
* };
120+
* ```
121+
* ```rust
122+
* let x = 'label: {
123+
* if exit() {
124+
* break 'label 42;
125+
* }
126+
* 0;
127+
* };
128+
* ```
129+
*/
130+
final class BreakExprCfgNode extends Nodes::BreakExprCfgNode {
131+
/**
132+
* Gets the target of this `break` expression.
133+
*
134+
* The target is either a `LoopExpr`, a `ForExpr`, a `WhileExpr`, or a
135+
* `BlockExpr`.
136+
*/
137+
ExprCfgNode getTarget() {
138+
any(ChildMapping mapping)
139+
.hasCfgChild(this.getBreakExpr().getTarget(), this.getBreakExpr(), result, this)
140+
}
25141
}
26142

27-
/** A CFG node that corresponds to an expression in the AST. */
28-
class ExprCfgNode extends AstCfgNode {
29-
override Expr node;
143+
/**
144+
* A function or method call expression. See `CallExpr` and `MethodCallExpr` for further details.
145+
*/
146+
final class CallExprBaseCfgNode extends Nodes::CallExprBaseCfgNode {
147+
private CallExprBaseChildMapping node;
30148

31-
/** Gets the underlying expression. */
32-
Expr getExpr() { result = node }
149+
CallExprBaseCfgNode() { node = this.getAstNode() }
150+
151+
ExprCfgNode getArgument(int i) {
152+
any(ChildMapping mapping).hasCfgChild(node, node.getArgList().getArg(i), this, result)
153+
}
33154
}
34155

35-
/** A CFG node that corresponds to a call in the AST. */
36-
class CallCfgNode extends ExprCfgNode {
37-
override CallExpr node;
156+
/**
157+
* A record expression. For example:
158+
* ```rust
159+
* let first = Foo { a: 1, b: 2 };
160+
* let second = Foo { a: 2, ..first };
161+
* Foo { a: 1, b: 2 }[2] = 10;
162+
* Foo { .. } = second;
163+
* ```
164+
*/
165+
final class RecordExprCfgNode extends Nodes::RecordExprCfgNode {
166+
private RecordExprChildMapping node;
167+
168+
RecordExprCfgNode() { node = this.getRecordExpr() }
169+
170+
ExprCfgNode getExpr(int i) {
171+
any(ChildMapping mapping)
172+
.hasCfgChild(node, node.getRecordExprFieldList().getField(i).getExpr(), this, result)
173+
}
38174
}
39175

40176
final class ExitCfgNode = CfgImpl::ExitNode;

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ private predicate isPostOrder(AstNode n) {
1414
n instanceof IdentPat
1515
or
1616
n instanceof LiteralPat
17+
or
18+
n instanceof Param
1719
}
1820

1921
private module CfgNodesInput implements InputSig<Location> {
@@ -37,6 +39,38 @@ private module CfgNodesInput implements InputSig<Location> {
3739

3840
import MakeCfgNodes<Location, CfgNodesInput>
3941

42+
class MatchExprChildMapping extends ParentAstNode, MatchExpr {
43+
override predicate relevantChild(AstNode child) {
44+
child = this.getAnArm().getPat()
45+
or
46+
child = this.getAnArm().getGuard().getCondition()
47+
or
48+
child = this.getAnArm().getExpr()
49+
}
50+
}
51+
52+
class BlockExprChildMapping extends ParentAstNode, BlockExpr {
53+
override predicate relevantChild(AstNode child) { child = this.getStmtList().getTailExpr() }
54+
}
55+
56+
class BreakExprTargetChildMapping extends ParentAstNode, Expr {
57+
override predicate relevantChild(AstNode child) { child.(BreakExpr).getTarget() = this }
58+
}
59+
60+
class CallExprBaseChildMapping extends ParentAstNode, CallExprBase {
61+
override predicate relevantChild(AstNode child) { child = this.getArgList().getAnArg() }
62+
}
63+
64+
class RecordExprChildMapping extends ParentAstNode, RecordExpr {
65+
override predicate relevantChild(AstNode child) {
66+
child = this.getRecordExprFieldList().getAField().getExpr()
67+
}
68+
}
69+
70+
class FormatArgsExprChildMapping extends ParentAstNode, CfgImpl::ExprTrees::FormatArgsExprTree {
71+
override predicate relevantChild(AstNode child) { child = this.getChildNode(_) }
72+
}
73+
4074
private class ChildMappingImpl extends ChildMapping {
4175
pragma[nomagic]
4276
predicate reachesBasicBlock(AstNode parent, AstNode child, CfgNode cfn, BasicBlock bb) {

rust/ql/lib/codeql/rust/dataflow/Ssa.qll

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ module Ssa {
99
private import rust
1010
private import codeql.rust.controlflow.BasicBlocks
1111
private import codeql.rust.controlflow.ControlFlowGraph
12+
private import codeql.rust.controlflow.CfgNodes
1213
private import codeql.rust.controlflow.internal.ControlFlowGraphImpl as CfgImpl
1314
private import internal.SsaImpl as SsaImpl
1415

@@ -221,11 +222,11 @@ module Ssa {
221222
* end
222223
* ```
223224
*/
224-
predicate assigns(CfgNode value) {
225-
exists(AssignmentExpr ae, BasicBlock bb, int i |
225+
predicate assigns(ExprCfgNode value) {
226+
exists(AssignmentExprCfgNode ae, BasicBlock bb, int i |
226227
this.definesAt(_, bb, i) and
227-
ae.getLhs() = bb.getNode(i).getAstNode() and
228-
value.getAstNode() = ae.getRhs()
228+
ae.getLhs() = bb.getNode(i) and
229+
value = ae.getRhs()
229230
)
230231
}
231232

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

Lines changed: 21 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ abstract class DataFlowCall extends TDataFlowCall {
4747
abstract DataFlowCallable getEnclosingCallable();
4848

4949
/** Gets the underlying source code call, if any. */
50-
abstract CallCfgNode asCall();
50+
abstract CallExprCfgNode asCall();
5151

5252
/** Gets a textual representation of this call. */
5353
abstract string toString();
@@ -57,16 +57,14 @@ abstract class DataFlowCall extends TDataFlowCall {
5757
}
5858

5959
final class NormalCall extends DataFlowCall, TNormalCall {
60-
private CallCfgNode c;
60+
private CallExprCfgNode c;
6161

6262
NormalCall() { this = TNormalCall(c) }
6363

6464
/** Gets the underlying call in the CFG, if any. */
65-
override CallCfgNode asCall() { result = c }
65+
override CallExprCfgNode asCall() { result = c }
6666

67-
override DataFlowCallable getEnclosingCallable() {
68-
result = TCfgScope(c.getExpr().getEnclosingCfgScope())
69-
}
67+
override DataFlowCallable getEnclosingCallable() { result = TCfgScope(c.getExpr().getScope()) }
7068

7169
override string toString() { result = c.toString() }
7270

@@ -88,7 +86,7 @@ module Node {
8886
/**
8987
* Gets the expression that corresponds to this node, if any.
9088
*/
91-
Expr asExpr() { none() }
89+
ExprCfgNode asExpr() { none() }
9290

9391
/** Gets the enclosing callable. */
9492
DataFlowCallable getEnclosingCallable() { result = TCfgScope(this.getCfgScope()) }
@@ -136,13 +134,13 @@ module Node {
136134

137135
ExprNode() { this = TExprNode(n) }
138136

139-
override CfgScope getCfgScope() { result = this.asExpr().getEnclosingCfgScope() }
137+
override CfgScope getCfgScope() { result = this.asExpr().getScope() }
140138

141-
override Location getLocation() { result = n.getExpr().getLocation() }
139+
override Location getLocation() { result = n.getLocation() }
142140

143-
override string toString() { result = n.getExpr().toString() }
141+
override string toString() { result = n.toString() }
144142

145-
override Expr asExpr() { result = n.getExpr() }
143+
override ExprCfgNode asExpr() { result = n }
146144

147145
override CfgNode getCfgNode() { result = n }
148146
}
@@ -201,7 +199,7 @@ module Node {
201199
}
202200

203201
final private class ExprOutNode extends ExprNode, OutNode {
204-
ExprOutNode() { this.asExpr() instanceof CallExpr }
202+
ExprOutNode() { this.asExpr() instanceof CallExprCfgNode }
205203

206204
/** Gets the underlying call CFG node that includes this out node. */
207205
override DataFlowCall getCall() { result.(NormalCall).asCall() = this.getCfgNode() }
@@ -238,7 +236,7 @@ module SsaFlow {
238236
Impl::Node asNode(Node n) {
239237
n = TSsaNode(result)
240238
or
241-
result.(Impl::ExprNode).getExpr() = n.(Node::ExprNode).getCfgNode()
239+
result.(Impl::ExprNode).getExpr() = n.asExpr()
242240
or
243241
n = toParameterNode(result.(Impl::ParameterNode).getParameter())
244242
}
@@ -252,29 +250,18 @@ module SsaFlow {
252250
}
253251
}
254252

255-
/**
256-
* Holds for expressions `e` that evaluate to the value of any last (in
257-
* evaluation order) subexpressions within it. E.g., expressions that propagate
258-
* a values from a subexpression.
259-
*
260-
* For instance, the predicate holds for if expressions as `if b { e1 } else {
261-
* e2 }` evalates to the value of one of the subexpressions `e1` or `e2`.
262-
*/
263-
private predicate propagatesValue(Expr e) {
264-
e instanceof IfExpr or
265-
e instanceof LoopExpr or
266-
e instanceof ReturnExpr or
267-
e instanceof BreakExpr or
268-
e.(BlockExpr).getStmtList().hasTailExpr() or
269-
e instanceof MatchExpr
270-
}
271-
272253
/**
273254
* Gets a node that may execute last in `n`, and which, when it executes last,
274255
* will be the value of `n`.
275256
*/
276-
private ExprCfgNode getALastEvalNode(ExprCfgNode n) {
277-
propagatesValue(n.getExpr()) and result.getASuccessor() = n
257+
private ExprCfgNode getALastEvalNode(ExprCfgNode e) {
258+
e = any(IfExprCfgNode n | result = [n.getThen(), n.getElse()]) or
259+
result = e.(LoopExprCfgNode).getLoopBody() or
260+
result = e.(ReturnExprCfgNode).getExpr() or
261+
result = e.(BreakExprCfgNode).getExpr() or
262+
result = e.(BlockExprCfgNode).getTailExpr() or
263+
result = e.(MatchExprCfgNode).getArmExpr(_) or
264+
result.(BreakExprCfgNode).getTarget() = e
278265
}
279266

280267
module LocalFlow {
@@ -322,7 +309,7 @@ module RustDataFlow implements InputSig<Location> {
322309
class DataFlowExpr = ExprCfgNode;
323310

324311
/** Gets the node corresponding to `e`. */
325-
Node exprNode(DataFlowExpr e) { result.getCfgNode() = e }
312+
Node exprNode(DataFlowExpr e) { result.asExpr() = e }
326313

327314
final class DataFlowCall = DataFlowCallAlias;
328315

@@ -488,7 +475,7 @@ private module Cached {
488475
TSsaNode(SsaImpl::DataFlowIntegration::SsaNode node)
489476

490477
cached
491-
newtype TDataFlowCall = TNormalCall(CallCfgNode c)
478+
newtype TDataFlowCall = TNormalCall(CallExprCfgNode c)
492479

493480
cached
494481
newtype TOptionalContentSet =

0 commit comments

Comments
 (0)