Skip to content

Commit f912731

Browse files
authored
Merge pull request #21565 from aschackmull/csharp/cfg2
C#: Replace CFG with the shared implementation
2 parents 6efb213 + 67c0515 commit f912731

File tree

116 files changed

+40608
-31942
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

116 files changed

+40608
-31942
lines changed

csharp/ql/campaigns/Solorigate/src/ModifiedFnvFunctionDetection.ql

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@ import csharp
1313
import Solorigate
1414
import experimental.code.csharp.Cryptography.NonCryptographicHashes
1515

16+
ControlFlowNode loopExitNode(LoopStmt loop) { result.isAfter(loop) }
17+
1618
from Variable v, Literal l, LoopStmt loop, Expr additional_xor
1719
where
1820
maybeUsedInFnvFunction(v, _, _, loop) and
1921
exists(BitwiseXorOperation xor2 | xor2.getAnOperand() = l and additional_xor = xor2 |
20-
loop.getAControlFlowExitNode().getASuccessor*() = xor2.getAControlFlowNode() and
22+
loopExitNode(loop).getASuccessor*() = xor2.getControlFlowNode() and
2123
xor2.getAnOperand() = v.getAnAccess()
2224
)
2325
select l, "This literal is used in an $@ after an FNV-like hash calculation with variable $@.",
Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,2 @@
11
import csharp
2-
import semmle.code.csharp.controlflow.internal.Completion
3-
import ControlFlow
4-
import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl::Consistency
5-
import semmle.code.csharp.controlflow.internal.Splitting
2+
import ControlFlow::Consistency

csharp/ql/consistency-queries/DataFlowConsistency.ql

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,11 @@
11
import csharp
2-
private import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl as ControlFlowGraphImpl
32
private import semmle.code.csharp.dataflow.internal.DataFlowImplSpecific
43
private import semmle.code.csharp.dataflow.internal.TaintTrackingImplSpecific
54
private import codeql.dataflow.internal.DataFlowImplConsistency
65

76
private module Input implements InputSig<Location, CsharpDataFlow> {
87
private import CsharpDataFlow
98

10-
private predicate isStaticAssignable(Assignable a) { a.(Modifiable).isStatic() }
11-
12-
predicate uniqueEnclosingCallableExclude(Node node) {
13-
// TODO: Remove once static initializers are folded into the
14-
// static constructors
15-
isStaticAssignable(ControlFlowGraphImpl::getNodeCfgScope(node.getControlFlowNode()))
16-
}
17-
18-
predicate uniqueCallEnclosingCallableExclude(DataFlowCall call) {
19-
// TODO: Remove once static initializers are folded into the
20-
// static constructors
21-
isStaticAssignable(ControlFlowGraphImpl::getNodeCfgScope(call.getControlFlowNode()))
22-
}
23-
249
predicate uniqueNodeLocationExclude(Node n) {
2510
// Methods with multiple implementations
2611
n instanceof ParameterNode
@@ -70,17 +55,14 @@ private module Input implements InputSig<Location, CsharpDataFlow> {
7055
init.getInitializer().getNumberOfChildren() > 1
7156
)
7257
or
73-
exists(ControlFlow::Nodes::ElementNode cfn, ControlFlow::Nodes::Split split |
74-
exists(arg.asExprAtNode(cfn))
75-
|
76-
split = cfn.getASplit() and
77-
not split = call.getControlFlowNode().getASplit()
78-
or
79-
split = call.getControlFlowNode().getASplit() and
80-
not split = cfn.getASplit()
81-
)
82-
or
8358
call.(NonDelegateDataFlowCall).getDispatchCall().isReflection()
59+
or
60+
// Exclude calls that are both getter and setter calls, as they share the same argument nodes.
61+
exists(AccessorCall ac |
62+
call.(NonDelegateDataFlowCall).getDispatchCall().getCall() = ac and
63+
ac instanceof AssignableRead and
64+
ac instanceof AssignableWrite
65+
)
8466
)
8567
}
8668
}

