Skip to content

Commit 3fab514

Browse files
authored
Merge pull request #1673 from hvitved/csharp/cfg/split-static-limit
C#: Apply static CFG splitting limit
2 parents 01fd161 + 4774bc9 commit 3fab514

File tree

4 files changed

+2079
-258
lines changed

4 files changed

+2079
-258
lines changed

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

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ private import ControlFlow
1414
private import SuccessorTypes
1515

1616
/** The maximum number of splits allowed for a given node. */
17-
private int maxSplits() { result = 7 }
17+
private int maxSplits() { result = 5 }
1818

1919
cached
2020
private module Cached {
@@ -46,13 +46,10 @@ private module Cached {
4646
TSplitsNil() or
4747
TSplitsCons(SplitInternal head, Splits tail) {
4848
exists(
49-
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c, int rnk,
50-
int numberOfSplits
49+
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Completion c, int rnk
5150
|
52-
case2aFromRank(pred, predSplits, succ, tail, c, rnk + 1, numberOfSplits) and
51+
case2aFromRank(pred, predSplits, succ, tail, c, rnk + 1) and
5352
head = case2aSomeAtRank(pred, predSplits, succ, c, rnk)
54-
|
55-
numberOfSplits < maxSplits() or head.getKind().isMandatory()
5653
)
5754
}
5855

@@ -86,6 +83,18 @@ class SplitImpl extends TSplit {
8683
string toString() { none() }
8784
}
8885

86+
/**
87+
* Holds if split kinds `sk1` and `sk2` may overlap. That is, they may apply
88+
* to at least one common control flow element inside callable `c`.
89+
*/
90+
private predicate overlapping(Callable c, SplitKind sk1, SplitKind sk2) {
91+
exists(ControlFlowElement cfe |
92+
sk1.appliesTo(cfe) and
93+
sk2.appliesTo(cfe) and
94+
c = cfe.getEnclosingCallable()
95+
)
96+
}
97+
8998
/**
9099
* A split kind. Each control flow node can have at most one split of a
91100
* given kind.
@@ -103,12 +112,17 @@ abstract class SplitKind extends TSplitKind {
103112
*/
104113
abstract int getListOrder();
105114

115+
/** Gets the rank of this split kind among all overlapping kinds for `c`. */
116+
private int getRank(Callable c) {
117+
this = rank[result](SplitKind sk | overlapping(c, this, sk) | sk order by sk.getListOrder())
118+
}
119+
106120
/**
107-
* Holds if a split of this kind is mandatory. That is, a split of this kind must
108-
* be taken into account, regardless of whether we might exceed the maximum number
109-
* of splits (`maxSplits()`).
121+
* Holds if this split kind should be included when constructing the control
122+
* flow graph for callable `c`. For performance reasons, the number of splits
123+
* is restricted by the `maxSplits()` predicate.
110124
*/
111-
abstract predicate isMandatory();
125+
private predicate isEnabled(Callable c) { this.getRank(c) <= maxSplits() }
112126

113127
/**
114128
* Gets the rank of this split kind among all the split kinds that apply to
@@ -117,6 +131,7 @@ abstract class SplitKind extends TSplitKind {
117131
*/
118132
int getListRank(ControlFlowElement cfe) {
119133
this.appliesTo(cfe) and
134+
this.isEnabled(cfe.getEnclosingCallable()) and
120135
this = rank[result](SplitKind sk | sk.appliesTo(cfe) | sk order by sk.getListOrder())
121136
}
122137

@@ -281,8 +296,6 @@ module FinallySplitting {
281296
private class FinallySplitKind extends SplitKind, TFinallySplitKind {
282297
override int getListOrder() { result = 0 }
283298

284-
override predicate isMandatory() { any() }
285-
286299
override string toString() { result = "Finally" }
287300
}
288301

@@ -434,8 +447,6 @@ module ExceptionHandlerSplitting {
434447
private class ExceptionHandlerSplitKind extends SplitKind, TExceptionHandlerSplitKind {
435448
override int getListOrder() { result = 1 }
436449

437-
override predicate isMandatory() { any() }
438-
439450
override string toString() { result = "ExceptionHandler" }
440451
}
441452

@@ -732,8 +743,6 @@ module BooleanSplitting {
732743
)
733744
}
734745

735-
override predicate isMandatory() { none() }
736-
737746
override string toString() { result = kind.toString() }
738747
}
739748

@@ -1071,33 +1080,28 @@ private module SuccSplits {
10711080
*/
10721081
predicate case2aFromRank(
10731082
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits,
1074-
Completion c, int rnk, int numberOfSplits
1083+
Completion c, int rnk
10751084
) {
10761085
case2aux(pred, predSplits, succ, c) and
10771086
succSplits = TSplitsNil() and
1078-
rnk = max(any(SplitKind sk).getListRank(succ)) + 1 and
1079-
numberOfSplits = 0
1087+
rnk = max(any(SplitKind sk).getListRank(succ)) + 1
10801088
or
1081-
case2aFromRank(pred, predSplits, succ, succSplits, c, rnk + 1, numberOfSplits) and
1089+
case2aFromRank(pred, predSplits, succ, succSplits, c, rnk + 1) and
10821090
case2aNoneAtRank(pred, predSplits, succ, c, rnk)
10831091
or
1084-
exists(Splits mid, SplitInternal split, int numberOfSplitsMid |
1085-
split = case2aCons(pred, predSplits, succ, mid, c, rnk, numberOfSplitsMid)
1092+
exists(Splits mid, SplitInternal split |
1093+
split = case2aCons(pred, predSplits, succ, mid, c, rnk)
10861094
|
1087-
if numberOfSplitsMid < maxSplits() or split.getKind().isMandatory()
1088-
then succSplits = TSplitsCons(split, mid) and numberOfSplits = numberOfSplitsMid + 1
1089-
else (
1090-
succSplits = mid and numberOfSplits = numberOfSplitsMid
1091-
)
1095+
succSplits = TSplitsCons(split, mid)
10921096
)
10931097
}
10941098

10951099
pragma[noinline]
10961100
private SplitInternal case2aCons(
10971101
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits,
1098-
Completion c, int rnk, int numberOfSplits
1102+
Completion c, int rnk
10991103
) {
1100-
case2aFromRank(pred, predSplits, succ, succSplits, c, rnk + 1, numberOfSplits) and
1104+
case2aFromRank(pred, predSplits, succ, succSplits, c, rnk + 1) and
11011105
result = case2aSomeAtRank(pred, predSplits, succ, c, rnk)
11021106
}
11031107

@@ -1131,7 +1135,7 @@ private module SuccSplits {
11311135
ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits,
11321136
Completion c
11331137
) {
1134-
case2aFromRank(pred, predSplits, succ, succSplits, c, 1, _)
1138+
case2aFromRank(pred, predSplits, succ, succSplits, c, 1)
11351139
or
11361140
case2bForall(pred, predSplits, succ, c, TSplitsNil()) and
11371141
succSplits = TSplitsNil()

csharp/ql/test/library-tests/controlflow/splits/SplittingStressTest.cs

Lines changed: 153 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
class SplittingStressTest
22
{
3-
void M(bool b1, bool b2, bool b3, bool b4, bool b5, bool b6, bool b7, bool b8, bool b9, bool b10, bool b11, bool b12, bool b13, bool b14, bool b15, bool b16, bool b17, bool b18, bool b19, bool b20, bool b21, bool b22, bool b23, bool b24, bool b25, bool b26, bool b27, bool b28, bool b29, bool b30, bool b31, bool b32, bool b33, bool b34, bool b35, bool b36, bool b37, bool b38, bool b39, bool b40)
3+
void M1(bool b1, bool b2, bool b3, bool b4, bool b5, bool b6, bool b7, bool b8, bool b9, bool b10, bool b11, bool b12, bool b13, bool b14, bool b15, bool b16, bool b17, bool b18, bool b19, bool b20, bool b21, bool b22, bool b23, bool b24, bool b25, bool b26, bool b27, bool b28, bool b29, bool b30, bool b31, bool b32, bool b33, bool b34, bool b35, bool b36, bool b37, bool b38, bool b39, bool b40)
44
{
55
if (b1)
66
;
@@ -166,4 +166,156 @@ void M(bool b1, bool b2, bool b3, bool b4, bool b5, bool b6, bool b7, bool b8, b
166166
;
167167
;
168168
}
169+
170+
void M2(int i, bool b1, bool b2, bool b3, bool b4, bool b5, bool b6, bool b7, bool b8, bool b9, bool b10, bool b11, bool b12, bool b13, bool b14, bool b15, bool b16, bool b17, bool b18, bool b19, bool b20, bool b21, bool b22, bool b23, bool b24, bool b25, bool b26, bool b27, bool b28, bool b29)
171+
{
172+
while (i-- > 0)
173+
{
174+
if (i == 1)
175+
{
176+
if (b1)
177+
;
178+
}
179+
if (i == 2)
180+
{
181+
if (b2)
182+
;
183+
}
184+
if (i == 3)
185+
{
186+
if (b3)
187+
;
188+
}
189+
if (i == 4)
190+
{
191+
if (b4)
192+
;
193+
}
194+
if (i == 5)
195+
{
196+
if (b5)
197+
;
198+
}
199+
if (i == 6)
200+
{
201+
if (b6)
202+
;
203+
}
204+
if (i == 7)
205+
{
206+
if (b7)
207+
;
208+
}
209+
if (i == 8)
210+
{
211+
if (b8)
212+
;
213+
}
214+
if (i == 9)
215+
{
216+
if (b9)
217+
;
218+
}
219+
if (i == 10)
220+
{
221+
if (b10)
222+
;
223+
}
224+
if (i == 11)
225+
{
226+
if (b11)
227+
;
228+
}
229+
if (i == 12)
230+
{
231+
if (b12)
232+
;
233+
}
234+
if (i == 13)
235+
{
236+
if (b13)
237+
;
238+
}
239+
if (i == 14)
240+
{
241+
if (b14)
242+
;
243+
}
244+
if (i == 15)
245+
{
246+
if (b15)
247+
;
248+
}
249+
if (i == 16)
250+
{
251+
if (b16)
252+
;
253+
}
254+
if (i == 17)
255+
{
256+
if (b17)
257+
;
258+
}
259+
if (i == 18)
260+
{
261+
if (b18)
262+
;
263+
}
264+
if (i == 19)
265+
{
266+
if (b19)
267+
;
268+
}
269+
if (i == 20)
270+
{
271+
if (b20)
272+
;
273+
}
274+
if (i == 21)
275+
{
276+
if (b21)
277+
;
278+
}
279+
if (i == 22)
280+
{
281+
if (b22)
282+
;
283+
}
284+
if (i == 23)
285+
{
286+
if (b23)
287+
;
288+
}
289+
if (i == 24)
290+
{
291+
if (b24)
292+
;
293+
}
294+
if (i == 25)
295+
{
296+
if (b25)
297+
;
298+
}
299+
if (i == 26)
300+
{
301+
if (b26)
302+
;
303+
}
304+
if (i == 27)
305+
{
306+
if (b27)
307+
;
308+
}
309+
if (i == 28)
310+
{
311+
if (b28)
312+
;
313+
}
314+
if (i == 29)
315+
{
316+
if (b29)
317+
;
318+
}
319+
}
320+
}
169321
}

0 commit comments

Comments
 (0)