Merge pull request #1368 from hvitved/csharp/cil-nullness

CIL: Account for multiple `VariableUpdate::getSource()`s in nullness analysis
This commit is contained in:
Calum Grant
2019-05-29 20:55:08 +01:00
committed by GitHub
10 changed files with 61 additions and 11 deletions

View File

@@ -30,13 +30,25 @@ private module Cached {
}
import Cached
pragma[noinline]
private predicate alwaysNullVariableUpdate(VariableUpdate vu) {
forex(Expr src | src = vu.getSource() | alwaysNullExpr(src))
}
/** Holds if expression `expr` always evaluates to `null`. */
private predicate alwaysNullExpr(Expr expr) {
expr instanceof NullLiteral
or
alwaysNullMethod(expr.(StaticCall).getTarget())
or
forex(VariableUpdate vu | DefUse::variableUpdateUse(_, vu, expr) | alwaysNullExpr(vu.getSource()))
forex(VariableUpdate vu | DefUse::variableUpdateUse(_, vu, expr) |
alwaysNullVariableUpdate(vu)
)
}
pragma[noinline]
private predicate alwaysNotNullVariableUpdate(VariableUpdate vu) {
forex(Expr src | src = vu.getSource() | alwaysNotNullExpr(src))
}
/** Holds if expression `expr` always evaluates to non-null. */
@@ -48,6 +60,6 @@ private predicate alwaysNotNullExpr(Expr expr) {
alwaysNotNullMethod(expr.(StaticCall).getTarget())
or
forex(VariableUpdate vu | DefUse::variableUpdateUse(_, vu, expr) |
alwaysNotNullExpr(vu.getSource())
alwaysNotNullVariableUpdate(vu)
)
}

View File

@@ -8,7 +8,7 @@ predicate relevantMethod(CIL::Method m) {
or
m.getDeclaringType().getName() = "ThrowHelper"
or
m.getLocation().(CIL::Assembly).getName() = "DataFlow"
m.getLocation().(CIL::Assembly).getName().matches("DataFlow%")
}
// Check that the assembly hasn't been marked as a stub.

View File

@@ -1,3 +1,5 @@
// Generate DataFlow.dll: `csc /o /target:library DataFlow.cs_ /out:DataFlow.dll`
using System;
namespace Dataflow

BIN
csharp/ql/test/library-tests/cil/dataflow/DataFlow.dll Normal file → Executable file

Binary file not shown.

View File

@@ -12,6 +12,6 @@
| dataflow.cs:46:35:46:39 | "t1b" | dataflow.cs:46:18:46:40 | call to method Taint1 |
| dataflow.cs:49:35:49:38 | "t6" | dataflow.cs:49:18:49:45 | call to method TaintIndirect |
| dataflow.cs:49:41:49:44 | "t6" | dataflow.cs:49:18:49:45 | call to method TaintIndirect |
| dataflow.cs:95:30:95:33 | null | dataflow.cs:89:24:89:51 | ... ? ... : ... |
| dataflow.cs:95:30:95:33 | null | dataflow.cs:101:20:101:33 | call to method IndirectNull |
| dataflow.cs:102:23:102:26 | null | dataflow.cs:89:24:89:51 | ... ? ... : ... |
| dataflow.cs:102:30:102:33 | null | dataflow.cs:89:24:89:51 | ... ? ... : ... |
| dataflow.cs:102:30:102:33 | null | dataflow.cs:108:20:108:33 | call to method IndirectNull |
| dataflow.cs:109:23:109:26 | null | dataflow.cs:89:24:89:51 | ... ? ... : ... |

View File

@@ -0,0 +1,24 @@
// Generate DataFlowUnoptimized.dll: `csc /target:library DataFlowUnoptimized.cs_ /out:DataFlowUnoptimized.dll`
using System;
namespace DataflowUnoptimized
{
public class MaybeNullMethods
{
public bool cond = false;
public string MaybeNull()
{
if (cond)
return null;
else
return "not null";
}
public string MaybeNull2()
{
return cond ? null : "not null";
}
}
}

View File

@@ -30,3 +30,8 @@ alwaysNotNull
| dataflow.cs:90:24:90:34 | access to local variable nullMethods |
| dataflow.cs:91:24:91:34 | access to local variable nullMethods |
| dataflow.cs:92:26:92:32 | access to local variable nonNull |
| dataflow.cs:95:25:95:31 | access to local variable nonNull |
| dataflow.cs:96:26:96:32 | access to local variable nonNull |
| dataflow.cs:97:32:97:73 | object creation of type MaybeNullMethods |
| dataflow.cs:98:21:98:36 | access to local variable maybeNullMethods |
| dataflow.cs:99:22:99:37 | access to local variable maybeNullMethods |

View File

@@ -21,8 +21,8 @@
| dataflow.cs:48:28:48:28 | 1 | dataflow.cs:48:18:48:29 | call to method Taint3 |
| dataflow.cs:49:35:49:38 | "t6" | dataflow.cs:49:18:49:45 | call to method TaintIndirect |
| dataflow.cs:49:41:49:44 | "t6" | dataflow.cs:49:18:49:45 | call to method TaintIndirect |
| dataflow.cs:95:30:95:33 | null | dataflow.cs:74:21:74:52 | ... ?? ... |
| dataflow.cs:95:30:95:33 | null | dataflow.cs:89:24:89:51 | ... ? ... : ... |
| dataflow.cs:95:30:95:33 | null | dataflow.cs:101:20:101:33 | call to method IndirectNull |
| dataflow.cs:102:23:102:26 | null | dataflow.cs:74:21:74:52 | ... ?? ... |
| dataflow.cs:102:23:102:26 | null | dataflow.cs:89:24:89:51 | ... ? ... : ... |
| dataflow.cs:102:30:102:33 | null | dataflow.cs:74:21:74:52 | ... ?? ... |
| dataflow.cs:102:30:102:33 | null | dataflow.cs:89:24:89:51 | ... ? ... : ... |
| dataflow.cs:102:30:102:33 | null | dataflow.cs:108:20:108:33 | call to method IndirectNull |
| dataflow.cs:109:23:109:26 | null | dataflow.cs:74:21:74:52 | ... ?? ... |
| dataflow.cs:109:23:109:26 | null | dataflow.cs:89:24:89:51 | ... ? ... : ... |

View File

@@ -90,6 +90,13 @@ class Test
var notNull2 = nullMethods.VirtualReturnsNull();
var notNull3 = nullMethods.VirtualNullProperty;
var notNonNull = nonNull.VirtualNonNull;
// The following are maybe null
var maybeNull = nonNull.MaybeNull();
var maybeNull2 = nonNull.MaybeNull2();
var maybeNullMethods = new DataflowUnoptimized.MaybeNullMethods();
maybeNull = maybeNullMethods.MaybeNull();
maybeNull2 = maybeNullMethods.MaybeNull2();
}
object IndirectNull() => null;