@@ -108,8 +108,8 @@ module ControlFlow {
108
108
/**
109
109
* Holds if this node post-dominates `that` node.
110
110
*
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.
113
113
*
114
114
* Example:
115
115
*
@@ -145,9 +145,9 @@ module ControlFlow {
145
145
/**
146
146
* Holds if this node strictly post-dominates `that` node.
147
147
*
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).
151
151
*
152
152
* Example:
153
153
*
@@ -259,6 +259,38 @@ module ControlFlow {
259
259
override string toString ( ) { result = "enter " + getCallable ( ) .toString ( ) }
260
260
}
261
261
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
+
262
294
/** A node for a callable exit point. */
263
295
class ExitNode extends Node , TExitNode {
264
296
/** Gets the callable that this exit applies to. */
@@ -343,6 +375,8 @@ module ControlFlow {
343
375
module BasicBlocks {
344
376
class EntryBlock = BBs:: EntryBasicBlock ;
345
377
378
+ class AnnotatedExitBlock = BBs:: AnnotatedExitBasicBlock ;
379
+
346
380
class ExitBlock = BBs:: ExitBasicBlock ;
347
381
348
382
class JoinBlock = BBs:: JoinBlock ;
@@ -1953,6 +1987,10 @@ module ControlFlow {
1953
1987
private module Cached {
1954
1988
private import semmle.code.csharp.Caching
1955
1989
1990
+ private predicate isAbnormalExitType ( SuccessorType t ) {
1991
+ t instanceof ExceptionSuccessor or t instanceof ExitSuccessor
1992
+ }
1993
+
1956
1994
/**
1957
1995
* Internal representation of control flow nodes in the control flow graph.
1958
1996
* The control flow graph is pruned for unreachable nodes.
@@ -1963,6 +2001,12 @@ module ControlFlow {
1963
2001
Stages:: ControlFlowStage:: forceCachingInSameStage ( ) and
1964
2002
succEntrySplits ( c , _, _, _)
1965
2003
} 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
1966
2010
TExitNode ( Callable c ) {
1967
2011
exists ( Reachability:: SameSplitsBlock b | b .isReachable ( _) |
1968
2012
succExitSplits ( b .getAnElement ( ) , _, c , _)
@@ -1985,8 +2029,12 @@ module ControlFlow {
1985
2029
exists ( ControlFlowElement predElement , Splits predSplits |
1986
2030
pred = TElementNode ( predElement , predSplits )
1987
2031
|
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
+ )
1990
2038
or
1991
2039
// Element node -> element node
1992
2040
exists ( ControlFlowElement succElement , Splits succSplits , Completion c |
@@ -1996,6 +2044,10 @@ module ControlFlow {
1996
2044
t .matchesCompletion ( c )
1997
2045
)
1998
2046
)
2047
+ or
2048
+ // Callable exit (annotated) -> callable exit
2049
+ pred .( Nodes:: AnnotatedExitNode ) .getCallable ( ) = result .( Nodes:: ExitNode ) .getCallable ( ) and
2050
+ t instanceof SuccessorTypes:: NormalSuccessor
1999
2051
}
2000
2052
2001
2053
/**
0 commit comments