Skip to content

Commit 02fd1dc

Browse files
authored
Merge pull request #20738 from aschackmull/csharp/guards-misc
C#: Misc Guards-related cleanup.
2 parents 5d9d6b9 + 7ab25b5 commit 02fd1dc

File tree

6 files changed

+29
-169
lines changed

6 files changed

+29
-169
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: deprecated
3+
---
4+
* `ControlFlowElement.controlsBlock` has been deprecated in favor of the Guards library.

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@ module Stages {
3333

3434
cached
3535
private predicate forceCachingInSameStageRev() {
36-
any(ControlFlowElement cfe).controlsBlock(_, _, _)
37-
or
3836
exists(GuardedExpr ge)
3937
or
4038
forceCachingInSameStageRev()

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

Lines changed: 4 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -87,148 +87,20 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element {
8787
result.getAControlFlowNode()
8888
}
8989

90-
pragma[noinline]
91-
private predicate immediatelyControlsBlockSplit0(
92-
ConditionBlock cb, BasicBlock succ, ConditionalSuccessor s
93-
) {
94-
// Only calculate dominance by explicit recursion for split nodes;
95-
// all other nodes can use regular CFG dominance
96-
this instanceof Impl::SplitAstNode and
97-
cb.getLastNode() = this.getAControlFlowNode() and
98-
succ = cb.getASuccessor(s)
99-
}
100-
101-
pragma[noinline]
102-
private predicate immediatelyControlsBlockSplit1(
103-
ConditionBlock cb, BasicBlock succ, ConditionalSuccessor s, BasicBlock pred, SuccessorType t
104-
) {
105-
this.immediatelyControlsBlockSplit0(cb, succ, s) and
106-
pred = succ.getAPredecessorByType(t) and
107-
pred != cb
108-
}
109-
110-
pragma[noinline]
111-
private predicate immediatelyControlsBlockSplit2(
112-
ConditionBlock cb, BasicBlock succ, ConditionalSuccessor s, BasicBlock pred, SuccessorType t
113-
) {
114-
this.immediatelyControlsBlockSplit1(cb, succ, s, pred, t) and
115-
(
116-
succ.dominates(pred)
117-
or
118-
// `pred` might be another split of this element
119-
pred.getLastNode().getAstNode() = this and
120-
t = s
121-
)
122-
}
123-
12490
/**
125-
* Holds if basic block `succ` is immediately controlled by this control flow
126-
* element with conditional value `s`. That is, `succ` can only be reached from
127-
* the callable entry point by going via the `s` edge out of *some* basic block
128-
* `pred` ending with this element, and `pred` is an immediate predecessor
129-
* of `succ`.
130-
*
131-
* Moreover, this control flow element corresponds to multiple control flow nodes,
132-
* which is why
133-
*
134-
* ```ql
135-
* exists(ConditionBlock cb |
136-
* cb.getLastNode() = this.getAControlFlowNode() |
137-
* cb.immediatelyControls(succ, s)
138-
* )
139-
* ```
91+
* DEPRECATED: Use `Guard` class instead.
14092
*
141-
* does not work.
142-
*
143-
* `cb` records all of the possible condition blocks for this control flow element
144-
* that a path from the callable entry point to `succ` may go through.
145-
*/
146-
pragma[nomagic]
147-
private predicate immediatelyControlsBlockSplit(
148-
BasicBlock succ, ConditionalSuccessor s, ConditionBlock cb
149-
) {
150-
this.immediatelyControlsBlockSplit0(cb, succ, s) and
151-
forall(BasicBlock pred, SuccessorType t |
152-
this.immediatelyControlsBlockSplit1(cb, succ, s, pred, t)
153-
|
154-
this.immediatelyControlsBlockSplit2(cb, succ, s, pred, t)
155-
)
156-
}
157-
158-
pragma[noinline]
159-
private predicate controlsJoinBlockPredecessor(
160-
JoinBlock controlled, ConditionalSuccessor s, int i, ConditionBlock cb
161-
) {
162-
this.controlsBlockSplit(controlled.getJoinBlockPredecessor(i), s, cb)
163-
}
164-
165-
private predicate controlsJoinBlockSplit(JoinBlock controlled, ConditionalSuccessor s, int i) {
166-
i = -1 and
167-
this.controlsJoinBlockPredecessor(controlled, s, _, _)
168-
or
169-
this.controlsJoinBlockSplit(controlled, s, i - 1) and
170-
(
171-
this.controlsJoinBlockPredecessor(controlled, s, i, _)
172-
or
173-
controlled.dominates(controlled.getJoinBlockPredecessor(i))
174-
)
175-
}
176-
177-
cached
178-
private predicate controlsBlockSplit(
179-
BasicBlock controlled, ConditionalSuccessor s, ConditionBlock cb
180-
) {
181-
Stages::GuardsStage::forceCachingInSameStage() and
182-
this.immediatelyControlsBlockSplit(controlled, s, cb)
183-
or
184-
// Equivalent with
185-
//
186-
// ```ql
187-
// exists(JoinBlockPredecessor pred | pred = controlled.getAPredecessor() |
188-
// this.controlsBlockSplit(pred, s)
189-
// ) and
190-
// forall(JoinBlockPredecessor pred | pred = controlled.getAPredecessor() |
191-
// this.controlsBlockSplit(pred, s)
192-
// or
193-
// controlled.dominates(pred)
194-
// )
195-
// ```
196-
//
197-
// but uses no universal recursion for better performance.
198-
exists(int last |
199-
last = max(int i | exists(controlled.(JoinBlock).getJoinBlockPredecessor(i)))
200-
|
201-
this.controlsJoinBlockSplit(controlled, s, last)
202-
) and
203-
this.controlsJoinBlockPredecessor(controlled, s, _, cb)
204-
or
205-
not controlled instanceof JoinBlock and
206-
this.controlsBlockSplit(controlled.getAPredecessor(), s, cb)
207-
}
208-
209-
/**
21093
* Holds if basic block `controlled` is controlled by this control flow element
21194
* with conditional value `s`. That is, `controlled` can only be reached from
21295
* the callable entry point by going via the `s` edge out of *some* basic block
21396
* ending with this element.
21497
*
215-
* This predicate is different from
216-
*
217-
* ```ql
218-
* exists(ConditionBlock cb |
219-
* cb.getLastNode() = this.getAControlFlowNode() |
220-
* cb.controls(controlled, s)
221-
* )
222-
* ```
223-
*
224-
* as control flow splitting is taken into account.
225-
*
22698
* `cb` records all of the possible condition blocks for this control flow element
22799
* that a path from the callable entry point to `controlled` may go through.
228100
*/
229-
predicate controlsBlock(BasicBlock controlled, ConditionalSuccessor s, ConditionBlock cb) {
230-
this.controlsBlockSplit(controlled, s, cb)
231-
or
101+
deprecated predicate controlsBlock(
102+
BasicBlock controlled, ConditionalSuccessor s, ConditionBlock cb
103+
) {
232104
cb.getLastNode() = this.getAControlFlowNode() and
233105
cb.edgeDominates(controlled, s)
234106
}

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,15 @@ private module GuardsInput implements
4949
override predicate isNull() { any() }
5050
}
5151

52-
private class BooleanConstant extends ConstantExpr instanceof BoolLiteral {
53-
override boolean asBooleanValue() { result = super.getBoolValue() }
52+
private predicate boolConst(Expr e, boolean b) {
53+
e.getType() instanceof BoolType and
54+
e.getValue() = b.toString()
55+
}
56+
57+
private class BooleanConstant extends ConstantExpr {
58+
BooleanConstant() { boolConst(this, _) }
59+
60+
override boolean asBooleanValue() { boolConst(this, result) }
5461
}
5562

5663
private predicate intConst(Expr e, int i) {

csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2583,10 +2583,10 @@ class NodeRegion instanceof ControlFlow::BasicBlock {
25832583
* Holds if the nodes in `nr` are unreachable when the call context is `call`.
25842584
*/
25852585
predicate isUnreachableInCall(NodeRegion nr, DataFlowCall call) {
2586-
exists(ExplicitParameterNode paramNode, Guard guard, ControlFlow::BooleanSuccessor bs |
2587-
viableConstantBooleanParamArg(paramNode, bs.getValue().booleanNot(), call) and
2586+
exists(ExplicitParameterNode paramNode, Guard guard, GuardValue val |
2587+
viableConstantParamArg(paramNode, val.getDualValue(), call) and
25882588
paramNode.getSsaDefinition().getARead() = guard and
2589-
guard.controlsBlock(nr, bs, _)
2589+
guard.valueControls(nr, val)
25902590
)
25912591
}
25922592

@@ -2904,33 +2904,19 @@ class CastNode extends Node {
29042904

29052905
class DataFlowExpr = Expr;
29062906

2907-
/** Holds if `e` is an expression that always has the same Boolean value `val`. */
2908-
private predicate constantBooleanExpr(Expr e, boolean val) {
2909-
e.getType() instanceof BoolType and
2910-
e.getValue() = val.toString()
2911-
or
2912-
exists(Ssa::ExplicitDefinition def, Expr src |
2913-
e = def.getARead() and
2914-
src = def.getADefinition().getSource() and
2915-
constantBooleanExpr(src, val)
2916-
)
2917-
}
2907+
/** An argument that always has the same value. */
2908+
private class ConstantArgumentNode extends ExprNode {
2909+
ConstantArgumentNode() { Guards::InternalUtil::exprHasValue(this.(ArgumentNode).asExpr(), _) }
29182910

2919-
/** An argument that always has the same Boolean value. */
2920-
private class ConstantBooleanArgumentNode extends ExprNode {
2921-
ConstantBooleanArgumentNode() { constantBooleanExpr(this.(ArgumentNode).asExpr(), _) }
2922-
2923-
/** Gets the Boolean value of this expression. */
2924-
boolean getBooleanValue() { constantBooleanExpr(this.getExpr(), result) }
2911+
/** Gets the value of this expression. */
2912+
GuardValue getValue() { Guards::InternalUtil::exprHasValue(this.getExpr(), result) }
29252913
}
29262914

29272915
pragma[noinline]
2928-
private predicate viableConstantBooleanParamArg(
2929-
ParameterNode paramNode, boolean b, DataFlowCall call
2930-
) {
2931-
exists(ConstantBooleanArgumentNode arg |
2916+
private predicate viableConstantParamArg(ParameterNode paramNode, GuardValue val, DataFlowCall call) {
2917+
exists(ConstantArgumentNode arg |
29322918
viableParamArg(call, paramNode, arg) and
2933-
b = arg.getBooleanValue()
2919+
val = arg.getValue()
29342920
)
29352921
}
29362922

csharp/ql/lib/semmle/code/csharp/security/dataflow/ConditionalBypassQuery.qll

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,17 +72,10 @@ class ReverseDnsSource extends Source {
7272
}
7373
}
7474

75-
pragma[noinline]
76-
private predicate conditionControlsCall0(
77-
SensitiveExecutionMethodCall call, Expr e, ControlFlow::BooleanSuccessor s
78-
) {
79-
forex(BasicBlock bb | bb = call.getAControlFlowNode().getBasicBlock() | e.controlsBlock(bb, s, _))
80-
}
81-
8275
private predicate conditionControlsCall(
8376
SensitiveExecutionMethodCall call, SensitiveExecutionMethod def, Expr e, boolean cond
8477
) {
85-
exists(ControlFlow::BooleanSuccessor s | cond = s.getValue() | conditionControlsCall0(call, e, s)) and
78+
e.(Guard).directlyControls(call.getBasicBlock(), cond) and
8679
def = call.getTarget().getUnboundDeclaration()
8780
}
8881

0 commit comments

Comments
 (0)