Skip to content

Commit

Permalink
Rust: Use nodes from CfgNodes.qll in DataFlowImpl.qll
Browse files Browse the repository at this point in the history
  • Loading branch information
hvitved committed Nov 7, 2024
1 parent b9e5084 commit ebe8882
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 50 deletions.
124 changes: 124 additions & 0 deletions rust/ql/lib/codeql/rust/controlflow/CfgNodes.qll
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,127 @@ class AstCfgNode extends CfgNode {

AstCfgNode() { node = this.getAstNode() }
}

/**
* An assignment expression, for example
*
* ```rust
* x = y;
* ```
*/
final class AssignmentExprCfgNode extends BinaryExprCfgNode {
AssignmentExpr a;

AssignmentExprCfgNode() { a = this.getBinaryExpr() }

/** Gets the underlying `AssignmentExpr`. */
AssignmentExpr getAssignmentExpr() { result = a }
}

/**
* A match expression. For example:
* ```rust
* match x {
* Option::Some(y) => y,
* Option::None => 0,
* }
* ```
* ```rust
* match x {
* Some(y) if y != 0 => 1 / y,
* _ => 0,
* }
* ```
*/
final class MatchExprCfgNode extends Nodes::MatchExprCfgNode {
private MatchExpr node;

MatchExprCfgNode() { node = this.getMatchExpr() }

/**
* Gets the pattern of the `i`th match arm, if it exists.
*/
PatCfgNode getArmPat(int i) {
any(ChildMapping mapping).hasCfgChild(node, node.getArm(i).getPat(), this, result)
}

/**
* Gets the guard of the `i`th match arm, if it exists.
*/
ExprCfgNode getArmGuard(int i) {
any(ChildMapping mapping)
.hasCfgChild(node, node.getArm(i).getGuard().getCondition(), this, result)
}

/**
* Gets the expression of the `i`th match arm, if it exists.
*/
ExprCfgNode getArmExpr(int i) {
any(ChildMapping mapping).hasCfgChild(node, node.getArm(i).getExpr(), this, result)
}
}

/**
* A block expression. For example:
* ```rust
* {
* let x = 42;
* }
* ```
* ```rust
* 'label: {
* let x = 42;
* x
* }
* ```
*/
final class BlockExprCfgNode extends Nodes::BlockExprCfgNode {
private BlockExprChildMapping node;

BlockExprCfgNode() { node = this.getAstNode() }

/**
* Gets the tail expression of this block, if it exists.
*/
ExprCfgNode getTailExpr() {
any(ChildMapping mapping).hasCfgChild(node, node.getStmtList().getTailExpr(), this, result)
}
}

