Skip to content

Commit a89be2e

Browse files
committed
C#: Extend (Annotated)ExitNode to also cover static fields
1 parent 474c808 commit a89be2e

File tree

5 files changed

+53
-15
lines changed

5 files changed

+53
-15
lines changed

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

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -268,13 +268,13 @@ module ControlFlow {
268268

269269
/** A node for a callable exit point, annotated with the type of exit. */
270270
class AnnotatedExitNode extends Node, TAnnotatedExitNode {
271-
private Callable c;
271+
private CfgScope scope;
272272
private boolean normal;
273273

274-
AnnotatedExitNode() { this = TAnnotatedExitNode(c, normal) }
274+
AnnotatedExitNode() { this = TAnnotatedExitNode(scope, normal) }
275275

276276
/** Gets the callable that this exit applies to. */
277-
Callable getCallable() { result = c }
277+
CfgScope getCallable() { result = scope }
278278

279279
/** Holds if this node represents a normal exit. */
280280
predicate isNormal() { normal = true }
@@ -285,31 +285,35 @@ module ControlFlow {
285285

286286
override Callable getEnclosingCallable() { result = this.getCallable() }
287287

288-
override Location getLocation() { result = this.getCallable().getLocation() }
288+
override Location getLocation() { result = scope.getLocation() }
289289

290290
override string toString() {
291291
exists(string s |
292292
normal = true and s = "normal"
293293
or
294294
normal = false and s = "abnormal"
295295
|
296-
result = "exit " + this.getCallable() + " (" + s + ")"
296+
result = "exit " + scope + " (" + s + ")"
297297
)
298298
}
299299
}
300300

301301
/** A node for a callable exit point. */
302302
class ExitNode extends Node, TExitNode {
303+
private CfgScope scope;
304+
305+
ExitNode() { this = TExitNode(scope) }
306+
303307
/** Gets the callable that this exit applies to. */
304-
Callable getCallable() { this = TExitNode(result) }
308+
Callable getCallable() { result = scope }
305309

306310
override BasicBlocks::ExitBlock getBasicBlock() { result = Node.super.getBasicBlock() }
307311

308312
override Callable getEnclosingCallable() { result = this.getCallable() }
309313

310-
override Location getLocation() { result = this.getCallable().getLocation() }
314+
override Location getLocation() { result = scope.getLocation() }
311315

312-
override string toString() { result = "exit " + this.getCallable().toString() }
316+
override string toString() { result = "exit " + scope }
313317
}
314318

315319
/**

csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImpl.qll

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,24 @@ module ControlFlowTree {
9797
predicate idOf(Range_ x, int y) = equivalenceRelation(id/2)(x, y)
9898
}
9999

100+
/**
101+
* The `expr_parent_top_level_adjusted()` relation restricted to exclude relations
102+
* between properties and their getters' expression bodies in properties such as
103+
* `int P => 0`.
104+
*
105+
* This is in order to only associate the expression body with one CFG scope, namely
106+
* the getter (and not the declaration itself).
107+
*/
108+
private predicate expr_parent_top_level_adjusted2(
109+
Expr child, int i, @top_level_exprorstmt_parent parent
110+
) {
111+
expr_parent_top_level_adjusted(child, i, parent) and
112+
not exists(Getter g |
113+
g.getDeclaration() = parent and
114+
i = 0
115+
)
116+
}
117+
100118
/** Holds if `first` is first executed when entering `scope`. */
101119
predicate scopeFirst(CfgScope scope, ControlFlowElement first) {
102120
scope =
@@ -109,17 +127,23 @@ predicate scopeFirst(CfgScope scope, ControlFlowElement first) {
109127
else first(c.getBody(), first)
110128
)
111129
or
112-
expr_parent_top_level_adjusted(any(Expr e | first(e, first)), _, scope) and
130+
expr_parent_top_level_adjusted2(any(Expr e | first(e, first)), _, scope) and
113131
not scope instanceof Callable
114132
}
115133

116134
/** Holds if `scope` is exited when `last` finishes with completion `c`. */
117-
predicate scopeLast(Callable scope, ControlFlowElement last, Completion c) {
118-
last(scope.getBody(), last, c) and
119-
not c instanceof GotoCompletion
135+
predicate scopeLast(CfgScope scope, ControlFlowElement last, Completion c) {
136+
scope =
137+
any(Callable callable |
138+
last(callable.getBody(), last, c) and
139+
not c instanceof GotoCompletion
140+
or
141+
last(InitializerSplitting::lastConstructorInitializer(scope, _), last, c) and
142+
not callable.hasBody()
143+
)
120144
or
121-
last(InitializerSplitting::lastConstructorInitializer(scope, _), last, c) and
122-
not scope.hasBody()
145+
expr_parent_top_level_adjusted2(any(Expr e | last(e, last, c)), _, scope) and
146+
not scope instanceof Callable
123147
}
124148

125149
private class ConstructorTree extends ControlFlowTree, Constructor {

csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -677,7 +677,7 @@
677677
| Initializers.cs:8:5:8:16 | enter Initializers | Initializers.cs:8:5:8:16 | exit Initializers | 16 |
678678
| Initializers.cs:10:5:10:16 | enter Initializers | Initializers.cs:10:5:10:16 | exit Initializers | 16 |
679679
| Initializers.cs:12:10:12:10 | enter M | Initializers.cs:12:10:12:10 | exit M | 22 |
680-
| Initializers.cs:18:16:18:16 | enter H | Initializers.cs:18:16:18:20 | ... = ... | 3 |
680+
| Initializers.cs:18:16:18:16 | enter H | Initializers.cs:18:16:18:16 | exit H | 5 |
681681
| Initializers.cs:20:11:20:23 | enter NoConstructor | Initializers.cs:20:11:20:23 | exit NoConstructor | 9 |
682682
| Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:9:31:11 | exit Sub | 12 |
683683
| Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:33:9:33:11 | exit Sub | 9 |

csharp/ql/test/library-tests/controlflow/graph/Dominance.expected

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2505,6 +2505,8 @@ dominance
25052505
| Initializers.cs:15:42:15:61 | object creation of type Initializers | Initializers.cs:15:37:15:63 | { ..., ... } |
25062506
| Initializers.cs:15:59:15:60 | "" | Initializers.cs:15:42:15:61 | object creation of type Initializers |
25072507
| Initializers.cs:18:16:18:16 | enter H | Initializers.cs:18:20:18:20 | 1 |
2508+
| Initializers.cs:18:16:18:16 | exit H (normal) | Initializers.cs:18:16:18:16 | exit H |
2509+
| Initializers.cs:18:16:18:20 | ... = ... | Initializers.cs:18:16:18:16 | exit H (normal) |
25082510
| Initializers.cs:18:20:18:20 | 1 | Initializers.cs:18:16:18:20 | ... = ... |
25092511
| Initializers.cs:20:11:20:23 | enter NoConstructor | Initializers.cs:22:23:22:23 | this access |
25102512
| Initializers.cs:20:11:20:23 | exit NoConstructor (normal) | Initializers.cs:20:11:20:23 | exit NoConstructor |
@@ -6631,6 +6633,8 @@ postDominance
66316633
| Initializers.cs:15:39:15:39 | access to local variable i | Initializers.cs:15:18:15:63 | array creation of type Initializers[] |
66326634
| Initializers.cs:15:42:15:61 | object creation of type Initializers | Initializers.cs:15:59:15:60 | "" |
66336635
| Initializers.cs:15:59:15:60 | "" | Initializers.cs:15:39:15:39 | access to local variable i |
6636+
| Initializers.cs:18:16:18:16 | exit H | Initializers.cs:18:16:18:16 | exit H (normal) |
6637+
| Initializers.cs:18:16:18:16 | exit H (normal) | Initializers.cs:18:16:18:20 | ... = ... |
66346638
| Initializers.cs:18:16:18:20 | ... = ... | Initializers.cs:18:20:18:20 | 1 |
66356639
| Initializers.cs:18:20:18:20 | 1 | Initializers.cs:18:16:18:16 | enter H |
66366640
| Initializers.cs:20:11:20:23 | exit NoConstructor | Initializers.cs:20:11:20:23 | exit NoConstructor (normal) |

csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8252,6 +8252,12 @@ Initializers.cs:
82528252
#-----| -> 1
82538253

82548254
# 18| ... = ...
8255+
#-----| -> exit H (normal)
8256+
8257+
# 18| exit H
8258+
8259+
# 18| exit H (normal)
8260+
#-----| -> exit H
82558261

82568262
# 18| 1
82578263
#-----| -> ... = ...

0 commit comments

Comments
 (0)