Merge pull request #2139 from hvitved/csharp/dataflow/callcontext-bool-pruning

C#: Data-flow pruning based on call contexts
This commit is contained in:
Calum Grant
2019-10-21 09:49:05 +01:00
committed by GitHub
4 changed files with 380 additions and 1 deletions

View File

@@ -3,10 +3,12 @@ private import cil
private import dotnet
private import DataFlowPublic
private import DataFlowDispatch
private import DataFlowImplCommon::Public
private import ControlFlowReachability
private import DelegateDataFlow
private import semmle.code.csharp.Caching
private import semmle.code.csharp.ExprOrStmtParent
private import semmle.code.csharp.controlflow.Guards
private import semmle.code.csharp.dataflow.LibraryTypeDataFlow
private import semmle.code.csharp.dispatch.Dispatch
private import semmle.code.csharp.frameworks.EntityFramework
@@ -439,6 +441,22 @@ private module Cached {
c.(FieldLikeContent).getField() = node2.asExpr().(FieldLikeRead).getTarget()
)
}
/**
* Holds if the node `n` is unreachable when the call context is `call`.
*/
cached
predicate isUnreachableInCall(Node n, DataFlowCall call) {
exists(
SsaDefinitionNode paramNode, Ssa::ExplicitDefinition param, Guard guard,
ControlFlow::SuccessorTypes::BooleanSuccessor bs
|
viableConstantBooleanParamArg(paramNode, bs.getValue().booleanNot(), call) and
paramNode.getDefinition() = param and
param.getARead() = guard and
guard.controlsBlock(n.getControlFlowNode().getBasicBlock(), bs)
)
}
}
import Cached
@@ -1358,4 +1376,31 @@ class DataFlowType = DotNet::Type;
class DataFlowLocation = Location;
predicate isUnreachableInCall(Node n, DataFlowCall call) { none() } // stub implementation
/** Holds if `e` is an expression that always has the same Boolean value `val`. */
private predicate constantBooleanExpr(Expr e, boolean val) {
e = any(AbstractValues::BooleanValue bv | val = bv.getValue()).getAnExpr()
or
exists(Ssa::ExplicitDefinition def, Expr src |
e = def.getARead() and
src = def.getADefinition().getSource() and
constantBooleanExpr(src, val)
)
}
/** An argument that always has the same Boolean value. */
private class ConstantBooleanArgumentNode extends ExprNode {
ConstantBooleanArgumentNode() { constantBooleanExpr(this.(ArgumentNode).asExpr(), _) }
/** Gets the Boolean value of this expression. */
boolean getBooleanValue() { constantBooleanExpr(this.getExpr(), result) }
}
pragma[noinline]
private predicate viableConstantBooleanParamArg(
SsaDefinitionNode paramNode, boolean b, DataFlowCall call
) {
exists(ConstantBooleanArgumentNode arg |
viableParamArg(call, paramNode, arg) and
b = arg.getBooleanValue()
)
}

View File

