Skip to content

Commit 97c2387

Browse files
authored
Merge pull request #17644 from hvitved/rust/break-continue-target
2 parents f7db47b + 6da3972 commit 97c2387

File tree

14 files changed

+801
-147
lines changed

14 files changed

+801
-147
lines changed

rust/ql/.generated.list

Lines changed: 0 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/ql/.gitattributes

Lines changed: 0 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/ql/lib/codeql/rust/controlflow/ControlFlowGraph.qll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ final class BooleanSuccessor = BooleanSuccessorImpl;
1919

2020
final class MatchSuccessor = MatchSuccessorImpl;
2121

22-
final class LoopJumpSuccessor = LoopJumpSuccessorImpl;
22+
final class BreakSuccessor = BreakSuccessorImpl;
23+
24+
final class ContinueSuccessor = ContinueSuccessorImpl;
2325

2426
final class ReturnSuccessor = ReturnSuccessorImpl;
2527

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

Lines changed: 14 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,8 @@ newtype TCompletion =
77
TSimpleCompletion() or
88
TBooleanCompletion(Boolean b) or
99
TMatchCompletion(Boolean isMatch) or
10-
TLoopCompletion(TLoopJumpType kind, TLabelType label) {
11-
label = TNoLabel()
12-
or
13-
kind = TBreakJump() and label = TLabel(any(BreakExpr b).getLifetime().getText())
14-
or
15-
kind = TContinueJump() and label = TLabel(any(ContinueExpr b).getLifetime().getText())
16-
} or
10+
TBreakCompletion() or
11+
TContinueCompletion() or
1712
TReturnCompletion()
1813

1914
/** A completion of a statement or an expression. */
@@ -148,42 +143,23 @@ class MatchCompletion extends TMatchCompletion, ConditionalCompletion {
148143
}
149144

150145
/**
151-
* A completion that represents a break or a continue.
146+
* A completion that represents a `break`.
152147
*/
153-
class LoopJumpCompletion extends TLoopCompletion, Completion {
154-
override LoopJumpSuccessor getAMatchingSuccessorType() {
155-
result = TLoopSuccessor(this.getKind(), this.getLabelType())
156-
}
157-
158-
final TLoopJumpType getKind() { this = TLoopCompletion(result, _) }
159-
160-
final TLabelType getLabelType() { this = TLoopCompletion(_, result) }
148+
class BreakCompletion extends TBreakCompletion, Completion {
149+
override BreakSuccessor getAMatchingSuccessorType() { any() }
161150

162-
final predicate hasLabel() { this.getLabelType() = TLabel(_) }
151+
override predicate isValidForSpecific(AstNode e) { e instanceof BreakExpr }
163152

164-
final string getLabelName() { TLabel(result) = this.getLabelType() }
165-
166-
final predicate isContinue() { this.getKind() = TContinueJump() }
153+
override string toString() { result = this.getAMatchingSuccessorType().toString() }
154+
}
167155

168-
final predicate isBreak() { this.getKind() = TBreakJump() }
156+
/**
157+
* A completion that represents a `continue`.
158+
*/
159+
class ContinueCompletion extends TContinueCompletion, Completion {
160+
override ContinueSuccessor getAMatchingSuccessorType() { any() }
169161

170-
override predicate isValidForSpecific(AstNode e) {
171-
this.isBreak() and
172-
e instanceof BreakExpr and
173-
(
174-
not e.(BreakExpr).hasLifetime() and not this.hasLabel()
175-
or
176-
e.(BreakExpr).getLifetime().getText() = this.getLabelName()
177-
)
178-
or
179-
this.isContinue() and
180-
e instanceof ContinueExpr and
181-
(
182-
not e.(ContinueExpr).hasLifetime() and not this.hasLabel()
183-
or
184-
e.(ContinueExpr).getLifetime().getText() = this.getLabelName()
185-
)
186-
}
162+
override predicate isValidForSpecific(AstNode e) { e instanceof ContinueExpr }
187163

188164
override string toString() { result = this.getAMatchingSuccessorType().toString() }
189165
}

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

Lines changed: 32 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -145,44 +145,26 @@ class BlockExprTree extends StandardPostOrderTree, BlockExpr {
145145
result = super.getStmtList().getTailExpr()
146146
}
147147

148-
override predicate propagatesAbnormal(AstNode child) { none() }
149-
150-
/** Holds if this block captures the break completion `c`. */
151-
private predicate capturesBreakCompletion(LoopJumpCompletion c) {
152-
c.isBreak() and
153-
c.getLabelName() = this.getLabel().getLifetime().getText()
154-
}
155-
156-
override predicate succ(AstNode pred, AstNode succ, Completion c) {
157-
super.succ(pred, succ, c)
158-
or
159-
// Edge for exiting the block with a break expressions
160-
last(this.getChildNode(_), pred, c) and
161-
this.capturesBreakCompletion(c) and
162-
succ = this
163-
}
164-
165-
override predicate last(AstNode last, Completion c) {
166-
super.last(last, c)
167-
or
168-
// Any abnormal completions that this block does not capture should propagate
169-
last(this.getChildNode(_), last, c) and
170-
not completionIsNormal(c) and
171-
not this.capturesBreakCompletion(c)
172-
}
148+
override predicate propagatesAbnormal(AstNode child) { child = this.getChildNode(_) }
173149
}
174150

