diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll b/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll index b00a4047c1fb3..ecf688f03931e 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll @@ -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. */ @@ -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) } diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll index 386dd92d498bc..5586368a7d619 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll @@ -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 { } diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImplSpecific.qll b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImplSpecific.qll index 854bbcc7d73f8..9a6f615dab429 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImplSpecific.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImplSpecific.qll @@ -11,11 +11,11 @@ module CfgInput implements InputSig { 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; diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll b/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll index 255ac8c796555..6a58482348a69 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll @@ -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. */