/**
* A break expression. For example:
* ```rust
* loop {
* if not_ready() {
* break;
* }
* }
* ```
* ```rust
* let x = 'label: loop {
* if done() {
* break 'label 42;
* }
* };
* ```
* ```rust
* let x = 'label: {
* if exit() {
* break 'label 42;
* }
* 0;
* };
* ```
*/
final class BreakExprCfgNode extends Nodes::BreakExprCfgNode {
/**
* Gets the target of this `break` expression.
*
* The target is either a `LoopExpr`, a `ForExpr`, a `WhileExpr`, or a
* `BlockExpr`.
*/
ExprCfgNode getTarget() {
any(ChildMapping mapping)
.hasCfgChild(this.getBreakExpr().getTarget(), this.getBreakExpr(), result, this)
}
}
18 changes: 18 additions & 0 deletions rust/ql/lib/codeql/rust/controlflow/internal/CfgNodes.qll
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,24 @@ private module CfgNodesInput implements InputSig<Location> {

import MakeCfgNodes<Location, CfgNodesInput>

class MatchExprChildMapping extends AstNodeWithChild, MatchExpr {
override predicate relevantChild(AstNode child) {
child = this.getAnArm().getPat()
or
child = this.getAnArm().getGuard().getCondition()
or
child = this.getAnArm().getExpr()
}
}

class BlockExprChildMapping extends AstNodeWithChild, BlockExpr {
override predicate relevantChild(AstNode child) { child = this.getStmtList().getTailExpr() }
}

class BreakExprTargetChildMapping extends AstNodeWithChild, Expr {
override predicate relevantChild(AstNode child) { child.(BreakExpr).getTarget() = this }
}

private class ChildMappingImpl extends ChildMapping {
pragma[nomagic]
predicate reachesBasicBlock(AstNode parent, AstNode child, CfgNode cfn, BasicBlock bb) {
Expand Down
9 changes: 5 additions & 4 deletions rust/ql/lib/codeql/rust/dataflow/Ssa.qll
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module Ssa {
private import rust
private import codeql.rust.controlflow.BasicBlocks
private import codeql.rust.controlflow.ControlFlowGraph
private import codeql.rust.controlflow.CfgNodes
private import codeql.rust.controlflow.internal.ControlFlowGraphImpl as CfgImpl
private import internal.SsaImpl as SsaImpl

Expand Down Expand Up @@ -221,11 +222,11 @@ module Ssa {
* end
* ```
*/
predicate assigns(CfgNode value) {
exists(AssignmentExpr ae, BasicBlock bb, int i |
predicate assigns(ExprCfgNode value) {
exists(AssignmentExprCfgNode ae, BasicBlock bb, int i |
this.definesAt(_, bb, i) and
ae.getLhs() = bb.getNode(i).getAstNode() and
value.getAstNode() = ae.getRhs()
ae.getLhs() = bb.getNode(i) and
value = ae.getRhs()
)
}

Expand Down
43 changes: 16 additions & 27 deletions rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ module Node {
/**
* Gets the expression that corresponds to this node, if any.
*/
Expr asExpr() { none() }
ExprCfgNode asExpr() { none() }

/**
* Gets the control flow node that corresponds to this data flow node.
Expand Down Expand Up @@ -67,11 +67,11 @@ module Node {

ExprNode() { this = TExprNode(n) }

override Location getLocation() { result = n.getExpr().getLocation() }
override Location getLocation() { result = n.getLocation() }

override string toString() { result = n.getExpr().toString() }
override string toString() { result = n.toString() }

override Expr asExpr() { result = n.getExpr() }
override ExprCfgNode asExpr() { result = n }

override CfgNode getCfgNode() { result = n }
}
Expand Down Expand Up @@ -152,7 +152,7 @@ module SsaFlow {
Impl::Node asNode(Node n) {
n = TSsaNode(result)
or
result.(Impl::ExprNode).getExpr() = n.(Node::ExprNode).getCfgNode()
result.(Impl::ExprNode).getExpr() = n.asExpr()
or
n = toParameterNode(result.(Impl::ParameterNode).getParameter())
}
Expand All @@ -166,29 +166,18 @@ module SsaFlow {
}
}

/**
* Holds for expressions `e` that evaluate to the value of any last (in
* evaluation order) subexpressions within it. E.g., expressions that propagate
* a values from a subexpression.
*
* For instance, the predicate holds for if expressions as `if b { e1 } else {
* e2 }` evalates to the value of one of the subexpressions `e1` or `e2`.
*/
private predicate propagatesValue(Expr e) {
e instanceof IfExpr or
e instanceof LoopExpr or
e instanceof ReturnExpr or
e instanceof BreakExpr or
e.(BlockExpr).getStmtList().hasTailExpr() or
e instanceof MatchExpr
}

/**
* Gets a node that may execute last in `n`, and which, when it executes last,
* will be the value of `n`.
*/
private ExprCfgNode getALastEvalNode(ExprCfgNode n) {
propagatesValue(n.getExpr()) and result.getASuccessor() = n
private ExprCfgNode getALastEvalNode(ExprCfgNode e) {
e = any(IfExprCfgNode n | result = [n.getThen(), n.getElse()]) or
result = e.(LoopExprCfgNode).getLoopBody() or
result = e.(ReturnExprCfgNode).getExpr() or
result = e.(BreakExprCfgNode).getExpr() or
result = e.(BlockExprCfgNode).getTailExpr() or
result = e.(MatchExprCfgNode).getArmExpr(_) or
result.(BreakExprCfgNode).getTarget() = e
}

module LocalFlow {
Expand Down Expand Up @@ -230,10 +219,10 @@ module RustDataFlow implements InputSig<Location> {
class DataFlowExpr = ExprCfgNode;

/** Gets the node corresponding to `e`. */
Node exprNode(DataFlowExpr e) { result.getCfgNode() = e }
Node exprNode(DataFlowExpr e) { result.asExpr() = e }

final class DataFlowCall extends TNormalCall {
private CallExpr c;
private CallExprCfgNode c;

DataFlowCall() { this = TNormalCall(c) }

Expand Down Expand Up @@ -400,7 +389,7 @@ private module Cached {
TSsaNode(SsaImpl::DataFlowIntegration::SsaNode node)

cached
newtype TDataFlowCall = TNormalCall(CallExpr c)
newtype TDataFlowCall = TNormalCall(CallExprCfgNode c)

cached
newtype TOptionalContentSet =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,25 +112,20 @@ uniqueCallEnclosingCallable
| unreachable.rs:2:5:2:18 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:6:5:6:24 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:10:5:10:20 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:19:9:19:22 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:21:9:21:22 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:25:9:25:22 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:27:9:27:22 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:30:13:30:26 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:33:13:33:26 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:37:8:37:13 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:39:9:39:22 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:42:8:42:13 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:43:9:43:22 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:46:9:46:22 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:48:5:48:18 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:50:8:50:13 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:51:17:51:22 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:54:13:54:26 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:56:17:56:30 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:58:13:58:26 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:62:8:62:13 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:67:5:67:18 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:71:8:71:13 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:72:9:72:22 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:73:16:73:25 | CallExpr | Call should have one enclosing callable but has 0. |
Expand All @@ -157,15 +152,13 @@ uniqueCallEnclosingCallable
| unreachable.rs:111:8:111:13 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:112:9:112:22 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:114:13:114:20 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:114:13:114:20 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:115:9:115:22 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:116:22:116:29 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:116:22:116:29 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:117:9:117:22 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:120:8:120:13 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:121:9:121:22 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:123:13:123:20 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:123:13:123:20 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:124:9:124:22 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:125:21:125:28 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:125:21:125:28 | CallExpr | Call should have one enclosing callable but has 0. |
Expand All @@ -174,36 +167,24 @@ uniqueCallEnclosingCallable
| unreachable.rs:136:13:136:26 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:139:5:139:18 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:141:11:141:24 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:149:5:149:18 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:154:9:154:22 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:156:9:156:22 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:159:8:159:13 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:160:15:160:20 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:161:13:161:26 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:165:13:165:26 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:169:13:169:26 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:171:9:171:22 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:175:12:175:17 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:177:13:177:26 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:179:9:179:22 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:183:12:183:17 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:185:13:185:26 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:188:5:188:18 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:189:5:189:18 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:190:5:190:18 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:198:22:198:41 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:199:9:199:22 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:202:9:202:22 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:205:5:205:18 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:207:16:207:29 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:209:9:209:22 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:212:9:212:22 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:215:5:215:18 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:219:19:219:38 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:220:9:220:22 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:224:5:224:18 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:226:13:226:32 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:228:9:228:22 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:232:5:232:18 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:236:8:236:13 | CallExpr | Call should have one enclosing callable but has 0. |
| unreachable.rs:237:9:237:22 | CallExpr | Call should have one enclosing callable but has 0. |
Expand Down

0 comments on commit ebe8882

Please sign in to comment.