Skip to content

Commit e7691be

Browse files
owen-mcCopilot
andcommitted
Address labeled CFG review feedback
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent fc044f4 commit e7691be

3 files changed

Lines changed: 18 additions & 49 deletions

File tree

‎go/ql/lib/semmle/go/controlflow/ControlFlowGraphImpl.qll‎

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -445,14 +445,6 @@ module CfgImpl {
445445
l = n.(Go::GotoStmt).getLabel()
446446
}
447447

448-
private predicate hasLabelOrEnclosingLabel(Ast::AstNode n, Label l) {
449-
hasLabel(n, l)
450-
or
451-
exists(Go::LabeledStmt labeled |
452-
labeled.getStmt() = n and hasLabelOrEnclosingLabel(labeled, l)
453-
)
454-
}
455-
456448
predicate preOrderExpr(Ast::Expr e) {
457449
// The call of a `defer` statement is not invoked at the statement
458450
// itself; its callee expression and arguments are evaluated in place,
@@ -796,24 +788,16 @@ module CfgImpl {
796788
n.isAdditional(ast, "catch-return") and
797789
c.getSuccessorType() instanceof ReturnSuccessor
798790
or
799-
// A `break` in a communication clause body terminates the enclosing
800-
// `select` statement, continuing after it. This mirrors the shared
801-
// library's handling of `break` in a `switch` case body, but `select` is
802-
// modeled language-specifically (it is not a `Switch`), so the break
803-
// must be caught here. The break completion bubbles up the AST until it
804-
// reaches a top-level statement of the comm clause body, at which point
805-
// flow resumes after the `select`. An unlabeled `break` targets the
806-
// innermost enclosing construct; a labeled `break` only targets this
807-
// `select` if it (or a `LabeledStmt` wrapping it) carries that label.
791+
// An unlabeled `break` in a communication clause body terminates the
792+
// enclosing `select`. Labeled breaks are handled by the shared
793+
// `LabeledStmt` logic.
808794
exists(Go::SelectStmt sel, Go::CommClause cc |
809795
cc = sel.getACommClause() and
810796
ast = cc.getStmt(_) and
811797
n.isAfter(sel) and
812798
c.getSuccessorType() instanceof BreakSuccessor
813799
|
814800
not c.hasLabel(_)
815-
or
816-
exists(Label l | c.hasLabel(l) and hasLabelOrEnclosingLabel(sel, l))
817801
)
818802
or
819803
exists(Go::FuncDef fd |

‎go/ql/test/library-tests/semmle/go/controlflow/GotoTarget/gotos.go‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ self:
3535
goto self // $ gotoTarget=self
3636
}
3737

38+
func gotoDirectTarget() {
39+
step1:
40+
goto step2 // $ gotoTarget=step2
41+
step2:
42+
goto step1 // $ gotoTarget=step1
43+
}
44+
3845
func gotoEnclosingStackedLabel(flag bool) {
3946
outer:
4047
inner:

‎shared/controlflow/codeql/controlflow/ControlFlowGraph.qll‎

Lines changed: 8 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1285,23 +1285,9 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
12851285
)
12861286
}
12871287

1288-
/** Holds if `n` has `l`, possibly through enclosing labeled statements. */
1289-
private predicate hasLabel(AstNode n, Input1::Label l) {
1290-
Input1::hasLabel(n, l)
1291-
or
1292-
exists(LabeledStmt labeled | labeled.getStmt() = n and hasLabel(labeled, l))
1293-
}
1294-
1295-
/**
1296-
* Holds if `target` is a labeled statement at the start of `root`,
1297-
* possibly nested under other labeled statements.
1298-
*/
1299-
private predicate labeledTargetInRoot(Stmt root, LabeledStmt target) {
1300-
root = target
1301-
or
1302-
exists(LabeledStmt labeled |
1303-
root = labeled and labeledTargetInRoot(labeled.getStmt(), target)
1304-
)
1288+
/** Holds if `n` is marked with a `LabeledStmt` with label `l`. */
1289+
private predicate hasEnclosingLabel(AstNode n, Input1::Label l) {
1290+
exists(LabeledStmt labeled | labeled.getStmt+() = n and Input1::hasLabel(labeled, l))
13051291
}
13061292

13071293
private predicate callableHasParamDefault(Callable c, Expr defaultValue) {
@@ -1342,7 +1328,7 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
13421328
or
13431329
exists(Input1::Label l |
13441330
c.hasLabel(l) and
1345-
hasLabel(loop, l)
1331+
hasEnclosingLabel(loop, l)
13461332
)
13471333
)
13481334
)
@@ -1382,7 +1368,7 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
13821368
or
13831369
exists(Input1::Label l |
13841370
c.hasLabel(l) and
1385-
hasLabel(switch, l)
1371+
hasEnclosingLabel(switch, l)
13861372
)
13871373
)
13881374
or
@@ -1394,19 +1380,11 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
13941380
c.hasLabel(l)
13951381
)
13961382
or
1397-
exists(AstNode parent, Stmt root, LabeledStmt target, Input1::Label l |
1383+
exists(AstNode parent, LabeledStmt root, LabeledStmt target, Input1::Label l |
13981384
ast = getChild(parent, _) and
13991385
root = getChild(parent, _) and
1400-
labeledTargetInRoot(root, target) and
1401-
Input1::hasLabel(target, l) and
1402-
n.isBefore(target) and
1403-
c.getSuccessorType() instanceof GotoSuccessor and
1404-
c.hasLabel(l)
1405-
)
1406-
or
1407-
exists(LabeledStmt target, Input1::Label l |
1408-
ast = target.getStmt() and
1409-
Input1::hasLabel(target, l) and
1386+
root.getStmt*() = target and
1387+
Input1::hasLabel(pragma[only_bind_into](target), l) and
14101388
n.isBefore(target) and
14111389
c.getSuccessorType() instanceof GotoSuccessor and
14121390
c.hasLabel(l)

0 commit comments

Comments
 (0)