Skip to content

Commit 5e4ce8f

Browse files
authored
Merge pull request github#17800 from paldepind/rust-cfg-fixes
Rust: Various fixes to the CFG construction
2 parents e149071 + a1ebf98 commit 5e4ce8f

File tree

7 files changed

+986
-857
lines changed

7 files changed

+986
-857
lines changed

rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,7 @@ class SimpleCompletion extends NormalCompletion, TSimpleCompletion {
3636

3737
// `SimpleCompletion` is the "default" completion type, thus it is valid for
3838
// any node where there isn't another more specific completion type.
39-
override predicate isValidFor(AstNode e) {
40-
not any(Completion c).isValidForSpecific(e)
41-
or
42-
// A `?` expression can both proceed normally or cause an early return, so
43-
// we explicitly allow the former here.
44-
e instanceof TryExpr
45-
}
39+
override predicate isValidFor(AstNode e) { not any(Completion c).isValidForSpecific(e) }
4640

4741
override string toString() { result = "simple" }
4842
}
@@ -177,6 +171,8 @@ class MatchCompletion extends TMatchCompletion, ConditionalCompletion {
177171
override predicate isValidForSpecific(AstNode e) {
178172
e instanceof Pat and
179173
if isExhaustiveMatch(e) then value = true else any()
174+
or
175+
e instanceof TryExpr and value = true
180176
}
181177

182178
override MatchSuccessor getAMatchingSuccessorType() { result.getValue() = value }

rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll

Lines changed: 41 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -147,23 +147,15 @@ class BlockExprTree extends StandardPostOrderTree, BlockExpr {
147147
override predicate propagatesAbnormal(AstNode child) { child = this.getChildNode(_) }
148148
}
149149

150-
class BreakExprTree extends PostOrderTree, BreakExpr {
151-
override predicate propagatesAbnormal(AstNode child) { child = this.getExpr() }
152-
153-
override predicate first(AstNode node) {
154-
first(this.getExpr(), node)
155-
or
156-
not this.hasExpr() and node = this
157-
}
150+
class BreakExprTree extends StandardPostOrderTree, BreakExpr {
151+
override AstNode getChildNode(int i) { i = 0 and result = this.getExpr() }
158152

159153
override predicate last(AstNode last, Completion c) { none() }
160154

161155
override predicate succ(AstNode pred, AstNode succ, Completion c) {
162-
last(super.getExpr(), pred, c) and succ = this
156+
super.succ(pred, succ, c)
163157
or
164-
pred = this and
165-
c.isValidFor(pred) and
166-
succ = this.getTarget()
158+
pred = this and c.isValidFor(pred) and succ = this.getTarget()
167159
}
168160
}
169161

@@ -325,7 +317,7 @@ class LetStmtTree extends PreOrderTree, LetStmt {
325317
not this.hasInitializer()
326318
or
327319
// Edge from end of initializer to pattern.
328-
last(this.getInitializer(), pred, c) and first(this.getPat(), succ)
320+
last(this.getInitializer(), pred, c) and first(this.getPat(), succ) and completionIsNormal(c)
329321
or
330322
// Edge from failed pattern to `else` branch.
331323
last(this.getPat(), pred, c) and
@@ -502,14 +494,21 @@ class MatchExprTree extends PostOrderTree instanceof MatchExpr {
502494
override predicate first(AstNode node) { first(super.getExpr(), node) }
503495

504496
override predicate succ(AstNode pred, AstNode succ, Completion c) {
505-
// Edge from the scrutinee to the first arm.
497+
// Edge from the scrutinee to the first arm or to the match expression if no arms.
506498
last(super.getExpr(), pred, c) and
507-
first(super.getArm(0).getPat(), succ) and
499+
(
500+
first(super.getArm(0).getPat(), succ)
501+
or
502+
not exists(super.getArm(0)) and succ = this
503+
) and
508504
completionIsNormal(c)
509505
or
510-
// Edge from a failed match/guard in one arm to the beginning of the next arm.
506+
// Edge from a failed pattern or guard in one arm to the beginning of the next arm.
511507
exists(int i |
512-
last(super.getArm(i), pred, c) and
508+
(
509+
last(super.getArm(i).getPat(), pred, c) or
510+
last(super.getArm(i).getGuard().getCondition(), pred, c)
511+
) and
513512
first(super.getArm(i + 1), succ) and
514513
c.(ConditionalCompletion).failed()
515514
)
@@ -521,10 +520,7 @@ class MatchExprTree extends PostOrderTree instanceof MatchExpr {
521520

522521
class MethodCallExprTree extends StandardPostOrderTree, MethodCallExpr {
523522
override AstNode getChildNode(int i) {
524-
i = 0 and
525-
result = this.getReceiver()
526-
or
527-
result = this.getArgList().getArg(i + 1)
523+
if i = 0 then result = this.getReceiver() else result = this.getArgList().getArg(i - 1)
528524
}
529525
}
530526

@@ -605,89 +601,48 @@ class YeetExprTree extends StandardPostOrderTree instanceof YeetExpr {
605601
* `OrPat`s and `IdentPat`s.
606602
*/
607603
module PatternTrees {
608-
abstract class PreOrderPatTree extends PreOrderTree {
604+
abstract class StandardPatTree extends StandardTree {
609605
abstract Pat getPat(int i);
610606

611-
private Pat getPatRanked(int i) {
607+
Pat getPatRanked(int i) {
612608
result = rank[i + 1](Pat pat, int j | pat = this.getPat(j) | pat order by j)
613609
}
614610

615-
override predicate propagatesAbnormal(AstNode child) { child = this.getPatRanked(_) }
611+
override AstNode getChildNode(int i) { result = this.getPat(i) }
612+
}
616613

614+
abstract class PreOrderPatTree extends StandardPatTree, StandardPreOrderTree {
617615
override predicate succ(AstNode pred, AstNode succ, Completion c) {
618-
pred = this and
619-
completionIsValidFor(c, this) and
620616
c.(MatchCompletion).succeeded() and
621-
first(this.getPatRanked(0), succ)
622-
or
623-
exists(int i | last(this.getPatRanked(i), pred, c) |
624-
// Edge from successful pattern to the next
625-
c.(MatchCompletion).succeeded() and
626-
first(this.getPatRanked(i + 1), succ)
617+
(
618+
StandardPatTree.super.succ(pred, succ, c)
619+
or
620+
pred = this and first(this.getFirstChildNode(), succ) and completionIsValidFor(c, this)
627621
)
628622
}
629623

630624
override predicate last(AstNode node, Completion c) {
631-
node = this and
632-
completionIsValidFor(c, this) and
633-
c.(MatchCompletion).failed()
625+
super.last(node, c)
634626
or
635-
exists(int i | last(this.getPatRanked(i), node, c) |
636-
c.(MatchCompletion).failed()
637-
or
638-
not exists(this.getPatRanked(i + 1)) and
639-
completionIsNormal(c)
640-
)
627+
c.(MatchCompletion).failed() and
628+
completionIsValidFor(c, this) and
629+
(node = this or last(this.getPatRanked(_), node, c))
641630
}
642631
}
643632

644-
abstract class PostOrderPatTree extends PostOrderTree {
645-
abstract Pat getPat(int i);
646-
647-
private Pat getPatRanked(int i) {
648-
result = rank[i + 1](Pat pat, int j | pat = this.getPat(j) | pat order by j)
649-
}
650-
651-
override predicate propagatesAbnormal(AstNode child) { child = this.getPatRanked(_) }
652-
653-
override predicate first(AstNode node) {
654-
first(this.getPat(0), node)
655-
or
656-
not exists(this.getPat(_)) and
657-
node = this
658-
}
659-
660-
override predicate succ(AstNode pred, AstNode succ, Completion c) {
661-
exists(int i | last(this.getPat(i), pred, c) |
662-
// Edge from unsuccessful pattern to the next
663-
c.(MatchCompletion).failed() and
664-
first(this.getPat(i + 1), succ)
665-
or
666-
// Edge from successful pattern to this
667-
c.(MatchCompletion).succeeded() and
668-
succ = this
669-
or
670-
// Edge from last pattern to this
671-
not exists(this.getPat(i + 1)) and
672-
succ = this and
673-
completionIsNormal(c)
674-
)
675-
}
676-
}
633+
abstract class PostOrderPatTree extends StandardPatTree, StandardPostOrderTree { }
677634

678635
class IdentPatTree extends PostOrderPatTree, IdentPat {
679636
override Pat getPat(int i) { i = 0 and result = this.getPat() }
680637

681638
override predicate last(AstNode node, Completion c) {
682639
super.last(node, c)
683640
or
684-
last(this.getPat(), node, c) and
685-
c.(MatchCompletion).failed()
641+
last(this.getPat(), node, c) and c.(MatchCompletion).failed()
686642
}
687643

688644
override predicate succ(AstNode pred, AstNode succ, Completion c) {
689-
super.succ(pred, succ, c) and
690-
not (succ = this and c.(MatchCompletion).failed())
645+
super.succ(pred, succ, c) and c.(MatchCompletion).succeeded()
691646
}
692647
}
693648

@@ -705,6 +660,14 @@ module PatternTrees {
705660

706661
class OrPatTree extends PostOrderPatTree instanceof OrPat {
707662
override Pat getPat(int i) { result = OrPat.super.getPat(i) }
663+
664+
override predicate succ(AstNode pred, AstNode succ, Completion c) {
665+
// Failed patterns advance normally between children
666+
c.(MatchCompletion).failed() and super.succ(pred, succ, c)
667+
or
668+
// Successful pattern step to this
669+
c.(MatchCompletion).succeeded() and succ = this and last(this.getPat(_), pred, c)
670+
}
708671
}
709672

710673
class ParenPatTree extends ControlFlowTree, ParenPat {

rust/ql/lib/codeql/rust/controlflow/internal/Scope.qll

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ abstract class CfgScope extends AstNode {
1212
}
1313

1414
final class FunctionScope extends CfgScope, Function {
15+
FunctionScope() {
16+
// A function without a body corresponds to a trait method signature and
17+
// should not have a CFG scope.
18+
this.hasBody()
19+
}
20+
1521
override predicate scopeFirst(AstNode node) {
1622
first(this.(FunctionTree).getFirstChildNode(), node)
1723
}

0 commit comments

Comments
 (0)