Skip to content

Commit c57015a

Browse files
committed
C#: Data-flow pruning based on call contexts
1 parent 853cbd8 commit c57015a

File tree

2 files changed

+50
-46
lines changed

2 files changed

+50
-46
lines changed

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

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ private import cil
33
private import dotnet
44
private import DataFlowPublic
55
private import DataFlowDispatch
6+
private import DataFlowImplCommon::Public
67
private import ControlFlowReachability
78
private import DelegateDataFlow
89
private import semmle.code.csharp.Caching
910
private import semmle.code.csharp.ExprOrStmtParent
11+
private import semmle.code.csharp.controlflow.Guards
1012
private import semmle.code.csharp.dataflow.LibraryTypeDataFlow
1113
private import semmle.code.csharp.dispatch.Dispatch
1214
private import semmle.code.csharp.frameworks.EntityFramework
@@ -439,6 +441,22 @@ private module Cached {
439441
c.(FieldLikeContent).getField() = node2.asExpr().(FieldLikeRead).getTarget()
440442
)
441443
}
444+
445+
/**
446+
* Holds if the node `n` is unreachable when the call context is `call`.
447+
*/
448+
cached
449+
predicate isUnreachableInCall(Node n, DataFlowCall call) {
450+
exists(
451+
SsaDefinitionNode paramNode, Ssa::ExplicitDefinition param, Guard guard,
452+
ControlFlow::SuccessorTypes::BooleanSuccessor bs
453+
|
454+
viableConstantBooleanParamArg(paramNode, bs.getValue().booleanNot(), call) and
455+
paramNode.getDefinition() = param and
456+
param.getARead() = guard and
457+
guard.controlsBlock(n.getControlFlowNode().getBasicBlock(), bs)
458+
)
459+
}
442460
}
443461

444462
import Cached
@@ -1358,4 +1376,31 @@ class DataFlowType = DotNet::Type;
13581376

13591377
class DataFlowLocation = Location;
13601378

1361-
predicate isUnreachableInCall(Node n, DataFlowCall call) { none() } // stub implementation
1379+
/** Holds if `e` is an expression that always has the same Boolean value `val`. */
1380+
private predicate constantBooleanExpr(Expr e, boolean val) {
1381+
e = any(AbstractValues::BooleanValue bv | val = bv.getValue()).getAnExpr()
1382+
or
1383+
exists(Ssa::ExplicitDefinition def, Expr src |
1384+
e = def.getARead() and
1385+
src = def.getADefinition().getSource() and
1386+
constantBooleanExpr(src, val)
1387+
)
1388+
}
1389+
1390+
/** An argument that always has the same Boolean value. */
1391+
private class ConstantBooleanArgumentNode extends ExprNode {
1392+
ConstantBooleanArgumentNode() { constantBooleanExpr(this.(ArgumentNode).asExpr(), _) }
1393+
1394+
/** Gets the Boolean value of this expression. */
1395+
boolean getBooleanValue() { constantBooleanExpr(this.getExpr(), result) }
1396+
}
1397+
1398+
pragma[noinline]
1399+
private predicate viableConstantBooleanParamArg(
1400+
SsaDefinitionNode paramNode, boolean b, DataFlowCall call
1401+
) {
1402+
exists(ConstantBooleanArgumentNode arg |
1403+
viableParamArg(call, paramNode, arg) and
1404+
b = arg.getBooleanValue()
1405+
)
1406+
}

0 commit comments

Comments
 (0)