@@ -0,0 +1,220 @@
public class A
{
public static void Sink(object o)
{
}
public object FlowThrough(object o, bool cond)
{
if (cond)
{
return o;
}
else
{
return null;
}
}
public void CallSinkIfTrue(object o, bool cond)
{
if (cond)
{
Sink(o);
}
}
public void CallSinkIfFalse(object o, bool cond)
{
if (!cond)
{
Sink(o);
}
}
public void CallSinkFromLoop(object o, bool cond)
{
while (cond)
{
Sink(o);
}
}
public void LocalCallSensitivity(object o, bool c)
{
object o1 = o;
object o2 = null;
if (c)
{
object tmp = o1;
o2 = 1 == 1 ? (tmp) : (tmp);
}
object o3 = o2;
Sink(o3);
}
public void LocalCallSensitivity2(object o, bool b, bool c)
{
object o1 = o;
object o2 = null;
if (b || c)
{
object tmp = o1;
o2 = 1 == 1 ? (tmp) : (tmp);
}
object o3 = o2;
Sink(o3);
}
public void M1()
{
// should not exhibit flow
CallSinkIfTrue(new object(), false);
CallSinkIfFalse(new object(), true);
CallSinkFromLoop(new object(), false);
LocalCallSensitivity(new object(), false);
Sink(FlowThrough(new object(), false));
// should exhibit flow
CallSinkIfTrue(new object(), true);
CallSinkIfFalse(new object(), false);
CallSinkFromLoop(new object(), true);
LocalCallSensitivity(new object(), true);
LocalCallSensitivity2(new object(), true, true);
LocalCallSensitivity2(new object(), false, true);
LocalCallSensitivity2(new object(), true, false);
Sink(FlowThrough(new object(), true));
// expected false positive
LocalCallSensitivity2(new object(), false, false);
}
public void M2()
{
bool t = true;
bool f = false;
// should not exhibit flow
CallSinkIfTrue(new object(), f);
CallSinkIfFalse(new object(), t);
CallSinkFromLoop(new object(), f);
LocalCallSensitivity(new object(), f);
Sink(FlowThrough(new object(), f));
// should exhibit flow
CallSinkIfTrue(new object(), t);
CallSinkIfFalse(new object(), f);
CallSinkFromLoop(new object(), t);
LocalCallSensitivity(new object(), t);
Sink(FlowThrough(new object(), t));
}
public void M3(InterfaceA b)
{
bool t = true;
bool f = false;
// should not exhibit flow
b.CallSinkIfTrue(new object(), f);
b.CallSinkIfFalse(new object(), t);
b.LocalCallSensitivity(new object(), f);
// should exhibit flow
b.CallSinkIfTrue(new object(), t);
b.CallSinkIfFalse(new object(), f);
b.LocalCallSensitivity(new object(), t);
}
class B : InterfaceA
{
public void CallSinkIfTrue(object o, bool cond)
{
if (cond)
{
Sink(o);
}
}
public void CallSinkIfFalse(object o, bool cond)
{
if (!cond)
{
Sink(o);
}
}
public void LocalCallSensitivity(object o, bool c)
{
object o1 = o;
object o2 = null;
if (c)
{
object tmp = o1;
o2 = 1 == 1 ? (tmp) : (tmp);
}
object o3 = o2;
Sink(o3);
}
}
}
public class A2
{
public static void Sink(object o)
{
}
public void M()
{
}
public void Callsite(InterfaceB intF)
{
B b = new B();
// in both possible implementations of foo, this callsite is relevant
// in IntA, it improves virtual dispatch,
// and in IntB, it improves the dataflow analysis.
intF.Foo(b, new object(), false);
}
private class B : A2
{
public void M()
{
}
}
private class IntA : InterfaceB
{
public void Foo(A2 obj, object o, bool cond)
{
obj.M();
Sink(o);
}
}
private class IntB : InterfaceB
{
public void Foo(A2 obj, object o, bool cond)
{
if (cond)
{
Sink(o);
}
}
}
}
public interface InterfaceA
{
void CallSinkIfTrue(object o, bool cond);
void CallSinkIfFalse(object o, bool cond);
void LocalCallSensitivity(object o, bool c);
}
public interface InterfaceB
{
void Foo(A2 a, object o, bool cond);
}

View File

