Skip to content

Commit c8a5397

Browse files
authored
Merge pull request github#6513 from hvitved/csharp/cfg/shared
C#: Make CFG library shared
2 parents cf9ab83 + ab2bc38 commit c8a5397

File tree

12 files changed

+15513
-5850
lines changed

12 files changed

+15513
-5850
lines changed

csharp/ql/lib/semmle/code/csharp/Caching.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ module Stages {
1818

1919
cached
2020
private predicate forceCachingInSameStageRev() {
21-
exists(SplitImpl si)
21+
exists(Split s)
2222
or
2323
exists(SuccessorType st)
2424
or

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ module ControlFlow {
183183
}
184184

185185
/** Gets a successor node of a given type, if any. */
186-
Node getASuccessorByType(SuccessorType t) { result = getASuccessorByType(this, t) }
186+
Node getASuccessorByType(SuccessorType t) { result = getASuccessor(this, t) }
187187

188188
/** Gets an immediate successor, if any. */
189189
Node getASuccessor() { result = getASuccessorByType(_) }
@@ -255,9 +255,15 @@ module ControlFlow {
255255

256256
override Callable getEnclosingCallable() { result = this.getCallable() }
257257

258-
override Location getLocation() { result = getCallable().getLocation() }
258+
private Assignable getAssignable() { this = TEntryNode(result) }
259+
260+
override Location getLocation() {
261+
result in [this.getCallable().getLocation(), this.getAssignable().getLocation()]
262+
}
259263

260-
override string toString() { result = "enter " + getCallable().toString() }
264+
override string toString() {
265+
result = "enter " + [this.getCallable().toString(), this.getAssignable().toString()]
266+
}
261267
}
262268

263269
/** A node for a callable exit point, annotated with the type of exit. */
@@ -314,7 +320,7 @@ module ControlFlow {
314320
* different splits for the element.
315321
*/
316322
class ElementNode extends Node, TElementNode {
317-
private Splitting::Splits splits;
323+
private Splits splits;
318324
private ControlFlowElement cfe;
319325

320326
ElementNode() { this = TElementNode(cfe, splits) }

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

Lines changed: 16 additions & 228 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,22 @@
4343
*/
4444

4545
import csharp
46-
private import semmle.code.csharp.controlflow.ControlFlowGraph::ControlFlow
4746
private import Completion
48-
private import SuccessorType
49-
private import SuccessorTypes
5047
private import Splitting
5148
private import semmle.code.csharp.ExprOrStmtParent
5249
private import semmle.code.csharp.commons.Compilation
50+
import ControlFlowGraphImplShared
51+
52+
/** An element that defines a new CFG scope. */
53+
class CfgScope extends Element, @top_level_exprorstmt_parent {
54+
CfgScope() {
55+
this instanceof Callable
56+
or
57+
// For now, static initializer values have their own scope. Eventually, they
58+
// should be treated like instance initializers.
59+
this.(Assignable).(Modifiable).isStatic()
60+
}
61+
}
5362

5463
/**
5564
* A compilation.
@@ -71,16 +80,11 @@ CompilationExt getCompilation(SourceFile f) {
7180
result = TBuildless()
7281
}
7382

74-
/** An element that defines a new CFG scope. */
75-
class CfgScope extends Element, @top_level_exprorstmt_parent {
76-
CfgScope() { not this instanceof Attribute }
77-
}
78-
7983
module ControlFlowTree {
8084
class Range_ = @callable or @control_flow_element;
8185

8286
class Range extends Element, Range_ {
83-
Range() { this = getAChild*(any(CfgScope scope)) }
87+
Range() { this = getAChild*(any(@top_level_exprorstmt_parent p | not p instanceof Attribute)) }
8488
}
8589

8690
Element getAChild(Element p) {
@@ -93,61 +97,6 @@ module ControlFlowTree {
9397
predicate idOf(Range_ x, int y) = equivalenceRelation(id/2)(x, y)
9498
}
9599

96-
abstract private class ControlFlowTree extends ControlFlowTree::Range {
97-
/**
98-
* Holds if `first` is the first element executed within this control
99-
* flow element.
100-
*/
101-
pragma[nomagic]
102-
abstract predicate first(ControlFlowElement first);
103-
104-
/**
105-
* Holds if `last` with completion `c` is a potential last element executed
106-
* within this control flow element.
107-
*/
108-
pragma[nomagic]
109-
abstract predicate last(ControlFlowElement last, Completion c);
110-
111-
/** Holds if abnormal execution of `child` should propagate upwards. */
112-
abstract predicate propagatesAbnormal(ControlFlowElement child);
113-
114-
/**
115-
* Holds if `succ` is a control flow successor for `pred`, given that `pred`
116-
* finishes with completion `c`.
117-
*/
118-
pragma[nomagic]
119-
abstract predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c);
120-
}
121-
122-
/**
123-
* Holds if `first` is the first element executed within control flow
124-
* element `cft`.
125-
*/
126-
predicate first(ControlFlowTree cft, ControlFlowElement first) { cft.first(first) }
127-
128-
/**
129-
* Holds if `last` with completion `c` is a potential last element executed
130-
* within control flow element `cft`.
131-
*/
132-
predicate last(ControlFlowTree cft, ControlFlowElement last, Completion c) {
133-
cft.last(last, c)
134-
or
135-
exists(ControlFlowElement cfe |
136-
cft.propagatesAbnormal(cfe) and
137-
last(cfe, last, c) and
138-
not c instanceof NormalCompletion
139-
)
140-
}
141-
142-
/**
143-
* Holds if `succ` is a control flow successor for `pred`, given that `pred`
144-
* finishes with completion `c`.
145-
*/
146-
pragma[nomagic]
147-
predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
148-
any(ControlFlowTree cft).succ(pred, succ, c)
149-
}
150-
151100
/** Holds if `first` is first executed when entering `scope`. */
152101
predicate scopeFirst(CfgScope scope, ControlFlowElement first) {
153102
scope =
@@ -161,8 +110,7 @@ predicate scopeFirst(CfgScope scope, ControlFlowElement first) {
161110
)
162111
or
163112
expr_parent_top_level_adjusted(any(Expr e | first(e, first)), _, scope) and
164-
not scope instanceof Callable and
165-
not scope instanceof InitializerSplitting::InitializedInstanceMember
113+
not scope instanceof Callable
166114
}
167115

168116
/** Holds if `scope` is exited when `last` finishes with completion `c`. */
@@ -204,53 +152,6 @@ private class ConstructorTree extends ControlFlowTree, Constructor {
204152
}
205153
}
206154

207-
/**
208-
* A control flow element where the children are evaluated following a
209-
* standard left-to-right evaluation. The actual evaluation order is
210-
* determined by the predicate `getChildElement()`.
211-
*/
212-
abstract private class StandardElement extends ControlFlowTree {
213-
/** Gets the `i`th child element, in order of evaluation, starting from 0. */
214-
abstract ControlFlowElement getChildElement(int i);
215-
216-
/** Gets the first child element of this element. */
217-
final ControlFlowElement getFirstChild() { result = this.getChildElement(0) }
218-
219-
/** Holds if this element has no children. */
220-
final predicate isLeafElement() { not exists(this.getFirstChild()) }
221-
222-
/** Gets the last child element of this element. */
223-
final ControlFlowTree getLastChild() {
224-
exists(int last |
225-
result = this.getChildElement(last) and
226-
not exists(this.getChildElement(last + 1))
227-
)
228-
}
229-
230-
final override predicate propagatesAbnormal(ControlFlowElement child) {
231-
child = this.getChildElement(_)
232-
}
233-
234-
override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
235-
exists(int i |
236-
last(this.getChildElement(i), pred, c) and
237-
first(this.getChildElement(i + 1), succ) and
238-
c instanceof NormalCompletion
239-
)
240-
}
241-
}
242-
243-
abstract private class PreOrderTree extends ControlFlowTree {
244-
final override predicate first(ControlFlowElement first) { first = this }
245-
}
246-
247-
abstract private class PostOrderTree extends ControlFlowTree {
248-
override predicate last(ControlFlowElement last, Completion c) {
249-
last = this and
250-
c.isValidFor(last)
251-
}
252-
}
253-
254155
abstract private class SwitchTree extends ControlFlowTree, Switch {
255156
override predicate propagatesAbnormal(ControlFlowElement child) { child = this.getExpr() }
256157

@@ -368,7 +269,7 @@ module Expressions {
368269
)
369270
}
370271

371-
private class StandardExpr extends StandardElement, PostOrderTree, Expr {
272+
private class StandardExpr extends StandardPostOrderTree, Expr {
372273
StandardExpr() {
373274
// The following expressions need special treatment
374275
not this instanceof LogicalNotExpr and
@@ -396,21 +297,6 @@ module Expressions {
396297
}
397298

398299
final override ControlFlowElement getChildElement(int i) { result = getExprChild(this, i) }
399-
400-
final override predicate first(ControlFlowElement first) {
401-
first(this.getFirstChild(), first)
402-
or
403-
not exists(this.getFirstChild()) and
404-
first = this
405-
}
406-
407-
final override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
408-
StandardElement.super.succ(pred, succ, c)
409-
or
410-
last(this.getLastChild(), pred, c) and
411-
succ = this and
412-
c instanceof NormalCompletion
413-
}
414300
}
415301

416302
/**
@@ -1095,7 +981,7 @@ private class PropertyPatternExprExprTree extends PostOrderTree, PropertyPattern
1095981
}
1096982

1097983
module Statements {
1098-
private class StandardStmt extends StandardElement, PreOrderTree, Stmt {
984+
private class StandardStmt extends StandardPreOrderTree, Stmt {
1099985
StandardStmt() {
1100986
// The following statements need special treatment
1101987
not this instanceof IfStmt and
@@ -1140,22 +1026,6 @@ module Statements {
11401026
result =
11411027
rank[i + 1](ControlFlowElement cfe, int j | cfe = this.getChildElement0(j) | cfe order by j)
11421028
}
1143-
1144-
final override predicate last(ControlFlowElement last, Completion c) {
1145-
last(this.getLastChild(), last, c)
1146-
or
1147-
this.isLeafElement() and
1148-
last = this and
1149-
c.isValidFor(this)
1150-
}
1151-
1152-
final override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
1153-
StandardElement.super.succ(pred, succ, c)
1154-
or
1155-
pred = this and
1156-
first(this.getFirstChild(), succ) and
1157-
c instanceof SimpleCompletion
1158-
}
11591029
}
11601030

11611031
private class IfStmtTree extends PreOrderTree, IfStmt {
@@ -1779,88 +1649,6 @@ module Statements {
17791649
}
17801650
}
17811651

1782-
cached
1783-
private module Cached {
1784-
private import semmle.code.csharp.Caching
1785-
1786-
private predicate isAbnormalExitType(SuccessorType t) {
1787-
t instanceof ExceptionSuccessor or t instanceof ExitSuccessor
1788-
}
1789-
1790-
/**
1791-
* Internal representation of control flow nodes in the control flow graph.
1792-
* The control flow graph is pruned for unreachable nodes.
1793-
*/
1794-
cached
1795-
newtype TNode =
1796-
TEntryNode(Callable c) {
1797-
Stages::ControlFlowStage::forceCachingInSameStage() and
1798-
succEntrySplits(c, _, _, _)
1799-
} or
1800-
TAnnotatedExitNode(Callable c, boolean normal) {
1801-
exists(Reachability::SameSplitsBlock b, SuccessorType t | b.isReachable(_) |
1802-
succExitSplits(b.getAnElement(), _, c, t) and
1803-
if isAbnormalExitType(t) then normal = false else normal = true
1804-
)
1805-
} or
1806-
TExitNode(Callable c) {
1807-
exists(Reachability::SameSplitsBlock b | b.isReachable(_) |
1808-
succExitSplits(b.getAnElement(), _, c, _)
1809-
)
1810-
} or
1811-
TElementNode(ControlFlowElement cfe, Splits splits) {
1812-
exists(Reachability::SameSplitsBlock b | b.isReachable(splits) | cfe = b.getAnElement())
1813-
}
1814-
1815-
/** Gets a successor node of a given flow type, if any. */
1816-
cached
1817-
Node getASuccessorByType(Node pred, SuccessorType t) {
1818-
// Callable entry node -> callable body
1819-
exists(ControlFlowElement succElement, Splits succSplits |
1820-
result = TElementNode(succElement, succSplits)
1821-
|
1822-
succEntrySplits(pred.(Nodes::EntryNode).getCallable(), succElement, succSplits, t)
1823-
)
1824-
or
1825-
exists(ControlFlowElement predElement, Splits predSplits |
1826-
pred = TElementNode(predElement, predSplits)
1827-
|
1828-
// Element node -> callable exit (annotated)
1829-
result =
1830-
any(Nodes::AnnotatedExitNode exit |
1831-
succExitSplits(predElement, predSplits, exit.getCallable(), t) and
1832-
if isAbnormalExitType(t) then not exit.isNormal() else exit.isNormal()
1833-
)
1834-
or
1835-
// Element node -> element node
1836-
exists(ControlFlowElement succElement, Splits succSplits, Completion c |
1837-
result = TElementNode(succElement, succSplits)
1838-
|
1839-
succSplits(predElement, predSplits, succElement, succSplits, c) and
1840-
t = c.getAMatchingSuccessorType()
1841-
)
1842-
)
1843-
or
1844-
// Callable exit (annotated) -> callable exit
1845-
pred.(Nodes::AnnotatedExitNode).getCallable() = result.(Nodes::ExitNode).getCallable() and
1846-
t instanceof SuccessorTypes::NormalSuccessor
1847-
}
1848-
1849-
/**
1850-
* Gets a first control flow element executed within `cfe`.
1851-
*/
1852-
cached
1853-
ControlFlowElement getAControlFlowEntryNode(ControlFlowElement cfe) { first(cfe, result) }
1854-
1855-
/**
1856-
* Gets a potential last control flow element executed within `cfe`.
1857-
*/
1858-
cached
1859-
ControlFlowElement getAControlFlowExitNode(ControlFlowElement cfe) { last(cfe, result, _) }
1860-
}
1861-
1862-
import Cached
1863-
18641652
/** A control flow element that is split into multiple control flow nodes. */
18651653
class SplitControlFlowElement extends ControlFlowElement {
18661654
SplitControlFlowElement() { strictcount(this.getAControlFlowNode()) > 1 }

0 commit comments

Comments
 (0)