Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a92404a

Browse files
committed
C#: Add LabeledStmtTree for goto CFG edges
1 parent 06d42da commit a92404a

1 file changed

Lines changed: 51 additions & 32 deletions

File tree

csharp/ql/src/semmle/code/csharp/controlflow/internal/ControlFlowGraphImpl.qll

Lines changed: 51 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -96,23 +96,6 @@ predicate last(ControlFlowTree cft, ControlFlowElement last, Completion c) {
9696
)
9797
}
9898

99-
pragma[noinline]
100-
private LabeledStmt getLabledStmt(string label, Callable c) {
101-
result.getEnclosingCallable() = c and
102-
label = result.getLabel()
103-
}
104-
105-
pragma[nomagic]
106-
private predicate goto(ControlFlowElement cfe, GotoCompletion gc, string label, Callable enclosing) {
107-
last(_, cfe, gc) and
108-
// Special case: when a `goto` happens inside a `try` statement with a
109-
// `finally` block, flow does not go directly to the target, but instead
110-
// to the `finally` block (and from there possibly to the target)
111-
not cfe = any(Statements::TryStmtTree t | t.hasFinally()).getAFinallyPredecessor(_, true) and
112-
label = gc.getLabel() and
113-
enclosing = cfe.getEnclosingCallable()
114-
}
115-
11699
/**
117100
* Holds if `succ` is a control flow successor for `pred`, given that `pred`
118101
* finishes with completion `c`.
@@ -136,13 +119,6 @@ predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
136119
m = InitializerSplitting::lastConstructorInitializer(con) and
137120
first(con.getBody(), succ)
138121
)
139-
or
140-
// Flow from element with `goto` completion to first element of relevant
141-
// target
142-
exists(string label, Callable enclosing |
143-
goto(pred, c, label, enclosing) and
144-
first(getLabledStmt(label, enclosing), succ)
145-
)
146122
}
147123

148124
/** Holds if `first` is first executed when entering `scope`. */
@@ -933,18 +909,18 @@ module Statements {
933909
// The following statements need special treatment
934910
not this instanceof IfStmt and
935911
not this instanceof SwitchStmt and
936-
(this instanceof DefaultCase or not this instanceof CaseStmt) and
912+
not this instanceof CaseStmt and
937913
not this instanceof LoopStmt and
938914
not this instanceof TryStmt and
939915
not this instanceof SpecificCatchClause and
940-
not this instanceof JumpStmt
916+
not this instanceof JumpStmt and
917+
not this instanceof LabeledStmt
941918
}
942919

943920
private ControlFlowTree getChildElement0(int i) {
944921
not this instanceof GeneralCatchClause and
945922
not this instanceof FixedStmt and
946923
not this instanceof UsingBlockStmt and
947-
not this instanceof DefaultCase and
948924
result = this.getChild(i)
949925
or
950926
this = any(GeneralCatchClause gcc | i = 0 and result = gcc.getBlock())
@@ -967,9 +943,6 @@ module Statements {
967943
result = us.getBody() and
968944
i = max([1, count(us.getVariableDeclExpr(_))])
969945
)
970-
or
971-
result = this.(DefaultCase).getStmt() and
972-
i = 0
973946
}
974947

975948
final override ControlFlowTree getChildElement(int i) {
@@ -1045,8 +1018,9 @@ module Statements {
10451018
last(this.getStmt(_), last, c) and
10461019
not c instanceof BreakCompletion and
10471020
not c instanceof NormalCompletion and
1048-
not getLabledStmt(c.(GotoCompletion).getLabel(), this.getEnclosingCallable()) instanceof
1049-
CaseStmt
1021+
not any(LabeledStmtTree t |
1022+
t.hasLabelInCallable(c.(GotoCompletion).getLabel(), this.getEnclosingCallable())
1023+
) instanceof CaseStmt
10501024
or
10511025
// Last case exits with a non-match
10521026
exists(CaseStmt cs, int last_ |
@@ -1570,6 +1544,51 @@ module Statements {
15701544
c instanceof NormalCompletion
15711545
}
15721546
}
1547+
1548+
pragma[nomagic]
1549+
private predicate goto(ControlFlowElement cfe, GotoCompletion gc, string label, Callable enclosing) {
1550+
last(_, cfe, gc) and
1551+
// Special case: when a `goto` happens inside a `try` statement with a
1552+
// `finally` block, flow does not go directly to the target, but instead
1553+
// to the `finally` block (and from there possibly to the target)
1554+
not cfe = any(Statements::TryStmtTree t | t.hasFinally()).getAFinallyPredecessor(_, true) and
1555+
label = gc.getLabel() and
1556+
enclosing = cfe.getEnclosingCallable()
1557+
}
1558+
1559+
private class LabeledStmtTree extends PreOrderTree, LabeledStmt {
1560+
final override predicate propagatesAbnormal(ControlFlowElement child) { none() }
1561+
1562+
final override predicate last(ControlFlowElement last, Completion c) {
1563+
if this instanceof DefaultCase
1564+
then last(this.getStmt(), last, c)
1565+
else (
1566+
not this instanceof CaseStmt and
1567+
last = this and
1568+
c.isValidFor(this)
1569+
)
1570+
}
1571+
1572+
pragma[noinline]
1573+
predicate hasLabelInCallable(string label, Callable c) {
1574+
this.getEnclosingCallable() = c and
1575+
label = this.getLabel()
1576+
}
1577+
1578+
final override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
1579+
this instanceof DefaultCase and
1580+
pred = this and
1581+
first(this.getStmt(), succ) and
1582+
c instanceof SimpleCompletion
1583+
or
1584+
// Flow from element with matching `goto` completion to this statement
1585+
exists(string label, Callable enclosing |
1586+
goto(pred, c, label, enclosing) and
1587+
this.hasLabelInCallable(label, enclosing) and
1588+
succ = this
1589+
)
1590+
}
1591+
}
15731592
}
15741593

15751594
cached

0 commit comments

Comments
 (0)