From 1f5e02f539efc89124d7b74405e2e2ed373443e4 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 21 Oct 2024 13:41:11 +0200 Subject: [PATCH 1/2] Rust: Move all expression CFG trees inside an `ExprTrees` module --- .../internal/ControlFlowGraphImpl.qll | 758 +++++++++--------- .../rust/controlflow/internal/Scope.qll | 2 +- 2 files changed, 384 insertions(+), 376 deletions(-) diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll index fdca529831d6..418927b7a1ba 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll @@ -65,148 +65,6 @@ private module CfgImpl = import CfgImpl -class ArrayExprTree extends StandardPostOrderTree, ArrayExpr { - override AstNode getChildNode(int i) { result = this.getExpr(i) } -} - -class AsmExprTree extends LeafTree instanceof AsmExpr { } - -class AwaitExprTree extends StandardPostOrderTree instanceof AwaitExpr { - override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() } -} - -// NOTE: `become` is a reserved but unused keyword. -class BecomeExprTree extends StandardPostOrderTree instanceof BecomeExpr { - override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() } -} - -class BinaryOpExprTree extends StandardPostOrderTree instanceof BinaryExpr { - BinaryOpExprTree() { not this instanceof BinaryLogicalOperation } - - override AstNode getChildNode(int i) { - i = 0 and result = super.getLhs() - or - i = 1 and result = super.getRhs() - } -} - -class LogicalOrTree extends PostOrderTree, LogicalOrExpr { - final override predicate propagatesAbnormal(AstNode child) { child = this.getAnOperand() } - - override predicate first(AstNode node) { first(this.getLhs(), node) } - - override predicate succ(AstNode pred, AstNode succ, Completion c) { - // Edge from lhs to rhs - last(this.getLhs(), pred, c) and - c.(BooleanCompletion).failed() and - first(this.getRhs(), succ) - or - // Edge from lhs to this - last(this.getLhs(), pred, c) and - c.(BooleanCompletion).succeeded() and - succ = this - or - // Edge from rhs to this - last(this.getRhs(), pred, c) and - succ = this and - completionIsNormal(c) - } -} - -class LogicalAndTree extends PostOrderTree, LogicalAndExpr { - final override predicate propagatesAbnormal(AstNode child) { child = this.getAnOperand() } - - override predicate first(AstNode node) { first(this.getLhs(), node) } - - override predicate succ(AstNode pred, AstNode succ, Completion c) { - // Edge from lhs to rhs - last(this.getLhs(), pred, c) and - c.(BooleanCompletion).succeeded() and - first(this.getRhs(), succ) - or - // Edge from lhs to this - last(this.getLhs(), pred, c) and - c.(BooleanCompletion).failed() and - succ = this - or - // Edge from rhs to this - last(this.getRhs(), pred, c) and - succ = this and - completionIsNormal(c) - } -} - -class BlockExprTree extends StandardPostOrderTree, BlockExpr { - override AstNode getChildNode(int i) { - result = this.getStmtList().getStatement(i) - or - i = this.getStmtList().getNumberOfStatements() and - result = this.getStmtList().getTailExpr() - } - - override predicate propagatesAbnormal(AstNode child) { child = this.getChildNode(_) } -} - -class BreakExprTree extends StandardPostOrderTree, BreakExpr { - override AstNode getChildNode(int i) { i = 0 and result = this.getExpr() } - - override predicate last(AstNode last, Completion c) { none() } - - override predicate succ(AstNode pred, AstNode succ, Completion c) { - super.succ(pred, succ, c) - or - pred = this and c.isValidFor(pred) and succ = this.getTarget() - } -} - -class CallExprTree extends StandardPostOrderTree instanceof CallExpr { - override AstNode getChildNode(int i) { - i = 0 and result = super.getExpr() - or - result = super.getArgList().getArg(i - 1) - } -} - -class CastExprTree extends StandardPostOrderTree instanceof CastExpr { - override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() } -} - -class ClosureExprTree extends StandardTree, ClosureExpr { - override predicate first(AstNode first) { first = this } - - override predicate last(AstNode last, Completion c) { - last = this and - completionIsValidFor(c, this) - } - - override predicate propagatesAbnormal(AstNode child) { none() } - - override AstNode getChildNode(int i) { - result = this.getParamList().getParam(i) - or - i = this.getParamList().getNumberOfParams() and - result = this.getBody() - } -} - -class ContinueExprTree extends LeafTree, ContinueExpr { - override predicate last(AstNode last, Completion c) { none() } - - override predicate succ(AstNode pred, AstNode succ, Completion c) { - pred = this and - c.isValidFor(pred) and - first(this.getTarget().(LoopingExprTree).getLoopContinue(), succ) - } -} - -class ExprStmtTree extends StandardPreOrderTree instanceof ExprStmt { - override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() } -} - -class FieldExprTree extends StandardPostOrderTree instanceof FieldExpr { - override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() } -} - class FunctionTree extends StandardTree, Function { override predicate first(AstNode first) { first = this } @@ -229,58 +87,6 @@ class ParamTree extends StandardPostOrderTree, Param { override AstNode getChildNode(int i) { i = 0 and result = this.getPat() } } -class IfExprTree extends PostOrderTree instanceof IfExpr { - override predicate first(AstNode node) { first(super.getCondition(), node) } - - override predicate propagatesAbnormal(AstNode child) { - child = [super.getCondition(), super.getThen(), super.getElse()] - } - - private ConditionalCompletion conditionCompletion(Completion c) { - if super.getCondition() instanceof LetExpr - then result = c.(MatchCompletion) - else result = c.(BooleanCompletion) - } - - override predicate succ(AstNode pred, AstNode succ, Completion c) { - // Edges from the condition to the branches - last(super.getCondition(), pred, c) and - ( - first(super.getThen(), succ) and this.conditionCompletion(c).succeeded() - or - first(super.getElse(), succ) and this.conditionCompletion(c).failed() - or - not super.hasElse() and succ = this and this.conditionCompletion(c).failed() - ) - or - // An edge from the then branch to the last node - last(super.getThen(), pred, c) and - succ = this and - completionIsNormal(c) - or - // An edge from the else branch to the last node - last(super.getElse(), pred, c) and - succ = this and - completionIsNormal(c) - } -} - -class FormatArgsExprTree extends StandardPostOrderTree, FormatArgsExpr { - override AstNode getChildNode(int i) { - i = -1 and result = this.getTemplate() - or - result = this.getArg(i).getExpr() - } -} - -class IndexExprTree extends StandardPostOrderTree instanceof IndexExpr { - override AstNode getChildNode(int i) { - i = 0 and result = super.getBase() - or - i = 1 and result = super.getIndex() - } -} - class ItemTree extends LeafTree, Item { ItemTree() { not this instanceof MacroCall and @@ -288,19 +94,6 @@ class ItemTree extends LeafTree, Item { } } -// `LetExpr` is a pre-order tree such that the pattern itself ends up -// dominating successors in the graph in the same way that patterns do in -// `match` expressions. -class LetExprTree extends StandardPreOrderTree, LetExpr { - override AstNode getChildNode(int i) { - i = 0 and - result = this.getExpr() - or - i = 1 and - result = this.getPat() - } -} - class LetStmtTree extends PreOrderTree, LetStmt { final override predicate propagatesAbnormal(AstNode child) { child = [this.getInitializer(), this.getLetElse().getBlockExpr()] @@ -332,97 +125,6 @@ class LetStmtTree extends PreOrderTree, LetStmt { } } -class LiteralExprTree extends LeafTree instanceof LiteralExpr { } - -abstract class LoopingExprTree extends PostOrderTree { - override predicate propagatesAbnormal(AstNode child) { child = this.getLoopBody() } - - abstract BlockExpr getLoopBody(); - - /** - * Gets the node to execute when continuing the loop; either after - * executing the last node in the body or after an explicit `continue`. - */ - abstract AstNode getLoopContinue(); - - override predicate succ(AstNode pred, AstNode succ, Completion c) { - // Edge back to the start for final expression and continue expressions - last(this.getLoopBody(), pred, c) and - completionIsNormal(c) and - first(this.getLoopContinue(), succ) - } -} - -class LoopExprTree extends LoopingExprTree instanceof LoopExpr { - override BlockExpr getLoopBody() { result = LoopExpr.super.getLoopBody() } - - override AstNode getLoopContinue() { result = this.getLoopBody() } - - override predicate first(AstNode node) { first(this.getLoopBody(), node) } -} - -class WhileExprTree extends LoopingExprTree instanceof WhileExpr { - override BlockExpr getLoopBody() { result = WhileExpr.super.getLoopBody() } - - override AstNode getLoopContinue() { result = super.getCondition() } - - override predicate propagatesAbnormal(AstNode child) { - super.propagatesAbnormal(child) - or - child = super.getCondition() - } - - override predicate first(AstNode node) { first(super.getCondition(), node) } - - private ConditionalCompletion conditionCompletion(Completion c) { - if super.getCondition() instanceof LetExpr - then result = c.(MatchCompletion) - else result = c.(BooleanCompletion) - } - - override predicate succ(AstNode pred, AstNode succ, Completion c) { - super.succ(pred, succ, c) - or - last(super.getCondition(), pred, c) and - this.conditionCompletion(c).succeeded() and - first(this.getLoopBody(), succ) - or - last(super.getCondition(), pred, c) and - this.conditionCompletion(c).failed() and - succ = this - } -} - -class ForExprTree extends LoopingExprTree instanceof ForExpr { - override BlockExpr getLoopBody() { result = ForExpr.super.getLoopBody() } - - override AstNode getLoopContinue() { result = super.getPat() } - - override predicate propagatesAbnormal(AstNode child) { - super.propagatesAbnormal(child) - or - child = super.getIterable() - } - - override predicate first(AstNode node) { first(super.getIterable(), node) } - - override predicate succ(AstNode pred, AstNode succ, Completion c) { - super.succ(pred, succ, c) - or - last(super.getIterable(), pred, c) and - first(super.getPat(), succ) and - completionIsNormal(c) - or - last(super.getPat(), pred, c) and - c.(MatchCompletion).succeeded() and - first(this.getLoopBody(), succ) - or - last(super.getPat(), pred, c) and - c.(MatchCompletion).failed() and - succ = this - } -} - class MacroCallTree extends ControlFlowTree, MacroCall { override predicate first(AstNode first) { first(this.getExpanded(), first) @@ -443,10 +145,6 @@ class MacroCallTree extends ControlFlowTree, MacroCall { override predicate propagatesAbnormal(AstNode child) { child = this.getExpanded() } } -class MacroExprTree extends StandardPostOrderTree, MacroExpr { - override AstNode getChildNode(int i) { i = 0 and result = this.getMacroCall() } -} - class MacroStmtsTree extends StandardPreOrderTree, MacroStmts { override AstNode getChildNode(int i) { result = this.getStatement(i) @@ -486,44 +184,6 @@ class MatchArmTree extends ControlFlowTree, MatchArm { } } -class MatchExprTree extends PostOrderTree instanceof MatchExpr { - override predicate propagatesAbnormal(AstNode child) { - child = [super.getExpr(), super.getAnArm().getExpr()] - } - - override predicate first(AstNode node) { first(super.getExpr(), node) } - - override predicate succ(AstNode pred, AstNode succ, Completion c) { - // Edge from the scrutinee to the first arm or to the match expression if no arms. - last(super.getExpr(), pred, c) and - ( - first(super.getArm(0).getPat(), succ) - or - not exists(super.getArm(0)) and succ = this - ) and - completionIsNormal(c) - or - // Edge from a failed pattern or guard in one arm to the beginning of the next arm. - exists(int i | - ( - last(super.getArm(i).getPat(), pred, c) or - last(super.getArm(i).getGuard().getCondition(), pred, c) - ) and - first(super.getArm(i + 1), succ) and - c.(ConditionalCompletion).failed() - ) - or - // Edge from the end of each arm to the match expression. - last(super.getArm(_).getExpr(), pred, c) and succ = this and completionIsNormal(c) - } -} - -class MethodCallExprTree extends StandardPostOrderTree, MethodCallExpr { - override AstNode getChildNode(int i) { - if i = 0 then result = this.getReceiver() else result = this.getArgList().getArg(i - 1) - } -} - class NameTree extends LeafTree, Name { } class NameRefTree extends LeafTree, NameRef { } @@ -544,54 +204,402 @@ class ParenExprTree extends ControlFlowTree, ParenExpr { override predicate succ(AstNode pred, AstNode succ, Completion c) { none() } } -class PathExprTree extends LeafTree instanceof PathExpr { } +class TypeRefTree extends LeafTree instanceof TypeRef { } -class PrefixExprTree extends StandardPostOrderTree instanceof PrefixExpr { - override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() } -} +/** + * Provides `ControlFlowTree`s for expressions. + * + * Since expressions construct values, they are modeled in post-order, except for + * `LetExpr`s. + */ +module ExprTrees { + class ArrayExprTree extends StandardPostOrderTree, ArrayExpr { + override AstNode getChildNode(int i) { result = this.getExpr(i) } + } -class RangeExprTree extends StandardPostOrderTree instanceof RangeExpr { - override AstNode getChildNode(int i) { - i = 0 and result = super.getStart() - or - i = 1 and result = super.getEnd() + class AsmExprTree extends LeafTree instanceof AsmExpr { } + + class AwaitExprTree extends StandardPostOrderTree instanceof AwaitExpr { + override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() } } -} -class RecordExprTree extends StandardPostOrderTree instanceof RecordExpr { - override AstNode getChildNode(int i) { - result = super.getRecordExprFieldList().getField(i).getExpr() + // NOTE: `become` is a reserved but unused keyword. + class BecomeExprTree extends StandardPostOrderTree instanceof BecomeExpr { + override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() } } -} -class RefExprTree extends StandardPostOrderTree instanceof RefExpr { - override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() } -} + class BinaryOpExprTree extends StandardPostOrderTree instanceof BinaryExpr { + BinaryOpExprTree() { not this instanceof BinaryLogicalOperation } -class ReturnExprTree extends StandardPostOrderTree instanceof ReturnExpr { - override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() } -} + override AstNode getChildNode(int i) { + i = 0 and result = super.getLhs() + or + i = 1 and result = super.getRhs() + } + } -class TryExprTree extends StandardPostOrderTree instanceof TryExpr { - override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() } -} + class LogicalOrTree extends PostOrderTree, LogicalOrExpr { + final override predicate propagatesAbnormal(AstNode child) { child = this.getAnOperand() } -class TupleExprTree extends StandardPostOrderTree instanceof TupleExpr { - override AstNode getChildNode(int i) { result = super.getField(i) } -} + override predicate first(AstNode node) { first(this.getLhs(), node) } -class TypeRefTree extends LeafTree instanceof TypeRef { } + override predicate succ(AstNode pred, AstNode succ, Completion c) { + // Edge from lhs to rhs + last(this.getLhs(), pred, c) and + c.(BooleanCompletion).failed() and + first(this.getRhs(), succ) + or + // Edge from lhs to this + last(this.getLhs(), pred, c) and + c.(BooleanCompletion).succeeded() and + succ = this + or + // Edge from rhs to this + last(this.getRhs(), pred, c) and + succ = this and + completionIsNormal(c) + } + } -class UnderscoreExprTree extends LeafTree instanceof UnderscoreExpr { } + class LogicalAndTree extends PostOrderTree, LogicalAndExpr { + final override predicate propagatesAbnormal(AstNode child) { child = this.getAnOperand() } -// NOTE: `yield` is a reserved but unused keyword. -class YieldExprTree extends StandardPostOrderTree instanceof YieldExpr { - override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() } -} + override predicate first(AstNode node) { first(this.getLhs(), node) } + + override predicate succ(AstNode pred, AstNode succ, Completion c) { + // Edge from lhs to rhs + last(this.getLhs(), pred, c) and + c.(BooleanCompletion).succeeded() and + first(this.getRhs(), succ) + or + // Edge from lhs to this + last(this.getLhs(), pred, c) and + c.(BooleanCompletion).failed() and + succ = this + or + // Edge from rhs to this + last(this.getRhs(), pred, c) and + succ = this and + completionIsNormal(c) + } + } + + class BlockExprTree extends StandardPostOrderTree, BlockExpr { + override AstNode getChildNode(int i) { + result = this.getStmtList().getStatement(i) + or + i = this.getStmtList().getNumberOfStatements() and + result = this.getStmtList().getTailExpr() + } + + override predicate propagatesAbnormal(AstNode child) { child = this.getChildNode(_) } + } + + class BreakExprTree extends StandardPostOrderTree, BreakExpr { + override AstNode getChildNode(int i) { i = 0 and result = this.getExpr() } + + override predicate last(AstNode last, Completion c) { none() } + + override predicate succ(AstNode pred, AstNode succ, Completion c) { + super.succ(pred, succ, c) + or + pred = this and c.isValidFor(pred) and succ = this.getTarget() + } + } + + class CallExprTree extends StandardPostOrderTree instanceof CallExpr { + override AstNode getChildNode(int i) { + i = 0 and result = super.getExpr() + or + result = super.getArgList().getArg(i - 1) + } + } + + class CastExprTree extends StandardPostOrderTree instanceof CastExpr { + override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() } + } + + class ClosureExprTree extends StandardTree, ClosureExpr { + override predicate first(AstNode first) { first = this } + + override predicate last(AstNode last, Completion c) { + last = this and + completionIsValidFor(c, this) + } + + override predicate propagatesAbnormal(AstNode child) { none() } + + override AstNode getChildNode(int i) { + result = this.getParamList().getParam(i) + or + i = this.getParamList().getNumberOfParams() and + result = this.getBody() + } + } + + class ContinueExprTree extends LeafTree, ContinueExpr { + override predicate last(AstNode last, Completion c) { none() } + + override predicate succ(AstNode pred, AstNode succ, Completion c) { + pred = this and + c.isValidFor(pred) and + first(this.getTarget().(LoopingExprTree).getLoopContinue(), succ) + } + } + + class ExprStmtTree extends StandardPreOrderTree instanceof ExprStmt { + override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() } + } + + class FieldExprTree extends StandardPostOrderTree instanceof FieldExpr { + override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() } + } + + class IfExprTree extends PostOrderTree instanceof IfExpr { + override predicate first(AstNode node) { first(super.getCondition(), node) } + + override predicate propagatesAbnormal(AstNode child) { + child = [super.getCondition(), super.getThen(), super.getElse()] + } + + private ConditionalCompletion conditionCompletion(Completion c) { + if super.getCondition() instanceof LetExpr + then result = c.(MatchCompletion) + else result = c.(BooleanCompletion) + } + + override predicate succ(AstNode pred, AstNode succ, Completion c) { + // Edges from the condition to the branches + last(super.getCondition(), pred, c) and + ( + first(super.getThen(), succ) and this.conditionCompletion(c).succeeded() + or + first(super.getElse(), succ) and this.conditionCompletion(c).failed() + or + not super.hasElse() and succ = this and this.conditionCompletion(c).failed() + ) + or + // An edge from the then branch to the last node + last(super.getThen(), pred, c) and + succ = this and + completionIsNormal(c) + or + // An edge from the else branch to the last node + last(super.getElse(), pred, c) and + succ = this and + completionIsNormal(c) + } + } + + class FormatArgsExprTree extends StandardPostOrderTree, FormatArgsExpr { + override AstNode getChildNode(int i) { + i = -1 and result = this.getTemplate() + or + result = this.getArg(i).getExpr() + } + } + + class IndexExprTree extends StandardPostOrderTree instanceof IndexExpr { + override AstNode getChildNode(int i) { + i = 0 and result = super.getBase() + or + i = 1 and result = super.getIndex() + } + } + + // `LetExpr` is a pre-order tree such that the pattern itself ends up + // dominating successors in the graph in the same way that patterns do in + // `match` expressions. + class LetExprTree extends StandardPreOrderTree, LetExpr { + override AstNode getChildNode(int i) { + i = 0 and + result = this.getExpr() + or + i = 1 and + result = this.getPat() + } + } + + class LiteralExprTree extends LeafTree instanceof LiteralExpr { } + + abstract class LoopingExprTree extends PostOrderTree { + override predicate propagatesAbnormal(AstNode child) { child = this.getLoopBody() } + + abstract BlockExpr getLoopBody(); + + /** + * Gets the node to execute when continuing the loop; either after + * executing the last node in the body or after an explicit `continue`. + */ + abstract AstNode getLoopContinue(); + + override predicate succ(AstNode pred, AstNode succ, Completion c) { + // Edge back to the start for final expression and continue expressions + last(this.getLoopBody(), pred, c) and + completionIsNormal(c) and + first(this.getLoopContinue(), succ) + } + } + + class LoopExprTree extends LoopingExprTree instanceof LoopExpr { + override BlockExpr getLoopBody() { result = LoopExpr.super.getLoopBody() } + + override AstNode getLoopContinue() { result = this.getLoopBody() } + + override predicate first(AstNode node) { first(this.getLoopBody(), node) } + } + + class WhileExprTree extends LoopingExprTree instanceof WhileExpr { + override BlockExpr getLoopBody() { result = WhileExpr.super.getLoopBody() } + + override AstNode getLoopContinue() { result = super.getCondition() } + + override predicate propagatesAbnormal(AstNode child) { + super.propagatesAbnormal(child) + or + child = super.getCondition() + } + + override predicate first(AstNode node) { first(super.getCondition(), node) } + + private ConditionalCompletion conditionCompletion(Completion c) { + if super.getCondition() instanceof LetExpr + then result = c.(MatchCompletion) + else result = c.(BooleanCompletion) + } + + override predicate succ(AstNode pred, AstNode succ, Completion c) { + super.succ(pred, succ, c) + or + last(super.getCondition(), pred, c) and + this.conditionCompletion(c).succeeded() and + first(this.getLoopBody(), succ) + or + last(super.getCondition(), pred, c) and + this.conditionCompletion(c).failed() and + succ = this + } + } + + class ForExprTree extends LoopingExprTree instanceof ForExpr { + override BlockExpr getLoopBody() { result = ForExpr.super.getLoopBody() } + + override AstNode getLoopContinue() { result = super.getPat() } + + override predicate propagatesAbnormal(AstNode child) { + super.propagatesAbnormal(child) + or + child = super.getIterable() + } + + override predicate first(AstNode node) { first(super.getIterable(), node) } + + override predicate succ(AstNode pred, AstNode succ, Completion c) { + super.succ(pred, succ, c) + or + last(super.getIterable(), pred, c) and + first(super.getPat(), succ) and + completionIsNormal(c) + or + last(super.getPat(), pred, c) and + c.(MatchCompletion).succeeded() and + first(this.getLoopBody(), succ) + or + last(super.getPat(), pred, c) and + c.(MatchCompletion).failed() and + succ = this + } + } + + class MacroExprTree extends StandardPostOrderTree, MacroExpr { + override AstNode getChildNode(int i) { i = 0 and result = this.getMacroCall() } + } + + class MatchExprTree extends PostOrderTree instanceof MatchExpr { + override predicate propagatesAbnormal(AstNode child) { + child = [super.getExpr(), super.getAnArm().getExpr()] + } + + override predicate first(AstNode node) { first(super.getExpr(), node) } + + override predicate succ(AstNode pred, AstNode succ, Completion c) { + // Edge from the scrutinee to the first arm or to the match expression if no arms. + last(super.getExpr(), pred, c) and + ( + first(super.getArm(0).getPat(), succ) + or + not exists(super.getArm(0)) and succ = this + ) and + completionIsNormal(c) + or + // Edge from a failed pattern or guard in one arm to the beginning of the next arm. + exists(int i | + ( + last(super.getArm(i).getPat(), pred, c) or + last(super.getArm(i).getGuard().getCondition(), pred, c) + ) and + first(super.getArm(i + 1), succ) and + c.(ConditionalCompletion).failed() + ) + or + // Edge from the end of each arm to the match expression. + last(super.getArm(_).getExpr(), pred, c) and succ = this and completionIsNormal(c) + } + } + + class MethodCallExprTree extends StandardPostOrderTree, MethodCallExpr { + override AstNode getChildNode(int i) { + if i = 0 then result = this.getReceiver() else result = this.getArgList().getArg(i - 1) + } + } + + class PathExprTree extends LeafTree instanceof PathExpr { } -// NOTE: `yeet` is experimental and not a part of Rust. -class YeetExprTree extends StandardPostOrderTree instanceof YeetExpr { - override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() } + class PrefixExprTree extends StandardPostOrderTree instanceof PrefixExpr { + override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() } + } + + class RangeExprTree extends StandardPostOrderTree instanceof RangeExpr { + override AstNode getChildNode(int i) { + i = 0 and result = super.getStart() + or + i = 1 and result = super.getEnd() + } + } + + class RecordExprTree extends StandardPostOrderTree instanceof RecordExpr { + override AstNode getChildNode(int i) { + result = super.getRecordExprFieldList().getField(i).getExpr() + } + } + + class RefExprTree extends StandardPostOrderTree instanceof RefExpr { + override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() } + } + + class ReturnExprTree extends StandardPostOrderTree instanceof ReturnExpr { + override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() } + } + + class TryExprTree extends StandardPostOrderTree instanceof TryExpr { + override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() } + } + + class TupleExprTree extends StandardPostOrderTree instanceof TupleExpr { + override AstNode getChildNode(int i) { result = super.getField(i) } + } + + class UnderscoreExprTree extends LeafTree instanceof UnderscoreExpr { } + + // NOTE: `yield` is a reserved but unused keyword. + class YieldExprTree extends StandardPostOrderTree instanceof YieldExpr { + override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() } + } + + // NOTE: `yeet` is experimental and not a part of Rust. + class YeetExprTree extends StandardPostOrderTree instanceof YeetExpr { + override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() } + } } /** diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/Scope.qll b/rust/ql/lib/codeql/rust/controlflow/internal/Scope.qll index d85539ad9261..8a49ab975632 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/Scope.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/Scope.qll @@ -27,7 +27,7 @@ final class FunctionScope extends CfgScope, Function { final class ClosureScope extends CfgScope, ClosureExpr { override predicate scopeFirst(AstNode node) { - first(this.(ClosureExprTree).getFirstChildNode(), node) + first(this.(ExprTrees::ClosureExprTree).getFirstChildNode(), node) } override predicate scopeLast(AstNode node, Completion c) { last(this.getBody(), node, c) } From a6a68ef8be2cd6c66d3c7b3092e0b67bb1eb3099 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 21 Oct 2024 14:43:22 +0200 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Simon Friis Vindum --- .../codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll index 418927b7a1ba..688f0d1e96a9 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll @@ -238,7 +238,7 @@ module ExprTrees { } } - class LogicalOrTree extends PostOrderTree, LogicalOrExpr { + class LogicalOrExprTree extends PostOrderTree, LogicalOrExpr { final override predicate propagatesAbnormal(AstNode child) { child = this.getAnOperand() } override predicate first(AstNode node) { first(this.getLhs(), node) } @@ -261,7 +261,7 @@ module ExprTrees { } } - class LogicalAndTree extends PostOrderTree, LogicalAndExpr { + class LogicalAndExprTree extends PostOrderTree, LogicalAndExpr { final override predicate propagatesAbnormal(AstNode child) { child = this.getAnOperand() } override predicate first(AstNode node) { first(this.getLhs(), node) }