Skip to content

Commit 10ab330

Browse files
authored
Merge pull request github#4575 from hvitved/csharp/cfg/post-dominance
C#: Restrict post-dominance to normal execution
2 parents 45d117b + 438b8dd commit 10ab330

21 files changed

+3706
-2315
lines changed

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

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ class BasicBlock extends TBasicBlockStart {
213213
/**
214214
* Holds if this basic block strictly post-dominates basic block `bb`.
215215
*
216-
* That is, all paths reaching an exit point basic block from basic
216+
* That is, all paths reaching a normal exit point basic block from basic
217217
* block `bb` must go through this basic block (which must be different
218218
* from `bb`).
219219
*
@@ -239,7 +239,7 @@ class BasicBlock extends TBasicBlockStart {
239239
/**
240240
* Holds if this basic block post-dominates basic block `bb`.
241241
*
242-
* That is, all paths reaching an exit point basic block from basic
242+
* That is, all paths reaching a normal exit point basic block from basic
243243
* block `bb` must go through this basic block.
244244
*
245245
* Example:
@@ -333,10 +333,15 @@ private module Internal {
333333
/** Holds if `pred` is a basic block predecessor of `succ`. */
334334
private predicate predBB(BasicBlock succ, BasicBlock pred) { succBB(pred, succ) }
335335

336+
/** Holds if `bb` is an exit basic block that represents normal exit. */
337+
private predicate normalExitBB(BasicBlock bb) {
338+
bb.getANode().(ControlFlow::Nodes::AnnotatedExitNode).isNormal()
339+
}
340+
336341
/** Holds if `dom` is an immediate post-dominator of `bb`. */
337342
cached
338343
predicate bbIPostDominates(BasicBlock dom, BasicBlock bb) =
339-
idominance(exitBB/1, predBB/2)(_, dom, bb)
344+
idominance(normalExitBB/1, predBB/2)(_, dom, bb)
340345
}
341346

342347
private import Internal
@@ -354,17 +359,22 @@ private predicate entryBB(BasicBlock bb) {
354359
bb.getFirstNode() instanceof ControlFlow::Nodes::EntryNode
355360
}
356361

362+
/**
363+
* An annotated exit basic block, that is, a basic block that contains
364+
* an annotated exit node.
365+
*/
366+
class AnnotatedExitBasicBlock extends BasicBlock {
367+
AnnotatedExitBasicBlock() { this.getANode() instanceof ControlFlow::Nodes::AnnotatedExitNode }
368+
}
369+
357370
/**
358371
* An exit basic block, that is, a basic block whose last node is
359372
* the exit node of a callable.
360373
*/
361374
class ExitBasicBlock extends BasicBlock {
362-
ExitBasicBlock() { exitBB(this) }
375+
ExitBasicBlock() { this.getLastNode() instanceof ControlFlow::Nodes::ExitNode }
363376
}
364377

