Rust: Use nodes from CfgNodes.qll in DataFlowImpl.qll

This commit is contained in:
Tom Hvitved
2024-11-19 15:01:32 +01:00
parent ca18005e44
commit e6887f982e
7 changed files with 49 additions and 48 deletions

View File

@@ -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
@@ -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()
)
}

View File

@@ -48,7 +48,7 @@ final class DataFlowCall extends TDataFlowCall {
MethodCallExprCfgNode asMethodCallExprCfgNode() { this = TMethodCall(result) }
ExprCfgNode asExprCfgNode() {
CallExprBaseCfgNode asExprCfgNode() {
result = this.asCallExprCfgNode() or result = this.asMethodCallExprCfgNode()
}
@@ -76,7 +76,7 @@ module Node {
/**
* Gets the expression that corresponds to this node, if any.
*/
Expr asExpr() { none() }
ExprCfgNode asExpr() { none() }
/** Gets the enclosing callable. */
DataFlowCallable getEnclosingCallable() { result = TCfgScope(this.getCfgScope()) }
@@ -115,13 +115,13 @@ module Node {
abstract class AstCfgFlowNode extends Node {
AstCfgNode n;
override CfgNode getCfgNode() { result = n }
final override CfgNode getCfgNode() { result = n }
override CfgScope getCfgScope() { result = n.getAstNode().getEnclosingCfgScope() }
final override CfgScope getCfgScope() { result = n.getAstNode().getEnclosingCfgScope() }
override Location getLocation() { result = n.getAstNode().getLocation() }
final override Location getLocation() { result = n.getAstNode().getLocation() }
override string toString() { result = n.getAstNode().toString() }
final override string toString() { result = n.getAstNode().toString() }
}
/**
@@ -137,7 +137,7 @@ module Node {
ExprNode() { this = TExprNode(n) }
override Expr asExpr() { result = n.getExpr() }
override ExprCfgNode asExpr() { result = n }
}
final class PatNode extends AstCfgFlowNode, TPatNode {
@@ -159,7 +159,7 @@ module Node {
ParameterNode() { this = TParameterNode(n) }
/** Gets the parameter in the AST that this node corresponds to. */
Param getParameter() { result = n.getParam() }
ParamCfgNode getParameter() { result = n }
}
final class ArgumentNode = NaNode;
@@ -197,7 +197,7 @@ module Node {
}
final private class ExprOutNode extends ExprNode, OutNode {
ExprOutNode() { this.asExpr() instanceof CallExpr }
ExprOutNode() { this.asExpr() instanceof CallExprCfgNode }
/** Gets the underlying call CFG node that includes this out node. */
override DataFlowCall getCall() { result.asExprCfgNode() = this.getCfgNode() }
@@ -228,13 +228,13 @@ final class Node = Node::Node;
module SsaFlow {
private module Impl = SsaImpl::DataFlowIntegration;
private Node::ParameterNode toParameterNode(Param p) { result.getParameter() = p }
private Node::ParameterNode toParameterNode(ParamCfgNode p) { result.getParameter() = p }
/** Converts a control flow node into an SSA control flow node. */
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())
}
@@ -248,29 +248,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 {
@@ -278,9 +267,9 @@ module LocalFlow {
predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) {
nodeFrom.getCfgNode() = getALastEvalNode(nodeTo.getCfgNode())
or
exists(LetStmt s |
nodeFrom.getCfgNode().getAstNode() = s.getInitializer() and
nodeTo.getCfgNode().getAstNode() = s.getPat()
exists(LetStmtCfgNode s |
nodeFrom.getCfgNode() = s.getInitializer() and
nodeTo.getCfgNode() = s.getPat()
)
or
// An edge from a pattern/expression to its corresponding SSA definition.
@@ -288,6 +277,11 @@ module LocalFlow {
nodeTo.(Node::SsaNode).getDefinitionExt().(Ssa::WriteDefinition).getControlFlowNode()
or
SsaFlow::localFlowStep(_, nodeFrom, nodeTo, _)
or
exists(AssignmentExprCfgNode a |
a.getRhs() = nodeFrom.getCfgNode() and
a.getLhs() = nodeTo.getCfgNode()
)
}
}
@@ -329,7 +323,7 @@ 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 = DataFlowCallAlias;

View File

@@ -474,14 +474,14 @@ private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInpu
/** Holds if SSA definition `def` assigns `value` to the underlying variable. */
predicate ssaDefAssigns(WriteDefinition def, Expr value) {
exists(BasicBlock bb, int i | def.definesAt(_, bb, i) and value = bb.getNode(i))
none() // handled in `DataFlowImpl.qll` instead
}
class Parameter = Param;
class Parameter = CfgNodes::ParamCfgNode;
/** Holds if SSA definition `def` initializes parameter `p` at function entry. */
predicate ssaDefInitializesParam(WriteDefinition def, Parameter p) {
exists(BasicBlock bb, int i | bb.getNode(i).getAstNode() = p and def.definesAt(_, bb, i))
none() // handled in `DataFlowImpl.qll` instead
}
class Guard extends CfgNodes::AstCfgNode {

View File

@@ -46,6 +46,7 @@
| main.rs:51:17:51:17 | 1 | main.rs:51:9:51:13 | i |
| main.rs:53:5:53:5 | [SSA] i | main.rs:54:10:54:10 | i |
| main.rs:53:5:53:5 | i | main.rs:53:5:53:5 | [SSA] i |
| main.rs:53:9:53:17 | CallExpr | main.rs:53:5:53:5 | i |
| main.rs:61:9:61:9 | [SSA] i | main.rs:62:11:62:11 | i |
| main.rs:61:9:61:9 | i | main.rs:61:9:61:9 | [SSA] i |
| main.rs:61:13:61:31 | CallExpr | main.rs:61:9:61:9 | i |
@@ -93,7 +94,6 @@
| main.rs:122:9:122:9 | [SSA] a | main.rs:128:5:128:5 | a |
| main.rs:122:9:122:9 | a | main.rs:122:9:122:9 | [SSA] a |
| main.rs:122:13:127:5 | BlockExpr | main.rs:122:9:122:9 | a |
| main.rs:123:12:123:12 | b | main.rs:123:9:125:9 | IfExpr |
| main.rs:124:13:124:26 | BreakExpr | main.rs:122:13:127:5 | BlockExpr |
| main.rs:124:26:124:26 | 1 | main.rs:124:13:124:26 | BreakExpr |
| main.rs:126:9:126:9 | 2 | main.rs:122:13:127:5 | BlockExpr |
@@ -103,7 +103,8 @@
| main.rs:132:9:132:9 | [SSA] a | main.rs:138:5:138:5 | a |
| main.rs:132:9:132:9 | a | main.rs:132:9:132:9 | [SSA] a |
| main.rs:132:13:137:5 | BlockExpr | main.rs:132:9:132:9 | a |
| main.rs:133:12:133:12 | b | main.rs:133:9:135:9 | IfExpr |
| main.rs:134:13:134:26 | BreakExpr | main.rs:132:13:137:5 | BlockExpr |
| main.rs:134:26:134:26 | 1 | main.rs:134:13:134:26 | BreakExpr |
| main.rs:136:9:136:22 | BreakExpr | main.rs:132:13:137:5 | BlockExpr |
| main.rs:136:22:136:22 | 2 | main.rs:136:9:136:22 | BreakExpr |
| main.rs:138:5:138:5 | a | main.rs:131:38:139:1 | BlockExpr |

View File

@@ -4,6 +4,7 @@ edges
| main.rs:24:13:24:21 | CallExpr : unit | main.rs:27:10:27:10 | c | provenance | |
| main.rs:31:13:31:21 | CallExpr : unit | main.rs:36:10:36:10 | b | provenance | |
| main.rs:45:15:45:23 | CallExpr : unit | main.rs:47:10:47:10 | b | provenance | |
| main.rs:53:9:53:17 | CallExpr : unit | main.rs:54:10:54:10 | i | provenance | |
nodes
| main.rs:15:10:15:18 | CallExpr | semmle.label | CallExpr |
| main.rs:19:13:19:21 | CallExpr : unit | semmle.label | CallExpr : unit |
@@ -14,6 +15,8 @@ nodes
| main.rs:36:10:36:10 | b | semmle.label | b |
| main.rs:45:15:45:23 | CallExpr : unit | semmle.label | CallExpr : unit |
| main.rs:47:10:47:10 | b | semmle.label | b |
| main.rs:53:9:53:17 | CallExpr : unit | semmle.label | CallExpr : unit |
| main.rs:54:10:54:10 | i | semmle.label | i |
subpaths
testFailures
#select
@@ -22,3 +25,4 @@ testFailures
| main.rs:27:10:27:10 | c | main.rs:24:13:24:21 | CallExpr : unit | main.rs:27:10:27:10 | c | $@ | main.rs:24:13:24:21 | CallExpr : unit | CallExpr : unit |
| main.rs:36:10:36:10 | b | main.rs:31:13:31:21 | CallExpr : unit | main.rs:36:10:36:10 | b | $@ | main.rs:31:13:31:21 | CallExpr : unit | CallExpr : unit |
| main.rs:47:10:47:10 | b | main.rs:45:15:45:23 | CallExpr : unit | main.rs:47:10:47:10 | b | $@ | main.rs:45:15:45:23 | CallExpr : unit | CallExpr : unit |
| main.rs:54:10:54:10 | i | main.rs:53:9:53:17 | CallExpr : unit | main.rs:54:10:54:10 | i | $@ | main.rs:53:9:53:17 | CallExpr : unit | CallExpr : unit |

View File

@@ -51,7 +51,7 @@ fn assignment() {
let mut i = 1;
sink(i);
i = source(2);
sink(i); // $ MISSING: hasValueFlow=2
sink(i); // $ hasValueFlow=2
}
// -----------------------------------------------------------------------------

View File

@@ -5,26 +5,27 @@
import rust
private import codeql.dataflow.test.InlineFlowTest
private import codeql.rust.controlflow.CfgNodes
private import codeql.rust.dataflow.DataFlow
private import codeql.rust.dataflow.internal.DataFlowImpl
private import codeql.rust.dataflow.internal.TaintTrackingImpl
private import internal.InlineExpectationsTestImpl as InlineExpectationsTestImpl
// Holds if the target expression of `call` is a path and the string representation of the path is `name`.
private predicate callTargetName(CallExpr call, string name) {
call.getExpr().(PathExpr).toString() = name
private predicate callTargetName(CallExprCfgNode call, string name) {
call.getExpr().(PathExprCfgNode).toString() = name
}
private module FlowTestImpl implements InputSig<Location, RustDataFlow> {
predicate defaultSource(DataFlow::Node source) { callTargetName(source.asExpr(), "source") }
predicate defaultSink(DataFlow::Node sink) {
any(CallExpr call | callTargetName(call, "sink")).getArgList().getAnArg() = sink.asExpr()
any(CallExprCfgNode call | callTargetName(call, "sink")).getArgument(_) = sink.asExpr()
}
private string getSourceArgString(DataFlow::Node src) {
defaultSource(src) and
result = src.asExpr().(CallExpr).getArgList().getArg(0).toString()
result = src.asExpr().(CallExprCfgNode).getArgument(0).toString()
}
bindingset[src, sink]