csharp/ql/consistency-queries/VariableCaptureConsistency.ql

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,6 @@
11
import csharp
22
import semmle.code.csharp.dataflow.internal.DataFlowPrivate::VariableCapture::Flow::ConsistencyChecks
33
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate::VariableCapture::Flow::ConsistencyChecks as ConsistencyChecks
4-
private import semmle.code.csharp.controlflow.BasicBlocks
5-
private import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl
6-
7-
query predicate uniqueEnclosingCallable(BasicBlock bb, string msg) {
8-
ConsistencyChecks::uniqueEnclosingCallable(bb, msg) and
9-
getNodeCfgScope(bb.getFirstNode()) instanceof Callable
10-
}
114

125
query predicate consistencyOverview(string msg, int n) { none() }
136

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
category: breaking
3+
---
4+
* The C# control flow graph (CFG) implementation has been completely
5+
rewritten. The CFG now includes additional nodes to more accurately represent
6+
certain constructs. This also means that any existing code that implicitly
7+
relies on very specific details about the CFG may need to be updated.
8+
The CFG no longer uses splitting, which means that AST nodes now have a unique
9+
CFG node representation.
10+
Additionally, the following breaking changes have been made:
11+
- `ControlFlow::Node` has been renamed to `ControlFlowNode`.
12+
- `ControlFlow::Nodes` has been renamed to `ControlFlowNodes`.
13+
- `BasicBlock.getCallable` has been renamed to `BasicBlock.getEnclosingCallable`.
14+
- `BasicBlocks.qll` has been deleted.
15+
- `ControlFlowNode.getAstNode` has changed its meaning. The AST-to-CFG
16+
mapping remains one-to-many, but now for a different reason. It used to be
17+
because of splitting, but now it's because of additional "helper" CFG
18+
nodes. To get the (now canonical) CFG node for a given AST node, use
19+
`ControlFlowNode.asExpr()` or `ControlFlowNode.asStmt()` or
20+
`ControlFlowElement.getControlFlowNode()` instead.