@@ -0,0 +1,91 @@
edges
| CallSensitivityFlow.cs:19:39:19:39 | o | CallSensitivityFlow.cs:23:18:23:18 | access to parameter o |
| CallSensitivityFlow.cs:27:40:27:40 | o | CallSensitivityFlow.cs:31:18:31:18 | access to parameter o |
| CallSensitivityFlow.cs:35:41:35:41 | o | CallSensitivityFlow.cs:39:18:39:18 | [cond (line 35): true] access to parameter o |
| CallSensitivityFlow.cs:43:45:43:45 | o | CallSensitivityFlow.cs:53:14:53:15 | access to local variable o3 |
| CallSensitivityFlow.cs:56:46:56:46 | o | CallSensitivityFlow.cs:66:14:66:15 | access to local variable o3 |
| CallSensitivityFlow.cs:56:46:56:46 | o | CallSensitivityFlow.cs:66:14:66:15 | access to local variable o3 |
| CallSensitivityFlow.cs:56:46:56:46 | o | CallSensitivityFlow.cs:66:14:66:15 | access to local variable o3 |
| CallSensitivityFlow.cs:78:24:78:35 | object creation of type Object | CallSensitivityFlow.cs:19:39:19:39 | o |
| CallSensitivityFlow.cs:79:25:79:36 | object creation of type Object | CallSensitivityFlow.cs:27:40:27:40 | o |
| CallSensitivityFlow.cs:80:26:80:37 | object creation of type Object | CallSensitivityFlow.cs:35:41:35:41 | o |
| CallSensitivityFlow.cs:81:30:81:41 | object creation of type Object | CallSensitivityFlow.cs:43:45:43:45 | o |
| CallSensitivityFlow.cs:82:31:82:42 | object creation of type Object | CallSensitivityFlow.cs:56:46:56:46 | o |
| CallSensitivityFlow.cs:83:31:83:42 | object creation of type Object | CallSensitivityFlow.cs:56:46:56:46 | o |
| CallSensitivityFlow.cs:84:31:84:42 | object creation of type Object | CallSensitivityFlow.cs:56:46:56:46 | o |
| CallSensitivityFlow.cs:85:26:85:37 | object creation of type Object | CallSensitivityFlow.cs:85:14:85:44 | call to method FlowThrough |
| CallSensitivityFlow.cs:87:31:87:42 | object creation of type Object | CallSensitivityFlow.cs:56:46:56:46 | o |
| CallSensitivityFlow.cs:101:24:101:35 | object creation of type Object | CallSensitivityFlow.cs:19:39:19:39 | o |
| CallSensitivityFlow.cs:102:25:102:36 | object creation of type Object | CallSensitivityFlow.cs:27:40:27:40 | o |
| CallSensitivityFlow.cs:103:26:103:37 | object creation of type Object | CallSensitivityFlow.cs:35:41:35:41 | o |
| CallSensitivityFlow.cs:104:30:104:41 | object creation of type Object | CallSensitivityFlow.cs:43:45:43:45 | o |
| CallSensitivityFlow.cs:105:26:105:37 | object creation of type Object | CallSensitivityFlow.cs:105:14:105:41 | call to method FlowThrough |
| CallSensitivityFlow.cs:117:26:117:37 | object creation of type Object | CallSensitivityFlow.cs:124:43:124:43 | o |
| CallSensitivityFlow.cs:118:27:118:38 | object creation of type Object | CallSensitivityFlow.cs:133:44:133:44 | o |
| CallSensitivityFlow.cs:119:32:119:43 | object creation of type Object | CallSensitivityFlow.cs:142:49:142:49 | o |
| CallSensitivityFlow.cs:124:43:124:43 | o | CallSensitivityFlow.cs:128:22:128:22 | access to parameter o |
| CallSensitivityFlow.cs:133:44:133:44 | o | CallSensitivityFlow.cs:137:22:137:22 | access to parameter o |
| CallSensitivityFlow.cs:142:49:142:49 | o | CallSensitivityFlow.cs:152:18:152:19 | access to local variable o3 |
| CallSensitivityFlow.cs:175:21:175:32 | object creation of type Object | CallSensitivityFlow.cs:189:40:189:40 | o |
| CallSensitivityFlow.cs:189:40:189:40 | o | CallSensitivityFlow.cs:192:18:192:18 | access to parameter o |
nodes
| CallSensitivityFlow.cs:19:39:19:39 | o | semmle.label | o |
| CallSensitivityFlow.cs:23:18:23:18 | access to parameter o | semmle.label | access to parameter o |
| CallSensitivityFlow.cs:27:40:27:40 | o | semmle.label | o |
| CallSensitivityFlow.cs:31:18:31:18 | access to parameter o | semmle.label | access to parameter o |
| CallSensitivityFlow.cs:35:41:35:41 | o | semmle.label | o |
| CallSensitivityFlow.cs:39:18:39:18 | [cond (line 35): true] access to parameter o | semmle.label | [cond (line 35): true] access to parameter o |
| CallSensitivityFlow.cs:43:45:43:45 | o | semmle.label | o |
| CallSensitivityFlow.cs:53:14:53:15 | access to local variable o3 | semmle.label | access to local variable o3 |
| CallSensitivityFlow.cs:56:46:56:46 | o | semmle.label | o |
| CallSensitivityFlow.cs:56:46:56:46 | o | semmle.label | o |
| CallSensitivityFlow.cs:56:46:56:46 | o | semmle.label | o |
| CallSensitivityFlow.cs:66:14:66:15 | access to local variable o3 | semmle.label | access to local variable o3 |
| CallSensitivityFlow.cs:78:24:78:35 | object creation of type Object | semmle.label | object creation of type Object |
| CallSensitivityFlow.cs:79:25:79:36 | object creation of type Object | semmle.label | object creation of type Object |
| CallSensitivityFlow.cs:80:26:80:37 | object creation of type Object | semmle.label | object creation of type Object |
| CallSensitivityFlow.cs:81:30:81:41 | object creation of type Object | semmle.label | object creation of type Object |
| CallSensitivityFlow.cs:82:31:82:42 | object creation of type Object | semmle.label | object creation of type Object |
| CallSensitivityFlow.cs:83:31:83:42 | object creation of type Object | semmle.label | object creation of type Object |
| CallSensitivityFlow.cs:84:31:84:42 | object creation of type Object | semmle.label | object creation of type Object |
| CallSensitivityFlow.cs:85:14:85:44 | call to method FlowThrough | semmle.label | call to method FlowThrough |
| CallSensitivityFlow.cs:85:26:85:37 | object creation of type Object | semmle.label | object creation of type Object |
| CallSensitivityFlow.cs:87:31:87:42 | object creation of type Object | semmle.label | object creation of type Object |
| CallSensitivityFlow.cs:101:24:101:35 | object creation of type Object | semmle.label | object creation of type Object |
| CallSensitivityFlow.cs:102:25:102:36 | object creation of type Object | semmle.label | object creation of type Object |
| CallSensitivityFlow.cs:103:26:103:37 | object creation of type Object | semmle.label | object creation of type Object |
| CallSensitivityFlow.cs:104:30:104:41 | object creation of type Object | semmle.label | object creation of type Object |
| CallSensitivityFlow.cs:105:14:105:41 | call to method FlowThrough | semmle.label | call to method FlowThrough |
| CallSensitivityFlow.cs:105:26:105:37 | object creation of type Object | semmle.label | object creation of type Object |
| CallSensitivityFlow.cs:117:26:117:37 | object creation of type Object | semmle.label | object creation of type Object |
| CallSensitivityFlow.cs:118:27:118:38 | object creation of type Object | semmle.label | object creation of type Object |
| CallSensitivityFlow.cs:119:32:119:43 | object creation of type Object | semmle.label | object creation of type Object |
| CallSensitivityFlow.cs:124:43:124:43 | o | semmle.label | o |
| CallSensitivityFlow.cs:128:22:128:22 | access to parameter o | semmle.label | access to parameter o |
| CallSensitivityFlow.cs:133:44:133:44 | o | semmle.label | o |
| CallSensitivityFlow.cs:137:22:137:22 | access to parameter o | semmle.label | access to parameter o |
| CallSensitivityFlow.cs:142:49:142:49 | o | semmle.label | o |
| CallSensitivityFlow.cs:152:18:152:19 | access to local variable o3 | semmle.label | access to local variable o3 |
| CallSensitivityFlow.cs:175:21:175:32 | object creation of type Object | semmle.label | object creation of type Object |
| CallSensitivityFlow.cs:189:40:189:40 | o | semmle.label | o |
| CallSensitivityFlow.cs:192:18:192:18 | access to parameter o | semmle.label | access to parameter o |
| CallSensitivityFlow.cs:203:22:203:22 | access to parameter o | semmle.label | access to parameter o |
#select
| CallSensitivityFlow.cs:78:24:78:35 | object creation of type Object | CallSensitivityFlow.cs:78:24:78:35 | object creation of type Object | CallSensitivityFlow.cs:23:18:23:18 | access to parameter o | $@ | CallSensitivityFlow.cs:23:18:23:18 | access to parameter o | access to parameter o |
| CallSensitivityFlow.cs:79:25:79:36 | object creation of type Object | CallSensitivityFlow.cs:79:25:79:36 | object creation of type Object | CallSensitivityFlow.cs:31:18:31:18 | access to parameter o | $@ | CallSensitivityFlow.cs:31:18:31:18 | access to parameter o | access to parameter o |
| CallSensitivityFlow.cs:80:26:80:37 | object creation of type Object | CallSensitivityFlow.cs:80:26:80:37 | object creation of type Object | CallSensitivityFlow.cs:39:18:39:18 | [cond (line 35): true] access to parameter o | $@ | CallSensitivityFlow.cs:39:18:39:18 | [cond (line 35): true] access to parameter o | [cond (line 35): true] access to parameter o |
| CallSensitivityFlow.cs:81:30:81:41 | object creation of type Object | CallSensitivityFlow.cs:81:30:81:41 | object creation of type Object | CallSensitivityFlow.cs:53:14:53:15 | access to local variable o3 | $@ | CallSensitivityFlow.cs:53:14:53:15 | access to local variable o3 | access to local variable o3 |
| CallSensitivityFlow.cs:82:31:82:42 | object creation of type Object | CallSensitivityFlow.cs:82:31:82:42 | object creation of type Object | CallSensitivityFlow.cs:66:14:66:15 | access to local variable o3 | $@ | CallSensitivityFlow.cs:66:14:66:15 | access to local variable o3 | access to local variable o3 |
| CallSensitivityFlow.cs:83:31:83:42 | object creation of type Object | CallSensitivityFlow.cs:83:31:83:42 | object creation of type Object | CallSensitivityFlow.cs:66:14:66:15 | access to local variable o3 | $@ | CallSensitivityFlow.cs:66:14:66:15 | access to local variable o3 | access to local variable o3 |
| CallSensitivityFlow.cs:84:31:84:42 | object creation of type Object | CallSensitivityFlow.cs:84:31:84:42 | object creation of type Object | CallSensitivityFlow.cs:66:14:66:15 | access to local variable o3 | $@ | CallSensitivityFlow.cs:66:14:66:15 | access to local variable o3 | access to local variable o3 |
| CallSensitivityFlow.cs:85:26:85:37 | object creation of type Object | CallSensitivityFlow.cs:85:26:85:37 | object creation of type Object | CallSensitivityFlow.cs:85:14:85:44 | call to method FlowThrough | $@ | CallSensitivityFlow.cs:85:14:85:44 | call to method FlowThrough | call to method FlowThrough |
| CallSensitivityFlow.cs:87:31:87:42 | object creation of type Object | CallSensitivityFlow.cs:87:31:87:42 | object creation of type Object | CallSensitivityFlow.cs:66:14:66:15 | access to local variable o3 | $@ | CallSensitivityFlow.cs:66:14:66:15 | access to local variable o3 | access to local variable o3 |
| CallSensitivityFlow.cs:101:24:101:35 | object creation of type Object | CallSensitivityFlow.cs:101:24:101:35 | object creation of type Object | CallSensitivityFlow.cs:23:18:23:18 | access to parameter o | $@ | CallSensitivityFlow.cs:23:18:23:18 | access to parameter o | access to parameter o |
| CallSensitivityFlow.cs:102:25:102:36 | object creation of type Object | CallSensitivityFlow.cs:102:25:102:36 | object creation of type Object | CallSensitivityFlow.cs:31:18:31:18 | access to parameter o | $@ | CallSensitivityFlow.cs:31:18:31:18 | access to parameter o | access to parameter o |
| CallSensitivityFlow.cs:103:26:103:37 | object creation of type Object | CallSensitivityFlow.cs:103:26:103:37 | object creation of type Object | CallSensitivityFlow.cs:39:18:39:18 | [cond (line 35): true] access to parameter o | $@ | CallSensitivityFlow.cs:39:18:39:18 | [cond (line 35): true] access to parameter o | [cond (line 35): true] access to parameter o |
| CallSensitivityFlow.cs:104:30:104:41 | object creation of type Object | CallSensitivityFlow.cs:104:30:104:41 | object creation of type Object | CallSensitivityFlow.cs:53:14:53:15 | access to local variable o3 | $@ | CallSensitivityFlow.cs:53:14:53:15 | access to local variable o3 | access to local variable o3 |
| CallSensitivityFlow.cs:105:26:105:37 | object creation of type Object | CallSensitivityFlow.cs:105:26:105:37 | object creation of type Object | CallSensitivityFlow.cs:105:14:105:41 | call to method FlowThrough | $@ | CallSensitivityFlow.cs:105:14:105:41 | call to method FlowThrough | call to method FlowThrough |
| CallSensitivityFlow.cs:117:26:117:37 | object creation of type Object | CallSensitivityFlow.cs:117:26:117:37 | object creation of type Object | CallSensitivityFlow.cs:128:22:128:22 | access to parameter o | $@ | CallSensitivityFlow.cs:128:22:128:22 | access to parameter o | access to parameter o |
| CallSensitivityFlow.cs:118:27:118:38 | object creation of type Object | CallSensitivityFlow.cs:118:27:118:38 | object creation of type Object | CallSensitivityFlow.cs:137:22:137:22 | access to parameter o | $@ | CallSensitivityFlow.cs:137:22:137:22 | access to parameter o | access to parameter o |
| CallSensitivityFlow.cs:119:32:119:43 | object creation of type Object | CallSensitivityFlow.cs:119:32:119:43 | object creation of type Object | CallSensitivityFlow.cs:152:18:152:19 | access to local variable o3 | $@ | CallSensitivityFlow.cs:152:18:152:19 | access to local variable o3 | access to local variable o3 |
| CallSensitivityFlow.cs:175:21:175:32 | object creation of type Object | CallSensitivityFlow.cs:175:21:175:32 | object creation of type Object | CallSensitivityFlow.cs:192:18:192:18 | access to parameter o | $@ | CallSensitivityFlow.cs:192:18:192:18 | access to parameter o | access to parameter o |

View File

@@ -0,0 +1,23 @@
/**
* @kind path-problem
*/
import csharp
import DataFlow::PathGraph
class Conf extends DataFlow::Configuration {
Conf() { this = "CallSensitiveFlowConf" }
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ObjectCreation }
override predicate isSink(DataFlow::Node sink) {
exists(MethodCall mc |
mc.getTarget().hasName("Sink") and
mc.getAnArgument() = sink.asExpr()
)
}
}
from DataFlow::PathNode source, DataFlow::PathNode sink, Conf conf
where conf.hasFlowPath(source, sink)
select source, source, sink, "$@", sink, sink.toString()