365-
/** Holds if `bb` is an exit basic block. */
366-
private predicate exitBB(BasicBlock bb) { bb.getLastNode() instanceof ControlFlow::Nodes::ExitNode }
367-
368378
private module JoinBlockPredecessors {
369379
private import ControlFlow::Nodes
370380

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

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,8 @@ module ControlFlow {
108108
/**
109109
* Holds if this node post-dominates `that` node.
110110
*
111-
* That is, all paths reaching a callable exit node (`ExitNode`)
112-
* from `that` node must go through this node.
111+
* That is, all paths reaching a normal callable exit node (an `AnnotatedExitNode`
112+
* with a normal exit type) from `that` node must go through this node.
113113
*
114114
* Example:
115115
*
@@ -145,9 +145,9 @@ module ControlFlow {
145145
/**
146146
* Holds if this node strictly post-dominates `that` node.
147147
*
148-
* That is, all paths reaching a callable exit node (`ExitNode`)
149-
* from `that` node must go through this node (which must be different
150-
* from `that` node).
148+
* That is, all paths reaching a normal callable exit node (an `AnnotatedExitNode`
149+
* with a normal exit type) from `that` node must go through this node
150+
* (which must be different from `that` node).
151151
*
152152
* Example:
153153
*
@@ -259,6 +259,38 @@ module ControlFlow {
259259
override string toString() { result = "enter " + getCallable().toString() }
260260
}
261261

262+
/** A node for a callable exit point, annotated with the type of exit. */
263+
class AnnotatedExitNode extends Node, TAnnotatedExitNode {
264+
private Callable c;
265+
private boolean normal;
266+
267+
AnnotatedExitNode() { this = TAnnotatedExitNode(c, normal) }
268+
269+
/** Gets the callable that this exit applies to. */
270+
Callable getCallable() { result = c }
271+
272+
/** Holds if this node represent a normal exit. */
273+
predicate isNormal() { normal = true }
274+
275+
override BasicBlocks::AnnotatedExitBlock getBasicBlock() {
276+
result = Node.super.getBasicBlock()
277+
}
278+
279+
override Callable getEnclosingCallable() { result = this.getCallable() }
280+
281+
override Location getLocation() { result = getCallable().getLocation() }
282+
283+
override string toString() {
284+
exists(string s |
285+
normal = true and s = "normal"
286+
or
287+
normal = false and s = "abnormal"
288+
|
289+
result = "exit " + getCallable() + " (" + s + ")"
290+
)
291+
}
292+
}
293+
262294
/** A node for a callable exit point. */
263295
class ExitNode extends Node, TExitNode {
264296
/** Gets the callable that this exit applies to. */
@@ -343,6 +375,8 @@ module ControlFlow {
343375
module BasicBlocks {
344376
class EntryBlock = BBs::EntryBasicBlock;
345377

378+
class AnnotatedExitBlock = BBs::AnnotatedExitBasicBlock;
379+
346380
class ExitBlock = BBs::ExitBasicBlock;
347381

348382
class JoinBlock = BBs::JoinBlock;
@@ -1953,6 +1987,10 @@ module ControlFlow {
19531987
private module Cached {
19541988
private import semmle.code.csharp.Caching
19551989

1990+
private predicate isAbnormalExitType(SuccessorType t) {
1991+
t instanceof ExceptionSuccessor or t instanceof ExitSuccessor
1992+
}
1993+
19561994
/**
19571995
* Internal representation of control flow nodes in the control flow graph.
19581996
* The control flow graph is pruned for unreachable nodes.
@@ -1963,6 +2001,12 @@ module ControlFlow {
19632001
Stages::ControlFlowStage::forceCachingInSameStage() and
19642002
succEntrySplits(c, _, _, _)
19652003
} or
2004+
TAnnotatedExitNode(Callable c, boolean normal) {
2005+
exists(Reachability::SameSplitsBlock b, SuccessorType t | b.isReachable(_) |
2006+
succExitSplits(b.getAnElement(), _, c, t) and
2007+
if isAbnormalExitType(t) then normal = false else normal = true
2008+
)
2009+
} or
19662010
TExitNode(Callable c) {
19672011
exists(Reachability::SameSplitsBlock b | b.isReachable(_) |
19682012
succExitSplits(b.getAnElement(), _, c, _)
@@ -1985,8 +2029,12 @@ module ControlFlow {
19852029
exists(ControlFlowElement predElement, Splits predSplits |
19862030
pred = TElementNode(predElement, predSplits)
19872031
|
1988-
// Element node -> callable exit
1989-
succExitSplits(predElement, predSplits, result.(Nodes::ExitNode).getCallable(), t)
2032+
// Element node -> callable exit (annotated)
2033+
result =
2034+
any(Nodes::AnnotatedExitNode exit |
2035+
succExitSplits(predElement, predSplits, exit.getCallable(), t) and
2036+
if isAbnormalExitType(t) then not exit.isNormal() else exit.isNormal()
2037+
)
19902038
or
19912039
// Element node -> element node
19922040
exists(ControlFlowElement succElement, Splits succSplits, Completion c |
@@ -1996,6 +2044,10 @@ module ControlFlow {
19962044
t.matchesCompletion(c)
19972045
)
19982046
)
2047+
or
2048+
// Callable exit (annotated) -> callable exit
2049+
pred.(Nodes::AnnotatedExitNode).getCallable() = result.(Nodes::ExitNode).getCallable() and
2050+
t instanceof SuccessorTypes::NormalSuccessor
19992051
}
20002052

20012053
/**

0 commit comments

Comments
 (0)