Skip to content

Commit

Permalink
Rust: Add a few control flow tree classes
Browse files Browse the repository at this point in the history
  • Loading branch information
paldepind committed Sep 10, 2024
1 parent d72ee2f commit e1f83de
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 6 deletions.
14 changes: 12 additions & 2 deletions rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
private import rust
private import codeql.util.Boolean
private import codeql.rust.controlflow.ControlFlowGraph
private import rust
private import SuccessorType
private import SuccessorTypes

private newtype TCompletion =
TSimpleCompletion() or
TBooleanCompletion(boolean b) { b in [false, true] } or
TBooleanCompletion(Boolean b) or
TReturnCompletion()

/** A completion of a statement or an expression. */
Expand Down Expand Up @@ -82,3 +83,12 @@ class ReturnCompletion extends TReturnCompletion, Completion {

override string toString() { result = "return" }
}

/** Hold if `c` represents normal evaluation of a statement or an expression. */
predicate completionIsNormal(Completion c) { c instanceof NormalCompletion }

/** Hold if `c` represents simple and normal evaluation of a statement or an expression. */
predicate completionIsSimple(Completion c) { c instanceof SimpleCompletion }

/** Holds if `c` is a valid completion for `n`. */
predicate completionIsValidFor(Completion c, AstNode n) { c.isValidFor(n) }
Original file line number Diff line number Diff line change
@@ -1 +1,47 @@
private import rust
import ControlFlowGraphImplSpecific::CfgImpl
import Completion

class CallTree extends StandardPostOrderTree instanceof Call {
override ControlFlowTree getChildNode(int i) { result = super.getArg(i) }
}

class BinaryOpTree extends StandardPostOrderTree instanceof BinaryOp {
override ControlFlowTree getChildNode(int i) {
i = 0 and result = super.getLhs()
or
i = 1 and result = super.getRhs()
}
}

class IfTree extends PostOrderTree instanceof If {
override predicate first(AstNode node) { first(super.getCondition(), node) }

override predicate propagatesAbnormal(AstNode child) { none() }

override predicate succ(AstNode pred, AstNode succ, Completion c) {
// Edges from the condition to each branch
last(super.getCondition(), pred, c) and
(
first(super.getThen(), succ) and c.(BooleanCompletion).getValue() = true
or
first(super.getElse(), succ) and c.(BooleanCompletion).getValue() = false
)
or
// An edge from the then branch to the last node
last(super.getThen(), pred, c) and
succ = this and
completionIsSimple(c)
or
// An edge from the else branch to the last node
last(super.getElse(), pred, c) and
succ = this and
completionIsSimple(c)
}
}

class LetTree extends StandardPostOrderTree instanceof Let {
override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() }
}

class LiteralTree extends LeafTree instanceof Literal { }
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ module CfgInput implements InputSig<Rust::Location> {

class Completion = C::Completion;

predicate completionIsNormal(Completion c) { c instanceof C::NormalCompletion }
predicate completionIsNormal = C::completionIsNormal/1;

predicate completionIsSimple(Completion c) { c instanceof C::SimpleCompletion }
predicate completionIsSimple = C::completionIsSimple/1;

predicate completionIsValidFor(Completion c, AstNode e) { c.isValidFor(e) }
predicate completionIsValidFor = C::completionIsValidFor/2;

/** An AST node with an associated control-flow graph. */
class CfgScope = Scope::CfgScope;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
private import codeql.util.Boolean

cached
newtype TSuccessorType =
TSuccessorSuccessor() or
TBooleanSuccessor(boolean b) { b in [false, true] } or
TBooleanSuccessor(Boolean b) or
TReturnSuccessor()

/** The type of a control flow successor. */
Expand Down

0 comments on commit e1f83de

Please sign in to comment.