csharp/ql/lib/experimental/code/csharp/Cryptography/NonCryptographicHashes.qll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ predicate maybeUsedInFnvFunction(Variable v, Operation xor, Operation mul, LoopS
3030
e2.getAChild*() = v.getAnAccess() and
3131
e1 = xor.getAnOperand() and
3232
e2 = mul.getAnOperand() and
33-
xor.getAControlFlowNode().getASuccessor*() = mul.getAControlFlowNode() and
33+
xor.getControlFlowNode().getASuccessor*() = mul.getControlFlowNode() and
3434
(xor instanceof AssignXorExpr or xor instanceof BitwiseXorExpr) and
3535
(mul instanceof AssignMulExpr or mul instanceof MulExpr)
3636
) and
@@ -55,11 +55,11 @@ private predicate maybeUsedInElfHashFunction(Variable v, Operation xor, Operatio
5555
v = addAssign.getTargetVariable() and
5656
addAssign.getAChild*() = add and
5757
(xor instanceof BitwiseXorExpr or xor instanceof AssignXorExpr) and
58-
addAssign.getAControlFlowNode().getASuccessor*() = xor.getAControlFlowNode() and
58+
addAssign.getControlFlowNode().getASuccessor*() = xor.getControlFlowNode() and
5959
xorAssign.getAChild*() = xor and
6060
v = xorAssign.getTargetVariable() and
6161
(notOp instanceof UnaryBitwiseOperation or notOp instanceof AssignBitwiseOperation) and
62-
xor.getAControlFlowNode().getASuccessor*() = notOp.getAControlFlowNode() and
62+
xor.getControlFlowNode().getASuccessor*() = notOp.getControlFlowNode() and
6363
notAssign.getAChild*() = notOp and
6464
v = notAssign.getTargetVariable() and
6565
loop.getAChild*() = add.getEnclosingStmt() and

csharp/ql/lib/printCfg.ql

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @tags ide-contextual-queries/print-cfg
88
*/
99

10-
private import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl
10+
import csharp
1111

1212
external string selectedSourceFile();
1313

@@ -21,15 +21,15 @@ external int selectedSourceColumn();
2121

2222
private predicate selectedSourceColumnAlias = selectedSourceColumn/0;
2323

24-
module ViewCfgQueryInput implements ViewCfgQueryInputSig<File> {
24+
module ViewCfgQueryInput implements ControlFlow::ViewCfgQueryInputSig<File> {
2525
predicate selectedSourceFile = selectedSourceFileAlias/0;
2626

2727
predicate selectedSourceLine = selectedSourceLineAlias/0;
2828

2929
predicate selectedSourceColumn = selectedSourceColumnAlias/0;
3030

3131
predicate cfgScopeSpan(
32-
CfgScope scope, File file, int startLine, int startColumn, int endLine, int endColumn
32+
Callable scope, File file, int startLine, int startColumn, int endLine, int endColumn
3333
) {
3434
file = scope.getFile() and
3535
scope.getLocation().getStartLine() = startLine and
@@ -40,11 +40,20 @@ module ViewCfgQueryInput implements ViewCfgQueryInputSig<File> {
4040
|
4141
loc = scope.(Callable).getBody().getLocation()
4242
or
43-
loc = scope.(Field).getInitializer().getLocation()
43+
loc = any(AssignExpr init | scope.(ObjectInitMethod).initializes(init)).getLocation()
4444
or
45-
loc = scope.(Property).getInitializer().getLocation()
45+
exists(AssignableMember a, Constructor ctor |
46+
scope = ctor and
47+
ctor.isStatic() and
48+
a.isStatic() and
49+
a.getDeclaringType() = ctor.getDeclaringType()
50+
|
51+
loc = a.(Field).getInitializer().getLocation()
52+
or
53+
loc = a.(Property).getInitializer().getLocation()
54+
)
4655
)
4756
}
4857
}
4958

50-
import ViewCfgQuery<File, ViewCfgQueryInput>
59+
import ControlFlow::ViewCfgQuery<File, ViewCfgQueryInput>

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

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ class AssignableRead extends AssignableAccess {
8585
}
8686

8787
pragma[noinline]
88-
private ControlFlow::Node getAnAdjacentReadSameVar() {
89-
SsaImpl::adjacentReadPairSameVar(_, this.getAControlFlowNode(), result)
88+
private ControlFlowNode getAnAdjacentReadSameVar() {
89+
SsaImpl::adjacentReadPairSameVar(_, this.getControlFlowNode(), result)
9090
}
9191

9292
/**
@@ -114,11 +114,7 @@ class AssignableRead extends AssignableAccess {
114114
* - The read of `this.Field` on line 11 is next to the read on line 10.
115115
*/
116116
pragma[nomagic]
117-
AssignableRead getANextRead() {
118-
forex(ControlFlow::Node cfn | cfn = result.getAControlFlowNode() |
119-
cfn = this.getAnAdjacentReadSameVar()
120-
)
121-
}
117+
AssignableRead getANextRead() { result.getControlFlowNode() = this.getAnAdjacentReadSameVar() }
122118
}
123119

124120
/**
@@ -410,7 +406,7 @@ private import AssignableInternal
410406
*/
411407
class AssignableDefinition extends TAssignableDefinition {
412408
/**
413-
* DEPRECATED: Use `this.getExpr().getAControlFlowNode()` instead.
409+
* DEPRECATED: Use `this.getExpr().getControlFlowNode()` instead.
414410
*
415411
* Gets a control flow node that updates the targeted assignable when
416412
* reached.
@@ -419,9 +415,7 @@ class AssignableDefinition extends TAssignableDefinition {
419415
* the definitions of `x` and `y` in `M(out x, out y)` and `(x, y) = (0, 1)`
420416
* relate to the same call to `M` and assignment node, respectively.
421417
*/
422-
deprecated ControlFlow::Node getAControlFlowNode() {
423-
result = this.getExpr().getAControlFlowNode()
424-
}
418+
deprecated ControlFlowNode getAControlFlowNode() { result = this.getExpr().getControlFlowNode() }
425419

426420
/**
427421
* Gets the underlying expression that updates the targeted assignable when
@@ -494,7 +488,7 @@ class AssignableDefinition extends TAssignableDefinition {
494488
*/
495489
pragma[nomagic]
496490
AssignableRead getAFirstRead() {
497-
forex(ControlFlow::Node cfn | cfn = result.getAControlFlowNode() |
491+
exists(ControlFlowNode cfn | cfn = result.getControlFlowNode() |
498492
exists(Ssa::ExplicitDefinition def | result = def.getAFirstReadAtNode(cfn) |
499493
this = def.getADefinition()
500494
)
@@ -572,11 +566,9 @@ module AssignableDefinitions {
572566
}
573567

574568
/** Holds if a node in basic block `bb` assigns to `ref` parameter `p` via definition `def`. */
575-
private predicate basicBlockRefParamDef(
576-
ControlFlow::BasicBlock bb, Parameter p, AssignableDefinition def
577-
) {
569+
private predicate basicBlockRefParamDef(BasicBlock bb, Parameter p, AssignableDefinition def) {
578570
def = any(RefArg arg).getAnAnalyzableRefDef(p) and
579-
bb.getANode() = def.getExpr().getAControlFlowNode()
571+
bb.getANode() = def.getExpr().getControlFlowNode()
580572
}
581573

582574
/**
@@ -585,17 +577,15 @@ module AssignableDefinitions {
585577
* any assignments to `p`.
586578
*/
587579
pragma[nomagic]
588-
private predicate parameterReachesWithoutDef(Parameter p, ControlFlow::BasicBlock bb) {
580+
private predicate parameterReachesWithoutDef(Parameter p, BasicBlock bb) {
589581
forall(AssignableDefinition def | basicBlockRefParamDef(bb, p, def) |
590582
isUncertainRefCall(def.getTargetAccess())
591583
) and
592584
(
593585
any(RefArg arg).isAnalyzable(p) and
594586
p.getCallable().getEntryPoint() = bb.getFirstNode()
595587
or
596-
exists(ControlFlow::BasicBlock mid | parameterReachesWithoutDef(p, mid) |
597-
bb = mid.getASuccessor()
598-
)
588+
exists(BasicBlock mid | parameterReachesWithoutDef(p, mid) | bb = mid.getASuccessor())
599589
)
600590
}
601591

@@ -607,7 +597,7 @@ module AssignableDefinitions {
607597
cached
608598
predicate isUncertainRefCall(RefArg arg) {
609599
arg.isPotentialAssignment() and
610-
exists(ControlFlow::BasicBlock bb, Parameter p | arg.isAnalyzable(p) |
600+
exists(BasicBlock bb, Parameter p | arg.isAnalyzable(p) |
611601
parameterReachesWithoutDef(p, bb) and
612602
bb.getLastNode() = p.getCallable().getExitPoint()
613603
)
@@ -688,7 +678,7 @@ module AssignableDefinitions {
688678
/** Gets the underlying parameter. */
689679
Parameter getParameter() { result = p }
690680

691-
deprecated override ControlFlow::Node getAControlFlowNode() {
681+
deprecated override ControlFlowNode getAControlFlowNode() {
692682
result = p.getCallable().getEntryPoint()
693683
}
694684

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

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,6 @@ private import csharp
77
* in the same stage across different files.
88
*/
99
module Stages {
10-
cached
11-
module ControlFlowStage {
12-
private import semmle.code.csharp.controlflow.internal.Splitting
13-
14-
cached
15-
predicate forceCachingInSameStage() { any() }
16-
17-
cached
18-
private predicate forceCachingInSameStageRev() {
19-
exists(Split s)
20-
or
21-
exists(ControlFlow::Node n)
22-
or
23-
forceCachingInSameStageRev()
24-
}
25-
}
26-
2710
cached
2811
module GuardsStage {
2912
private import semmle.code.csharp.controlflow.Guards

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ private import TypeRef
2222
* an anonymous function (`AnonymousFunctionExpr`), or a local function
2323
* (`LocalFunction`).
2424
*/
25-
class Callable extends Parameterizable, ExprOrStmtParent, @callable {
25+
class Callable extends Parameterizable, ControlFlowElementOrCallable, @callable {
2626
/** Gets the return type of this callable. */
2727
Type getReturnType() { none() }
2828

@@ -157,10 +157,10 @@ class Callable extends Parameterizable, ExprOrStmtParent, @callable {
157157
final predicate hasExpressionBody() { exists(this.getExpressionBody()) }
158158

159159
/** Gets the entry point in the control graph for this callable. */
160-
ControlFlow::Nodes::EntryNode getEntryPoint() { result.getCallable() = this }
160+
ControlFlow::EntryNode getEntryPoint() { result.getEnclosingCallable() = this }
161161

162162
/** Gets the exit point in the control graph for this callable. */
163-
ControlFlow::Nodes::ExitNode getExitPoint() { result.getCallable() = this }
163+
ControlFlow::ExitNode getExitPoint() { result.getEnclosingCallable() = this }
164164

165165
/**
166166
* Gets the enclosing callable of this callable, if any.

0 commit comments

Comments
 (0)