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

Skip to content

Commit 6644537

Browse files
committed
C#: Speedup Assertions::strictlyDominates() and ControlFlowElement::controlsBlock()
Only calculate dominance by explicit recursion for split nodes; all other nodes can use regular CFG dominance.
1 parent 9e73ed7 commit 6644537

4 files changed

Lines changed: 82 additions & 30 deletions

File tree

csharp/ql/src/semmle/code/csharp/commons/Assertions.qll

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ class Assertion extends MethodCall {
5151

5252
pragma[nomagic]
5353
private JoinBlockPredecessor getAPossiblyDominatedPredecessor(JoinBlock jb) {
54+
// Only calculate dominance by explicit recursion for split nodes;
55+
// all other nodes can use regular CFG dominance
56+
this instanceof ControlFlow::Internal::SplitControlFlowElement and
5457
exists(BasicBlock bb |
5558
bb = this.getAControlFlowNode().getBasicBlock() |
5659
result = bb.getASuccessor*()
@@ -70,6 +73,22 @@ class Assertion extends MethodCall {
7073
)
7174
}
7275

76+
pragma[nomagic]
77+
private predicate strictlyDominatesSplit(BasicBlock bb) {
78+
this.getAControlFlowNode().getBasicBlock().immediatelyDominates(bb)
79+
or
80+
if bb instanceof JoinBlock then
81+
this.isPossiblyDominatedJoinBlock(bb) and
82+
forall(BasicBlock pred |
83+
pred = this.getAPossiblyDominatedPredecessor(bb) |
84+
this.strictlyDominatesSplit(pred)
85+
or
86+
this.getAControlFlowNode().getBasicBlock() = pred
87+
)
88+
else
89+
this.strictlyDominatesSplit(bb.getAPredecessor())
90+
}
91+
7392
/**
7493
* Holds if this assertion strictly dominates basic block `bb`. That is, `bb`
7594
* can only be reached from the callable entry point by going via *some* basic
@@ -81,18 +100,9 @@ class Assertion extends MethodCall {
81100
*/
82101
pragma[nomagic]
83102
predicate strictlyDominates(BasicBlock bb) {
84-
this.getAControlFlowNode().getBasicBlock().immediatelyDominates(bb)
103+
this.strictlyDominatesSplit(bb)
85104
or
86-
if bb instanceof JoinBlock then
87-
this.isPossiblyDominatedJoinBlock(bb) and
88-
forall(BasicBlock pred |
89-
pred = this.getAPossiblyDominatedPredecessor(bb) |
90-
this.strictlyDominates(pred)
91-
or
92-
this.getAControlFlowNode().getBasicBlock() = pred
93-
)
94-
else
95-
this.strictlyDominates(bb.getAPredecessor())
105+
this.getAControlFlowNode().getBasicBlock().strictlyDominates(bb)
96106
}
97107
}
98108

csharp/ql/src/semmle/code/csharp/controlflow/BasicBlocks.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,7 @@ class ConditionBlock extends BasicBlock {
473473
* successor of this block, and `succ` can only be reached from
474474
* the callable entry point by going via the `s` edge out of this basic block.
475475
*/
476+
pragma[nomagic]
476477
predicate immediatelyControls(BasicBlock succ, ConditionalSuccessor s) {
477478
succ = this.getASuccessorByType(s) and
478479
forall(BasicBlock pred |

csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowElement.qll

Lines changed: 53 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,23 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element {
7979
* `pred` ending with this element, and `pred` is an immediate predecessor
8080
* of `succ`.
8181
*
82-
* This predicate is different from
83-
* `this.getAControlFlowNode().getBasicBlock().(ConditionBlock).immediatelyControls(succ, s)`
84-
* in that it takes control flow splitting into account.
82+
* Moroever, this control flow element corresponds to multiple control flow nodes,
83+
* which is why
84+
*
85+
* ```
86+
* exists(ConditionBlock cb |
87+
* cb.getLastNode() = this.getAControlFlowNode() |
88+
* cb.immediatelyControls(succ, s)
89+
* )
90+
* ```
91+
*
92+
* does not work.
8593
*/
8694
pragma[nomagic]
87-
private predicate immediatelyControls(BasicBlock succ, ConditionalSuccessor s) {
95+
private predicate immediatelyControlsBlockSplit(BasicBlock succ, ConditionalSuccessor s) {
96+
// Only calculate dominance by explicit recursion for split nodes;
97+
// all other nodes can use regular CFG dominance
98+
this instanceof ControlFlow::Internal::SplitControlFlowElement and
8899
exists(ConditionBlock cb |
89100
cb.getLastNode() = this.getAControlFlowNode() |
90101
succ = cb.getASuccessorByType(s) and
@@ -103,7 +114,7 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element {
103114
pragma[nomagic]
104115
private JoinBlockPredecessor getAPossiblyControlledPredecessor(JoinBlock controlled, ConditionalSuccessor s) {
105116
exists(BasicBlock mid |
106-
this.immediatelyControls(mid, s) |
117+
this.immediatelyControlsBlockSplit(mid, s) |
107118
result = mid.getASuccessor*()
108119
) and
109120
result.getASuccessor() = controlled and
@@ -121,28 +132,44 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element {
121132
)
122133
}
123134

135+
cached
136+
private predicate controlsBlockSplit(BasicBlock controlled, ConditionalSuccessor s) {
137+
this.immediatelyControlsBlockSplit(controlled, s)
138+
or
139+
if controlled instanceof JoinBlock then
140+
this.isPossiblyControlledJoinBlock(controlled, s) and
141+
forall(BasicBlock pred |
142+
pred = this.getAPossiblyControlledPredecessor(controlled, s) |
143+
this.controlsBlock(pred, s)
144+
)
145+
else
146+
this.controlsBlockSplit(controlled.getAPredecessor(), s)
147+
}
148+
124149
/**
125150
* Holds if basic block `controlled` is controlled by this control flow element
126151
* with conditional value `s`. That is, `controlled` can only be reached from
127152
* the callable entry point by going via the `s` edge out of *some* basic block
128153
* ending with this element.
129154
*
130155
* This predicate is different from
131-
* `this.getAControlFlowNode().getBasicBlock().(ConditionBlock).controls(controlled, s)`
132-
* in that it takes control flow splitting into account.
156+
*
157+
* ```
158+
* exists(ConditionBlock cb |
159+
* cb.getLastNode() = this.getAControlFlowNode() |
160+
* cb.controls(controlled, s)
161+
* )
162+
* ```
163+
*
164+
* as control flow splitting is taken into account.
133165
*/
134-
cached
135166
predicate controlsBlock(BasicBlock controlled, ConditionalSuccessor s) {
136-
this.immediatelyControls(controlled, s)
167+
this.controlsBlockSplit(controlled, s)
137168
or
138-
if controlled instanceof JoinBlock then
139-
this.isPossiblyControlledJoinBlock(controlled, s) and
140-
forall(BasicBlock pred |
141-
pred = this.getAPossiblyControlledPredecessor(controlled, s) |
142-
this.controlsBlock(pred, s)
143-
)
144-
else
145-
this.controlsBlock(controlled.getAPredecessor(), s)
169+
exists(ConditionBlock cb |
170+
cb.getLastNode() = this.getAControlFlowNode() |
171+
cb.controls(controlled, s)
172+
)
146173
}
147174

148175
/**
@@ -151,8 +178,15 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element {
151178
* from the callable entry point by going via the `s` edge out of this element.
152179
*
153180
* This predicate is different from
154-
* `this.getAControlFlowNode().getBasicBlock().(ConditionBlock).controls(controlled.getAControlFlowNode().getBasicBlock(), s)`
155-
* in that it takes control flow splitting into account.
181+
*
182+
* ```
183+
* exists(ConditionBlock cb |
184+
* cb.getLastNode() = this.getAControlFlowNode() |
185+
* cb.controls(controlled.getAControlFlowNode().getBasicBlock(), s)
186+
* )
187+
* ```
188+
*
189+
* as control flow splitting is taken into account.
156190
*/
157191
pragma[inline] // potentially very large predicate, so must be inlined
158192
predicate controlsElement(ControlFlowElement controlled, ConditionalSuccessor s) {

csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4185,6 +4185,13 @@ module ControlFlow {
41854185
}
41864186
}
41874187
import Cached
4188+
4189+
/** A control flow element that is split into multiple control flow nodes. */
4190+
class SplitControlFlowElement extends ControlFlowElement {
4191+
SplitControlFlowElement() {
4192+
strictcount(this.getAControlFlowNode()) > 1
4193+
}
4194+
}
41884195
}
41894196
private import Internal
41904197
}

0 commit comments

Comments
 (0)