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 6, 2024
1 parent 15dcc79 commit e6aef8c
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 31 deletions.
79 changes: 79 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,82 @@ 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 MatchExprChildMapping node;

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

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

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

/**
* Gets the expression of the `i`th match arm, if it exists.
*/
ExprCfgNode getArmExpr(int i) { node.hasCfgChild(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() { node.hasCfgChild(node.getStmtList().getTailExpr(), this, result) }
}
14 changes: 14 additions & 0 deletions rust/ql/lib/codeql/rust/controlflow/internal/CfgNodes.qll
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,20 @@ private module CfgNodesInput implements InputSig<Location> {

import MakeCfgNodes<Location, CfgNodesInput>

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

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

private class ChildMappingImpl extends ChildMapping {
ChildMappingImpl() { exists(this) }

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
42 changes: 15 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,17 @@ 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(_)
}

module LocalFlow {
Expand Down Expand Up @@ -230,10 +218,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 @@ -398,7 +386,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

0 comments on commit e6aef8c

Please sign in to comment.