@@ -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 ) {
0 commit comments