175-
class BreakExprTree extends PostOrderTree instanceof BreakExpr {
176-
override predicate propagatesAbnormal(AstNode child) { child = super.getExpr() }
151+
class BreakExprTree extends PostOrderTree, BreakExpr {
152+
override predicate propagatesAbnormal(AstNode child) { child = this.getExpr() }
177153

178154
override predicate first(AstNode node) {
179-
first(super.getExpr(), node)
155+
first(this.getExpr(), node)
180156
or
181-
not super.hasExpr() and node = this
157+
not this.hasExpr() and node = this
182158
}
183159

160+
override predicate last(AstNode last, Completion c) { none() }
161+
184162
override predicate succ(AstNode pred, AstNode succ, Completion c) {
185163
last(super.getExpr(), pred, c) and succ = this
164+
or
165+
pred = this and
166+
c.isValidFor(pred) and
167+
succ = this.getTarget()
186168
}
187169
}
188170

@@ -200,7 +182,15 @@ class CastExprTree extends StandardPostOrderTree instanceof CastExpr {
200182

201183
class ClosureExprTree extends LeafTree instanceof ClosureExpr { }
202184

203-
class ContinueExprTree extends LeafTree instanceof ContinueExpr { }
185+
class ContinueExprTree extends LeafTree, ContinueExpr {
186+
override predicate last(AstNode last, Completion c) { none() }
187+
188+
override predicate succ(AstNode pred, AstNode succ, Completion c) {
189+
pred = this and
190+
c.isValidFor(pred) and
191+
first(this.getTarget().(LoopingExprTree).getLoopContinue(), succ)
192+
}
193+
}
204194

205195
class ExprStmtTree extends StandardPreOrderTree instanceof ExprStmt {
206196
override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() }
@@ -310,57 +300,27 @@ class LetStmtTree extends PreOrderTree instanceof LetStmt {
310300
class LiteralExprTree extends LeafTree instanceof LiteralExpr { }
311301

312302
abstract class LoopingExprTree extends PostOrderTree {
313-
override predicate propagatesAbnormal(AstNode child) { none() }
303+
override predicate propagatesAbnormal(AstNode child) { child = this.getLoopBody() }
314304

315305
abstract BlockExpr getLoopBody();
316306

317-
abstract Label getLabel();
318-
319307
/**
320308
* Gets the node to execute when continuing the loop; either after
321309
* executing the last node in the body or after an explicit `continue`.
322310
*/
323311
abstract AstNode getLoopContinue();
324312

325-
/** Holds if this loop captures the `c` completion. */
326-
private predicate capturesLoopJumpCompletion(LoopJumpCompletion c) {
327-
not c.hasLabel()
328-
or
329-
c.getLabelName() = this.getLabel().getLifetime().getText()
330-
}
331-
332313
override predicate succ(AstNode pred, AstNode succ, Completion c) {
333-
// Edge for exiting the loop with a break expressions
334-
last(this.getLoopBody(), pred, c) and
335-
c.(LoopJumpCompletion).isBreak() and
336-
this.capturesLoopJumpCompletion(c) and
337-
succ = this
338-
or
339314
// Edge back to the start for final expression and continue expressions
340315
last(this.getLoopBody(), pred, c) and
341-
(
342-
completionIsNormal(c)
343-
or
344-
c.(LoopJumpCompletion).isContinue() and this.capturesLoopJumpCompletion(c)
345-
) and
316+
completionIsNormal(c) and
346317
first(this.getLoopContinue(), succ)
347318
}
348-
349-
override predicate last(AstNode last, Completion c) {
350-
super.last(last, c)
351-
or
352-
// Any abnormal completions that this loop does not capture should propagate
353-
last(this.getLoopBody(), last, c) and
354-
not completionIsNormal(c) and
355-
not this.capturesLoopJumpCompletion(c)
356-
}
357319
}
358320

359321
class LoopExprTree extends LoopingExprTree instanceof LoopExpr {
360322
override BlockExpr getLoopBody() { result = LoopExpr.super.getLoopBody() }
361323

362-
override Label getLabel() { result = LoopExpr.super.getLabel() }
363-
364324
override AstNode getLoopContinue() { result = this.getLoopBody() }
365325

366326
override predicate first(AstNode node) { first(this.getLoopBody(), node) }
@@ -369,11 +329,13 @@ class LoopExprTree extends LoopingExprTree instanceof LoopExpr {
369329
class WhileExprTree extends LoopingExprTree instanceof WhileExpr {
370330
override BlockExpr getLoopBody() { result = WhileExpr.super.getLoopBody() }
371331

372-
override Label getLabel() { result = WhileExpr.super.getLabel() }
373-
374332
override AstNode getLoopContinue() { result = super.getCondition() }
375333

376-
override predicate propagatesAbnormal(AstNode child) { child = super.getCondition() }
334+
override predicate propagatesAbnormal(AstNode child) {
335+
super.propagatesAbnormal(child)
336+
or
337+
child = super.getCondition()
338+
}
377339

378340
override predicate first(AstNode node) { first(super.getCondition(), node) }
379341

@@ -399,11 +361,13 @@ class WhileExprTree extends LoopingExprTree instanceof WhileExpr {
399361
class ForExprTree extends LoopingExprTree instanceof ForExpr {
400362
override BlockExpr getLoopBody() { result = ForExpr.super.getLoopBody() }
401363

402-
override Label getLabel() { result = ForExpr.super.getLabel() }
403-
404364
override AstNode getLoopContinue() { result = super.getPat() }
405365

406-
override predicate propagatesAbnormal(AstNode child) { child = super.getIterable() }
366+
override predicate propagatesAbnormal(AstNode child) {
367+
super.propagatesAbnormal(child)
368+
or
369+
child = super.getIterable()
370+
}
407371

408372
override predicate first(AstNode node) { first(super.getIterable(), node) }
409373

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

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ newtype TSuccessorType =
1515
TSuccessorSuccessor() or
1616
TBooleanSuccessor(Boolean b) or
1717
TMatchSuccessor(Boolean b) or
18-
TLoopSuccessor(TLoopJumpType kind, TLabelType label) { exists(TLoopCompletion(kind, label)) } or
18+
TBreakSuccessor() or
19+
TContinueSuccessor() or
1920
TReturnSuccessor()
2021

2122
/** The type of a control flow successor. */
@@ -59,28 +60,17 @@ class MatchSuccessorImpl extends ConditionalSuccessorImpl, TMatchSuccessor {
5960
}
6061

6162
/**
62-
* A control flow successor of a loop control flow expression, `continue` or `break`.
63+
* A control flow successor of a `break` expression.
6364
*/
64-
class LoopJumpSuccessorImpl extends SuccessorTypeImpl, TLoopSuccessor {
65-
private TLoopJumpType getKind() { this = TLoopSuccessor(result, _) }
66-
67-
private TLabelType getLabelType() { this = TLoopSuccessor(_, result) }
68-
69-
predicate hasLabel() { this.getLabelType() = TLabel(_) }
70-
71-
string getLabelName() { this = TLoopSuccessor(_, TLabel(result)) }
72-
73-
predicate isContinue() { this.getKind() = TContinueJump() }
74-
75-
predicate isBreak() { this.getKind() = TBreakJump() }
65+
class BreakSuccessorImpl extends SuccessorTypeImpl, TBreakSuccessor {
66+
override string toString() { result = "break" }
67+
}
7668

77-
override string toString() {
78-
exists(string kind, string label |
79-
(if this.isContinue() then kind = "continue" else kind = "break") and
80-
(if this.hasLabel() then label = "(" + this.getLabelName() + ")" else label = "") and
81-
result = kind + label
82-
)
83-
}
69+
/**
70+
* A control flow successor of a `continue` expression.
71+
*/
72+
class ContinueSuccessorImpl extends SuccessorTypeImpl, TContinueSuccessor {
73+
override string toString() { result = "continue" }
8474
}
8575

8676
/**

0 commit comments

Comments
 (0)