зеркало из https://github.com/github/codeql.git
Merge pull request #593 from hvitved/csharp/nullness
C#: Rewrite nullness queries
This commit is contained in:
Коммит
67d4099e3f
|
@ -10,7 +10,10 @@
|
|||
## Changes to existing queries
|
||||
|
||||
| *@name of query (Query ID)* | *Impact on results* | *How/why the query has changed* |
|
||||
|------------------------------|------------------------|-----------------------------------|
|
||||
| Off-by-one comparison against container length (cs/index-out-of-bounds) | Fewer false positives | Results have been removed when there are additional guards on the index. |
|
||||
| Dereferenced variable is always null (cs/dereferenced-value-is-always-null) | Improved results | The query has been rewritten from scratch, and the analysis is now based on static single assignment (SSA) forms. The query is now enabled by default in LGTM. |
|
||||
| Dereferenced variable may be null (cs/dereferenced-value-may-be-null) | Improved results | The query has been rewritten from scratch, and the analysis is now based on static single assignment (SSA) forms. The query is now enabled by default in LGTM. |
|
||||
|
||||
## Changes to code extraction
|
||||
|
||||
|
|
|
@ -2,13 +2,39 @@
|
|||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
|
||||
<overview>
|
||||
<p>If a variable is dereferenced, and the variable has a null value on all possible execution paths
|
||||
leading to the dereferencing, it is guaranteed to result in a <code>NullReferenceException</code>.
|
||||
<p>If a variable is dereferenced, for example as the qualifier in a method call, and the
|
||||
variable has a <code>null</code> value on all possible execution paths leading to the
|
||||
dereferencing, the dereferencing is guaranteed to result in a <code>NullReferenceException</code>.
|
||||
</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>Examine the code to check for possible errors.</p>
|
||||
|
||||
<p>Ensure that the variable does not have a <code>null</code> value when it is dereferenced.
|
||||
</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
<p>
|
||||
In the following examples, the condition <code>s.Length > 0</code> is only
|
||||
executed if <code>s</code> is <code>null</code>.
|
||||
</p>
|
||||
|
||||
<sample src="NullAlwaysBad.cs" />
|
||||
|
||||
<p>
|
||||
In the revised example, the condition is guarded correctly by using <code>&&</code> instead of
|
||||
<code>||</code>.
|
||||
</p>
|
||||
|
||||
<sample src="NullAlwaysGood.cs" />
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>Microsoft, <a href="https://docs.microsoft.com/en-us/dotnet/api/system.nullreferenceexception">NullReferenceException Class</a>.</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/**
|
||||
* @name Dereferenced variable is always null
|
||||
* @description Finds uses of a variable that may cause a NullPointerException
|
||||
* @description Dereferencing a variable whose value is 'null' causes a 'NullReferenceException'.
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
* @precision medium
|
||||
* @precision very-high
|
||||
* @id cs/dereferenced-value-is-always-null
|
||||
* @tags reliability
|
||||
* correctness
|
||||
|
@ -14,6 +14,6 @@
|
|||
import csharp
|
||||
import semmle.code.csharp.dataflow.Nullness
|
||||
|
||||
from VariableAccess access, LocalVariable var
|
||||
where access = unguardedNullDereference(var)
|
||||
select access, "Variable $@ is always null here.", var, var.getName()
|
||||
from Dereference d, Ssa::SourceVariable v
|
||||
where d.isFirstAlwaysNull(v)
|
||||
select d, "Variable $@ is always null here.", v, v.toString()
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
|
||||
namespace NullAlways
|
||||
{
|
||||
class Bad
|
||||
{
|
||||
void DoPrint(string s)
|
||||
{
|
||||
if (s != null || s.Length > 0)
|
||||
Console.WriteLine(s);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
|
||||
namespace NullAlways
|
||||
{
|
||||
class Good
|
||||
{
|
||||
void DoPrint(string s)
|
||||
{
|
||||
if (s != null && s.Length > 0)
|
||||
Console.WriteLine(s);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,13 +2,41 @@
|
|||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
|
||||
<overview>
|
||||
<p>If a variable is dereferenced, and the variable may have a null value on some execution paths
|
||||
leading to the dereferencing, the dereferencing may result in a <code>NullReferenceException</code>.
|
||||
<p>If a variable is dereferenced, for example as the qualifier in a method call, and the
|
||||
variable may have a <code>null</code> value on some execution paths leading to the
|
||||
dereferencing, the dereferencing may result in a <code>NullReferenceException</code>.
|
||||
</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>Examine the code to check for possible errors.</p>
|
||||
|
||||
<p>Ensure that the variable does not have a <code>null</code> value when it is dereferenced.
|
||||
</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
<p>
|
||||
In the following example, the method <code>DoPrint()</code> dereferences its parameter
|
||||
<code>o</code> unconditionally, resulting in a <code>NullReferenceException</code> via
|
||||
the call <code>DoPrint(null)</code>.
|
||||
</p>
|
||||
|
||||
<sample src="NullMaybeBad.cs" />
|
||||
|
||||
<p>
|
||||
In the revised example, the method <code>DoPrint()</code> guards the dereferencing with
|
||||
a <code>null</code> check.
|
||||
</p>
|
||||
|
||||
<sample src="NullMaybeGood.cs" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>Microsoft, <a href="https://docs.microsoft.com/en-us/dotnet/api/system.nullreferenceexception">NullReferenceException Class</a>.</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
/**
|
||||
* @name Dereferenced variable may be null
|
||||
* @description Finds uses of a variable that may cause a NullPointerException
|
||||
* @description Dereferencing a variable whose value may be 'null' may cause a
|
||||
* 'NullReferenceException'.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @precision high
|
||||
* @id cs/dereferenced-value-may-be-null
|
||||
* @tags reliability
|
||||
* correctness
|
||||
|
@ -14,8 +15,6 @@
|
|||
import csharp
|
||||
import semmle.code.csharp.dataflow.Nullness
|
||||
|
||||
from VariableAccess access, LocalVariable var
|
||||
where access = unguardedMaybeNullDereference(var)
|
||||
// do not flag definite nulls here; these are already flagged by NullAlways.ql
|
||||
and not access = unguardedNullDereference(var)
|
||||
select access, "Variable $@ may be null here.", var, var.getName()
|
||||
from Dereference d, Ssa::SourceVariable v, string msg, Element reason
|
||||
where d.isFirstMaybeNull(v.getAnSsaDefinition(), msg, reason)
|
||||
select d, "Variable $@ may be null here " + msg + ".", v, v.toString(), reason, "this"
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
|
||||
class Bad
|
||||
{
|
||||
void DoPrint(object o)
|
||||
{
|
||||
Console.WriteLine(o.ToString());
|
||||
}
|
||||
|
||||
void M()
|
||||
{
|
||||
DoPrint("Hello");
|
||||
DoPrint(null);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
|
||||
class Good
|
||||
{
|
||||
void DoPrint(object o)
|
||||
{
|
||||
if (o != null)
|
||||
Console.WriteLine(o.ToString());
|
||||
}
|
||||
|
||||
void M()
|
||||
{
|
||||
DoPrint("Hello");
|
||||
DoPrint(null);
|
||||
}
|
||||
}
|
|
@ -966,12 +966,17 @@ class TryStmt extends Stmt, @try_stmt {
|
|||
exists(ControlFlowElement mid |
|
||||
mid = getATriedElement() and
|
||||
not mid instanceof TryStmt and
|
||||
result = mid.getAChild() and
|
||||
mid.getEnclosingCallable() = result.getEnclosingCallable()
|
||||
result = getAChild(mid, mid.getEnclosingCallable())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private ControlFlowElement getAChild(ControlFlowElement cfe, Callable c) {
|
||||
result = cfe.getAChild() and
|
||||
c = result.getEnclosingCallable()
|
||||
}
|
||||
|
||||
/**
|
||||
* A `catch` clause within a `try` statement.
|
||||
*
|
||||
|
|
|
@ -2497,7 +2497,11 @@ module ControlFlow {
|
|||
class PreBasicBlock extends ControlFlowElement {
|
||||
PreBasicBlock() { startsBB(this) }
|
||||
|
||||
PreBasicBlock getASuccessor() { result = succ(this.getLastElement(), _) }
|
||||
PreBasicBlock getASuccessorByType(SuccessorType t) {
|
||||
result = succ(this.getLastElement(), any(Completion c | t.matchesCompletion(c)))
|
||||
}
|
||||
|
||||
PreBasicBlock getASuccessor() { result = this.getASuccessorByType(_) }
|
||||
|
||||
PreBasicBlock getAPredecessor() {
|
||||
result.getASuccessor() = this
|
||||
|
@ -3099,6 +3103,12 @@ module ControlFlow {
|
|||
}
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private ControlFlowElement getAChild(ControlFlowElement cfe, Callable c) {
|
||||
result = cfe.getAChild() and
|
||||
c = result.getEnclosingCallable()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a descendant that belongs to the `finally` block of try statement
|
||||
* `try`.
|
||||
|
@ -3108,8 +3118,7 @@ module ControlFlow {
|
|||
or
|
||||
exists(ControlFlowElement mid |
|
||||
mid = getAFinallyDescendant(try) and
|
||||
result = mid.getAChild() and
|
||||
mid.getEnclosingCallable() = result.getEnclosingCallable() and
|
||||
result = getAChild(mid, mid.getEnclosingCallable()) and
|
||||
not exists(TryStmt nestedTry |
|
||||
result = nestedTry.getFinally() and
|
||||
nestedTry != try
|
||||
|
|
|
@ -9,12 +9,31 @@ private import semmle.code.csharp.commons.ComparisonTest
|
|||
private import semmle.code.csharp.commons.StructuralComparison::Internal
|
||||
private import semmle.code.csharp.controlflow.BasicBlocks
|
||||
private import semmle.code.csharp.controlflow.Completion
|
||||
private import semmle.code.csharp.dataflow.Nullness
|
||||
private import semmle.code.csharp.frameworks.System
|
||||
|
||||
/** An abstract value. */
|
||||
abstract class AbstractValue extends TAbstractValue {
|
||||
/** Holds if taking the `s` branch out of `cfe` implies that `e` has this value. */
|
||||
abstract predicate branchImplies(ControlFlowElement cfe, ConditionalSuccessor s, Expr e);
|
||||
/** Holds if the `s` branch out of `cfe` is taken iff `e` has this value. */
|
||||
abstract predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e);
|
||||
|
||||
/** Gets an abstract value that represents the dual of this value, if any. */
|
||||
abstract AbstractValue getDualValue();
|
||||
|
||||
/**
|
||||
* Gets an expression that has this abstract value. Two expressions that have the
|
||||
* same concrete value also have the same abstract value, but not necessarily the
|
||||
* other way around.
|
||||
*
|
||||
* Moreover, `e = this.getAnExpr() implies not e = this.getDualValue().getAnExpr()`.
|
||||
*/
|
||||
abstract Expr getAnExpr();
|
||||
|
||||
/**
|
||||
* Holds if this is a singleton abstract value. That is, two expressions that have
|
||||
* this abstract value also have the same concrete value.
|
||||
*/
|
||||
abstract predicate isSingleton();
|
||||
|
||||
/** Gets a textual representation of this abstract value. */
|
||||
abstract string toString();
|
||||
|
@ -27,7 +46,7 @@ module AbstractValues {
|
|||
/** Gets the underlying Boolean value. */
|
||||
boolean getValue() { this = TBooleanValue(result) }
|
||||
|
||||
override predicate branchImplies(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
|
||||
override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
|
||||
s.(BooleanSuccessor).getValue() = this.getValue() and
|
||||
exists(BooleanCompletion c |
|
||||
s.matchesCompletion(c) |
|
||||
|
@ -36,6 +55,44 @@ module AbstractValues {
|
|||
)
|
||||
}
|
||||
|
||||
override BooleanValue getDualValue() {
|
||||
result.getValue() = this.getValue().booleanNot()
|
||||
}
|
||||
|
||||
override Expr getAnExpr() {
|
||||
result.getType() instanceof BoolType and
|
||||
result.getValue() = this.getValue().toString()
|
||||
}
|
||||
|
||||
override predicate isSingleton() { any() }
|
||||
|
||||
override string toString() { result = this.getValue().toString() }
|
||||
}
|
||||
|
||||
/** An integer value. */
|
||||
class IntergerValue extends AbstractValue, TIntegerValue {
|
||||
/** Gets the underlying integer value. */
|
||||
int getValue() { this = TIntegerValue(result) }
|
||||
|
||||
override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
|
||||
none()
|
||||
}
|
||||
|
||||
override BooleanValue getDualValue() {
|
||||
none()
|
||||
}
|
||||
|
||||
override Expr getAnExpr() {
|
||||
result.getValue().toInt() = this.getValue() and
|
||||
(
|
||||
result.getType() instanceof Enum
|
||||
or
|
||||
result.getType() instanceof IntegralType
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSingleton() { any() }
|
||||
|
||||
override string toString() { result = this.getValue().toString() }
|
||||
}
|
||||
|
||||
|
@ -44,7 +101,7 @@ module AbstractValues {
|
|||
/** Holds if this value represents `null`. */
|
||||
predicate isNull() { this = TNullValue(true) }
|
||||
|
||||
override predicate branchImplies(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
|
||||
override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
|
||||
this = TNullValue(s.(NullnessSuccessor).getValue()) and
|
||||
exists(NullnessCompletion c |
|
||||
s.matchesCompletion(c) |
|
||||
|
@ -53,6 +110,22 @@ module AbstractValues {
|
|||
)
|
||||
}
|
||||
|
||||
override NullValue getDualValue() {
|
||||
if this.isNull() then not result.isNull() else result.isNull()
|
||||
}
|
||||
|
||||
override DereferenceableExpr getAnExpr() {
|
||||
if this.isNull() then
|
||||
result instanceof AlwaysNullExpr
|
||||
else
|
||||
exists(Expr e |
|
||||
nonNullValue(e) |
|
||||
nonNullValueImplied*(e, result)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSingleton() { this.isNull() }
|
||||
|
||||
override string toString() {
|
||||
if this.isNull() then result = "null" else result = "non-null"
|
||||
}
|
||||
|
@ -66,7 +139,7 @@ module AbstractValues {
|
|||
/** Holds if this value represents a match. */
|
||||
predicate isMatch() { this = TMatchValue(_, true) }
|
||||
|
||||
override predicate branchImplies(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
|
||||
override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
|
||||
this = TMatchValue(_, s.(MatchingSuccessor).getValue()) and
|
||||
exists(MatchingCompletion c, SwitchStmt ss, CaseStmt cs |
|
||||
s.matchesCompletion(c) |
|
||||
|
@ -77,6 +150,17 @@ module AbstractValues {
|
|||
)
|
||||
}
|
||||
|
||||
override MatchValue getDualValue() {
|
||||
result = any(MatchValue mv |
|
||||
mv.getCaseStmt() = this.getCaseStmt() and
|
||||
if this.isMatch() then not mv.isMatch() else mv.isMatch()
|
||||
)
|
||||
}
|
||||
|
||||
override Expr getAnExpr() { none() }
|
||||
|
||||
override predicate isSingleton() { none() }
|
||||
|
||||
override string toString() {
|
||||
exists(string s |
|
||||
s = this.getCaseStmt().toString() |
|
||||
|
@ -90,7 +174,7 @@ module AbstractValues {
|
|||
/** Holds if this value represents an empty collection. */
|
||||
predicate isEmpty() { this = TEmptyCollectionValue(true) }
|
||||
|
||||
override predicate branchImplies(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
|
||||
override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
|
||||
this = TEmptyCollectionValue(s.(EmptinessSuccessor).getValue()) and
|
||||
exists(EmptinessCompletion c, ForeachStmt fs |
|
||||
s.matchesCompletion(c) |
|
||||
|
@ -100,6 +184,14 @@ module AbstractValues {
|
|||
)
|
||||
}
|
||||
|
||||
override EmptyCollectionValue getDualValue() {
|
||||
if this.isEmpty() then not result.isEmpty() else result.isEmpty()
|
||||
}
|
||||
|
||||
override Expr getAnExpr() { none() }
|
||||
|
||||
override predicate isSingleton() { none() }
|
||||
|
||||
override string toString() {
|
||||
if this.isEmpty() then result = "empty" else result = "non-empty"
|
||||
}
|
||||
|
@ -112,6 +204,8 @@ private import AbstractValues
|
|||
* an expression that may evaluate to `null`.
|
||||
*/
|
||||
class DereferenceableExpr extends Expr {
|
||||
private boolean isNullableType;
|
||||
|
||||
DereferenceableExpr() {
|
||||
exists(Expr e, Type t |
|
||||
// There is currently a bug in the extractor: the type of `x?.Length` is
|
||||
|
@ -119,12 +213,19 @@ class DereferenceableExpr extends Expr {
|
|||
// `getNullEquivParent()` as a workaround
|
||||
this = getNullEquivParent*(e) and
|
||||
t = e.getType() |
|
||||
t instanceof NullableType
|
||||
t instanceof NullableType and
|
||||
isNullableType = true
|
||||
or
|
||||
t instanceof RefType
|
||||
t instanceof RefType and
|
||||
isNullableType = false
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if this expression has a nullable type `T?`. */
|
||||
predicate hasNullableType() {
|
||||
isNullableType = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an expression that directly tests whether this expression is `null`.
|
||||
*
|
||||
|
@ -155,7 +256,7 @@ class DereferenceableExpr extends Expr {
|
|||
ct.getExpr() = result |
|
||||
ct.getAnArgument() = this and
|
||||
ct.getAnArgument() = e and
|
||||
nonNullValue(e) and
|
||||
e = any(NullValue nv | not nv.isNull()).getAnExpr() and
|
||||
ck = ct.getComparisonKind() and
|
||||
this != e and
|
||||
isNull = false and
|
||||
|
@ -177,9 +278,22 @@ class DereferenceableExpr extends Expr {
|
|||
if ie.(IsConstantExpr).getConstant() instanceof NullLiteral then
|
||||
// E.g. `x is null`
|
||||
isNull = branch
|
||||
else
|
||||
else (
|
||||
// E.g. `x is string` or `x is ""`
|
||||
(branch = true and isNull = false)
|
||||
branch = true and isNull = false
|
||||
or
|
||||
// E.g. `x is string` where `x` has type `string`
|
||||
ie = any(IsTypeExpr ite | ite.getCheckedType() = ite.getExpr().getType()) and
|
||||
branch = false and
|
||||
isNull = true
|
||||
)
|
||||
)
|
||||
or
|
||||
this.hasNullableType() and
|
||||
result = any(PropertyAccess pa |
|
||||
pa.getQualifier() = this and
|
||||
pa.getTarget().hasName("HasValue") and
|
||||
if branch = true then isNull = false else isNull = true
|
||||
)
|
||||
or
|
||||
isCustomNullCheck(result, this, v, isNull)
|
||||
|
@ -189,7 +303,7 @@ class DereferenceableExpr extends Expr {
|
|||
/**
|
||||
* Gets an expression that tests via matching whether this expression is `null`.
|
||||
*
|
||||
* If the returned element matches (`v.isMatch()`) or non-matches
|
||||
* If the returned expression matches (`v.isMatch()`) or non-matches
|
||||
* (`not v.isMatch()`), then this expression is guaranteed to be `null`
|
||||
* if `isNull` is true, and non-`null` if `isNull` is false.
|
||||
*
|
||||
|
@ -307,19 +421,23 @@ class AccessOrCallExpr extends Expr {
|
|||
}
|
||||
|
||||
private Declaration getDeclarationTarget(Expr e) {
|
||||
e = any(AssignableRead ar | result = ar.getTarget()) or
|
||||
e = any(AssignableAccess aa | result = aa.getTarget()) or
|
||||
result = e.(Call).getTarget()
|
||||
}
|
||||
|
||||
private Ssa::Definition getAnSsaQualifier(Expr e) {
|
||||
e = getATrackedRead(result)
|
||||
e = getATrackedAccess(result)
|
||||
or
|
||||
not e = getATrackedRead(_) and
|
||||
not e = getATrackedAccess(_) and
|
||||
result = getAnSsaQualifier(e.(QualifiableExpr).getQualifier())
|
||||
}
|
||||
|
||||
private AssignableRead getATrackedRead(Ssa::Definition def) {
|
||||
result = def.getARead() and
|
||||
private AssignableAccess getATrackedAccess(Ssa::Definition def) {
|
||||
(
|
||||
result = def.getARead()
|
||||
or
|
||||
result = def.(Ssa::ExplicitDefinition).getADefinition().getTargetAccess()
|
||||
) and
|
||||
not def instanceof Ssa::ImplicitUntrackedDefinition
|
||||
}
|
||||
|
||||
|
@ -384,6 +502,15 @@ class GuardedExpr extends AccessOrCallExpr {
|
|||
v = v0
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this expression must have abstract value `v`. That is, this
|
||||
* expression is guarded by a structurally equal expression having abstract
|
||||
* value `v`.
|
||||
*/
|
||||
predicate mustHaveValue(AbstractValue v) {
|
||||
exists(Expr e | e = this.getAGuard(e, v))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this expression is guarded by expression `cond`, which must
|
||||
* evaluate to `b`. The expression `sub` is a sub expression of `cond`
|
||||
|
@ -401,7 +528,7 @@ class GuardedExpr extends AccessOrCallExpr {
|
|||
/** An expression guarded by a `null` check. */
|
||||
class NullGuardedExpr extends GuardedExpr {
|
||||
NullGuardedExpr() {
|
||||
exists(Expr e, NullValue v | e = this.getAGuard(e, v) | not v.isNull())
|
||||
this.mustHaveValue(any(NullValue v | not v.isNull()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -412,6 +539,10 @@ module Internal {
|
|||
newtype TAbstractValue =
|
||||
TBooleanValue(boolean b) { b = true or b = false }
|
||||
or
|
||||
TIntegerValue(int i) {
|
||||
i = any(Expr e).getValue().toInt()
|
||||
}
|
||||
or
|
||||
TNullValue(boolean b) { b = true or b = false }
|
||||
or
|
||||
TMatchValue(CaseStmt cs, boolean b) { b = true or b = false }
|
||||
|
@ -420,11 +551,28 @@ module Internal {
|
|||
|
||||
/** Holds if expression `e` is a non-`null` value. */
|
||||
predicate nonNullValue(Expr e) {
|
||||
e.stripCasts() = any(Expr s | s.hasValue() and not s instanceof NullLiteral)
|
||||
e instanceof ObjectCreation
|
||||
or
|
||||
e instanceof ArrayCreation
|
||||
or
|
||||
e.hasValue() and
|
||||
not e instanceof NullLiteral
|
||||
or
|
||||
e instanceof ThisAccess
|
||||
or
|
||||
e instanceof AddExpr and
|
||||
e.getType() instanceof StringType
|
||||
}
|
||||
|
||||
/** Holds if expression `e2` is a non-`null` value whenever `e1` is. */
|
||||
predicate nonNullValueImplied(Expr e1, Expr e2) {
|
||||
e1 = e2.(CastExpr).getExpr()
|
||||
or
|
||||
e1 = e2.(AssignExpr).getRValue()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the parent expression of `e` which is `null` only if `e` is `null`,
|
||||
* Gets the parent expression of `e` which is `null` iff `e` is `null`,
|
||||
* if any. For example, `result = x?.y` and `e = x`, or `result = x + 1`
|
||||
* and `e = x`.
|
||||
*/
|
||||
|
@ -433,6 +581,8 @@ module Internal {
|
|||
qe.getQualifier() = e and
|
||||
qe.isConditional() and
|
||||
(
|
||||
// The accessed declaration must have a value type in order
|
||||
// for `only if` to hold
|
||||
result.(FieldAccess).getTarget().getType() instanceof ValueType
|
||||
or
|
||||
result.(Call).getTarget().getReturnType() instanceof ValueType
|
||||
|
@ -444,11 +594,28 @@ module Internal {
|
|||
result = bao and
|
||||
bao.getAnOperand() = e and
|
||||
bao.getAnOperand() = o and
|
||||
nonNullValue(o) and
|
||||
// The other operand must be provably non-null in order
|
||||
// for `only if` to hold
|
||||
o = any(NullValue nv | not nv.isNull()).getAnExpr() and
|
||||
e != o
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a child expression of `e` which is `null` only if `e` is `null`.
|
||||
*/
|
||||
Expr getANullImplyingChild(Expr e) {
|
||||
e = any(QualifiableExpr qe |
|
||||
qe.isConditional() and
|
||||
result = qe.getQualifier()
|
||||
)
|
||||
or
|
||||
// In C#, `null + 1` has type `int?` with value `null`
|
||||
e = any(BinaryArithmeticOperation bao |
|
||||
result = bao.getAnOperand()
|
||||
)
|
||||
}
|
||||
|
||||
/** An expression whose value may control the execution of another element. */
|
||||
class Guard extends Expr {
|
||||
private AbstractValue val;
|
||||
|
@ -461,7 +628,7 @@ module Internal {
|
|||
this instanceof DereferenceableExpr and
|
||||
val = TNullValue(_)
|
||||
or
|
||||
val.branchImplies(_, _, this)
|
||||
val.branch(_, _, this)
|
||||
or
|
||||
asserts(_, this, val)
|
||||
}
|
||||
|
@ -473,7 +640,7 @@ module Internal {
|
|||
predicate controls(BasicBlock bb, AbstractValue v) {
|
||||
exists(ControlFlowElement cfe, ConditionalSuccessor s, AbstractValue v0, Guard g |
|
||||
cfe.controlsBlock(bb, s) |
|
||||
v0.branchImplies(cfe, s, g) and
|
||||
v0.branch(cfe, s, g) and
|
||||
impliesSteps(g, v0, this, v)
|
||||
)
|
||||
}
|
||||
|
@ -515,7 +682,7 @@ module Internal {
|
|||
predicate preControlsDirect(PreBasicBlocks::PreBasicBlock bb, AbstractValue v) {
|
||||
exists(PreBasicBlocks::ConditionBlock cb, ConditionalSuccessor s |
|
||||
cb.controls(bb, s) |
|
||||
v.branchImplies(cb.getLastElement(), s, this)
|
||||
v.branch(cb.getLastElement(), s, this)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -526,6 +693,14 @@ module Internal {
|
|||
impliesSteps(g, v0, this, v)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the successor block that is reached when this guard has abstract value `v`. */
|
||||
PreBasicBlocks::PreBasicBlock getConditionalSuccessor(AbstractValue v) {
|
||||
exists(PreBasicBlocks::ConditionBlock pred, ConditionalSuccessor s |
|
||||
v.branch(pred.getLastElement(), s, this) |
|
||||
result = pred.getASuccessorByType(s)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -628,6 +803,259 @@ module Internal {
|
|||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the evaluation of `guard` to `vGuard` implies that `def` is assigned
|
||||
* expression `e`.
|
||||
*/
|
||||
private predicate conditionalAssign(Guard guard, AbstractValue vGuard, PreSsa::Definition def, Expr e) {
|
||||
// For example:
|
||||
// v = guard ? e : x;
|
||||
exists(ConditionalExpr c |
|
||||
c = def.getDefinition().getSource() |
|
||||
guard = c.getCondition() and
|
||||
vGuard = any(BooleanValue bv |
|
||||
bv.getValue() = true and
|
||||
e = c.getThen()
|
||||
or
|
||||
bv.getValue() = false and
|
||||
e = c.getElse()
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(PreSsa::Definition upd, PreBasicBlocks::PreBasicBlock bbGuard |
|
||||
e = upd.getDefinition().getSource() and
|
||||
upd = def.getAPhiInput() and
|
||||
guard.preControlsDirect(upd.getBasicBlock(), vGuard) and
|
||||
bbGuard.getAnElement() = guard and
|
||||
bbGuard.strictlyDominates(def.getBasicBlock()) and
|
||||
not guard.preControlsDirect(def.getBasicBlock(), vGuard) and
|
||||
forall(PreSsa::Definition other |
|
||||
other != upd and other = def.getAPhiInput() |
|
||||
// For example:
|
||||
// if (guard)
|
||||
// upd = a;
|
||||
// else
|
||||
// other = b;
|
||||
// def = phi(upd, other)
|
||||
guard.preControlsDirect(other.getBasicBlock(), vGuard.getDualValue())
|
||||
or
|
||||
// For example:
|
||||
// other = a;
|
||||
// if (guard)
|
||||
// upd = b;
|
||||
// def = phi(other, upd)
|
||||
other.getBasicBlock().dominates(bbGuard) and
|
||||
not PreSsa::ssaDefReachesEndOfBlock(guard.getConditionalSuccessor(vGuard), other, _)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the evaluation of `guard` to `vGuard` implies that `def` is assigned
|
||||
* an expression with abstract value `vDef`.
|
||||
*/
|
||||
private predicate conditionalAssignVal(Expr guard, AbstractValue vGuard, PreSsa::Definition def, AbstractValue vDef) {
|
||||
conditionalAssign(guard, vGuard, def, vDef.getAnExpr())
|
||||
}
|
||||
|
||||
private predicate relevantEq(PreSsa::Definition def, AbstractValue v) {
|
||||
conditionalAssignVal(_, _, def, v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an expression that directly tests whether expression `e1` is equal
|
||||
* to expression `e2`.
|
||||
*
|
||||
* If the returned expression evaluates to `v`, then expression `e1` is
|
||||
* guaranteed to be equal to `e2`, otherwise it is guaranteed to not be
|
||||
* equal to `e2`.
|
||||
*
|
||||
* For example, if the expression `x != ""` evaluates to `false` then the
|
||||
* expression `x` is guaranteed to be equal to `""`.
|
||||
*/
|
||||
private Expr getABooleanEqualityCheck(Expr e1, BooleanValue v, Expr e2) {
|
||||
exists(boolean branch |
|
||||
branch = v.getValue() |
|
||||
exists(ComparisonTest ct, ComparisonKind ck |
|
||||
ct.getExpr() = result and
|
||||
ct.getAnArgument() = e1 and
|
||||
ct.getAnArgument() = e2 and
|
||||
e2 != e1 and
|
||||
ck = ct.getComparisonKind() |
|
||||
ck.isEquality() and branch = true
|
||||
or
|
||||
ck.isInequality() and branch = false
|
||||
)
|
||||
or
|
||||
result = any(IsExpr ie |
|
||||
ie.getExpr() = e1 and
|
||||
e2 = ie.(IsConstantExpr).getConstant() and
|
||||
branch = true
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an expression that tests via matching whether expression `e1` is equal
|
||||
* to expression `e2`.
|
||||
*
|
||||
* If the returned expression matches (`v.isMatch()`), then expression `e1` is
|
||||
* guaranteed to be equal to `e2`. If the returned expression non-matches
|
||||
* (`not v.isMatch()`), then this expression is guaranteed to not be equal to `e2`.
|
||||
*
|
||||
* For example, if the case statement `case ""` matches in
|
||||
*
|
||||
* ```
|
||||
* switch (o)
|
||||
* {
|
||||
* case "":
|
||||
* return s;
|
||||
* default:
|
||||
* return "";
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* then `o` is guaranteed to be equal to `""`.
|
||||
*/
|
||||
private Expr getAMatchingEqualityCheck(Expr e1, MatchValue v, Expr e2) {
|
||||
exists(SwitchStmt ss, ConstCase cc |
|
||||
cc = v.getCaseStmt() |
|
||||
e1 = ss.getCondition() and
|
||||
result = e1 and
|
||||
cc = ss.getACase() and
|
||||
e2 = cc.getExpr() and
|
||||
v.isMatch()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an expression that tests whether expression `e1` is equal to
|
||||
* expression `e2`.
|
||||
*
|
||||
* If the returned expression has abstract value `v`, then expression `e1` is
|
||||
* guaranteed to be equal to `e2`, and if the returned expression has abstract
|
||||
* value `v.getDualValue()`, then this expression is guaranteed to be
|
||||
* non-equal to `e`.
|
||||
*
|
||||
* For example, if the expression `x != ""` evaluates to `false` then the
|
||||
* expression `x` is guaranteed to be equal to `""`.
|
||||
*/
|
||||
Expr getAnEqualityCheck(Expr e1, AbstractValue v, Expr e2) {
|
||||
result = getABooleanEqualityCheck(e1, v, e2)
|
||||
or
|
||||
result = getAMatchingEqualityCheck(e1, v, e2)
|
||||
}
|
||||
|
||||
private Expr getAnEqualityCheckVal(Expr e, AbstractValue v, AbstractValue vExpr) {
|
||||
result = getAnEqualityCheck(e, v, vExpr.getAnExpr())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the evaluation of `guard` to `vGuard` implies that `def` does not
|
||||
* have the value `vDef`.
|
||||
*/
|
||||
private predicate guardImpliesNotEqual(Expr guard, AbstractValue vGuard, PreSsa::Definition def, AbstractValue vDef) {
|
||||
relevantEq(def, vDef) and
|
||||
exists(AssignableRead ar |
|
||||
ar = def.getARead() |
|
||||
// For example:
|
||||
// if (de == null); vGuard = TBooleanValue(false); vDef = TNullValue(true)
|
||||
// but not
|
||||
// if (de == "abc"); vGuard = TBooleanValue(false); vDef = TNullValue(false)
|
||||
guard = getAnEqualityCheckVal(ar, vGuard.getDualValue(), vDef) and
|
||||
vDef.isSingleton()
|
||||
or
|
||||
// For example:
|
||||
// if (de != null); vGuard = TBooleanValue(true); vDef = TNullValue(true)
|
||||
// or
|
||||
// if (de == null); vGuard = TBooleanValue(true); vDef = TNullValue(false)
|
||||
exists(NullValue nv |
|
||||
guard = ar.(DereferenceableExpr).getANullCheck(vGuard, any(boolean b | nv = TNullValue(b))) |
|
||||
vDef = nv.getDualValue()
|
||||
)
|
||||
or
|
||||
// For example:
|
||||
// if (de == false); vGuard = TBooleanValue(true); vDef = TBooleanValue(true)
|
||||
guard = getAnEqualityCheckVal(ar, vGuard, vDef.getDualValue())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `def` can have a value that is not representable as an
|
||||
* abstract value.
|
||||
*/
|
||||
private predicate hasPossibleUnknownValue(PreSsa::Definition def) {
|
||||
exists(PreSsa::Definition input |
|
||||
input = def.getAPhiInput*() and
|
||||
not exists(input.getAPhiInput())
|
||||
|
|
||||
not exists(input.getDefinition().getSource())
|
||||
or
|
||||
exists(Expr e |
|
||||
e = stripConditionalExpr(input.getDefinition().getSource()) |
|
||||
not e = any(AbstractValue v).getAnExpr()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an ultimate definition of `def` that is not itself a phi node. The
|
||||
* boolean `fromBackEdge` indicates whether the flow from `result` to `def`
|
||||
* goes through a back edge.
|
||||
*/
|
||||
PreSsa::Definition getADefinition(PreSsa::Definition def, boolean fromBackEdge) {
|
||||
result = def and
|
||||
not exists(def.getAPhiInput()) and
|
||||
fromBackEdge = false
|
||||
or
|
||||
exists(PreSsa::Definition input, PreBasicBlocks::PreBasicBlock pred, boolean fbe |
|
||||
input = def.getAPhiInput() |
|
||||
pred = def.getBasicBlock().getAPredecessor() and
|
||||
PreSsa::ssaDefReachesEndOfBlock(pred, input, _) and
|
||||
result = getADefinition(input, fbe) and
|
||||
(if def.getBasicBlock().dominates(pred) then fromBackEdge = true else fromBackEdge = fbe)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e` has abstract value `v` and may be assigned to `def`. The Boolean
|
||||
* `fromBackEdge` indicates whether the flow from `e` to `def` goes through a
|
||||
* back edge.
|
||||
*/
|
||||
private predicate possibleValue(PreSsa::Definition def, boolean fromBackEdge, Expr e, AbstractValue v) {
|
||||
not hasPossibleUnknownValue(def) and
|
||||
exists(PreSsa::Definition input |
|
||||
input = getADefinition(def, fromBackEdge) |
|
||||
e = stripConditionalExpr(input.getDefinition().getSource()) and
|
||||
v.getAnExpr() = e
|
||||
)
|
||||
}
|
||||
|
||||
private predicate nonUniqueValue(PreSsa::Definition def, Expr e, AbstractValue v) {
|
||||
possibleValue(def, false, e, v) and
|
||||
possibleValue(def, _, any(Expr other | other != e), v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e` has abstract value `v` and may be assigned to `def` without going
|
||||
* through back edges, and all other possible ultimate definitions of `def` do not
|
||||
* have abstract value `v`. The trivial case where `def` is an explicit update with
|
||||
* source `e` is excluded.
|
||||
*/
|
||||
private predicate uniqueValue(PreSsa::Definition def, Expr e, AbstractValue v) {
|
||||
possibleValue(def, false, e, v) and
|
||||
not nonUniqueValue(def, e, v) and
|
||||
exists(Expr other | possibleValue(def, _, other, _) and other != e)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `guard` having abstract value `vGuard` implies that `def` has
|
||||
* abstract value `vDef`.
|
||||
*/
|
||||
private predicate guardImpliesEqual(Guard guard, AbstractValue vGuard, PreSsa::Definition def, AbstractValue vDef) {
|
||||
guard = getAnEqualityCheck(def.getARead(), vGuard, vDef.getAnExpr())
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper class for calculating structurally equal access/call expressions.
|
||||
*/
|
||||
|
@ -750,30 +1178,41 @@ module Internal {
|
|||
polarity = false
|
||||
)
|
||||
or
|
||||
exists(ConditionalExpr cond, boolean branch, BoolLiteral boolLit, boolean b |
|
||||
b = boolLit.getBoolValue() and
|
||||
exists(ConditionalExpr cond, boolean branch, Expr e, AbstractValue v |
|
||||
e = v.getAnExpr() and
|
||||
(
|
||||
cond.getThen() = boolLit and branch = true
|
||||
cond.getThen() = e and branch = true
|
||||
or
|
||||
cond.getElse() = boolLit and branch = false
|
||||
cond.getElse() = e and branch = false
|
||||
)
|
||||
|
|
||||
g1 = cond and
|
||||
v1 = TBooleanValue(b.booleanNot()) and
|
||||
v1 = v.getDualValue() and
|
||||
(
|
||||
// g1 === g2 ? e : ...;
|
||||
g2 = cond.getCondition() and
|
||||
v2 = TBooleanValue(branch.booleanNot())
|
||||
or
|
||||
// g1 === ... ? g2 : e
|
||||
g2 = cond.getThen() and
|
||||
branch = false and
|
||||
v2 = v1
|
||||
or
|
||||
// g1 === g2 ? ... : e
|
||||
g2 = cond.getElse() and
|
||||
branch = true and
|
||||
v2 = v1
|
||||
)
|
||||
)
|
||||
or
|
||||
v1 = g1.getAValue() and
|
||||
v1 = any(MatchValue mv |
|
||||
mv.isMatch() and
|
||||
g2 = g1 and
|
||||
v2.getAnExpr() = mv.getCaseStmt().(ConstCase).getExpr() and
|
||||
v1 != v2
|
||||
)
|
||||
or
|
||||
exists(boolean isNull |
|
||||
g1 = g2.(DereferenceableExpr).getANullCheck(v1, isNull) |
|
||||
v2 = any(NullValue nv | if nv.isNull() then isNull = true else isNull = false) and
|
||||
|
@ -785,12 +1224,46 @@ module Internal {
|
|||
v1 instanceof NullValue and
|
||||
v2 = v1
|
||||
or
|
||||
g1 instanceof DereferenceableExpr and
|
||||
g2 = getANullImplyingChild(g1) and
|
||||
v1 = any(NullValue nv | not nv.isNull()) and
|
||||
v2 = v1
|
||||
or
|
||||
g2 = g1.(AssignExpr).getRValue() and
|
||||
v1 = g1.getAValue() and
|
||||
v2 = v1
|
||||
or
|
||||
g2 = g1.(Assignment).getLValue() and
|
||||
v1 = g1.getAValue() and
|
||||
v2 = v1
|
||||
or
|
||||
g2 = g1.(CastExpr).getExpr() and
|
||||
v1 = g1.getAValue() and
|
||||
v2 = v1.(NullValue)
|
||||
or
|
||||
exists(PreSsa::Definition def |
|
||||
def.getDefinition().getSource() = g2 |
|
||||
g1 = def.getARead() and
|
||||
v1 = g1.getAValue() and
|
||||
v2 = v1
|
||||
)
|
||||
or
|
||||
exists(PreSsa::Definition def, AbstractValue v |
|
||||
// If for example `def = g2 ? v : ...`, then a guard `g1` proving `def != v`
|
||||
// ensures that `g2` evaluates to `false`.
|
||||
conditionalAssignVal(g2, v2.getDualValue(), def, v) and
|
||||
guardImpliesNotEqual(g1, v1, def, v)
|
||||
)
|
||||
or
|
||||
exists(PreSsa::Definition def, Expr e, AbstractValue v |
|
||||
// If for example `def = g2 ? v : ...` and all other assignments to `def` are
|
||||
// different from `v`, then a guard proving `def == v` ensures that `g2`
|
||||
// evaluates to `true`.
|
||||
uniqueValue(def, e, v) and
|
||||
guardImpliesEqual(g1, v1, def, v) and
|
||||
g2.preControlsDirect(any(PreBasicBlocks::PreBasicBlock bb | e = bb.getAnElement()), v2) and
|
||||
not g2.preControlsDirect(any(PreBasicBlocks::PreBasicBlock bb | g1 = bb.getAnElement()), v2)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* Provides predicates for performing nullness analyses.
|
||||
*
|
||||
* Nullness analyses are used to identify places in a program where
|
||||
* a null pointer exception (`NullReferenceException`) may be thrown.
|
||||
* a `null` pointer exception (`NullReferenceException`) may be thrown.
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
|
@ -18,493 +18,391 @@
|
|||
*/
|
||||
|
||||
import csharp
|
||||
private import ControlFlow
|
||||
private import semmle.code.csharp.commons.Assertions
|
||||
private import semmle.code.csharp.commons.ComparisonTest
|
||||
private import semmle.code.csharp.controlflow.Guards
|
||||
private import semmle.code.csharp.controlflow.Guards as G
|
||||
private import semmle.code.csharp.controlflow.Guards::AbstractValues
|
||||
private import semmle.code.csharp.dataflow.SSA
|
||||
private import semmle.code.csharp.frameworks.System
|
||||
private import semmle.code.csharp.frameworks.Test
|
||||
|
||||
/** An expression that may be `null`. */
|
||||
private class NullExpr extends Expr {
|
||||
NullExpr() {
|
||||
this instanceof NullLiteral or
|
||||
this.(ParenthesizedExpr).getExpr() instanceof NullExpr or
|
||||
this.(ConditionalExpr).getThen() instanceof NullExpr or
|
||||
this.(ConditionalExpr).getElse() instanceof NullExpr
|
||||
class MaybeNullExpr extends Expr {
|
||||
MaybeNullExpr() {
|
||||
this instanceof NullLiteral
|
||||
or
|
||||
this.(ConditionalExpr).getThen() instanceof MaybeNullExpr
|
||||
or
|
||||
this.(ConditionalExpr).getElse() instanceof MaybeNullExpr
|
||||
or
|
||||
this.(AssignExpr).getRValue() instanceof MaybeNullExpr
|
||||
or
|
||||
this.(Cast).getExpr() instanceof MaybeNullExpr
|
||||
}
|
||||
}
|
||||
|
||||
/** An expression that may be non-`null`. */
|
||||
private class NonNullExpr extends Expr {
|
||||
/** An expression that is always `null`. */
|
||||
class AlwaysNullExpr extends Expr {
|
||||
AlwaysNullExpr() {
|
||||
this instanceof NullLiteral
|
||||
or
|
||||
this = any(ConditionalExpr ce |
|
||||
ce.getThen() instanceof AlwaysNullExpr and
|
||||
ce.getElse() instanceof AlwaysNullExpr
|
||||
)
|
||||
or
|
||||
this.(AssignExpr).getRValue() instanceof AlwaysNullExpr
|
||||
or
|
||||
this.(Cast).getExpr() instanceof AlwaysNullExpr
|
||||
}
|
||||
}
|
||||
|
||||
/** An expression that is never `null`. */
|
||||
class NonNullExpr extends Expr {
|
||||
NonNullExpr() {
|
||||
not (this instanceof NullLiteral or this instanceof ConditionalExpr or this instanceof ParenthesizedExpr) or
|
||||
this.(ParenthesizedExpr).getExpr() instanceof NonNullExpr or
|
||||
this.(ConditionalExpr).getThen() instanceof NonNullExpr or
|
||||
this.(ConditionalExpr).getElse() instanceof NonNullExpr
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets an assignment to the variable `var` that may be `null`. */
|
||||
private AssignExpr nullSet(LocalScopeVariable var) {
|
||||
var.getAnAccess() = result.getLValue() and
|
||||
result.getRValue() instanceof NullExpr
|
||||
}
|
||||
|
||||
/** Gets an assignment to the variable `var` that may be non-`null`. */
|
||||
private Assignment nonNullSet(LocalScopeVariable var) {
|
||||
var.getAnAccess() = result.getLValue() and
|
||||
result.getRValue() instanceof NonNullExpr
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an expression that will result in a `NullReferenceException` if the
|
||||
* variable access `access` is `null`.
|
||||
*/
|
||||
private Expr nonNullAccess(LocalScopeVariableAccess access) {
|
||||
access.getType() instanceof RefType
|
||||
and (
|
||||
result.(ArrayAccess).getQualifier() = access or
|
||||
exists (MemberAccess ma | result=ma and not ma.isConditional() | access = ma.getQualifier()) or
|
||||
exists (MethodCall mc | result=mc and not mc.isConditional() | access = mc.getQualifier()) or
|
||||
exists (LockStmt stmt | stmt.getExpr() = access and result = access)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an expression that accesses the variable `var` such that it will
|
||||
* result in a `NullReferenceException` if the variable is `null`.
|
||||
*/
|
||||
private Expr nonNullUse(LocalScopeVariable var) {
|
||||
result = nonNullAccess(var.getAnAccess())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a local variable declaration expression that may
|
||||
* initialize the variable `var` with `null`.
|
||||
*/
|
||||
private LocalVariableDeclExpr initialNull(LocalVariable var) {
|
||||
result.getVariable() = var and
|
||||
result.getInitializer() instanceof NullExpr
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a local variable declaration expression that may
|
||||
* initialize the variable `var` with a non-`null` expression.
|
||||
*/
|
||||
private LocalVariableDeclExpr initialNonNull(LocalVariable var) {
|
||||
result.getVariable() = var and
|
||||
result.getInitializer() instanceof NonNullExpr
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an expression that either asserts that the variable `var`
|
||||
* is `null` or that may assign `null` to `var`.
|
||||
*/
|
||||
private Expr nullDef(LocalScopeVariable var) {
|
||||
nullSet(var) = result or
|
||||
initialNull(var) = result or
|
||||
exists(MethodCall mc, AssertNullMethod m, Expr arg |
|
||||
// E.g. `Assert.IsNull(var)`
|
||||
mc = result and
|
||||
mc.getTarget() = m and
|
||||
mc.getArgument(m.getAssertionIndex()) = arg and
|
||||
sameValue(arg, var.getAnAccess())
|
||||
) or
|
||||
exists(MethodCall mc, AssertTrueMethod m, Expr arg |
|
||||
// E.g. `Assert.IsTrue(var == null)`
|
||||
mc = result and
|
||||
arg = nullTest(var) and
|
||||
arg = mc.getArgument(m.getAssertionIndex()) and
|
||||
mc.getTarget() = m
|
||||
) or
|
||||
exists(MethodCall mc, AssertFalseMethod m, Expr arg |
|
||||
// E.g. `Assert.IsFalse(var != null)`
|
||||
mc = result and
|
||||
arg = failureIsNullTest(var) and
|
||||
arg = mc.getArgument(m.getAssertionIndex()) and
|
||||
mc.getTarget() = m
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an expression that either asserts that the variable `var` is
|
||||
* non-`null`, dereferences it, or may assign a non-`null` expression to it.
|
||||
*/
|
||||
private Expr nonNullDef(LocalScopeVariable var) {
|
||||
nonNullSet(var) = result or
|
||||
nonNullUse(var) = result or
|
||||
initialNonNull(var) = result or
|
||||
useAsOutParameter(var) = result or
|
||||
nonNullSettingLambda(var) = result or
|
||||
exists(MethodCall mc, AssertNonNullMethod m, Expr arg |
|
||||
// E.g. `Assert.IsNotNull(arg)`
|
||||
mc = result and
|
||||
mc.getTarget() = m and
|
||||
mc.getArgument(m.getAssertionIndex()) = arg and
|
||||
sameValue(arg, var.getAnAccess())
|
||||
) or
|
||||
exists(MethodCall mc, AssertTrueMethod m, Expr arg |
|
||||
// E.g. `Assert.IsTrue(arg != null)`
|
||||
mc = result and
|
||||
arg = nonNullTest(var) and
|
||||
arg = mc.getArgument(m.getAssertionIndex()) and
|
||||
mc.getTarget() = m
|
||||
) or
|
||||
exists(MethodCall mc, AssertFalseMethod m, Expr arg |
|
||||
// E.g. `Assert.IsFalse(arg == null)`
|
||||
mc = result and
|
||||
arg = failureIsNonNullTest(var) and
|
||||
arg = mc.getArgument(m.getAssertionIndex()) and
|
||||
mc.getTarget() = m
|
||||
)
|
||||
}
|
||||
|
||||
private Call useAsOutParameter(LocalScopeVariable var) {
|
||||
exists(LocalScopeVariableAccess a |
|
||||
a = result.getAnArgument() and a = var.getAnAccess() |
|
||||
a.isOutArgument() or a.isRefArgument())
|
||||
}
|
||||
|
||||
private AnonymousFunctionExpr nonNullSettingLambda(LocalScopeVariable var) {
|
||||
result = nonNullDef(var).getEnclosingCallable()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a logical 'or' expression in which the expression `e` is a
|
||||
* (possibly nested) operand.
|
||||
*/
|
||||
private LogicalOrExpr orParent(Expr e) {
|
||||
e = result.getAnOperand()
|
||||
G::Internal::nonNullValue(this)
|
||||
or
|
||||
exists(LogicalOrExpr orexpr | result = orParent(orexpr) and e = orexpr.getAnOperand())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a logical 'and' expression in which the expression `e` is a
|
||||
* (possibly nested) operand.
|
||||
*/
|
||||
private LogicalAndExpr andParent(Expr e) {
|
||||
e = result.getAnOperand()
|
||||
exists(NonNullExpr mid |
|
||||
G::Internal::nonNullValueImplied(mid, this)
|
||||
)
|
||||
or
|
||||
exists(LogicalAndExpr andexpr | result = andParent(andexpr) and e = andexpr.getAnOperand())
|
||||
this instanceof G::NullGuardedExpr
|
||||
or
|
||||
exists(Ssa::Definition def | nonNullDef(def) | this = def.getARead())
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if SSA definition `def` is never `null`. */
|
||||
private predicate nonNullDef(Ssa::Definition v) {
|
||||
v.(Ssa::ExplicitDefinition).getADefinition().getSource() instanceof NonNullExpr
|
||||
or
|
||||
exists(AssignableDefinition ad |
|
||||
ad = v.(Ssa::ExplicitDefinition).getADefinition() |
|
||||
ad instanceof AssignableDefinitions::IsPatternDefinition
|
||||
or
|
||||
ad instanceof AssignableDefinitions::TypeCasePatternDefinition
|
||||
or
|
||||
ad = any(AssignableDefinitions::LocalVariableDefinition d |
|
||||
d.getExpr() = any(SpecificCatchClause scc).getVariableDeclExpr()
|
||||
or
|
||||
d.getExpr() = any(ForeachStmt fs).getAVariableDeclExpr()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if variable access `access` has the "same value" as expression `expr`:
|
||||
* Holds if the `i`th node of basic block `bb` is a dereference `d` of SSA
|
||||
* definition `def`.
|
||||
*/
|
||||
private predicate dereferenceAt(BasicBlock bb, int i, Ssa::Definition def, Dereference d) {
|
||||
d = def.getAReadAtNode(bb.getNode(i))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e` having abstract value `vExpr` implies that SSA definition `def`
|
||||
* has abstract value `vDef`.
|
||||
*/
|
||||
private predicate exprImpliesSsaDef(Expr e, G::AbstractValue vExpr, Ssa::Definition def, G::AbstractValue vDef) {
|
||||
exists(G::Internal::Guard g |
|
||||
G::Internal::impliesSteps(e, vExpr, g, vDef) |
|
||||
g = def.getARead()
|
||||
or
|
||||
g = def.(Ssa::ExplicitDefinition).getADefinition().getTargetAccess()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `i`th node of basic block `bb` ensures that SSA definition
|
||||
* `def` is not `null` in any subsequent uses.
|
||||
*/
|
||||
private predicate ensureNotNullAt(BasicBlock bb, int i, Ssa::Definition def) {
|
||||
exists(Expr e, G::AbstractValue v, NullValue nv |
|
||||
G::Internal::asserts(bb.getNode(i).getElement(), e, v) |
|
||||
exprImpliesSsaDef(e, v, def, nv) and
|
||||
not nv.isNull()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `i`th node of basic block `bb` is a dereference `d` of SSA
|
||||
* definition `def`, and `def` may potentially be `null`.
|
||||
*/
|
||||
private predicate potentialNullDereferenceAt(BasicBlock bb, int i, Ssa::Definition def, Dereference d) {
|
||||
dereferenceAt(bb, i, def, d) and
|
||||
not exists(int j | ensureNotNullAt(bb, j, def) | j < i)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an element that tests whether a given SSA definition, `def`, is
|
||||
* `null` or not.
|
||||
*
|
||||
* - `access` is equal to `expr`, or
|
||||
* - `expr` is an assignment and the `access` is its left-hand side, or
|
||||
* - `expr` is an assignment and the `access` has the same value as its right-hand
|
||||
* side.
|
||||
* If the returned element takes the `s` branch, then `def` is guaranteed to be
|
||||
* `null` if `nv.isNull()` holds, and non-`null` otherwise.
|
||||
*/
|
||||
private predicate sameValue(Expr expr, LocalScopeVariableAccess access) {
|
||||
access = expr.stripCasts() or
|
||||
access = expr.(AssignExpr).getLValue() or
|
||||
sameValue(expr.(AssignExpr).getRValue(), access) or
|
||||
sameValue(expr.(ParenthesizedExpr).getExpr(), access)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an `is` expression in which the left-hand side is an access to the
|
||||
* variable `var`.
|
||||
*/
|
||||
private Expr instanceOfTest(LocalScopeVariable var) {
|
||||
exists(IsExpr e | result = e and
|
||||
sameValue(e.getExpr() , var.getAnAccess()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an expression performing a `null` check on the variable `var`:
|
||||
*
|
||||
* - either via a reference equality test with `null`, or
|
||||
* - by passing it as an argument to a method that performs the test.
|
||||
*/
|
||||
private Expr directNullTest(LocalScopeVariable var) {
|
||||
exists(ComparisonTest ct |
|
||||
result = ct.getExpr() and
|
||||
sameValue(ct.getAnArgument(), var.getAnAccess()) and
|
||||
ct.getAnArgument() instanceof NullLiteral |
|
||||
ct.(ComparisonOperationComparisonTest).getComparisonKind().isEquality() or
|
||||
ct.(StaticEqualsCallComparisonTest).isReferenceEquals() or
|
||||
ct.(OperatorCallComparisonTest).getComparisonKind().isEquality()
|
||||
)
|
||||
or
|
||||
exists(Call call, int i | result = call |
|
||||
call.getRuntimeArgument(i) = var.getAnAccess() and
|
||||
forex(Callable callable |
|
||||
call.getARuntimeTarget() = callable |
|
||||
nullTestInCallable(callable.getSourceDeclaration(), i)
|
||||
)
|
||||
)
|
||||
or
|
||||
// seems redundant, because all methods that use this method also peel ParenthesizedExpr
|
||||
// However, removing this line causes an increase of memory usage
|
||||
result.(ParenthesizedExpr).getExpr() = directNullTest(var)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if callable `c` performs a `null` test on its `i`th argument and
|
||||
* returns the result.
|
||||
*/
|
||||
private predicate nullTestInCallable(Callable c, int i) {
|
||||
exists(Parameter p |
|
||||
p = c.getParameter(i) and
|
||||
not p.isOverwritten() and
|
||||
forex(Expr e | c.canReturn(e) | stripConditionalExpr(e) = nullTest(p))
|
||||
)
|
||||
or
|
||||
nullTestInLibraryMethod(c, i)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if library method `m` performs a `null` test on its `i`th argument and
|
||||
* returns the result.
|
||||
*/
|
||||
private predicate nullTestInLibraryMethod(Method m, int i) {
|
||||
m.fromLibrary() and
|
||||
m.getName().toLowerCase().regexpMatch("(is)?null(orempty|orwhitespace)?") and
|
||||
m.getReturnType() instanceof BoolType and
|
||||
m.getNumberOfParameters() = 1 and
|
||||
i = 0
|
||||
}
|
||||
|
||||
private Expr stripConditionalExpr(Expr e) {
|
||||
if e instanceof ConditionalExpr then
|
||||
result = stripConditionalExpr(e.(ConditionalExpr).getThen()) or
|
||||
result = stripConditionalExpr(e.(ConditionalExpr).getElse())
|
||||
else
|
||||
result = e
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an expression performing a non-`null` check on the variable `var`:
|
||||
*
|
||||
* - either via an inequality test with `null`, or
|
||||
* - by performing an `is` test, or
|
||||
* - by passing it as an argument to a method that performs the test.
|
||||
*/
|
||||
private Expr directNonNullTest(LocalScopeVariable var) {
|
||||
exists(ComparisonTest ct |
|
||||
result = ct.getExpr() and
|
||||
sameValue(ct.getAnArgument(), var.getAnAccess()) and
|
||||
ct.getAnArgument() instanceof NullLiteral |
|
||||
ct.(ComparisonOperationComparisonTest).getComparisonKind().isInequality() or
|
||||
ct.(OperatorCallComparisonTest).getComparisonKind().isInequality()
|
||||
)
|
||||
or
|
||||
instanceOfTest(var) = result
|
||||
or
|
||||
exists(Call call, int i | result = call |
|
||||
call.getRuntimeArgument(i) = var.getAnAccess() and
|
||||
exists(call.getARuntimeTarget()) and
|
||||
forall(Callable callable |
|
||||
call.getARuntimeTarget() = callable |
|
||||
nonNullTestInCallable(callable.getSourceDeclaration(), i)
|
||||
)
|
||||
)
|
||||
or
|
||||
// seems redundant, because all methods that use this method also peel ParenthesizedExpr
|
||||
// However, removing this line causes an increase of memory usage
|
||||
result.(ParenthesizedExpr).getExpr() = directNonNullTest(var)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if callable `c` performs a non-`null` test on its `i`th argument and
|
||||
* returns the result.
|
||||
*/
|
||||
private predicate nonNullTestInCallable(Callable c, int i) {
|
||||
exists(Parameter p |
|
||||
p = c.getParameter(i) and
|
||||
not p.isOverwritten() and
|
||||
forex(Expr e | c.canReturn(e) | stripConditionalExpr(e) = nonNullTest(p))
|
||||
)
|
||||
or
|
||||
nonNullTestInLibraryMethod(c, i)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if library method `m` performs a non-`null` test on its `i`th argument
|
||||
* and returns the result.
|
||||
*/
|
||||
private predicate nonNullTestInLibraryMethod(Method m, int i) {
|
||||
m.fromLibrary() and
|
||||
m.getName().toLowerCase().regexpMatch("(is)?no(t|n)null") and
|
||||
m.getReturnType() instanceof BoolType and
|
||||
m.getNumberOfParameters() = 1 and
|
||||
i = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a `null` test in a _positive_ position for the variable `var`.
|
||||
*/
|
||||
private Expr nullTest(LocalScopeVariable var) {
|
||||
directNullTest(var) = result
|
||||
or
|
||||
result.(ParenthesizedExpr).getExpr() = nullTest(var)
|
||||
or
|
||||
exists(LogicalNotExpr notexpr | result = notexpr and
|
||||
notexpr.getAChildExpr() = failureIsNullTest(var))
|
||||
or
|
||||
result = andParent(nullTest(var))
|
||||
or
|
||||
exists(LogicalOrExpr orexpr | result = orexpr and
|
||||
orexpr.getLeftOperand() = nullTest(var) and
|
||||
orexpr.getRightOperand() = nullTest(var))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a non-`null` test in a _positive_ position for the variable `var`.
|
||||
*/
|
||||
private Expr nonNullTest(LocalScopeVariable var) {
|
||||
directNonNullTest(var) = result
|
||||
or
|
||||
result.(ParenthesizedExpr).getExpr() = nonNullTest(var)
|
||||
or
|
||||
exists(LogicalNotExpr notexpr | result = notexpr and
|
||||
notexpr.getAChildExpr() = failureIsNonNullTest(var))
|
||||
or
|
||||
result = andParent(nonNullTest(var))
|
||||
or
|
||||
exists(LogicalOrExpr orexpr | result = orexpr and
|
||||
orexpr.getLeftOperand() = nonNullTest(var) and
|
||||
orexpr.getRightOperand() = nonNullTest(var))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a non-`null` test in a _negative_ position for the variable `var`.
|
||||
*/
|
||||
private Expr failureIsNullTest(LocalScopeVariable var) {
|
||||
directNonNullTest(var) = result
|
||||
or
|
||||
result.(ParenthesizedExpr).getExpr() = failureIsNullTest(var)
|
||||
or
|
||||
exists(LogicalNotExpr notexpr | result = notexpr and
|
||||
notexpr.getAChildExpr() = failureIsNonNullTest(var))
|
||||
or
|
||||
result = orParent(failureIsNullTest(var))
|
||||
or
|
||||
exists(LogicalAndExpr andexpr | result = andexpr and
|
||||
andexpr.getLeftOperand() = failureIsNullTest(var) and
|
||||
andexpr.getRightOperand() = failureIsNullTest(var))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a `null` test in a _negative_ position for the variable `var`.
|
||||
*/
|
||||
private Expr failureIsNonNullTest(LocalScopeVariable var) {
|
||||
directNullTest(var) = result
|
||||
or
|
||||
result.(ParenthesizedExpr).getExpr() = failureIsNonNullTest(var)
|
||||
or
|
||||
exists(LogicalNotExpr notexpr | result = notexpr and
|
||||
notexpr.getAChildExpr() = failureIsNullTest(var))
|
||||
or
|
||||
result = orParent(directNullTest(var))
|
||||
or
|
||||
exists(LogicalAndExpr andexpr | result = andexpr and
|
||||
andexpr.getLeftOperand() = failureIsNonNullTest(var) and
|
||||
andexpr.getRightOperand() = failureIsNonNullTest(var))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an immediate successor node of the conditional node `cfgnode` where
|
||||
* the condition implies that the variable `var` is `null`.
|
||||
*/
|
||||
private ControlFlow::Node nullBranchKill(LocalScopeVariable var, ControlFlow::Node cfgnode) {
|
||||
(cfgnode.getElement() = nullTest(var) and result = cfgnode.getATrueSuccessor())
|
||||
or
|
||||
(cfgnode.getElement() = failureIsNullTest(var) and result = cfgnode.getAFalseSuccessor())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an immediate successor node of the conditional node `cfgnode` where
|
||||
* the condition implies that the variable `var` is non-`null`.
|
||||
*/
|
||||
private ControlFlow::Node nonNullBranchKill(LocalScopeVariable var, ControlFlow::Node cfgnode) {
|
||||
(cfgnode.getElement() = nonNullTest(var) and result = cfgnode.getATrueSuccessor())
|
||||
or
|
||||
(cfgnode.getElement() = failureIsNonNullTest(var) and result = cfgnode.getAFalseSuccessor())
|
||||
}
|
||||
|
||||
/** Gets a node where the variable `var` may be `null`. */
|
||||
ControlFlow::Node maybeNullNode(LocalScopeVariable var) {
|
||||
result = nullDef(var).getAControlFlowNode().getASuccessor()
|
||||
or
|
||||
exists(ControlFlow::Node mid |
|
||||
mid = maybeNullNode(var) and
|
||||
not mid.getElement() = nonNullDef(var) and
|
||||
mid.getASuccessor() = result and
|
||||
not result = nonNullBranchKill(var, mid)
|
||||
private ControlFlowElement getANullCheck(Ssa::Definition def, SuccessorTypes::ConditionalSuccessor s, NullValue nv) {
|
||||
exists(Expr e, G::AbstractValue v |
|
||||
v.branch(result, s, e) |
|
||||
exprImpliesSsaDef(e, v, def, nv)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a node where the variable `var` may be non-`null`. */
|
||||
ControlFlow::Node maybeNonNullNode(LocalScopeVariable var) {
|
||||
result = nonNullDef(var).getAControlFlowNode().getASuccessor()
|
||||
/** Holds if `def` is an SSA definition that may be `null`. */
|
||||
private predicate defMaybeNull(Ssa::Definition def, string msg, Element reason) {
|
||||
// A variable compared to `null` might be `null`
|
||||
exists(G::DereferenceableExpr de |
|
||||
de = def.getARead() |
|
||||
reason = de.getANullCheck(_, true) and
|
||||
msg = "as suggested by $@ null check" and
|
||||
not def instanceof Ssa::PseudoDefinition and
|
||||
not nonNullDef(def) and
|
||||
// Don't use a check as reason if there is a `null` assignment
|
||||
not def.(Ssa::ExplicitDefinition).getADefinition().getSource() instanceof MaybeNullExpr
|
||||
)
|
||||
or
|
||||
exists(ControlFlow::Node mid |
|
||||
mid = maybeNonNullNode(var) and
|
||||
not mid.getElement() = nullDef(var) and
|
||||
mid.getASuccessor() = result and
|
||||
not result = nullBranchKill(var, mid)
|
||||
// A parameter might be `null` if there is a `null` argument somewhere
|
||||
exists(AssignableDefinitions::ImplicitParameterDefinition pdef, Parameter p, MaybeNullExpr arg |
|
||||
pdef = def.(Ssa::ExplicitDefinition).getADefinition() |
|
||||
p = pdef.getParameter().getSourceDeclaration() and
|
||||
p.getAnAssignedArgument() = arg and
|
||||
reason = arg and
|
||||
msg = "because of $@ null argument" and
|
||||
not arg.getEnclosingCallable().getEnclosingCallable*() instanceof TestMethod
|
||||
)
|
||||
or
|
||||
// If the source of a variable is `null` then the variable may be `null`
|
||||
exists(AssignableDefinition adef |
|
||||
adef = def.(Ssa::ExplicitDefinition).getADefinition() |
|
||||
adef.getSource() instanceof MaybeNullExpr and
|
||||
reason = adef.getExpr() and
|
||||
msg = "because of $@ assignment"
|
||||
)
|
||||
or
|
||||
// A variable of nullable type may be null
|
||||
exists(Dereference d |
|
||||
dereferenceAt(_, _, def, d) |
|
||||
d.hasNullableType() and
|
||||
not def instanceof Ssa::PseudoDefinition and
|
||||
reason = def.getSourceVariable().getAssignable() and
|
||||
msg = "because it has a nullable type"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an expression whose evaluation may be guarded by
|
||||
* a non-`null` check for the variable `var`.
|
||||
* Holds if `def1` being `null` in basic block `bb1` implies that `def2` might
|
||||
* be `null` in basic block `bb2`. The SSA definitions share the same source
|
||||
* variable.
|
||||
*/
|
||||
private Expr nullGuarded(LocalScopeVariable var) {
|
||||
exists(LogicalOrExpr guard |
|
||||
guard.getLeftOperand() = failureIsNonNullTest(var) and
|
||||
result = guard.getRightOperand())
|
||||
private predicate defNullImpliesStep(Ssa::Definition def1, BasicBlock bb1, Ssa::Definition def2, BasicBlock bb2) {
|
||||
exists(Ssa::SourceVariable v |
|
||||
defMaybeNull(v.getAnSsaDefinition(), _, _) and
|
||||
def1.getSourceVariable() = v
|
||||
|
|
||||
def2.(Ssa::PseudoDefinition).getAnInput() = def1 and
|
||||
def2.definesAt(bb2, _)
|
||||
or
|
||||
exists(LogicalAndExpr guard |
|
||||
guard.getLeftOperand() = nonNullTest(var) and
|
||||
result = guard.getRightOperand())
|
||||
or
|
||||
exists(ConditionalExpr cond |
|
||||
cond.getCondition() = nullTest(var) and
|
||||
result = cond.getElse())
|
||||
or
|
||||
exists(ConditionalExpr cond |
|
||||
cond.getCondition() = nonNullTest(var) and
|
||||
result = cond.getThen())
|
||||
or
|
||||
result = any(NullGuardedExpr nge | nge = var.getAnAccess())
|
||||
or
|
||||
result.getParent() = nullGuarded(var)
|
||||
def2 = def1 and
|
||||
not exists(Ssa::PseudoDefinition def |
|
||||
def.getSourceVariable() = v and
|
||||
def.definesAt(bb2, _)
|
||||
)
|
||||
) and
|
||||
def1.isLiveAtEndOfBlock(bb1) and
|
||||
not ensureNotNullAt(bb1, _, def1) and
|
||||
bb2 = bb1.getASuccessor() and
|
||||
not exists(SuccessorTypes::ConditionalSuccessor s, NullValue nv |
|
||||
bb1.getLastNode() = getANullCheck(def1, s, nv).getAControlFlowNode() |
|
||||
bb2 = bb1.getASuccessorByType(s) and
|
||||
not nv.isNull()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a variable access that must be non-`null` to avoid a
|
||||
* `NullReferenceException`.
|
||||
* The transitive closure of `defNullImpliesStep()` originating from `defMaybeNull()`.
|
||||
* That is, those basic blocks for which the SSA definition is suspected of being `null`.
|
||||
*/
|
||||
private predicate dereferenced(LocalScopeVariableAccess access) {
|
||||
exists(nonNullAccess(access))
|
||||
private predicate defMaybeNullInBlock(Ssa::Definition def, Ssa::SourceVariable v, BasicBlock bb) {
|
||||
defMaybeNull(def, _, _) and
|
||||
def.definesAt(bb, _) and
|
||||
v = def.getSourceVariable()
|
||||
or
|
||||
exists(BasicBlock mid, Ssa::Definition midDef |
|
||||
defMaybeNullInBlock(midDef, v, mid) |
|
||||
defNullImpliesStep(midDef, mid, def, bb)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a dereferenced access to the variable `var` that
|
||||
*
|
||||
* - does not occur within a `null`-guarded expression, but
|
||||
* - occurs within an expression where the variable may be `null`.
|
||||
* Holds if `v` is a source variable that might reach a potential `null`
|
||||
* dereference.
|
||||
*/
|
||||
LocalScopeVariableAccess unguardedMaybeNullDereference(LocalScopeVariable var) {
|
||||
var.getAnAccess() = result and
|
||||
maybeNullNode(var).getElement() = result and
|
||||
dereferenced(result) and
|
||||
not result = nullGuarded(var)
|
||||
private predicate nullDerefCandidateVariable(Ssa::SourceVariable v) {
|
||||
exists(Ssa::Definition def, BasicBlock bb |
|
||||
potentialNullDereferenceAt(bb, _, def, _) |
|
||||
defMaybeNullInBlock(def, v, bb)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate defMaybeNullInBlockOrigin(Ssa::Definition origin, Ssa::Definition def, BasicBlock bb) {
|
||||
nullDerefCandidateVariable(def.getSourceVariable()) and
|
||||
defMaybeNull(def, _, _) and
|
||||
def.definesAt(bb, _) and
|
||||
origin = def
|
||||
or
|
||||
exists(BasicBlock mid, Ssa::Definition midDef |
|
||||
defMaybeNullInBlockOrigin(origin, midDef, mid) and
|
||||
defNullImpliesStep(midDef, mid, def, bb)
|
||||
)
|
||||
}
|
||||
|
||||
private Ssa::Definition getAPseudoInput(Ssa::Definition def) {
|
||||
result = def.(Ssa::PseudoDefinition).getAnInput()
|
||||
}
|
||||
|
||||
// `def.getAnUltimateDefinition()` includes inputs into uncertain
|
||||
// definitions, but we only want inputs into pseudo nodes
|
||||
private Ssa::Definition getAnUltimateDefinition(Ssa::Definition def) {
|
||||
result = getAPseudoInput*(def) and
|
||||
not result instanceof Ssa::PseudoDefinition
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a dereferenced access to the variable `var` that
|
||||
*
|
||||
* - does not occur within a `null`-guarded expression, but
|
||||
* - occurs within an expression where the variable may be `null`, and
|
||||
* - does not occur within an expression where the variable may be non-`null`.
|
||||
* Holds if SSA definition `def` can reach a read `ar`, without passing
|
||||
* through an intermediate dereference that always (`always = true`) or
|
||||
* maybe (`always = false`) throws a null reference exception.
|
||||
*/
|
||||
LocalScopeVariableAccess unguardedNullDereference(LocalScopeVariable var) {
|
||||
unguardedMaybeNullDereference(var) = result and
|
||||
not maybeNonNullNode(var).getElement() = result
|
||||
private predicate defReaches(Ssa::Definition def, AssignableRead ar, boolean always) {
|
||||
ar = def.getAFirstRead() and
|
||||
(always = true or always = false)
|
||||
or
|
||||
exists(AssignableRead mid |
|
||||
defReaches(def, mid, always) |
|
||||
ar = mid.getANextRead() and
|
||||
not mid = any(Dereference d |
|
||||
if always = true then d.isAlwaysNull(def.getSourceVariable()) else d.isMaybeNull(def, _, _)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression that dereferences a value. That is, an expression that may
|
||||
* result in a `NullReferenceException` if the value is `null`.
|
||||
*/
|
||||
class Dereference extends G::DereferenceableExpr {
|
||||
Dereference() {
|
||||
if this.hasNullableType() then (
|
||||
// Strictly speaking, these throw `InvalidOperationException`s and not
|
||||
// `NullReferenceException`s
|
||||
this = any(PropertyAccess pa | pa.getTarget().hasName("Value")).getQualifier()
|
||||
or
|
||||
exists(Type underlyingType |
|
||||
this = any(CastExpr ce | ce.getTargetType() = underlyingType).getExpr() |
|
||||
underlyingType = this.getType().(NullableType).getUnderlyingType()
|
||||
or
|
||||
underlyingType = this.getType() and
|
||||
not underlyingType instanceof NullableType
|
||||
)
|
||||
)
|
||||
else (
|
||||
this = any(QualifiableExpr qe | not qe.isConditional()).getQualifier() and
|
||||
not this instanceof ThisAccess and
|
||||
not this instanceof BaseAccess and
|
||||
not this instanceof TypeAccess
|
||||
or
|
||||
this = any(LockStmt stmt).getExpr()
|
||||
or
|
||||
this = any(ForeachStmt stmt).getIterableExpr()
|
||||
or
|
||||
exists(ExtensionMethodCall emc, Parameter p |
|
||||
this = emc.getArgumentForParameter(p) and
|
||||
p.hasExtensionMethodModifier() and
|
||||
not emc.isConditional() |
|
||||
p.fromSource() // assume all non-source extension methods perform a dereference
|
||||
implies
|
||||
exists(Ssa::ExplicitDefinition def, AssignableDefinitions::ImplicitParameterDefinition pdef |
|
||||
pdef = def.getADefinition() |
|
||||
p.getSourceDeclaration() = pdef.getParameter() and
|
||||
def.getARead() instanceof Dereference
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isAlwaysNull0(Ssa::Definition def) {
|
||||
forall(Ssa::Definition input |
|
||||
input = getAnUltimateDefinition(def) |
|
||||
input.(Ssa::ExplicitDefinition).getADefinition().getSource() instanceof AlwaysNullExpr
|
||||
) and
|
||||
not nonNullDef(def) and
|
||||
this = def.getARead() and
|
||||
not this instanceof G::NullGuardedExpr
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this expression dereferences SSA source variable `v`, which is
|
||||
* always `null`.
|
||||
*/
|
||||
predicate isAlwaysNull(Ssa::SourceVariable v) {
|
||||
this = v.getAnAccess() and
|
||||
// Exclude fields, properties, and captured variables, as they may not have an
|
||||
// accurate SSA representation
|
||||
v.getAssignable() = any(LocalScopeVariable lsv |
|
||||
strictcount(Callable c |
|
||||
c = any(AssignableDefinition ad | ad.getTarget() = lsv).getEnclosingCallable()
|
||||
) = 1
|
||||
) and
|
||||
(
|
||||
forex(Ssa::Definition def0 |
|
||||
this = def0.getARead() |
|
||||
this.isAlwaysNull0(def0)
|
||||
)
|
||||
or
|
||||
exists(NullValue nv |
|
||||
this.(G::GuardedExpr).mustHaveValue(nv) and
|
||||
nv.isNull()
|
||||
)
|
||||
) and
|
||||
not this instanceof G::NullGuardedExpr
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this expression dereferences SSA source variable `v`, which is
|
||||
* always `null`, and this expression can be reached from an SSA definition
|
||||
* for `v` without passing through another such dereference.
|
||||
*/
|
||||
predicate isFirstAlwaysNull(Ssa::SourceVariable v) {
|
||||
this.isAlwaysNull(v) and
|
||||
defReaches(v.getAnSsaDefinition(), this, true)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate nullDerefCandidate(Ssa::Definition origin) {
|
||||
exists(Ssa::Definition ssa, BasicBlock bb |
|
||||
potentialNullDereferenceAt(bb, _, ssa, this) |
|
||||
defMaybeNullInBlockOrigin(origin, ssa, bb)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this expression dereferences SSA definition `def`, which may
|
||||
* be `null`.
|
||||
*/
|
||||
predicate isMaybeNull(Ssa::Definition def, string msg, Element reason) {
|
||||
exists(Ssa::Definition origin, BasicBlock bb |
|
||||
this.nullDerefCandidate(origin) and
|
||||
defMaybeNull(origin, msg, reason) and
|
||||
potentialNullDereferenceAt(bb, _, def, this)
|
||||
) and
|
||||
not this.isAlwaysNull(def.getSourceVariable())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this expression dereferences SSA definition `def`, which may
|
||||
* be `null`, and this expression can be reached from `def` without passing
|
||||
* through another such dereference.
|
||||
*/
|
||||
predicate isFirstMaybeNull(Ssa::Definition def, string msg, Element reason) {
|
||||
this.isMaybeNull(def, msg, reason) and
|
||||
defReaches(def, this, false)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -422,9 +422,18 @@ module Ssa {
|
|||
* Gets an SSA definition that has this variable as its underlying
|
||||
* source variable.
|
||||
*/
|
||||
deprecated
|
||||
Definition getAnDefinition() {
|
||||
result.getSourceVariable() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an SSA definition that has this variable as its underlying
|
||||
* source variable.
|
||||
*/
|
||||
Definition getAnSsaDefinition() {
|
||||
result.getSourceVariable() = this
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides different types of `SourceVariable`s. */
|
||||
|
@ -1113,7 +1122,8 @@ module Ssa {
|
|||
call = succ |
|
||||
callable = call.getTarget() or
|
||||
callable = call.getTarget().(Method).getAnOverrider+() or
|
||||
callable = call.getTarget().(Method).getAnUltimateImplementor()
|
||||
callable = call.getTarget().(Method).getAnUltimateImplementor() or
|
||||
callable = getARuntimeDelegateTarget(call)
|
||||
)
|
||||
or
|
||||
pred = succ.(DelegateCreation).getArgument()
|
||||
|
|
|
@ -3,12 +3,16 @@
|
|||
| Assert.cs:39:27:39:27 | access to local variable s | Assert.cs:38:23:38:31 | ... != ... | Assert.cs:38:23:38:23 | access to local variable s | true |
|
||||
| Assert.cs:46:27:46:27 | access to local variable s | Assert.cs:45:24:45:32 | ... != ... | Assert.cs:45:24:45:24 | access to local variable s | false |
|
||||
| Assert.cs:53:27:53:27 | access to local variable s | Assert.cs:52:24:52:32 | ... == ... | Assert.cs:52:24:52:24 | access to local variable s | false |
|
||||
| Assert.cs:59:36:59:36 | access to parameter b | Assert.cs:58:20:58:20 | access to parameter b | Assert.cs:58:20:58:20 | access to parameter b | false |
|
||||
| Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:59:23:59:31 | ... != ... | Assert.cs:59:23:59:23 | access to local variable s | true |
|
||||
| Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:59:23:59:36 | ... && ... | Assert.cs:59:23:59:23 | access to local variable s | true |
|
||||
| Assert.cs:66:37:66:37 | access to parameter b | Assert.cs:65:20:65:20 | access to parameter b | Assert.cs:65:20:65:20 | access to parameter b | false |
|
||||
| Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:66:24:66:32 | ... == ... | Assert.cs:66:24:66:24 | access to local variable s | false |
|
||||
| Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:66:24:66:37 | ... \|\| ... | Assert.cs:66:24:66:24 | access to local variable s | false |
|
||||
| Assert.cs:73:36:73:36 | access to parameter b | Assert.cs:72:20:72:20 | access to parameter b | Assert.cs:72:20:72:20 | access to parameter b | true |
|
||||
| Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:31 | ... == ... | Assert.cs:73:23:73:23 | access to local variable s | true |
|
||||
| Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:36 | ... && ... | Assert.cs:73:23:73:23 | access to local variable s | true |
|
||||
| Assert.cs:80:37:80:37 | access to parameter b | Assert.cs:79:20:79:20 | access to parameter b | Assert.cs:79:20:79:20 | access to parameter b | true |
|
||||
| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:32 | ... != ... | Assert.cs:80:24:80:24 | access to local variable s | false |
|
||||
| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:37 | ... \|\| ... | Assert.cs:80:24:80:24 | access to local variable s | false |
|
||||
| Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:24 | ... == ... | Guards.cs:10:16:10:16 | access to parameter s | false |
|
||||
|
|
|
@ -10,18 +10,22 @@
|
|||
| Assert.cs:46:27:46:27 | access to local variable s | Assert.cs:45:24:45:32 | ... != ... | Assert.cs:45:24:45:24 | access to local variable s | false |
|
||||
| Assert.cs:53:27:53:27 | access to local variable s | Assert.cs:52:24:52:24 | access to local variable s | Assert.cs:52:24:52:24 | access to local variable s | non-null |
|
||||
| Assert.cs:53:27:53:27 | access to local variable s | Assert.cs:52:24:52:32 | ... == ... | Assert.cs:52:24:52:24 | access to local variable s | false |
|
||||
| Assert.cs:59:36:59:36 | access to parameter b | Assert.cs:58:20:58:20 | access to parameter b | Assert.cs:58:20:58:20 | access to parameter b | false |
|
||||
| Assert.cs:59:36:59:36 | access to parameter b | Assert.cs:58:20:58:32 | ... ? ... : ... | Assert.cs:58:20:58:20 | access to parameter b | non-null |
|
||||
| Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:59:23:59:23 | access to local variable s | Assert.cs:59:23:59:23 | access to local variable s | non-null |
|
||||
| Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:59:23:59:31 | ... != ... | Assert.cs:59:23:59:23 | access to local variable s | true |
|
||||
| Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:59:23:59:36 | ... && ... | Assert.cs:59:23:59:23 | access to local variable s | true |
|
||||
| Assert.cs:66:37:66:37 | access to parameter b | Assert.cs:65:20:65:20 | access to parameter b | Assert.cs:65:20:65:20 | access to parameter b | false |
|
||||
| Assert.cs:66:37:66:37 | access to parameter b | Assert.cs:65:20:65:32 | ... ? ... : ... | Assert.cs:65:20:65:20 | access to parameter b | non-null |
|
||||
| Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:66:24:66:24 | access to local variable s | Assert.cs:66:24:66:24 | access to local variable s | non-null |
|
||||
| Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:66:24:66:32 | ... == ... | Assert.cs:66:24:66:24 | access to local variable s | false |
|
||||
| Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:66:24:66:37 | ... \|\| ... | Assert.cs:66:24:66:24 | access to local variable s | false |
|
||||
| Assert.cs:73:36:73:36 | access to parameter b | Assert.cs:72:20:72:20 | access to parameter b | Assert.cs:72:20:72:20 | access to parameter b | true |
|
||||
| Assert.cs:73:36:73:36 | access to parameter b | Assert.cs:72:20:72:32 | ... ? ... : ... | Assert.cs:72:20:72:20 | access to parameter b | null |
|
||||
| Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:23 | access to local variable s | Assert.cs:73:23:73:23 | access to local variable s | null |
|
||||
| Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:31 | ... == ... | Assert.cs:73:23:73:23 | access to local variable s | true |
|
||||
| Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:36 | ... && ... | Assert.cs:73:23:73:23 | access to local variable s | true |
|
||||
| Assert.cs:80:37:80:37 | access to parameter b | Assert.cs:79:20:79:20 | access to parameter b | Assert.cs:79:20:79:20 | access to parameter b | true |
|
||||
| Assert.cs:80:37:80:37 | access to parameter b | Assert.cs:79:20:79:32 | ... ? ... : ... | Assert.cs:79:20:79:20 | access to parameter b | null |
|
||||
| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:24 | access to local variable s | Assert.cs:80:24:80:24 | access to local variable s | null |
|
||||
| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:32 | ... != ... | Assert.cs:80:24:80:24 | access to local variable s | false |
|
||||
|
@ -126,6 +130,7 @@
|
|||
| Guards.cs:132:16:132:16 | access to parameter s | Guards.cs:130:13:130:21 | ... is ... | Guards.cs:130:13:130:13 | access to parameter s | false |
|
||||
| Guards.cs:138:20:138:20 | access to parameter s | Guards.cs:137:13:137:13 | access to parameter s | Guards.cs:137:13:137:13 | access to parameter s | non-null |
|
||||
| Guards.cs:138:20:138:20 | access to parameter s | Guards.cs:137:13:137:23 | ... is ... | Guards.cs:137:13:137:13 | access to parameter s | true |
|
||||
| Guards.cs:139:16:139:16 | access to parameter s | Guards.cs:137:13:137:13 | access to parameter s | Guards.cs:137:13:137:13 | access to parameter s | null |
|
||||
| Guards.cs:139:16:139:16 | access to parameter s | Guards.cs:137:13:137:23 | ... is ... | Guards.cs:137:13:137:13 | access to parameter s | false |
|
||||
| Guards.cs:146:16:146:16 | access to parameter o | Guards.cs:144:13:144:25 | ... is ... | Guards.cs:144:13:144:13 | access to parameter o | false |
|
||||
| Guards.cs:154:24:154:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | match case Action<Object>: |
|
||||
|
|
|
@ -209,4 +209,57 @@ public class Guards
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void M18(bool b1)
|
||||
{
|
||||
var b2 = true;
|
||||
if (b1)
|
||||
b2 = false;
|
||||
switch (b2)
|
||||
{
|
||||
case true :
|
||||
return;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void M19(bool b1)
|
||||
{
|
||||
var b2 = false;
|
||||
if (b1)
|
||||
b2 = true;
|
||||
switch (b2)
|
||||
{
|
||||
case true :
|
||||
return;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void M20(bool b)
|
||||
{
|
||||
var i = 0;
|
||||
if (b)
|
||||
i = 1;
|
||||
switch (i)
|
||||
{
|
||||
case 1 :
|
||||
return;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
enum E { A, B, C }
|
||||
void M21(bool b)
|
||||
{
|
||||
var e = E.A;
|
||||
if (b)
|
||||
e = E.B;
|
||||
switch (e)
|
||||
{
|
||||
case E.B :
|
||||
return;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,68 +1,152 @@
|
|||
| Assert.cs:9:16:9:32 | String s = ... | non-null | Assert.cs:9:16:9:16 | access to local variable s | non-null |
|
||||
| Assert.cs:9:16:9:32 | String s = ... | null | Assert.cs:9:16:9:16 | access to local variable s | null |
|
||||
| Assert.cs:9:20:9:32 | ... ? ... : ... | non-null | Assert.cs:9:20:9:20 | access to parameter b | false |
|
||||
| Assert.cs:9:20:9:32 | ... ? ... : ... | non-null | Assert.cs:9:31:9:32 | "" | non-null |
|
||||
| Assert.cs:9:20:9:32 | ... ? ... : ... | null | Assert.cs:9:20:9:20 | access to parameter b | true |
|
||||
| Assert.cs:9:20:9:32 | ... ? ... : ... | null | Assert.cs:9:24:9:27 | null | null |
|
||||
| Assert.cs:10:22:10:22 | access to local variable s | non-null | Assert.cs:9:20:9:32 | ... ? ... : ... | non-null |
|
||||
| Assert.cs:10:22:10:22 | access to local variable s | null | Assert.cs:9:20:9:32 | ... ? ... : ... | null |
|
||||
| Assert.cs:10:22:10:30 | ... != ... | false | Assert.cs:9:20:9:20 | access to parameter b | true |
|
||||
| Assert.cs:10:22:10:30 | ... != ... | false | Assert.cs:10:22:10:22 | access to local variable s | null |
|
||||
| Assert.cs:10:22:10:30 | ... != ... | true | Assert.cs:9:20:9:20 | access to parameter b | false |
|
||||
| Assert.cs:10:22:10:30 | ... != ... | true | Assert.cs:10:22:10:22 | access to local variable s | non-null |
|
||||
| Assert.cs:11:27:11:27 | access to local variable s | non-null | Assert.cs:9:20:9:32 | ... ? ... : ... | non-null |
|
||||
| Assert.cs:11:27:11:27 | access to local variable s | null | Assert.cs:9:20:9:32 | ... ? ... : ... | null |
|
||||
| Assert.cs:16:16:16:32 | String s = ... | non-null | Assert.cs:16:16:16:16 | access to local variable s | non-null |
|
||||
| Assert.cs:16:16:16:32 | String s = ... | null | Assert.cs:16:16:16:16 | access to local variable s | null |
|
||||
| Assert.cs:16:20:16:32 | ... ? ... : ... | non-null | Assert.cs:16:20:16:20 | access to parameter b | false |
|
||||
| Assert.cs:16:20:16:32 | ... ? ... : ... | non-null | Assert.cs:16:31:16:32 | "" | non-null |
|
||||
| Assert.cs:16:20:16:32 | ... ? ... : ... | null | Assert.cs:16:20:16:20 | access to parameter b | true |
|
||||
| Assert.cs:16:20:16:32 | ... ? ... : ... | null | Assert.cs:16:24:16:27 | null | null |
|
||||
| Assert.cs:17:23:17:23 | access to local variable s | non-null | Assert.cs:16:20:16:32 | ... ? ... : ... | non-null |
|
||||
| Assert.cs:17:23:17:23 | access to local variable s | null | Assert.cs:16:20:16:32 | ... ? ... : ... | null |
|
||||
| Assert.cs:18:27:18:27 | access to local variable s | non-null | Assert.cs:16:20:16:32 | ... ? ... : ... | non-null |
|
||||
| Assert.cs:18:27:18:27 | access to local variable s | null | Assert.cs:16:20:16:32 | ... ? ... : ... | null |
|
||||
| Assert.cs:23:16:23:32 | String s = ... | non-null | Assert.cs:23:16:23:16 | access to local variable s | non-null |
|
||||
| Assert.cs:23:16:23:32 | String s = ... | null | Assert.cs:23:16:23:16 | access to local variable s | null |
|
||||
| Assert.cs:23:20:23:32 | ... ? ... : ... | non-null | Assert.cs:23:20:23:20 | access to parameter b | false |
|
||||
| Assert.cs:23:20:23:32 | ... ? ... : ... | non-null | Assert.cs:23:31:23:32 | "" | non-null |
|
||||
| Assert.cs:23:20:23:32 | ... ? ... : ... | null | Assert.cs:23:20:23:20 | access to parameter b | true |
|
||||
| Assert.cs:23:20:23:32 | ... ? ... : ... | null | Assert.cs:23:24:23:27 | null | null |
|
||||
| Assert.cs:24:26:24:26 | access to local variable s | non-null | Assert.cs:23:20:23:32 | ... ? ... : ... | non-null |
|
||||
| Assert.cs:24:26:24:26 | access to local variable s | null | Assert.cs:23:20:23:32 | ... ? ... : ... | null |
|
||||
| Assert.cs:25:27:25:27 | access to local variable s | non-null | Assert.cs:23:20:23:32 | ... ? ... : ... | non-null |
|
||||
| Assert.cs:25:27:25:27 | access to local variable s | null | Assert.cs:23:20:23:32 | ... ? ... : ... | null |
|
||||
| Assert.cs:30:16:30:32 | String s = ... | non-null | Assert.cs:30:16:30:16 | access to local variable s | non-null |
|
||||
| Assert.cs:30:16:30:32 | String s = ... | null | Assert.cs:30:16:30:16 | access to local variable s | null |
|
||||
| Assert.cs:30:20:30:32 | ... ? ... : ... | non-null | Assert.cs:30:20:30:20 | access to parameter b | false |
|
||||
| Assert.cs:30:20:30:32 | ... ? ... : ... | non-null | Assert.cs:30:31:30:32 | "" | non-null |
|
||||
| Assert.cs:30:20:30:32 | ... ? ... : ... | null | Assert.cs:30:20:30:20 | access to parameter b | true |
|
||||
| Assert.cs:30:20:30:32 | ... ? ... : ... | null | Assert.cs:30:24:30:27 | null | null |
|
||||
| Assert.cs:31:23:31:23 | access to local variable s | non-null | Assert.cs:30:20:30:32 | ... ? ... : ... | non-null |
|
||||
| Assert.cs:31:23:31:23 | access to local variable s | null | Assert.cs:30:20:30:32 | ... ? ... : ... | null |
|
||||
| Assert.cs:31:23:31:31 | ... == ... | false | Assert.cs:30:20:30:20 | access to parameter b | false |
|
||||
| Assert.cs:31:23:31:31 | ... == ... | false | Assert.cs:31:23:31:23 | access to local variable s | non-null |
|
||||
| Assert.cs:31:23:31:31 | ... == ... | true | Assert.cs:30:20:30:20 | access to parameter b | true |
|
||||
| Assert.cs:31:23:31:31 | ... == ... | true | Assert.cs:31:23:31:23 | access to local variable s | null |
|
||||
| Assert.cs:32:27:32:27 | access to local variable s | non-null | Assert.cs:30:20:30:32 | ... ? ... : ... | non-null |
|
||||
| Assert.cs:32:27:32:27 | access to local variable s | null | Assert.cs:30:20:30:32 | ... ? ... : ... | null |
|
||||
| Assert.cs:37:16:37:32 | String s = ... | non-null | Assert.cs:37:16:37:16 | access to local variable s | non-null |
|
||||
| Assert.cs:37:16:37:32 | String s = ... | null | Assert.cs:37:16:37:16 | access to local variable s | null |
|
||||
| Assert.cs:37:20:37:32 | ... ? ... : ... | non-null | Assert.cs:37:20:37:20 | access to parameter b | false |
|
||||
| Assert.cs:37:20:37:32 | ... ? ... : ... | non-null | Assert.cs:37:31:37:32 | "" | non-null |
|
||||
| Assert.cs:37:20:37:32 | ... ? ... : ... | null | Assert.cs:37:20:37:20 | access to parameter b | true |
|
||||
| Assert.cs:37:20:37:32 | ... ? ... : ... | null | Assert.cs:37:24:37:27 | null | null |
|
||||
| Assert.cs:38:23:38:23 | access to local variable s | non-null | Assert.cs:37:20:37:32 | ... ? ... : ... | non-null |
|
||||
| Assert.cs:38:23:38:23 | access to local variable s | null | Assert.cs:37:20:37:32 | ... ? ... : ... | null |
|
||||
| Assert.cs:38:23:38:31 | ... != ... | false | Assert.cs:37:20:37:20 | access to parameter b | true |
|
||||
| Assert.cs:38:23:38:31 | ... != ... | false | Assert.cs:38:23:38:23 | access to local variable s | null |
|
||||
| Assert.cs:38:23:38:31 | ... != ... | true | Assert.cs:37:20:37:20 | access to parameter b | false |
|
||||
| Assert.cs:38:23:38:31 | ... != ... | true | Assert.cs:38:23:38:23 | access to local variable s | non-null |
|
||||
| Assert.cs:39:27:39:27 | access to local variable s | non-null | Assert.cs:37:20:37:32 | ... ? ... : ... | non-null |
|
||||
| Assert.cs:39:27:39:27 | access to local variable s | null | Assert.cs:37:20:37:32 | ... ? ... : ... | null |
|
||||
| Assert.cs:44:16:44:32 | String s = ... | non-null | Assert.cs:44:16:44:16 | access to local variable s | non-null |
|
||||
| Assert.cs:44:16:44:32 | String s = ... | null | Assert.cs:44:16:44:16 | access to local variable s | null |
|
||||
| Assert.cs:44:20:44:32 | ... ? ... : ... | non-null | Assert.cs:44:20:44:20 | access to parameter b | false |
|
||||
| Assert.cs:44:20:44:32 | ... ? ... : ... | non-null | Assert.cs:44:31:44:32 | "" | non-null |
|
||||
| Assert.cs:44:20:44:32 | ... ? ... : ... | null | Assert.cs:44:20:44:20 | access to parameter b | true |
|
||||
| Assert.cs:44:20:44:32 | ... ? ... : ... | null | Assert.cs:44:24:44:27 | null | null |
|
||||
| Assert.cs:45:24:45:24 | access to local variable s | non-null | Assert.cs:44:20:44:32 | ... ? ... : ... | non-null |
|
||||
| Assert.cs:45:24:45:24 | access to local variable s | null | Assert.cs:44:20:44:32 | ... ? ... : ... | null |
|
||||
| Assert.cs:45:24:45:32 | ... != ... | false | Assert.cs:44:20:44:20 | access to parameter b | true |
|
||||
| Assert.cs:45:24:45:32 | ... != ... | false | Assert.cs:45:24:45:24 | access to local variable s | null |
|
||||
| Assert.cs:45:24:45:32 | ... != ... | true | Assert.cs:44:20:44:20 | access to parameter b | false |
|
||||
| Assert.cs:45:24:45:32 | ... != ... | true | Assert.cs:45:24:45:24 | access to local variable s | non-null |
|
||||
| Assert.cs:46:27:46:27 | access to local variable s | non-null | Assert.cs:44:20:44:32 | ... ? ... : ... | non-null |
|
||||
| Assert.cs:46:27:46:27 | access to local variable s | null | Assert.cs:44:20:44:32 | ... ? ... : ... | null |
|
||||
| Assert.cs:51:16:51:32 | String s = ... | non-null | Assert.cs:51:16:51:16 | access to local variable s | non-null |
|
||||
| Assert.cs:51:16:51:32 | String s = ... | null | Assert.cs:51:16:51:16 | access to local variable s | null |
|
||||
| Assert.cs:51:20:51:32 | ... ? ... : ... | non-null | Assert.cs:51:20:51:20 | access to parameter b | false |
|
||||
| Assert.cs:51:20:51:32 | ... ? ... : ... | non-null | Assert.cs:51:31:51:32 | "" | non-null |
|
||||
| Assert.cs:51:20:51:32 | ... ? ... : ... | null | Assert.cs:51:20:51:20 | access to parameter b | true |
|
||||
| Assert.cs:51:20:51:32 | ... ? ... : ... | null | Assert.cs:51:24:51:27 | null | null |
|
||||
| Assert.cs:52:24:52:24 | access to local variable s | non-null | Assert.cs:51:20:51:32 | ... ? ... : ... | non-null |
|
||||
| Assert.cs:52:24:52:24 | access to local variable s | null | Assert.cs:51:20:51:32 | ... ? ... : ... | null |
|
||||
| Assert.cs:52:24:52:32 | ... == ... | false | Assert.cs:51:20:51:20 | access to parameter b | false |
|
||||
| Assert.cs:52:24:52:32 | ... == ... | false | Assert.cs:52:24:52:24 | access to local variable s | non-null |
|
||||
| Assert.cs:52:24:52:32 | ... == ... | true | Assert.cs:51:20:51:20 | access to parameter b | true |
|
||||
| Assert.cs:52:24:52:32 | ... == ... | true | Assert.cs:52:24:52:24 | access to local variable s | null |
|
||||
| Assert.cs:53:27:53:27 | access to local variable s | non-null | Assert.cs:51:20:51:32 | ... ? ... : ... | non-null |
|
||||
| Assert.cs:53:27:53:27 | access to local variable s | null | Assert.cs:51:20:51:32 | ... ? ... : ... | null |
|
||||
| Assert.cs:58:16:58:32 | String s = ... | non-null | Assert.cs:58:16:58:16 | access to local variable s | non-null |
|
||||
| Assert.cs:58:16:58:32 | String s = ... | null | Assert.cs:58:16:58:16 | access to local variable s | null |
|
||||
| Assert.cs:58:20:58:32 | ... ? ... : ... | non-null | Assert.cs:58:20:58:20 | access to parameter b | false |
|
||||
| Assert.cs:58:20:58:32 | ... ? ... : ... | non-null | Assert.cs:58:31:58:32 | "" | non-null |
|
||||
| Assert.cs:58:20:58:32 | ... ? ... : ... | null | Assert.cs:58:20:58:20 | access to parameter b | true |
|
||||
| Assert.cs:58:20:58:32 | ... ? ... : ... | null | Assert.cs:58:24:58:27 | null | null |
|
||||
| Assert.cs:59:23:59:23 | access to local variable s | non-null | Assert.cs:58:20:58:32 | ... ? ... : ... | non-null |
|
||||
| Assert.cs:59:23:59:23 | access to local variable s | null | Assert.cs:58:20:58:32 | ... ? ... : ... | null |
|
||||
| Assert.cs:59:23:59:31 | ... != ... | false | Assert.cs:58:20:58:20 | access to parameter b | true |
|
||||
| Assert.cs:59:23:59:31 | ... != ... | false | Assert.cs:59:23:59:23 | access to local variable s | null |
|
||||
| Assert.cs:59:23:59:31 | ... != ... | true | Assert.cs:58:20:58:20 | access to parameter b | false |
|
||||
| Assert.cs:59:23:59:31 | ... != ... | true | Assert.cs:59:23:59:23 | access to local variable s | non-null |
|
||||
| Assert.cs:59:23:59:36 | ... && ... | true | Assert.cs:59:23:59:31 | ... != ... | true |
|
||||
| Assert.cs:59:23:59:36 | ... && ... | true | Assert.cs:59:36:59:36 | access to parameter b | true |
|
||||
| Assert.cs:60:27:60:27 | access to local variable s | non-null | Assert.cs:58:20:58:32 | ... ? ... : ... | non-null |
|
||||
| Assert.cs:60:27:60:27 | access to local variable s | null | Assert.cs:58:20:58:32 | ... ? ... : ... | null |
|
||||
| Assert.cs:65:16:65:32 | String s = ... | non-null | Assert.cs:65:16:65:16 | access to local variable s | non-null |
|
||||
| Assert.cs:65:16:65:32 | String s = ... | null | Assert.cs:65:16:65:16 | access to local variable s | null |
|
||||
| Assert.cs:65:20:65:32 | ... ? ... : ... | non-null | Assert.cs:65:20:65:20 | access to parameter b | false |
|
||||
| Assert.cs:65:20:65:32 | ... ? ... : ... | non-null | Assert.cs:65:31:65:32 | "" | non-null |
|
||||
| Assert.cs:65:20:65:32 | ... ? ... : ... | null | Assert.cs:65:20:65:20 | access to parameter b | true |
|
||||
| Assert.cs:65:20:65:32 | ... ? ... : ... | null | Assert.cs:65:24:65:27 | null | null |
|
||||
| Assert.cs:66:24:66:24 | access to local variable s | non-null | Assert.cs:65:20:65:32 | ... ? ... : ... | non-null |
|
||||
| Assert.cs:66:24:66:24 | access to local variable s | null | Assert.cs:65:20:65:32 | ... ? ... : ... | null |
|
||||
| Assert.cs:66:24:66:32 | ... == ... | false | Assert.cs:65:20:65:20 | access to parameter b | false |
|
||||
| Assert.cs:66:24:66:32 | ... == ... | false | Assert.cs:66:24:66:24 | access to local variable s | non-null |
|
||||
| Assert.cs:66:24:66:32 | ... == ... | true | Assert.cs:65:20:65:20 | access to parameter b | true |
|
||||
| Assert.cs:66:24:66:32 | ... == ... | true | Assert.cs:66:24:66:24 | access to local variable s | null |
|
||||
| Assert.cs:66:24:66:37 | ... \|\| ... | false | Assert.cs:66:24:66:32 | ... == ... | false |
|
||||
| Assert.cs:66:24:66:37 | ... \|\| ... | false | Assert.cs:66:37:66:37 | access to parameter b | false |
|
||||
| Assert.cs:67:27:67:27 | access to local variable s | non-null | Assert.cs:65:20:65:32 | ... ? ... : ... | non-null |
|
||||
| Assert.cs:67:27:67:27 | access to local variable s | null | Assert.cs:65:20:65:32 | ... ? ... : ... | null |
|
||||
| Assert.cs:72:16:72:32 | String s = ... | non-null | Assert.cs:72:16:72:16 | access to local variable s | non-null |
|
||||
| Assert.cs:72:16:72:32 | String s = ... | null | Assert.cs:72:16:72:16 | access to local variable s | null |
|
||||
| Assert.cs:72:20:72:32 | ... ? ... : ... | non-null | Assert.cs:72:20:72:20 | access to parameter b | false |
|
||||
| Assert.cs:72:20:72:32 | ... ? ... : ... | non-null | Assert.cs:72:31:72:32 | "" | non-null |
|
||||
| Assert.cs:72:20:72:32 | ... ? ... : ... | null | Assert.cs:72:20:72:20 | access to parameter b | true |
|
||||
| Assert.cs:72:20:72:32 | ... ? ... : ... | null | Assert.cs:72:24:72:27 | null | null |
|
||||
| Assert.cs:73:23:73:23 | access to local variable s | non-null | Assert.cs:72:20:72:32 | ... ? ... : ... | non-null |
|
||||
| Assert.cs:73:23:73:23 | access to local variable s | null | Assert.cs:72:20:72:32 | ... ? ... : ... | null |
|
||||
| Assert.cs:73:23:73:31 | ... == ... | false | Assert.cs:72:20:72:20 | access to parameter b | false |
|
||||
| Assert.cs:73:23:73:31 | ... == ... | false | Assert.cs:73:23:73:23 | access to local variable s | non-null |
|
||||
| Assert.cs:73:23:73:31 | ... == ... | true | Assert.cs:72:20:72:20 | access to parameter b | true |
|
||||
| Assert.cs:73:23:73:31 | ... == ... | true | Assert.cs:73:23:73:23 | access to local variable s | null |
|
||||
| Assert.cs:73:23:73:36 | ... && ... | true | Assert.cs:73:23:73:31 | ... == ... | true |
|
||||
| Assert.cs:73:23:73:36 | ... && ... | true | Assert.cs:73:36:73:36 | access to parameter b | true |
|
||||
| Assert.cs:74:27:74:27 | access to local variable s | non-null | Assert.cs:72:20:72:32 | ... ? ... : ... | non-null |
|
||||
| Assert.cs:74:27:74:27 | access to local variable s | null | Assert.cs:72:20:72:32 | ... ? ... : ... | null |
|
||||
| Assert.cs:79:16:79:32 | String s = ... | non-null | Assert.cs:79:16:79:16 | access to local variable s | non-null |
|
||||
| Assert.cs:79:16:79:32 | String s = ... | null | Assert.cs:79:16:79:16 | access to local variable s | null |
|
||||
| Assert.cs:79:20:79:32 | ... ? ... : ... | non-null | Assert.cs:79:20:79:20 | access to parameter b | false |
|
||||
| Assert.cs:79:20:79:32 | ... ? ... : ... | non-null | Assert.cs:79:31:79:32 | "" | non-null |
|
||||
| Assert.cs:79:20:79:32 | ... ? ... : ... | null | Assert.cs:79:20:79:20 | access to parameter b | true |
|
||||
| Assert.cs:79:20:79:32 | ... ? ... : ... | null | Assert.cs:79:24:79:27 | null | null |
|
||||
| Assert.cs:80:24:80:24 | access to local variable s | non-null | Assert.cs:79:20:79:32 | ... ? ... : ... | non-null |
|
||||
| Assert.cs:80:24:80:24 | access to local variable s | null | Assert.cs:79:20:79:32 | ... ? ... : ... | null |
|
||||
| Assert.cs:80:24:80:32 | ... != ... | false | Assert.cs:79:20:79:20 | access to parameter b | true |
|
||||
| Assert.cs:80:24:80:32 | ... != ... | false | Assert.cs:80:24:80:24 | access to local variable s | null |
|
||||
| Assert.cs:80:24:80:32 | ... != ... | true | Assert.cs:79:20:79:20 | access to parameter b | false |
|
||||
| Assert.cs:80:24:80:32 | ... != ... | true | Assert.cs:80:24:80:24 | access to local variable s | non-null |
|
||||
| Assert.cs:80:24:80:37 | ... \|\| ... | false | Assert.cs:80:24:80:32 | ... != ... | false |
|
||||
| Assert.cs:80:24:80:37 | ... \|\| ... | false | Assert.cs:80:37:80:37 | access to parameter b | false |
|
||||
|
@ -85,12 +169,16 @@
|
|||
| Guards.cs:32:40:32:51 | !... | true | Guards.cs:32:42:32:50 | ... == ... | false |
|
||||
| Guards.cs:32:42:32:50 | ... == ... | false | Guards.cs:32:42:32:42 | access to parameter y | non-null |
|
||||
| Guards.cs:32:42:32:50 | ... == ... | true | Guards.cs:32:42:32:42 | access to parameter y | null |
|
||||
| Guards.cs:33:31:33:35 | ... + ... | non-null | Guards.cs:33:31:33:31 | access to parameter x | non-null |
|
||||
| Guards.cs:33:31:33:35 | ... + ... | non-null | Guards.cs:33:35:33:35 | access to parameter y | non-null |
|
||||
| Guards.cs:35:13:35:21 | ... == ... | false | Guards.cs:35:13:35:13 | access to parameter x | non-null |
|
||||
| Guards.cs:35:13:35:21 | ... == ... | true | Guards.cs:35:13:35:13 | access to parameter x | null |
|
||||
| Guards.cs:35:13:35:34 | ... \|\| ... | false | Guards.cs:35:13:35:21 | ... == ... | false |
|
||||
| Guards.cs:35:13:35:34 | ... \|\| ... | false | Guards.cs:35:26:35:34 | ... == ... | false |
|
||||
| Guards.cs:35:26:35:34 | ... == ... | false | Guards.cs:35:26:35:26 | access to parameter y | non-null |
|
||||
| Guards.cs:35:26:35:34 | ... == ... | true | Guards.cs:35:26:35:26 | access to parameter y | null |
|
||||
| Guards.cs:36:32:36:36 | ... + ... | non-null | Guards.cs:36:32:36:32 | access to parameter x | non-null |
|
||||
| Guards.cs:36:32:36:36 | ... + ... | non-null | Guards.cs:36:36:36:36 | access to parameter y | non-null |
|
||||
| Guards.cs:38:13:38:37 | !... | false | Guards.cs:38:15:38:36 | ... \|\| ... | true |
|
||||
| Guards.cs:38:13:38:37 | !... | true | Guards.cs:38:15:38:36 | ... \|\| ... | false |
|
||||
| Guards.cs:38:15:38:23 | ... == ... | false | Guards.cs:38:15:38:15 | access to parameter x | non-null |
|
||||
|
@ -99,6 +187,8 @@
|
|||
| Guards.cs:38:15:38:36 | ... \|\| ... | false | Guards.cs:38:28:38:36 | ... == ... | false |
|
||||
| Guards.cs:38:28:38:36 | ... == ... | false | Guards.cs:38:28:38:28 | access to parameter y | non-null |
|
||||
| Guards.cs:38:28:38:36 | ... == ... | true | Guards.cs:38:28:38:28 | access to parameter y | null |
|
||||
| Guards.cs:39:31:39:35 | ... + ... | non-null | Guards.cs:39:31:39:31 | access to parameter x | non-null |
|
||||
| Guards.cs:39:31:39:35 | ... + ... | non-null | Guards.cs:39:35:39:35 | access to parameter y | non-null |
|
||||
| Guards.cs:41:13:41:39 | !... | false | Guards.cs:41:14:41:39 | !... | true |
|
||||
| Guards.cs:41:13:41:39 | !... | true | Guards.cs:41:14:41:39 | !... | false |
|
||||
| Guards.cs:41:14:41:39 | !... | false | Guards.cs:41:15:41:39 | !... | true |
|
||||
|
@ -111,6 +201,8 @@
|
|||
| Guards.cs:41:17:41:38 | ... && ... | true | Guards.cs:41:30:41:38 | ... != ... | true |
|
||||
| Guards.cs:41:30:41:38 | ... != ... | false | Guards.cs:41:30:41:30 | access to parameter y | null |
|
||||
| Guards.cs:41:30:41:38 | ... != ... | true | Guards.cs:41:30:41:30 | access to parameter y | non-null |
|
||||
| Guards.cs:42:32:42:36 | ... + ... | non-null | Guards.cs:42:32:42:32 | access to parameter x | non-null |
|
||||
| Guards.cs:42:32:42:36 | ... + ... | non-null | Guards.cs:42:36:42:36 | access to parameter y | non-null |
|
||||
| Guards.cs:44:13:44:25 | ... != ... | false | Guards.cs:44:13:44:17 | access to field Field | null |
|
||||
| Guards.cs:44:13:44:25 | ... != ... | true | Guards.cs:44:13:44:17 | access to field Field | non-null |
|
||||
| Guards.cs:47:13:47:25 | ... != ... | false | Guards.cs:47:13:47:17 | access to field Field | null |
|
||||
|
@ -121,6 +213,10 @@
|
|||
| Guards.cs:60:13:60:45 | ... == ... | true | Guards.cs:60:13:60:37 | access to field Field | null |
|
||||
| Guards.cs:68:16:68:24 | ... != ... | false | Guards.cs:68:16:68:16 | access to parameter s | null |
|
||||
| Guards.cs:68:16:68:24 | ... != ... | true | Guards.cs:68:16:68:16 | access to parameter s | non-null |
|
||||
| Guards.cs:71:13:71:20 | ... = ... | non-null | Guards.cs:71:13:71:13 | access to parameter s | non-null |
|
||||
| Guards.cs:71:13:71:20 | ... = ... | non-null | Guards.cs:71:17:71:20 | null | non-null |
|
||||
| Guards.cs:71:13:71:20 | ... = ... | null | Guards.cs:71:13:71:13 | access to parameter s | null |
|
||||
| Guards.cs:71:13:71:20 | ... = ... | null | Guards.cs:71:17:71:20 | null | null |
|
||||
| Guards.cs:72:31:72:31 | access to parameter s | non-null | Guards.cs:71:17:71:20 | null | non-null |
|
||||
| Guards.cs:72:31:72:31 | access to parameter s | null | Guards.cs:71:17:71:20 | null | null |
|
||||
| Guards.cs:78:13:78:26 | ... == ... | true | Guards.cs:78:15:78:21 | access to property Length | non-null |
|
||||
|
@ -143,6 +239,7 @@
|
|||
| Guards.cs:88:15:88:21 | access to property Length | non-null | Guards.cs:88:13:88:13 | access to parameter s | non-null |
|
||||
| Guards.cs:88:15:88:21 | access to property Length | null | Guards.cs:88:13:88:13 | access to parameter s | null |
|
||||
| Guards.cs:92:13:92:25 | ... - ... | non-null | Guards.cs:92:15:92:21 | access to property Length | non-null |
|
||||
| Guards.cs:92:13:92:25 | ... - ... | non-null | Guards.cs:92:25:92:25 | (...) ... | non-null |
|
||||
| Guards.cs:92:13:92:25 | ... - ... | null | Guards.cs:92:15:92:21 | access to property Length | null |
|
||||
| Guards.cs:92:13:92:30 | ... != ... | false | Guards.cs:92:13:92:25 | ... - ... | non-null |
|
||||
| Guards.cs:92:15:92:21 | access to property Length | non-null | Guards.cs:92:13:92:13 | access to parameter s | non-null |
|
||||
|
@ -150,10 +247,29 @@
|
|||
| Guards.cs:96:13:96:19 | ... == ... | true | Guards.cs:96:13:96:13 | access to parameter s | non-null |
|
||||
| Guards.cs:104:13:104:45 | ... == ... | false | Guards.cs:104:13:104:37 | access to field Field | non-null |
|
||||
| Guards.cs:104:13:104:45 | ... == ... | true | Guards.cs:104:13:104:37 | access to field Field | null |
|
||||
| Guards.cs:106:9:106:25 | ... = ... | non-null | Guards.cs:106:9:106:18 | access to property Property | non-null |
|
||||
| Guards.cs:106:9:106:25 | ... = ... | non-null | Guards.cs:106:22:106:25 | null | non-null |
|
||||
| Guards.cs:106:9:106:25 | ... = ... | null | Guards.cs:106:9:106:18 | access to property Property | null |
|
||||
| Guards.cs:106:9:106:25 | ... = ... | null | Guards.cs:106:22:106:25 | null | null |
|
||||
| Guards.cs:113:13:114:38 | String dummy = ... | non-null | Guards.cs:113:13:113:17 | access to local variable dummy | non-null |
|
||||
| Guards.cs:113:13:114:38 | String dummy = ... | null | Guards.cs:113:13:113:17 | access to local variable dummy | null |
|
||||
| Guards.cs:115:9:115:55 | ... = ... | non-null | Guards.cs:115:9:115:13 | access to local variable dummy | non-null |
|
||||
| Guards.cs:115:9:115:55 | ... = ... | non-null | Guards.cs:115:17:115:55 | ... ?? ... | non-null |
|
||||
| Guards.cs:115:9:115:55 | ... = ... | null | Guards.cs:115:9:115:13 | access to local variable dummy | null |
|
||||
| Guards.cs:115:9:115:55 | ... = ... | null | Guards.cs:115:17:115:55 | ... ?? ... | null |
|
||||
| Guards.cs:117:9:117:25 | ... = ... | non-null | Guards.cs:117:9:117:18 | access to property Property | non-null |
|
||||
| Guards.cs:117:9:117:25 | ... = ... | non-null | Guards.cs:117:22:117:25 | null | non-null |
|
||||
| Guards.cs:117:9:117:25 | ... = ... | null | Guards.cs:117:9:117:18 | access to property Property | null |
|
||||
| Guards.cs:117:9:117:25 | ... = ... | null | Guards.cs:117:22:117:25 | null | null |
|
||||
| Guards.cs:124:13:124:30 | Boolean b1 = ... | false | Guards.cs:124:13:124:14 | access to local variable b1 | false |
|
||||
| Guards.cs:124:13:124:30 | Boolean b1 = ... | true | Guards.cs:124:13:124:14 | access to local variable b1 | true |
|
||||
| Guards.cs:125:13:125:31 | Nullable<Boolean> b2 = ... | non-null | Guards.cs:125:13:125:14 | access to local variable b2 | non-null |
|
||||
| Guards.cs:125:13:125:31 | Nullable<Boolean> b2 = ... | null | Guards.cs:125:13:125:14 | access to local variable b2 | null |
|
||||
| Guards.cs:125:21:125:31 | call to method Equals | non-null | Guards.cs:125:18:125:19 | access to parameter s1 | non-null |
|
||||
| Guards.cs:125:21:125:31 | call to method Equals | null | Guards.cs:125:18:125:19 | access to parameter s1 | null |
|
||||
| Guards.cs:130:13:130:21 | ... is ... | false | Guards.cs:130:13:130:13 | access to parameter s | non-null |
|
||||
| Guards.cs:130:13:130:21 | ... is ... | true | Guards.cs:130:13:130:13 | access to parameter s | null |
|
||||
| Guards.cs:137:13:137:23 | ... is ... | false | Guards.cs:137:13:137:13 | access to parameter s | null |
|
||||
| Guards.cs:137:13:137:23 | ... is ... | true | Guards.cs:137:13:137:13 | access to parameter s | non-null |
|
||||
| Guards.cs:144:13:144:25 | ... is ... | true | Guards.cs:144:13:144:13 | access to parameter o | non-null |
|
||||
| Guards.cs:145:20:145:20 | access to local variable s | non-null | Guards.cs:144:13:144:13 | access to parameter o | non-null |
|
||||
|
@ -202,6 +318,25 @@
|
|||
| Guards.cs:197:13:197:29 | !... | true | Guards.cs:197:14:197:29 | call to method NullTestWrong | false |
|
||||
| Guards.cs:203:13:203:21 | ... != ... | false | Guards.cs:203:13:203:13 | access to parameter o | null |
|
||||
| Guards.cs:203:13:203:21 | ... != ... | true | Guards.cs:203:13:203:13 | access to parameter o | non-null |
|
||||
| Guards.cs:215:13:215:21 | Boolean b2 = ... | false | Guards.cs:215:13:215:14 | access to local variable b2 | false |
|
||||
| Guards.cs:215:13:215:21 | Boolean b2 = ... | true | Guards.cs:215:13:215:14 | access to local variable b2 | true |
|
||||
| Guards.cs:217:13:217:22 | ... = ... | false | Guards.cs:217:13:217:14 | access to local variable b2 | false |
|
||||
| Guards.cs:217:13:217:22 | ... = ... | true | Guards.cs:217:13:217:14 | access to local variable b2 | true |
|
||||
| Guards.cs:218:17:218:18 | access to local variable b2 | match case ...: | Guards.cs:216:13:216:14 | access to parameter b1 | false |
|
||||
| Guards.cs:218:17:218:18 | access to local variable b2 | match case ...: | Guards.cs:218:17:218:18 | access to local variable b2 | true |
|
||||
| Guards.cs:228:13:228:22 | Boolean b2 = ... | false | Guards.cs:228:13:228:14 | access to local variable b2 | false |
|
||||
| Guards.cs:228:13:228:22 | Boolean b2 = ... | true | Guards.cs:228:13:228:14 | access to local variable b2 | true |
|
||||
| Guards.cs:230:13:230:21 | ... = ... | false | Guards.cs:230:13:230:14 | access to local variable b2 | false |
|
||||
| Guards.cs:230:13:230:21 | ... = ... | true | Guards.cs:230:13:230:14 | access to local variable b2 | true |
|
||||
| Guards.cs:231:17:231:18 | access to local variable b2 | match case ...: | Guards.cs:229:13:229:14 | access to parameter b1 | true |
|
||||
| Guards.cs:231:17:231:18 | access to local variable b2 | match case ...: | Guards.cs:231:17:231:18 | access to local variable b2 | true |
|
||||
| Guards.cs:231:17:231:18 | access to local variable b2 | non-match case ...: | Guards.cs:229:13:229:14 | access to parameter b1 | false |
|
||||
| Guards.cs:244:17:244:17 | access to local variable i | match case ...: | Guards.cs:242:13:242:13 | access to parameter b | true |
|
||||
| Guards.cs:244:17:244:17 | access to local variable i | match case ...: | Guards.cs:244:17:244:17 | access to local variable i | 1 |
|
||||
| Guards.cs:244:17:244:17 | access to local variable i | non-match case ...: | Guards.cs:242:13:242:13 | access to parameter b | false |
|
||||
| Guards.cs:258:17:258:17 | access to local variable e | match case ...: | Guards.cs:256:13:256:13 | access to parameter b | true |
|
||||
| Guards.cs:258:17:258:17 | access to local variable e | match case ...: | Guards.cs:258:17:258:17 | access to local variable e | 1 |
|
||||
| Guards.cs:258:17:258:17 | access to local variable e | non-match case ...: | Guards.cs:256:13:256:13 | access to parameter b | false |
|
||||
| Splitting.cs:12:17:12:25 | ... != ... | false | Splitting.cs:12:17:12:17 | access to parameter o | null |
|
||||
| Splitting.cs:12:17:12:25 | ... != ... | true | Splitting.cs:12:17:12:17 | access to parameter o | non-null |
|
||||
| Splitting.cs:22:17:22:25 | ... != ... | false | Splitting.cs:22:17:22:17 | access to parameter o | null |
|
||||
|
@ -224,7 +359,13 @@
|
|||
| Splitting.cs:105:22:105:30 | ... != ... | true | Splitting.cs:105:22:105:22 | access to parameter o | non-null |
|
||||
| Splitting.cs:116:22:116:30 | ... != ... | false | Splitting.cs:116:22:116:22 | access to parameter o | null |
|
||||
| Splitting.cs:116:22:116:30 | ... != ... | true | Splitting.cs:116:22:116:22 | access to parameter o | non-null |
|
||||
| Splitting.cs:125:16:125:23 | Object o = ... | non-null | Splitting.cs:125:16:125:16 | access to local variable o | non-null |
|
||||
| Splitting.cs:125:16:125:23 | Object o = ... | null | Splitting.cs:125:16:125:16 | access to local variable o | null |
|
||||
| Splitting.cs:128:17:128:25 | ... != ... | false | Splitting.cs:128:17:128:17 | access to local variable o | null |
|
||||
| Splitting.cs:128:17:128:25 | ... != ... | true | Splitting.cs:128:17:128:17 | access to local variable o | non-null |
|
||||
| Splitting.cs:132:17:132:29 | ... = ... | non-null | Splitting.cs:132:17:132:17 | access to local variable o | non-null |
|
||||
| Splitting.cs:132:17:132:29 | ... = ... | non-null | Splitting.cs:132:21:132:29 | call to method M11 | non-null |
|
||||
| Splitting.cs:132:17:132:29 | ... = ... | null | Splitting.cs:132:17:132:17 | access to local variable o | null |
|
||||
| Splitting.cs:132:17:132:29 | ... = ... | null | Splitting.cs:132:21:132:29 | call to method M11 | null |
|
||||
| Splitting.cs:133:17:133:17 | access to local variable o | non-null | Splitting.cs:132:21:132:29 | call to method M11 | non-null |
|
||||
| Splitting.cs:133:17:133:17 | access to local variable o | null | Splitting.cs:132:21:132:29 | call to method M11 | null |
|
||||
|
|
|
@ -2,222 +2,66 @@ using System;
|
|||
|
||||
class A
|
||||
{
|
||||
public void notTest()
|
||||
public void Lock()
|
||||
{
|
||||
object not_ok = null;
|
||||
if (!(!(!(not_ok == null))))
|
||||
object synchronizedAlways = null;
|
||||
lock (synchronizedAlways) // BAD (always)
|
||||
{
|
||||
not_ok.GetHashCode();
|
||||
}
|
||||
object not = null;
|
||||
if (!(not != null))
|
||||
{
|
||||
not.GetHashCode();
|
||||
}
|
||||
}
|
||||
public void instanceOf()
|
||||
{
|
||||
object instanceof_ok = null;
|
||||
if (instanceof_ok is string)
|
||||
{
|
||||
instanceof_ok.GetHashCode();
|
||||
synchronizedAlways.GetHashCode(); // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
public void locked()
|
||||
public void ArrayAssignTest()
|
||||
{
|
||||
object synchronized_always = null;
|
||||
lock (synchronized_always)
|
||||
{
|
||||
synchronized_always.GetHashCode();
|
||||
}
|
||||
int[] arrayNull = null;
|
||||
arrayNull[0] = 10; // BAD (always)
|
||||
|
||||
int[] arrayOk;
|
||||
arrayOk = new int[10];
|
||||
arrayOk[0] = 42; // GOOD
|
||||
}
|
||||
|
||||
public void assignIf()
|
||||
public void Access()
|
||||
{
|
||||
string xx;
|
||||
string ok = null;
|
||||
if ((ok = (xx = null)) == null || ok.Length == 0)
|
||||
{
|
||||
}
|
||||
}
|
||||
public void assignIf2()
|
||||
{
|
||||
string ok2 = null;
|
||||
if (foo(ok2 = "hello") || ok2.Length == 0)
|
||||
{
|
||||
}
|
||||
}
|
||||
public void assignIfAnd()
|
||||
{
|
||||
string xx;
|
||||
string ok3 = null;
|
||||
if ((xx = (ok3 = null)) != null && ok3.Length == 0)
|
||||
{
|
||||
}
|
||||
int[] arrayAccess = null;
|
||||
string[] fieldAccess = null;
|
||||
object methodAccess = null;
|
||||
object methodCall = null;
|
||||
|
||||
Console.WriteLine(arrayAccess[1]); // BAD (always)
|
||||
Console.WriteLine(fieldAccess.Length); // BAD (always)
|
||||
Func<String> tmp = methodAccess.ToString; // BAD (always)
|
||||
Console.WriteLine(methodCall.ToString()); // BAD (always)
|
||||
|
||||
Console.WriteLine(arrayAccess[1]); // GOOD
|
||||
Console.WriteLine(fieldAccess.Length); // GOOD
|
||||
tmp = methodAccess.ToString; // GOOD
|
||||
Console.WriteLine(methodCall.ToString()); // GOOD
|
||||
}
|
||||
|
||||
|
||||
public bool foo(string o) { return false; }
|
||||
|
||||
public void dowhile()
|
||||
public void OutOrRef()
|
||||
{
|
||||
string do_ok = "";
|
||||
do
|
||||
{
|
||||
Console.WriteLine(do_ok.Length);
|
||||
do_ok = null;
|
||||
}
|
||||
while (do_ok != null);
|
||||
object varOut = null;
|
||||
TestMethod1(out varOut);
|
||||
varOut.ToString(); // GOOD
|
||||
|
||||
object varRef = null;
|
||||
TestMethod2(ref varRef);
|
||||
varRef.ToString(); // BAD (always)
|
||||
|
||||
string do_always = null;
|
||||
do
|
||||
{
|
||||
Console.WriteLine(do_always.Length);
|
||||
do_always = null;
|
||||
}
|
||||
while (do_always != null);
|
||||
|
||||
string do_maybe1 = null;
|
||||
do
|
||||
{
|
||||
Console.WriteLine(do_maybe1.Length);
|
||||
}
|
||||
while (do_maybe1 != null);
|
||||
|
||||
string do_maybe = "";
|
||||
do
|
||||
{
|
||||
Console.WriteLine(do_maybe.Length);
|
||||
do_maybe = null;
|
||||
}
|
||||
while (true);
|
||||
varRef = null;
|
||||
TestMethod3(ref varRef);
|
||||
varRef.ToString(); // GOOD
|
||||
}
|
||||
|
||||
public void while_()
|
||||
{
|
||||
string while_ok = "";
|
||||
while (while_ok != null)
|
||||
{
|
||||
Console.WriteLine(while_ok.Length);
|
||||
while_ok = null;
|
||||
}
|
||||
|
||||
bool TRUE = true;
|
||||
string while_always = null;
|
||||
while (TRUE)
|
||||
{
|
||||
Console.WriteLine(while_always.Length);
|
||||
while_always = null;
|
||||
|
||||
}
|
||||
|
||||
|
||||
string while_maybe = "";
|
||||
while (true)
|
||||
{
|
||||
Console.WriteLine(while_maybe.Length);
|
||||
while_maybe = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void array_assign_test()
|
||||
{
|
||||
int[] array_null = null;
|
||||
array_null[0] = 10;
|
||||
|
||||
int[] array_ok;
|
||||
array_ok = new int[10];
|
||||
array_ok[0] = 42;
|
||||
}
|
||||
|
||||
public void if_()
|
||||
{
|
||||
string if_ok = "";
|
||||
if (if_ok != null)
|
||||
{
|
||||
Console.WriteLine(if_ok.Length);
|
||||
if_ok = null;
|
||||
}
|
||||
|
||||
|
||||
string if_always = null;
|
||||
if (if_always == null)
|
||||
{
|
||||
Console.WriteLine(if_always.Length);
|
||||
if_always = null;
|
||||
}
|
||||
|
||||
string if_maybe = "";
|
||||
if (if_maybe != null && if_maybe.Length % 2 == 0)
|
||||
{
|
||||
if_maybe = null;
|
||||
}
|
||||
Console.WriteLine(if_maybe.Length);
|
||||
}
|
||||
|
||||
public void for_()
|
||||
{
|
||||
string for_ok;
|
||||
for (for_ok = ""; for_ok != null; for_ok = null)
|
||||
{
|
||||
Console.WriteLine(for_ok.Length);
|
||||
}
|
||||
|
||||
Console.WriteLine(for_ok.Length);
|
||||
|
||||
|
||||
for (string for_always = null; for_always == null; for_always = null)
|
||||
{
|
||||
Console.WriteLine(for_always.Length);
|
||||
}
|
||||
|
||||
|
||||
for (string for_maybe = ""; ; for_maybe = null)
|
||||
{
|
||||
Console.WriteLine(for_maybe.Length);
|
||||
}
|
||||
}
|
||||
|
||||
public void access()
|
||||
{
|
||||
int[] arrayaccess = null;
|
||||
string[] fieldaccess = null;
|
||||
Object methodaccess = null;
|
||||
Object methodcall = null;
|
||||
|
||||
Console.WriteLine(arrayaccess[1]);
|
||||
Console.WriteLine(fieldaccess.Length);
|
||||
Func<String> tmp = methodaccess.ToString;
|
||||
Console.WriteLine(methodcall.ToString());
|
||||
|
||||
Console.WriteLine(arrayaccess[1]);
|
||||
Console.WriteLine(fieldaccess.Length);
|
||||
tmp = methodaccess.ToString;
|
||||
Console.WriteLine(methodcall.ToString());
|
||||
}
|
||||
|
||||
public void out_or_ref()
|
||||
{
|
||||
object var_out = null;
|
||||
TestMethod1(out var_out);
|
||||
Console.WriteLine(var_out.ToString());
|
||||
|
||||
object var_ref = null;
|
||||
TestMethod2(ref var_ref);
|
||||
Console.WriteLine(var_ref.ToString());
|
||||
}
|
||||
|
||||
public void lambda_test()
|
||||
public void LambdaTest()
|
||||
{
|
||||
string actual = null;
|
||||
|
||||
MyDelegate fun = e => x => actual = e;
|
||||
|
||||
fun("hello")("world");
|
||||
Console.WriteLine(actual.Length);
|
||||
Console.WriteLine(actual.Length); // GOOD
|
||||
}
|
||||
|
||||
static void TestMethod1(out object num)
|
||||
|
@ -229,85 +73,11 @@ class A
|
|||
{
|
||||
}
|
||||
|
||||
static void Main() { }
|
||||
static void TestMethod3(ref object num)
|
||||
{
|
||||
num = 42;
|
||||
}
|
||||
|
||||
public delegate MyDelegate2 MyDelegate(string e);
|
||||
public delegate void MyDelegate2(string e);
|
||||
|
||||
class B
|
||||
{
|
||||
public void operatorCall()
|
||||
{
|
||||
B eq_call_always = null;
|
||||
B b2 = null;
|
||||
B b3 = null;
|
||||
B neq_call_always = null;
|
||||
|
||||
if (eq_call_always == null)
|
||||
Console.WriteLine(eq_call_always.ToString());
|
||||
|
||||
if (b2 != null)
|
||||
Console.WriteLine(b2.ToString());
|
||||
|
||||
if (b3 == null) { }
|
||||
else
|
||||
Console.WriteLine(b3.ToString());
|
||||
|
||||
if (neq_call_always != null) { }
|
||||
else
|
||||
Console.WriteLine(neq_call_always.ToString());
|
||||
|
||||
|
||||
|
||||
}
|
||||
public static bool operator ==(B b1, B b2)
|
||||
{
|
||||
return Object.Equals(b1, b2);
|
||||
}
|
||||
public static bool operator !=(B b1, B b2)
|
||||
{
|
||||
return !(b1 == b2);
|
||||
}
|
||||
}
|
||||
public struct CoOrds
|
||||
{
|
||||
public int x, y;
|
||||
|
||||
|
||||
public CoOrds(int p1, int p2)
|
||||
{
|
||||
x = p1;
|
||||
y = p2;
|
||||
}
|
||||
}
|
||||
|
||||
public class Casts
|
||||
{
|
||||
void test()
|
||||
{
|
||||
object o = null;
|
||||
if ((object)o != null)
|
||||
{
|
||||
// GOOD
|
||||
var eq = o.Equals(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Delegates
|
||||
{
|
||||
delegate void Del();
|
||||
|
||||
class Foo
|
||||
{
|
||||
public static void Run(Del d) { }
|
||||
public void Bar() { }
|
||||
}
|
||||
|
||||
void F()
|
||||
{
|
||||
Foo foo = null;
|
||||
Foo.Run(delegate { foo = new Foo(); });
|
||||
foo.Bar();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,35 +4,51 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|||
|
||||
class AssertTests
|
||||
{
|
||||
void Fn()
|
||||
void Fn(bool b)
|
||||
{
|
||||
string s = null;
|
||||
string s = b ? null : "";
|
||||
Debug.Assert(s != null);
|
||||
Console.WriteLine(s.Length);
|
||||
Console.WriteLine(s.Length); // GOOD
|
||||
|
||||
s = null;
|
||||
s = b ? null : "";
|
||||
Assert.IsNull(s);
|
||||
Console.WriteLine(s.Length); // always null
|
||||
Console.WriteLine(s.Length); // BAD (always)
|
||||
|
||||
s = null;
|
||||
s = b ? null : "";
|
||||
Assert.IsNotNull(s);
|
||||
Console.WriteLine(s.Length);
|
||||
Console.WriteLine(s.Length); // GOOD
|
||||
|
||||
s = null;
|
||||
s = b ? null : "";
|
||||
Assert.IsTrue(s == null);
|
||||
Console.WriteLine(s.Length); // always null
|
||||
Console.WriteLine(s.Length); // BAD (always)
|
||||
|
||||
s = null;
|
||||
s = b ? null : "";
|
||||
Assert.IsTrue(s != null);
|
||||
Console.WriteLine(s.Length);
|
||||
Console.WriteLine(s.Length); // GOOD
|
||||
|
||||
s = null;
|
||||
s = b ? null : "";
|
||||
Assert.IsFalse(s != null);
|
||||
Console.WriteLine(s.Length); // always null
|
||||
Console.WriteLine(s.Length); // BAD (always)
|
||||
|
||||
s = null;
|
||||
s = b ? null : "";
|
||||
Assert.IsFalse(s == null);
|
||||
Console.WriteLine(s.Length);
|
||||
Console.WriteLine(s.Length); // GOOD
|
||||
|
||||
s = b ? null : "";
|
||||
Assert.IsTrue(s != null && b);
|
||||
Console.WriteLine(s.Length); // GOOD
|
||||
|
||||
s = b ? null : "";
|
||||
Assert.IsFalse(s == null || b);
|
||||
Console.WriteLine(s.Length); // GOOD
|
||||
|
||||
s = b ? null : "";
|
||||
Assert.IsTrue(s == null && b);
|
||||
Console.WriteLine(s.Length); // BAD (always)
|
||||
|
||||
s = b ? null : "";
|
||||
Assert.IsFalse(s != null || b);
|
||||
Console.WriteLine(s.Length); // BAD (always)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
using System;
|
||||
|
||||
class B
|
||||
{
|
||||
public void OperatorCall()
|
||||
{
|
||||
B eqCallAlways = null;
|
||||
B b2 = null;
|
||||
B b3 = null;
|
||||
B neqCallAlways = null;
|
||||
|
||||
if (eqCallAlways == null)
|
||||
eqCallAlways.ToString(); // BAD (always)
|
||||
|
||||
if (b2 != null)
|
||||
b2.ToString(); // GOOD
|
||||
|
||||
if (b3 == null) { }
|
||||
else
|
||||
b3.ToString(); // GOOD
|
||||
|
||||
if (neqCallAlways != null) { }
|
||||
else
|
||||
neqCallAlways.ToString(); // BAD (always)
|
||||
}
|
||||
|
||||
public static bool operator ==(B b1, B b2)
|
||||
{
|
||||
return Object.Equals(b1, b2);
|
||||
}
|
||||
|
||||
public static bool operator !=(B b1, B b2)
|
||||
{
|
||||
return !(b1 == b2);
|
||||
}
|
||||
|
||||
public struct Coords
|
||||
{
|
||||
public int x, y;
|
||||
|
||||
public Coords(int p1, int p2)
|
||||
{
|
||||
x = p1;
|
||||
y = p2;
|
||||
}
|
||||
}
|
||||
|
||||
public class Casts
|
||||
{
|
||||
void test()
|
||||
{
|
||||
object o = null;
|
||||
if ((object)o != null)
|
||||
{
|
||||
var eq = o.Equals(o); // GOOD
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Delegates
|
||||
{
|
||||
delegate void Del();
|
||||
|
||||
class Foo
|
||||
{
|
||||
public static void Run(Del d) => d();
|
||||
public void Bar() { }
|
||||
}
|
||||
|
||||
void F()
|
||||
{
|
||||
Foo foo = null;
|
||||
Foo.Run(delegate { foo = new Foo(); });
|
||||
foo.Bar(); // GOOD
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,275 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
public class C
|
||||
{
|
||||
public void NotTest()
|
||||
{
|
||||
object o = null;
|
||||
if (!(!(!(o == null))))
|
||||
{
|
||||
o.GetHashCode(); // GOOD
|
||||
}
|
||||
|
||||
if (!(o != null))
|
||||
{
|
||||
o.GetHashCode(); // BAD (always)
|
||||
}
|
||||
}
|
||||
|
||||
public void AssertNull(object o)
|
||||
{
|
||||
if (o != null)
|
||||
throw new Exception("not null");
|
||||
}
|
||||
|
||||
static bool IsNull(object o) => o == null;
|
||||
|
||||
static bool IsNotNull(object o) => o != null;
|
||||
|
||||
public void AssertNonNull(object o)
|
||||
{
|
||||
if (o == null)
|
||||
throw new Exception("null");
|
||||
}
|
||||
|
||||
public void AssertTest()
|
||||
{
|
||||
var s = Maybe() ? null : "";
|
||||
Debug.Assert(s == null);
|
||||
s.ToString(); // BAD (always)
|
||||
|
||||
s = Maybe() ? null : "";
|
||||
Debug.Assert(s != null);
|
||||
s.ToString(); // GOOD
|
||||
}
|
||||
|
||||
public void AssertNullTest()
|
||||
{
|
||||
var o1 = new object();
|
||||
AssertNull(o1);
|
||||
o1.ToString(); // BAD (always) (false negative)
|
||||
|
||||
var o2 = Maybe() ? null : "";
|
||||
Assert.IsNull(o2);
|
||||
o2.ToString(); // BAD (always)
|
||||
}
|
||||
|
||||
public void AssertNotNullTest()
|
||||
{
|
||||
var o1 = Maybe() ? null : new object();
|
||||
AssertNonNull(o1);
|
||||
o1.ToString(); // GOOD (false positive)
|
||||
|
||||
var o2 = Maybe() ? null : new object();
|
||||
AssertNonNull(o1);
|
||||
o2.ToString(); // BAD (maybe)
|
||||
|
||||
var o3 = Maybe() ? null : new object();
|
||||
Assert.IsNotNull(o3);
|
||||
o3.ToString(); // GOOD
|
||||
}
|
||||
|
||||
public void TestNull()
|
||||
{
|
||||
object o = null;
|
||||
if (IsNotNull(o))
|
||||
o.ToString(); // GOOD
|
||||
|
||||
|
||||
if (!IsNull(o))
|
||||
o.ToString(); // GOOD
|
||||
}
|
||||
|
||||
public void InstanceOf()
|
||||
{
|
||||
object o = null;
|
||||
if (o is string)
|
||||
o.ToString(); // GOOD
|
||||
}
|
||||
|
||||
public void Lock()
|
||||
{
|
||||
var o = Maybe() ? null : new object();
|
||||
lock (o) // BAD (maybe)
|
||||
o.ToString(); // GOOD
|
||||
}
|
||||
|
||||
public void Foreach(IEnumerable<int> list)
|
||||
{
|
||||
if (Maybe())
|
||||
list = null;
|
||||
foreach (var x in list) // BAD (maybe)
|
||||
{
|
||||
x.ToString(); // GOOD
|
||||
list.ToString(); // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
public void Conditional()
|
||||
{
|
||||
string colours = null;
|
||||
var colour = colours == null || colours.Length == 0 ? "Black" : colours.ToString(); // GOOD
|
||||
}
|
||||
|
||||
public void Simple()
|
||||
{
|
||||
string[] children = null;
|
||||
var comparator = "";
|
||||
if (children == null)
|
||||
children = new string[0];
|
||||
if (children.Length > 1) { } // GOOD
|
||||
}
|
||||
|
||||
public void AssignIf()
|
||||
{
|
||||
string xx;
|
||||
String ok = null;
|
||||
if ((ok = (xx = null)) == null || ok.Length > 0) // GOOD
|
||||
;
|
||||
}
|
||||
|
||||
public void AssignIf2()
|
||||
{
|
||||
bool Foo(string o) => false;
|
||||
string ok2 = null;
|
||||
if (Foo(ok2 = "hello") || ok2.Length > 0) // GOOD
|
||||
;
|
||||
}
|
||||
|
||||
public void AssignIfAnd()
|
||||
{
|
||||
string xx;
|
||||
string ok3 = null;
|
||||
if ((xx = (ok3 = null)) != null && ok3.Length > 0) // GOOD
|
||||
;
|
||||
}
|
||||
|
||||
public void DoWhile()
|
||||
{
|
||||
var s = "";
|
||||
do
|
||||
{
|
||||
s.ToString(); // GOOD
|
||||
s = null;
|
||||
}
|
||||
while (s != null);
|
||||
|
||||
s = null;
|
||||
do
|
||||
{
|
||||
s.ToString(); // BAD (always)
|
||||
s = null;
|
||||
}
|
||||
while (s != null);
|
||||
|
||||
s = null;
|
||||
do
|
||||
{
|
||||
s.ToString(); // BAD (always)
|
||||
}
|
||||
while (s != null);
|
||||
|
||||
s = "";
|
||||
do
|
||||
{
|
||||
s.ToString(); // BAD (maybe)
|
||||
s = null;
|
||||
}
|
||||
while (true);
|
||||
}
|
||||
|
||||
public void While()
|
||||
{
|
||||
var s = "";
|
||||
while (s != null)
|
||||
{
|
||||
s.ToString(); // GOOD
|
||||
s = null;
|
||||
}
|
||||
|
||||
var b = true;
|
||||
s = null;
|
||||
while (b)
|
||||
{
|
||||
s.ToString(); // BAD (always)
|
||||
s = null;
|
||||
}
|
||||
|
||||
s = "";
|
||||
while (true)
|
||||
{
|
||||
s.ToString(); // BAD (maybe)
|
||||
s = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void If()
|
||||
{
|
||||
var s = Maybe() ? null : "";
|
||||
if (s != null)
|
||||
{
|
||||
s.ToString(); // GOOD
|
||||
s = null;
|
||||
}
|
||||
|
||||
if (s == null)
|
||||
s.ToString(); // BAD (always)
|
||||
|
||||
s = "";
|
||||
if (s != null && s.Length % 2 == 0)
|
||||
s = null;
|
||||
s.ToString(); // BAD (maybe)
|
||||
}
|
||||
|
||||
public void For()
|
||||
{
|
||||
String s;
|
||||
for (s = ""; s != null; s = null)
|
||||
{
|
||||
s.ToString(); // GOOD
|
||||
}
|
||||
s.ToString(); // BAD (always)
|
||||
|
||||
for (s = null; s == null; s = null)
|
||||
{
|
||||
s.ToString(); // BAD (always)
|
||||
}
|
||||
|
||||
for (s = ""; ; s = null)
|
||||
{
|
||||
s.ToString(); // BAD (maybe)
|
||||
}
|
||||
}
|
||||
|
||||
public void ArrayAssignTest()
|
||||
{
|
||||
int[] a = null;
|
||||
a[0] = 10; // BAD (always)
|
||||
|
||||
a = new int[10];
|
||||
a[0] = 42; // GOOD
|
||||
}
|
||||
|
||||
public void Access()
|
||||
{
|
||||
int[] ia = null;
|
||||
string[] sa = null;
|
||||
|
||||
ia[1] = 0; // BAD (always)
|
||||
var temp = sa.Length; // BAD (always)
|
||||
|
||||
ia[1] = 0; // BAD (always), but not first
|
||||
temp = sa.Length; // BAD (always), but not first
|
||||
}
|
||||
|
||||
bool m;
|
||||
C(bool m)
|
||||
{
|
||||
this.m = m;
|
||||
}
|
||||
|
||||
bool Maybe() => this.m;
|
||||
}
|
|
@ -0,0 +1,414 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
public class D
|
||||
{
|
||||
private bool maybe;
|
||||
public bool flag;
|
||||
public D(bool b, bool f)
|
||||
{
|
||||
this.maybe = b;
|
||||
this.flag = f;
|
||||
}
|
||||
|
||||
public void Caller()
|
||||
{
|
||||
Callee1(new object());
|
||||
Callee1(null);
|
||||
Callee2(new object());
|
||||
}
|
||||
|
||||
public void Callee1(object param)
|
||||
{
|
||||
param.ToString(); // BAD (maybe)
|
||||
}
|
||||
|
||||
public void Callee2(object param)
|
||||
{
|
||||
if (param != null)
|
||||
{
|
||||
param.ToString(); // GOOD
|
||||
}
|
||||
param.ToString(); // BAD (maybe)
|
||||
}
|
||||
|
||||
private static bool CustomIsNull(object x)
|
||||
{
|
||||
if (x is string) return false;
|
||||
if (x == null) return true;
|
||||
return x == null;
|
||||
}
|
||||
|
||||
public void NullGuards()
|
||||
{
|
||||
var o1 = maybe ? null : new object();
|
||||
if (o1 != null) o1.ToString(); // GOOD
|
||||
|
||||
var o2 = maybe ? null : "";
|
||||
if (o2 is string) o2.ToString(); // GOOD
|
||||
|
||||
object o3 = null;
|
||||
if ((o3 = maybe ? null : "") != null)
|
||||
o3.ToString(); // GOOD
|
||||
|
||||
var o4 = maybe ? null : "";
|
||||
if ((2 > 1 && o4 != null) != false)
|
||||
o4.ToString(); // GOOD
|
||||
|
||||
var o5 = (o4 != null) ? "" : null;
|
||||
if (o5 != null)
|
||||
o4.ToString(); // GOOD
|
||||
if (o4 != null)
|
||||
o5.ToString(); // GOOD (false positive)
|
||||
|
||||
var o6 = maybe ? null : "";
|
||||
if (!CustomIsNull(o6))
|
||||
o6.ToString(); // GOOD
|
||||
|
||||
var o7 = maybe ? null : "";
|
||||
var ok = o7 != null && 2 > 1;
|
||||
if (ok)
|
||||
o7.ToString(); // GOOD
|
||||
else
|
||||
o7.ToString(); // BAD (maybe)
|
||||
|
||||
var o8 = maybe ? null : "";
|
||||
int track = o8 == null ? 42 : 1 + 1;
|
||||
if (track == 2)
|
||||
o8.ToString(); // GOOD
|
||||
if (track != 42)
|
||||
o8.ToString(); // GOOD
|
||||
if (track < 42)
|
||||
o8.ToString(); // GOOD (false positive)
|
||||
if (track <= 41)
|
||||
o8.ToString(); // GOOD (false positive)
|
||||
}
|
||||
|
||||
public void Deref(int i)
|
||||
{
|
||||
int[] xs = maybe ? null : new int[2];
|
||||
if (i > 1)
|
||||
xs[0] = 5; // BAD (maybe)
|
||||
|
||||
if (i > 2)
|
||||
maybe = xs[1] > 5; // BAD (maybe)
|
||||
|
||||
if (i > 3)
|
||||
{
|
||||
var l = xs.Length; // BAD (maybe)
|
||||
}
|
||||
|
||||
if (i > 4)
|
||||
foreach (var _ in xs) ; // BAD (maybe)
|
||||
|
||||
if (i > 5)
|
||||
lock (xs) // BAD (maybe)
|
||||
xs.ToString(); // Not reported - same basic block
|
||||
|
||||
if (i > 6)
|
||||
{
|
||||
Debug.Assert(xs != null);
|
||||
xs[0] = xs[1]; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
public void F(bool b)
|
||||
{
|
||||
var x = b ? null : "abc";
|
||||
x = x == null ? "" : x;
|
||||
if (x == null)
|
||||
x.ToString(); // BAD (always)
|
||||
else
|
||||
x.ToString(); // GOOD
|
||||
}
|
||||
|
||||
public void LengthGuard(int[] a, int[] b)
|
||||
{
|
||||
int alen = a == null ? 0 : a.Length; // GOOD
|
||||
int blen = b == null ? 0 : b.Length; // GOOD
|
||||
var sum = 0;
|
||||
if (alen == blen)
|
||||
{
|
||||
for (int i = 0; i < alen; i++)
|
||||
{
|
||||
sum += a[i]; // GOOD (false positive)
|
||||
sum += b[i]; // GOOD (false positive)
|
||||
}
|
||||
}
|
||||
int alen2;
|
||||
if (a != null)
|
||||
alen2 = a.Length; // GOOD
|
||||
else
|
||||
alen2 = 0;
|
||||
for (int i = 1; i <= alen2; ++i)
|
||||
{
|
||||
sum += a[i - 1]; // GOOD (false positive)
|
||||
}
|
||||
}
|
||||
|
||||
public void MissedGuard(object obj)
|
||||
{
|
||||
obj.ToString(); // BAD (maybe)
|
||||
var x = obj != null ? 1 : 0;
|
||||
}
|
||||
|
||||
private object MkMaybe()
|
||||
{
|
||||
if (maybe) throw new Exception();
|
||||
return new object();
|
||||
}
|
||||
|
||||
public void Exceptions()
|
||||
{
|
||||
object obj = null;
|
||||
try
|
||||
{
|
||||
obj = MkMaybe();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
}
|
||||
obj.ToString(); // BAD (maybe)
|
||||
|
||||
object obj2 = null;
|
||||
try
|
||||
{
|
||||
obj2 = MkMaybe();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.Assert(false);
|
||||
}
|
||||
obj2.ToString(); // GOOD
|
||||
|
||||
object obj3 = null;
|
||||
try
|
||||
{
|
||||
obj3 = MkMaybe();
|
||||
}
|
||||
finally { }
|
||||
obj3.ToString(); // GOOD
|
||||
}
|
||||
|
||||
public void ClearNotNull()
|
||||
{
|
||||
var o = new Object();
|
||||
if (o == null)
|
||||
o.ToString(); // BAD (always)
|
||||
o.ToString(); // GOOD
|
||||
|
||||
try
|
||||
{
|
||||
MkMaybe();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (e == null)
|
||||
e.ToString(); // BAD (always)
|
||||
e.ToString(); // GOOD
|
||||
}
|
||||
|
||||
object n = null;
|
||||
var o2 = n == null ? new Object() : n;
|
||||
o2.ToString(); // GOOD
|
||||
|
||||
var o3 = "abc";
|
||||
if (o3 == null)
|
||||
o3.ToString(); // BAD (always)
|
||||
o3.ToString(); // GOOD
|
||||
|
||||
var o4 = "" + null;
|
||||
if (o4 == null)
|
||||
o4.ToString(); // BAD (always)
|
||||
o4.ToString(); // GOOD
|
||||
}
|
||||
|
||||
public void CorrelatedConditions(bool cond, int num)
|
||||
{
|
||||
object o = null;
|
||||
if (cond)
|
||||
o = new Object();
|
||||
if (cond)
|
||||
o.ToString(); // GOOD
|
||||
|
||||
o = null;
|
||||
if (flag)
|
||||
o = "";
|
||||
if (flag)
|
||||
o.ToString(); // GOOD
|
||||
|
||||
o = null;
|
||||
var other = maybe ? null : "";
|
||||
if (other == null)
|
||||
o = "";
|
||||
if (other != null)
|
||||
o.ToString(); // BAD (always) (reported as maybe)
|
||||
else
|
||||
o.ToString(); // GOOD (false positive)
|
||||
|
||||
var o2 = (num < 0) ? null : "";
|
||||
if (num < 0)
|
||||
o2 = "";
|
||||
else
|
||||
o2.ToString(); // GOOD (false positive)
|
||||
}
|
||||
|
||||
public void TrackingVariable(int[] a)
|
||||
{
|
||||
object o = null;
|
||||
object other = null;
|
||||
if (maybe)
|
||||
{
|
||||
o = "abc";
|
||||
other = "def";
|
||||
}
|
||||
|
||||
if (other is string)
|
||||
o.ToString(); // GOOD (false positive)
|
||||
|
||||
o = null;
|
||||
int count = 0;
|
||||
var found = false;
|
||||
for (var i = 0; i < a.Length; i++)
|
||||
{
|
||||
if (a[i] == 42)
|
||||
{
|
||||
o = ((int)a[i]).ToString();
|
||||
count++;
|
||||
if (2 > i) { }
|
||||
found = true;
|
||||
}
|
||||
if (a[i] > 10000)
|
||||
{
|
||||
o = null;
|
||||
count = 0;
|
||||
if (2 > i) { }
|
||||
found = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (count > 3)
|
||||
o.ToString(); // GOOD (false positive)
|
||||
|
||||
if (found)
|
||||
o.ToString(); // GOOD (false positive)
|
||||
|
||||
object prev = null;
|
||||
for (var i = 0; i < a.Length; ++i)
|
||||
{
|
||||
if (i != 0)
|
||||
prev.ToString(); // GOOD (false positive)
|
||||
prev = a[i];
|
||||
}
|
||||
|
||||
string s = null;
|
||||
{
|
||||
var s_null = true;
|
||||
foreach (var i in a)
|
||||
{
|
||||
s_null = false;
|
||||
s = "" + a;
|
||||
}
|
||||
if (!s_null)
|
||||
s.ToString(); // GOOD (false positive)
|
||||
}
|
||||
|
||||
object r = null;
|
||||
var stat = MyStatus.INIT;
|
||||
while (stat == MyStatus.INIT && stat != MyStatus.READY)
|
||||
{
|
||||
r = MkMaybe();
|
||||
if (stat == MyStatus.INIT)
|
||||
stat = MyStatus.READY;
|
||||
}
|
||||
r.ToString(); // GOOD (false positive)
|
||||
}
|
||||
|
||||
public enum MyStatus
|
||||
{
|
||||
READY,
|
||||
INIT
|
||||
}
|
||||
|
||||
public void G(object obj)
|
||||
{
|
||||
string msg = null;
|
||||
if (obj == null)
|
||||
msg = "foo";
|
||||
else if (obj.GetHashCode() > 7) // GOOD
|
||||
msg = "bar";
|
||||
|
||||
if (msg != null)
|
||||
{
|
||||
msg += "foobar";
|
||||
throw new Exception(msg);
|
||||
}
|
||||
obj.ToString(); // GOOD
|
||||
}
|
||||
|
||||
public void LoopCorr(int iters)
|
||||
{
|
||||
int[] a = null;
|
||||
if (iters > 0)
|
||||
a = new int[iters];
|
||||
|
||||
for (var i = 0; i < iters; ++i)
|
||||
a[i] = 0; // GOOD (false positive)
|
||||
|
||||
if (iters > 0)
|
||||
{
|
||||
string last = null;
|
||||
for (var i = 0; i < iters; i++)
|
||||
last = "abc";
|
||||
last.ToString(); // GOOD (false positive)
|
||||
}
|
||||
|
||||
int[] b = maybe ? null : new int[iters];
|
||||
if (iters > 0 && (b == null || b.Length < iters))
|
||||
throw new Exception();
|
||||
|
||||
for (var i = 0; i < iters; ++i)
|
||||
{
|
||||
b[i] = 0; // GOOD (false positive)
|
||||
}
|
||||
}
|
||||
|
||||
void Test(Exception e, bool b)
|
||||
{
|
||||
Exception ioe = null;
|
||||
if (b)
|
||||
ioe = new Exception("");
|
||||
|
||||
if (ioe != null)
|
||||
ioe = e;
|
||||
else
|
||||
ioe.ToString(); // BAD (always)
|
||||
}
|
||||
|
||||
public void LengthGuard2(int[] a, int[] b)
|
||||
{
|
||||
int alen = a == null ? 0 : a.Length; // GOOD
|
||||
int sum = 0;
|
||||
int i;
|
||||
for (i = 0; i < alen; i++)
|
||||
{
|
||||
sum += a[i]; // GOOD (false positive)
|
||||
}
|
||||
int blen = b == null ? 0 : b.Length; // GOOD
|
||||
for (i = 0; i < blen; i++)
|
||||
{
|
||||
sum += b[i]; // GOOD (false positive)
|
||||
}
|
||||
i = -3;
|
||||
}
|
||||
|
||||
public void CorrConds2(object x, object y)
|
||||
{
|
||||
if ((x != null && y == null) || (x == null && y != null))
|
||||
return;
|
||||
if (x != null)
|
||||
y.ToString(); // GOOD (false positive)
|
||||
if (y != null)
|
||||
x.ToString(); // GOOD (false positive)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,271 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public class E
|
||||
{
|
||||
public void Ex1(long[][][] a1, int ix, int len)
|
||||
{
|
||||
long[][] a2 = null;
|
||||
var haveA2 = ix < len && (a2 = a1[ix]) != null;
|
||||
long[] a3 = null;
|
||||
var haveA3 = haveA2 && (a3 = a2[ix]) != null; // GOOD (false positive)
|
||||
if (haveA3)
|
||||
a3[0] = 0; // GOOD (false positive)
|
||||
}
|
||||
|
||||
public void Ex2(bool x, bool y)
|
||||
{
|
||||
var s1 = x ? null : "";
|
||||
var s2 = (s1 == null) ? null : "";
|
||||
if (s2 == null)
|
||||
{
|
||||
s1 = y ? null : "";
|
||||
s2 = (s1 == null) ? null : "";
|
||||
}
|
||||
if (s2 != null)
|
||||
s1.ToString(); // GOOD (false positive)
|
||||
}
|
||||
|
||||
public void Ex3(IEnumerable<string> ss)
|
||||
{
|
||||
string last = null;
|
||||
foreach (var s in new string[] { "aa", "bb" })
|
||||
last = s;
|
||||
last.ToString(); // GOOD (false positive)
|
||||
|
||||
last = null;
|
||||
if (ss.Any())
|
||||
{
|
||||
foreach (var s in ss)
|
||||
last = s;
|
||||
|
||||
last.ToString(); // GOOD (false positive)
|
||||
}
|
||||
}
|
||||
|
||||
public void Ex4(IEnumerable<string> list, int step)
|
||||
{
|
||||
int index = 0;
|
||||
var result = new List<List<string>>();
|
||||
List<string> slice = null;
|
||||
var iter = list.GetEnumerator();
|
||||
while (iter.MoveNext())
|
||||
{
|
||||
var str = iter.Current;
|
||||
if (index % step == 0)
|
||||
{
|
||||
slice = new List<string>();
|
||||
result.Add(slice);
|
||||
}
|
||||
slice.Add(str); // GOOD (false positive)
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
public void Ex5(bool hasArr, int[] arr)
|
||||
{
|
||||
int arrLen = 0;
|
||||
if (hasArr)
|
||||
arrLen = arr == null ? 0 : arr.Length;
|
||||
|
||||
if (arrLen > 0)
|
||||
arr[0] = 0; // GOOD (false positive)
|
||||
}
|
||||
|
||||
public const int MY_CONST_A = 1;
|
||||
public const int MY_CONST_B = 2;
|
||||
public const int MY_CONST_C = 3;
|
||||
|
||||
public void Ex6(int[] vals, bool b1, bool b2)
|
||||
{
|
||||
int switchguard;
|
||||
if (vals != null && b1)
|
||||
switchguard = MY_CONST_A;
|
||||
else if (vals != null && b2)
|
||||
switchguard = MY_CONST_B;
|
||||
else
|
||||
switchguard = MY_CONST_C;
|
||||
|
||||
switch (switchguard)
|
||||
{
|
||||
case MY_CONST_A:
|
||||
vals[0] = 0; // GOOD
|
||||
break;
|
||||
case MY_CONST_C:
|
||||
break;
|
||||
case MY_CONST_B:
|
||||
vals[0] = 0; // GOOD
|
||||
break;
|
||||
default:
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
|
||||
public void Ex7(int[] arr1)
|
||||
{
|
||||
int[] arr2 = null;
|
||||
if (arr1.Length > 0)
|
||||
arr2 = new int[arr1.Length];
|
||||
|
||||
for (var i = 0; i < arr1.Length; i++)
|
||||
arr2[i] = arr1[i]; // GOOD (false positive)
|
||||
}
|
||||
|
||||
public void Ex8(int x, int lim)
|
||||
{
|
||||
bool stop = x < 1;
|
||||
int i = 0;
|
||||
var obj = new object();
|
||||
while (!stop)
|
||||
{
|
||||
int j = 0;
|
||||
while (!stop && j < lim)
|
||||
{
|
||||
int step = (j * obj.GetHashCode()) % 10; // GOOD (false positive)
|
||||
if (step == 0)
|
||||
{
|
||||
obj.ToString(); // GOOD
|
||||
i += 1;
|
||||
stop = i >= x;
|
||||
if (!stop)
|
||||
{
|
||||
obj = new object();
|
||||
}
|
||||
else
|
||||
{
|
||||
obj = null;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
j += step;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Ex9(bool cond, object obj1)
|
||||
{
|
||||
if (cond)
|
||||
{
|
||||
return;
|
||||
}
|
||||
object obj2 = obj1;
|
||||
if (obj2 != null && obj2.GetHashCode() % 5 > 2)
|
||||
{
|
||||
obj2.ToString(); // GOOD
|
||||
cond = true;
|
||||
}
|
||||
if (cond)
|
||||
obj2.ToString(); // GOOD (false positive)
|
||||
}
|
||||
|
||||
public void Ex10(int[] a)
|
||||
{
|
||||
int n = a == null ? 0 : a.Length;
|
||||
for (var i = 0; i < n; i++)
|
||||
{
|
||||
int x = a[i]; // GOOD (false positive)
|
||||
if (x > 7)
|
||||
a = new int[n];
|
||||
}
|
||||
}
|
||||
|
||||
public void Ex11(object obj, bool b1)
|
||||
{
|
||||
bool b2 = obj == null ? false : b1;
|
||||
if (b2 == null)
|
||||
{
|
||||
obj.ToString(); // GOOD (false positive)
|
||||
}
|
||||
if (obj == null)
|
||||
{
|
||||
b1 = true;
|
||||
}
|
||||
if (b1 == null)
|
||||
{
|
||||
obj.ToString(); // GOOD (false positive)
|
||||
}
|
||||
}
|
||||
|
||||
public void Ex12(object o)
|
||||
{
|
||||
var i = o.GetHashCode(); // BAD (maybe)
|
||||
var s = o?.ToString();
|
||||
}
|
||||
|
||||
public void Ex13(bool b)
|
||||
{
|
||||
var o = b ? null : "";
|
||||
o.M1(); // GOOD
|
||||
if (b)
|
||||
o.M2(); // BAD (maybe)
|
||||
else
|
||||
o.Select(x => x); // BAD (maybe)
|
||||
}
|
||||
|
||||
public int Ex14(string s)
|
||||
{
|
||||
if (s is string)
|
||||
return s.Length;
|
||||
return s.GetHashCode(); // BAD (always)
|
||||
}
|
||||
|
||||
public void Ex15(bool b)
|
||||
{
|
||||
var x = "";
|
||||
if (b)
|
||||
x = null;
|
||||
x.ToString(); // BAD (maybe)
|
||||
if (b)
|
||||
x.ToString(); // BAD (always)
|
||||
}
|
||||
|
||||
public void Ex16(bool b)
|
||||
{
|
||||
var x = "";
|
||||
if (b)
|
||||
x = null;
|
||||
if (b)
|
||||
x.ToString(); // BAD (always)
|
||||
x.ToString(); // BAD (maybe)
|
||||
}
|
||||
|
||||
public int Ex17(int? i)
|
||||
{
|
||||
return i.Value; // BAD (maybe)
|
||||
}
|
||||
|
||||
public int Ex18(int? i)
|
||||
{
|
||||
return (int)i; // BAD (maybe)
|
||||
}
|
||||
|
||||
public int Ex19(int? i)
|
||||
{
|
||||
if (i.HasValue)
|
||||
return i.Value; // GOOD
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int Ex20(int? i)
|
||||
{
|
||||
if (i != null)
|
||||
return i.Value; // GOOD
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int Ex21(int? i)
|
||||
{
|
||||
if (i == null)
|
||||
i = 0;
|
||||
return i.Value; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
public static class Extensions
|
||||
{
|
||||
public static void M1(this string s) { }
|
||||
public static int M2(this string s) => s.Length;
|
||||
}
|
||||
|
||||
// semmle-extractor-options: /r:System.Linq.dll
|
|
@ -0,0 +1,233 @@
|
|||
| Assert.cs:10:22:10:30 | ... != ... | false | Assert.cs:10:22:10:22 | access to local variable s | Assert.cs:10:27:10:30 | null |
|
||||
| Assert.cs:10:22:10:30 | ... != ... | false | Assert.cs:10:27:10:30 | null | Assert.cs:10:22:10:22 | access to local variable s |
|
||||
| Assert.cs:22:23:22:31 | ... == ... | true | Assert.cs:22:23:22:23 | access to local variable s | Assert.cs:22:28:22:31 | null |
|
||||
| Assert.cs:22:23:22:31 | ... == ... | true | Assert.cs:22:28:22:31 | null | Assert.cs:22:23:22:23 | access to local variable s |
|
||||
| Assert.cs:26:23:26:31 | ... != ... | false | Assert.cs:26:23:26:23 | access to local variable s | Assert.cs:26:28:26:31 | null |
|
||||
| Assert.cs:26:23:26:31 | ... != ... | false | Assert.cs:26:28:26:31 | null | Assert.cs:26:23:26:23 | access to local variable s |
|
||||
| Assert.cs:30:24:30:32 | ... != ... | false | Assert.cs:30:24:30:24 | access to local variable s | Assert.cs:30:29:30:32 | null |
|
||||
| Assert.cs:30:24:30:32 | ... != ... | false | Assert.cs:30:29:30:32 | null | Assert.cs:30:24:30:24 | access to local variable s |
|
||||
| Assert.cs:34:24:34:32 | ... == ... | true | Assert.cs:34:24:34:24 | access to local variable s | Assert.cs:34:29:34:32 | null |
|
||||
| Assert.cs:34:24:34:32 | ... == ... | true | Assert.cs:34:29:34:32 | null | Assert.cs:34:24:34:24 | access to local variable s |
|
||||
| Assert.cs:38:23:38:31 | ... != ... | false | Assert.cs:38:23:38:23 | access to local variable s | Assert.cs:38:28:38:31 | null |
|
||||
| Assert.cs:38:23:38:31 | ... != ... | false | Assert.cs:38:28:38:31 | null | Assert.cs:38:23:38:23 | access to local variable s |
|
||||
| Assert.cs:42:24:42:32 | ... == ... | true | Assert.cs:42:24:42:24 | access to local variable s | Assert.cs:42:29:42:32 | null |
|
||||
| Assert.cs:42:24:42:32 | ... == ... | true | Assert.cs:42:29:42:32 | null | Assert.cs:42:24:42:24 | access to local variable s |
|
||||
| Assert.cs:46:23:46:31 | ... == ... | true | Assert.cs:46:23:46:23 | access to local variable s | Assert.cs:46:28:46:31 | null |
|
||||
| Assert.cs:46:23:46:31 | ... == ... | true | Assert.cs:46:28:46:31 | null | Assert.cs:46:23:46:23 | access to local variable s |
|
||||
| Assert.cs:50:24:50:32 | ... != ... | false | Assert.cs:50:24:50:24 | access to local variable s | Assert.cs:50:29:50:32 | null |
|
||||
| Assert.cs:50:24:50:32 | ... != ... | false | Assert.cs:50:29:50:32 | null | Assert.cs:50:24:50:24 | access to local variable s |
|
||||
| B.cs:12:13:12:32 | call to operator == | true | B.cs:12:13:12:24 | access to local variable eqCallAlways | B.cs:12:29:12:32 | null |
|
||||
| B.cs:12:13:12:32 | call to operator == | true | B.cs:12:29:12:32 | null | B.cs:12:13:12:24 | access to local variable eqCallAlways |
|
||||
| B.cs:15:13:15:22 | call to operator != | false | B.cs:15:13:15:14 | access to local variable b2 | B.cs:15:19:15:22 | null |
|
||||
| B.cs:15:13:15:22 | call to operator != | false | B.cs:15:19:15:22 | null | B.cs:15:13:15:14 | access to local variable b2 |
|
||||
| B.cs:18:13:18:22 | call to operator == | true | B.cs:18:13:18:14 | access to local variable b3 | B.cs:18:19:18:22 | null |
|
||||
| B.cs:18:13:18:22 | call to operator == | true | B.cs:18:19:18:22 | null | B.cs:18:13:18:14 | access to local variable b3 |
|
||||
| B.cs:22:13:22:33 | call to operator != | false | B.cs:22:13:22:25 | access to local variable neqCallAlways | B.cs:22:30:22:33 | null |
|
||||
| B.cs:22:13:22:33 | call to operator != | false | B.cs:22:30:22:33 | null | B.cs:22:13:22:25 | access to local variable neqCallAlways |
|
||||
| B.cs:29:16:29:36 | call to method Equals | true | B.cs:29:30:29:31 | access to parameter b1 | B.cs:29:34:29:35 | access to parameter b2 |
|
||||
| B.cs:29:16:29:36 | call to method Equals | true | B.cs:29:34:29:35 | access to parameter b2 | B.cs:29:30:29:31 | access to parameter b1 |
|
||||
| B.cs:34:18:34:25 | call to operator == | true | B.cs:34:18:34:19 | access to parameter b1 | B.cs:34:24:34:25 | access to parameter b2 |
|
||||
| B.cs:34:18:34:25 | call to operator == | true | B.cs:34:24:34:25 | access to parameter b2 | B.cs:34:18:34:19 | access to parameter b1 |
|
||||
| B.cs:53:17:53:33 | ... != ... | false | B.cs:53:17:53:25 | (...) ... | B.cs:53:30:53:33 | null |
|
||||
| B.cs:53:17:53:33 | ... != ... | false | B.cs:53:30:53:33 | null | B.cs:53:17:53:25 | (...) ... |
|
||||
| B.cs:55:26:55:36 | call to method Equals | true | B.cs:55:26:55:26 | access to local variable o | B.cs:55:35:55:35 | access to local variable o |
|
||||
| B.cs:55:26:55:36 | call to method Equals | true | B.cs:55:35:55:35 | access to local variable o | B.cs:55:26:55:26 | access to local variable o |
|
||||
| C.cs:11:19:11:27 | ... == ... | true | C.cs:11:19:11:19 | access to local variable o | C.cs:11:24:11:27 | null |
|
||||
| C.cs:11:19:11:27 | ... == ... | true | C.cs:11:24:11:27 | null | C.cs:11:19:11:19 | access to local variable o |
|
||||
| C.cs:16:15:16:23 | ... != ... | false | C.cs:16:15:16:15 | access to local variable o | C.cs:16:20:16:23 | null |
|
||||
| C.cs:16:15:16:23 | ... != ... | false | C.cs:16:20:16:23 | null | C.cs:16:15:16:15 | access to local variable o |
|
||||
| C.cs:24:13:24:21 | ... != ... | false | C.cs:24:13:24:13 | access to parameter o | C.cs:24:18:24:21 | null |
|
||||
| C.cs:24:13:24:21 | ... != ... | false | C.cs:24:18:24:21 | null | C.cs:24:13:24:13 | access to parameter o |
|
||||
| C.cs:28:37:28:45 | ... == ... | true | C.cs:28:37:28:37 | access to parameter o | C.cs:28:42:28:45 | null |
|
||||
| C.cs:28:37:28:45 | ... == ... | true | C.cs:28:42:28:45 | null | C.cs:28:37:28:37 | access to parameter o |
|
||||
| C.cs:30:40:30:48 | ... != ... | false | C.cs:30:40:30:40 | access to parameter o | C.cs:30:45:30:48 | null |
|
||||
| C.cs:30:40:30:48 | ... != ... | false | C.cs:30:45:30:48 | null | C.cs:30:40:30:40 | access to parameter o |
|
||||
| C.cs:34:13:34:21 | ... == ... | true | C.cs:34:13:34:13 | access to parameter o | C.cs:34:18:34:21 | null |
|
||||
| C.cs:34:13:34:21 | ... == ... | true | C.cs:34:18:34:21 | null | C.cs:34:13:34:13 | access to parameter o |
|
||||
| C.cs:41:22:41:30 | ... == ... | true | C.cs:41:22:41:22 | access to local variable s | C.cs:41:27:41:30 | null |
|
||||
| C.cs:41:22:41:30 | ... == ... | true | C.cs:41:27:41:30 | null | C.cs:41:22:41:22 | access to local variable s |
|
||||
| C.cs:45:22:45:30 | ... != ... | false | C.cs:45:22:45:22 | access to local variable s | C.cs:45:27:45:30 | null |
|
||||
| C.cs:45:22:45:30 | ... != ... | false | C.cs:45:27:45:30 | null | C.cs:45:22:45:22 | access to local variable s |
|
||||
| C.cs:114:22:114:36 | ... == ... | true | C.cs:114:22:114:28 | access to local variable colours | C.cs:114:33:114:36 | null |
|
||||
| C.cs:114:22:114:36 | ... == ... | true | C.cs:114:33:114:36 | null | C.cs:114:22:114:28 | access to local variable colours |
|
||||
| C.cs:114:41:114:59 | ... == ... | true | C.cs:114:41:114:54 | access to property Length | C.cs:114:59:114:59 | 0 |
|
||||
| C.cs:114:41:114:59 | ... == ... | true | C.cs:114:59:114:59 | 0 | C.cs:114:41:114:54 | access to property Length |
|
||||
| C.cs:121:13:121:28 | ... == ... | true | C.cs:121:13:121:20 | access to local variable children | C.cs:121:25:121:28 | null |
|
||||
| C.cs:121:13:121:28 | ... == ... | true | C.cs:121:25:121:28 | null | C.cs:121:13:121:20 | access to local variable children |
|
||||
| C.cs:130:13:130:38 | ... == ... | true | C.cs:130:14:130:29 | ... = ... | C.cs:130:35:130:38 | null |
|
||||
| C.cs:130:13:130:38 | ... == ... | true | C.cs:130:35:130:38 | null | C.cs:130:14:130:29 | ... = ... |
|
||||
| C.cs:146:13:146:39 | ... != ... | false | C.cs:146:14:146:30 | ... = ... | C.cs:146:36:146:39 | null |
|
||||
| C.cs:146:13:146:39 | ... != ... | false | C.cs:146:36:146:39 | null | C.cs:146:14:146:30 | ... = ... |
|
||||
| C.cs:158:16:158:24 | ... != ... | false | C.cs:158:16:158:16 | access to local variable s | C.cs:158:21:158:24 | null |
|
||||
| C.cs:158:16:158:24 | ... != ... | false | C.cs:158:21:158:24 | null | C.cs:158:16:158:16 | access to local variable s |
|
||||
| C.cs:166:16:166:24 | ... != ... | false | C.cs:166:16:166:16 | access to local variable s | C.cs:166:21:166:24 | null |
|
||||
| C.cs:166:16:166:24 | ... != ... | false | C.cs:166:21:166:24 | null | C.cs:166:16:166:16 | access to local variable s |
|
||||
| C.cs:173:16:173:24 | ... != ... | false | C.cs:173:16:173:16 | access to local variable s | C.cs:173:21:173:24 | null |
|
||||
| C.cs:173:16:173:24 | ... != ... | false | C.cs:173:21:173:24 | null | C.cs:173:16:173:16 | access to local variable s |
|
||||
| C.cs:187:16:187:24 | ... != ... | false | C.cs:187:16:187:16 | access to local variable s | C.cs:187:21:187:24 | null |
|
||||
| C.cs:187:16:187:24 | ... != ... | false | C.cs:187:21:187:24 | null | C.cs:187:16:187:16 | access to local variable s |
|
||||
| C.cs:212:13:212:21 | ... != ... | false | C.cs:212:13:212:13 | access to local variable s | C.cs:212:18:212:21 | null |
|
||||
| C.cs:212:13:212:21 | ... != ... | false | C.cs:212:18:212:21 | null | C.cs:212:13:212:13 | access to local variable s |
|
||||
| C.cs:218:13:218:21 | ... == ... | true | C.cs:218:13:218:13 | access to local variable s | C.cs:218:18:218:21 | null |
|
||||
| C.cs:218:13:218:21 | ... == ... | true | C.cs:218:18:218:21 | null | C.cs:218:13:218:13 | access to local variable s |
|
||||
| C.cs:222:13:222:21 | ... != ... | false | C.cs:222:13:222:13 | access to local variable s | C.cs:222:18:222:21 | null |
|
||||
| C.cs:222:13:222:21 | ... != ... | false | C.cs:222:18:222:21 | null | C.cs:222:13:222:13 | access to local variable s |
|
||||
| C.cs:222:26:222:42 | ... == ... | true | C.cs:222:26:222:37 | ... % ... | C.cs:222:42:222:42 | 0 |
|
||||
| C.cs:222:26:222:42 | ... == ... | true | C.cs:222:42:222:42 | 0 | C.cs:222:26:222:37 | ... % ... |
|
||||
| C.cs:230:22:230:30 | ... != ... | false | C.cs:230:22:230:22 | access to local variable s | C.cs:230:27:230:30 | null |
|
||||
| C.cs:230:22:230:30 | ... != ... | false | C.cs:230:27:230:30 | null | C.cs:230:22:230:22 | access to local variable s |
|
||||
| C.cs:236:24:236:32 | ... == ... | true | C.cs:236:24:236:24 | access to local variable s | C.cs:236:29:236:32 | null |
|
||||
| C.cs:236:24:236:32 | ... == ... | true | C.cs:236:29:236:32 | null | C.cs:236:24:236:24 | access to local variable s |
|
||||
| D.cs:28:13:28:25 | ... != ... | false | D.cs:28:13:28:17 | access to parameter param | D.cs:28:22:28:25 | null |
|
||||
| D.cs:28:13:28:25 | ... != ... | false | D.cs:28:22:28:25 | null | D.cs:28:13:28:17 | access to parameter param |
|
||||
| D.cs:38:13:38:21 | ... == ... | true | D.cs:38:13:38:13 | access to parameter x | D.cs:38:18:38:21 | null |
|
||||
| D.cs:38:13:38:21 | ... == ... | true | D.cs:38:18:38:21 | null | D.cs:38:13:38:13 | access to parameter x |
|
||||
| D.cs:39:16:39:24 | ... == ... | true | D.cs:39:16:39:16 | access to parameter x | D.cs:39:21:39:24 | null |
|
||||
| D.cs:39:16:39:24 | ... == ... | true | D.cs:39:21:39:24 | null | D.cs:39:16:39:16 | access to parameter x |
|
||||
| D.cs:45:13:45:22 | ... != ... | false | D.cs:45:13:45:14 | access to local variable o1 | D.cs:45:19:45:22 | null |
|
||||
| D.cs:45:13:45:22 | ... != ... | false | D.cs:45:19:45:22 | null | D.cs:45:13:45:14 | access to local variable o1 |
|
||||
| D.cs:51:13:51:44 | ... != ... | false | D.cs:51:14:51:35 | ... = ... | D.cs:51:41:51:44 | null |
|
||||
| D.cs:51:13:51:44 | ... != ... | false | D.cs:51:41:51:44 | null | D.cs:51:14:51:35 | ... = ... |
|
||||
| D.cs:55:13:55:42 | ... != ... | false | D.cs:55:14:55:32 | ... && ... | D.cs:55:38:55:42 | false |
|
||||
| D.cs:55:13:55:42 | ... != ... | false | D.cs:55:38:55:42 | false | D.cs:55:14:55:32 | ... && ... |
|
||||
| D.cs:55:23:55:32 | ... != ... | false | D.cs:55:23:55:24 | access to local variable o4 | D.cs:55:29:55:32 | null |
|
||||
| D.cs:55:23:55:32 | ... != ... | false | D.cs:55:29:55:32 | null | D.cs:55:23:55:24 | access to local variable o4 |
|
||||
| D.cs:58:19:58:28 | ... != ... | false | D.cs:58:19:58:20 | access to local variable o4 | D.cs:58:25:58:28 | null |
|
||||
| D.cs:58:19:58:28 | ... != ... | false | D.cs:58:25:58:28 | null | D.cs:58:19:58:20 | access to local variable o4 |
|
||||
| D.cs:59:13:59:22 | ... != ... | false | D.cs:59:13:59:14 | access to local variable o5 | D.cs:59:19:59:22 | null |
|
||||
| D.cs:59:13:59:22 | ... != ... | false | D.cs:59:19:59:22 | null | D.cs:59:13:59:14 | access to local variable o5 |
|
||||
| D.cs:61:13:61:22 | ... != ... | false | D.cs:61:13:61:14 | access to local variable o4 | D.cs:61:19:61:22 | null |
|
||||
| D.cs:61:13:61:22 | ... != ... | false | D.cs:61:19:61:22 | null | D.cs:61:13:61:14 | access to local variable o4 |
|
||||
| D.cs:69:18:69:27 | ... != ... | false | D.cs:69:18:69:19 | access to local variable o7 | D.cs:69:24:69:27 | null |
|
||||
| D.cs:69:18:69:27 | ... != ... | false | D.cs:69:24:69:27 | null | D.cs:69:18:69:19 | access to local variable o7 |
|
||||
| D.cs:76:21:76:30 | ... == ... | true | D.cs:76:21:76:22 | access to local variable o8 | D.cs:76:27:76:30 | null |
|
||||
| D.cs:76:21:76:30 | ... == ... | true | D.cs:76:27:76:30 | null | D.cs:76:21:76:22 | access to local variable o8 |
|
||||
| D.cs:77:13:77:22 | ... == ... | true | D.cs:77:13:77:17 | access to local variable track | D.cs:77:22:77:22 | 2 |
|
||||
| D.cs:77:13:77:22 | ... == ... | true | D.cs:77:22:77:22 | 2 | D.cs:77:13:77:17 | access to local variable track |
|
||||
| D.cs:79:13:79:23 | ... != ... | false | D.cs:79:13:79:17 | access to local variable track | D.cs:79:22:79:23 | 42 |
|
||||
| D.cs:79:13:79:23 | ... != ... | false | D.cs:79:22:79:23 | 42 | D.cs:79:13:79:17 | access to local variable track |
|
||||
| D.cs:110:26:110:35 | ... != ... | false | D.cs:110:26:110:27 | access to local variable xs | D.cs:110:32:110:35 | null |
|
||||
| D.cs:110:26:110:35 | ... != ... | false | D.cs:110:32:110:35 | null | D.cs:110:26:110:27 | access to local variable xs |
|
||||
| D.cs:118:13:118:21 | ... == ... | true | D.cs:118:13:118:13 | access to local variable x | D.cs:118:18:118:21 | null |
|
||||
| D.cs:118:13:118:21 | ... == ... | true | D.cs:118:18:118:21 | null | D.cs:118:13:118:13 | access to local variable x |
|
||||
| D.cs:119:13:119:21 | ... == ... | true | D.cs:119:13:119:13 | access to local variable x | D.cs:119:18:119:21 | null |
|
||||
| D.cs:119:13:119:21 | ... == ... | true | D.cs:119:18:119:21 | null | D.cs:119:13:119:13 | access to local variable x |
|
||||
| D.cs:127:20:127:28 | ... == ... | true | D.cs:127:20:127:20 | access to parameter a | D.cs:127:25:127:28 | null |
|
||||
| D.cs:127:20:127:28 | ... == ... | true | D.cs:127:25:127:28 | null | D.cs:127:20:127:20 | access to parameter a |
|
||||
| D.cs:128:20:128:28 | ... == ... | true | D.cs:128:20:128:20 | access to parameter b | D.cs:128:25:128:28 | null |
|
||||
| D.cs:128:20:128:28 | ... == ... | true | D.cs:128:25:128:28 | null | D.cs:128:20:128:20 | access to parameter b |
|
||||
| D.cs:130:13:130:24 | ... == ... | true | D.cs:130:13:130:16 | access to local variable alen | D.cs:130:21:130:24 | access to local variable blen |
|
||||
| D.cs:130:13:130:24 | ... == ... | true | D.cs:130:21:130:24 | access to local variable blen | D.cs:130:13:130:16 | access to local variable alen |
|
||||
| D.cs:139:13:139:21 | ... != ... | false | D.cs:139:13:139:13 | access to parameter a | D.cs:139:18:139:21 | null |
|
||||
| D.cs:139:13:139:21 | ... != ... | false | D.cs:139:18:139:21 | null | D.cs:139:13:139:13 | access to parameter a |
|
||||
| D.cs:152:17:152:27 | ... != ... | false | D.cs:152:17:152:19 | access to parameter obj | D.cs:152:24:152:27 | null |
|
||||
| D.cs:152:17:152:27 | ... != ... | false | D.cs:152:24:152:27 | null | D.cs:152:17:152:19 | access to parameter obj |
|
||||
| D.cs:196:13:196:21 | ... == ... | true | D.cs:196:13:196:13 | access to local variable o | D.cs:196:18:196:21 | null |
|
||||
| D.cs:196:13:196:21 | ... == ... | true | D.cs:196:18:196:21 | null | D.cs:196:13:196:13 | access to local variable o |
|
||||
| D.cs:206:17:206:25 | ... == ... | true | D.cs:206:17:206:17 | access to local variable e | D.cs:206:22:206:25 | null |
|
||||
| D.cs:206:17:206:25 | ... == ... | true | D.cs:206:22:206:25 | null | D.cs:206:17:206:17 | access to local variable e |
|
||||
| D.cs:212:18:212:26 | ... == ... | true | D.cs:212:18:212:18 | access to local variable n | D.cs:212:23:212:26 | null |
|
||||
| D.cs:212:18:212:26 | ... == ... | true | D.cs:212:23:212:26 | null | D.cs:212:18:212:18 | access to local variable n |
|
||||
| D.cs:216:13:216:22 | ... == ... | true | D.cs:216:13:216:14 | access to local variable o3 | D.cs:216:19:216:22 | null |
|
||||
| D.cs:216:13:216:22 | ... == ... | true | D.cs:216:19:216:22 | null | D.cs:216:13:216:14 | access to local variable o3 |
|
||||
| D.cs:221:13:221:22 | ... == ... | true | D.cs:221:13:221:14 | access to local variable o4 | D.cs:221:19:221:22 | null |
|
||||
| D.cs:221:13:221:22 | ... == ... | true | D.cs:221:19:221:22 | null | D.cs:221:13:221:14 | access to local variable o4 |
|
||||
| D.cs:242:13:242:25 | ... == ... | true | D.cs:242:13:242:17 | access to local variable other | D.cs:242:22:242:25 | null |
|
||||
| D.cs:242:13:242:25 | ... == ... | true | D.cs:242:22:242:25 | null | D.cs:242:13:242:17 | access to local variable other |
|
||||
| D.cs:244:13:244:25 | ... != ... | false | D.cs:244:13:244:17 | access to local variable other | D.cs:244:22:244:25 | null |
|
||||
| D.cs:244:13:244:25 | ... != ... | false | D.cs:244:22:244:25 | null | D.cs:244:13:244:17 | access to local variable other |
|
||||
| D.cs:274:17:274:26 | ... == ... | true | D.cs:274:17:274:20 | access to array element | D.cs:274:25:274:26 | 42 |
|
||||
| D.cs:274:17:274:26 | ... == ... | true | D.cs:274:25:274:26 | 42 | D.cs:274:17:274:20 | access to array element |
|
||||
| D.cs:299:17:299:22 | ... != ... | false | D.cs:299:17:299:17 | access to local variable i | D.cs:299:22:299:22 | 0 |
|
||||
| D.cs:299:17:299:22 | ... != ... | false | D.cs:299:22:299:22 | 0 | D.cs:299:17:299:17 | access to local variable i |
|
||||
| D.cs:318:16:318:36 | ... == ... | true | D.cs:318:16:318:19 | access to local variable stat | D.cs:318:24:318:36 | access to constant INIT |
|
||||
| D.cs:318:16:318:36 | ... == ... | true | D.cs:318:24:318:36 | access to constant INIT | D.cs:318:16:318:19 | access to local variable stat |
|
||||
| D.cs:318:41:318:62 | ... != ... | false | D.cs:318:41:318:44 | access to local variable stat | D.cs:318:49:318:62 | access to constant READY |
|
||||
| D.cs:318:41:318:62 | ... != ... | false | D.cs:318:49:318:62 | access to constant READY | D.cs:318:41:318:44 | access to local variable stat |
|
||||
| D.cs:321:17:321:37 | ... == ... | true | D.cs:321:17:321:20 | access to local variable stat | D.cs:321:25:321:37 | access to constant INIT |
|
||||
| D.cs:321:17:321:37 | ... == ... | true | D.cs:321:25:321:37 | access to constant INIT | D.cs:321:17:321:20 | access to local variable stat |
|
||||
| D.cs:336:13:336:23 | ... == ... | true | D.cs:336:13:336:15 | access to parameter obj | D.cs:336:20:336:23 | null |
|
||||
| D.cs:336:13:336:23 | ... == ... | true | D.cs:336:20:336:23 | null | D.cs:336:13:336:15 | access to parameter obj |
|
||||
| D.cs:341:13:341:23 | ... != ... | false | D.cs:341:13:341:15 | access to local variable msg | D.cs:341:20:341:23 | null |
|
||||
| D.cs:341:13:341:23 | ... != ... | false | D.cs:341:20:341:23 | null | D.cs:341:13:341:15 | access to local variable msg |
|
||||
| D.cs:367:27:367:35 | ... == ... | true | D.cs:367:27:367:27 | access to local variable b | D.cs:367:32:367:35 | null |
|
||||
| D.cs:367:27:367:35 | ... == ... | true | D.cs:367:32:367:35 | null | D.cs:367:27:367:27 | access to local variable b |
|
||||
| D.cs:382:13:382:23 | ... != ... | false | D.cs:382:13:382:15 | access to local variable ioe | D.cs:382:20:382:23 | null |
|
||||
| D.cs:382:13:382:23 | ... != ... | false | D.cs:382:20:382:23 | null | D.cs:382:13:382:15 | access to local variable ioe |
|
||||
| D.cs:390:20:390:28 | ... == ... | true | D.cs:390:20:390:20 | access to parameter a | D.cs:390:25:390:28 | null |
|
||||
| D.cs:390:20:390:28 | ... == ... | true | D.cs:390:25:390:28 | null | D.cs:390:20:390:20 | access to parameter a |
|
||||
| D.cs:397:20:397:28 | ... == ... | true | D.cs:397:20:397:20 | access to parameter b | D.cs:397:25:397:28 | null |
|
||||
| D.cs:397:20:397:28 | ... == ... | true | D.cs:397:25:397:28 | null | D.cs:397:20:397:20 | access to parameter b |
|
||||
| D.cs:407:14:407:22 | ... != ... | false | D.cs:407:14:407:14 | access to parameter x | D.cs:407:19:407:22 | null |
|
||||
| D.cs:407:14:407:22 | ... != ... | false | D.cs:407:19:407:22 | null | D.cs:407:14:407:14 | access to parameter x |
|
||||
| D.cs:407:27:407:35 | ... == ... | true | D.cs:407:27:407:27 | access to parameter y | D.cs:407:32:407:35 | null |
|
||||
| D.cs:407:27:407:35 | ... == ... | true | D.cs:407:32:407:35 | null | D.cs:407:27:407:27 | access to parameter y |
|
||||
| D.cs:407:42:407:50 | ... == ... | true | D.cs:407:42:407:42 | access to parameter x | D.cs:407:47:407:50 | null |
|
||||
| D.cs:407:42:407:50 | ... == ... | true | D.cs:407:47:407:50 | null | D.cs:407:42:407:42 | access to parameter x |
|
||||
| D.cs:407:55:407:63 | ... != ... | false | D.cs:407:55:407:55 | access to parameter y | D.cs:407:60:407:63 | null |
|
||||
| D.cs:407:55:407:63 | ... != ... | false | D.cs:407:60:407:63 | null | D.cs:407:55:407:55 | access to parameter y |
|
||||
| D.cs:409:13:409:21 | ... != ... | false | D.cs:409:13:409:13 | access to parameter x | D.cs:409:18:409:21 | null |
|
||||
| D.cs:409:13:409:21 | ... != ... | false | D.cs:409:18:409:21 | null | D.cs:409:13:409:13 | access to parameter x |
|
||||
| D.cs:411:13:411:21 | ... != ... | false | D.cs:411:13:411:13 | access to parameter y | D.cs:411:18:411:21 | null |
|
||||
| D.cs:411:13:411:21 | ... != ... | false | D.cs:411:18:411:21 | null | D.cs:411:13:411:13 | access to parameter y |
|
||||
| E.cs:10:34:10:54 | ... != ... | false | E.cs:10:35:10:45 | ... = ... | E.cs:10:51:10:54 | null |
|
||||
| E.cs:10:34:10:54 | ... != ... | false | E.cs:10:51:10:54 | null | E.cs:10:35:10:45 | ... = ... |
|
||||
| E.cs:12:32:12:52 | ... != ... | false | E.cs:12:33:12:43 | ... = ... | E.cs:12:49:12:52 | null |
|
||||
| E.cs:12:32:12:52 | ... != ... | false | E.cs:12:49:12:52 | null | E.cs:12:33:12:43 | ... = ... |
|
||||
| E.cs:20:19:20:28 | ... == ... | true | E.cs:20:19:20:20 | access to local variable s1 | E.cs:20:25:20:28 | null |
|
||||
| E.cs:20:19:20:28 | ... == ... | true | E.cs:20:25:20:28 | null | E.cs:20:19:20:20 | access to local variable s1 |
|
||||
| E.cs:21:13:21:22 | ... == ... | true | E.cs:21:13:21:14 | access to local variable s2 | E.cs:21:19:21:22 | null |
|
||||
| E.cs:21:13:21:22 | ... == ... | true | E.cs:21:19:21:22 | null | E.cs:21:13:21:14 | access to local variable s2 |
|
||||
| E.cs:24:19:24:28 | ... == ... | true | E.cs:24:19:24:20 | access to local variable s1 | E.cs:24:25:24:28 | null |
|
||||
| E.cs:24:19:24:28 | ... == ... | true | E.cs:24:25:24:28 | null | E.cs:24:19:24:20 | access to local variable s1 |
|
||||
| E.cs:26:13:26:22 | ... != ... | false | E.cs:26:13:26:14 | access to local variable s2 | E.cs:26:19:26:22 | null |
|
||||
| E.cs:26:13:26:22 | ... != ... | false | E.cs:26:19:26:22 | null | E.cs:26:13:26:14 | access to local variable s2 |
|
||||
| E.cs:56:17:56:33 | ... == ... | true | E.cs:56:17:56:28 | ... % ... | E.cs:56:33:56:33 | 0 |
|
||||
| E.cs:56:17:56:33 | ... == ... | true | E.cs:56:33:56:33 | 0 | E.cs:56:17:56:28 | ... % ... |
|
||||
| E.cs:70:22:70:32 | ... == ... | true | E.cs:70:22:70:24 | access to parameter arr | E.cs:70:29:70:32 | null |
|
||||
| E.cs:70:22:70:32 | ... == ... | true | E.cs:70:29:70:32 | null | E.cs:70:22:70:24 | access to parameter arr |
|
||||
| E.cs:83:13:83:24 | ... != ... | false | E.cs:83:13:83:16 | access to parameter vals | E.cs:83:21:83:24 | null |
|
||||
| E.cs:83:13:83:24 | ... != ... | false | E.cs:83:21:83:24 | null | E.cs:83:13:83:16 | access to parameter vals |
|
||||
| E.cs:85:18:85:29 | ... != ... | false | E.cs:85:18:85:21 | access to parameter vals | E.cs:85:26:85:29 | null |
|
||||
| E.cs:85:18:85:29 | ... != ... | false | E.cs:85:26:85:29 | null | E.cs:85:18:85:21 | access to parameter vals |
|
||||
| E.cs:90:17:90:27 | access to local variable switchguard | match case ...: | E.cs:90:17:90:27 | access to local variable switchguard | E.cs:92:18:92:27 | access to constant MY_CONST_A |
|
||||
| E.cs:90:17:90:27 | access to local variable switchguard | match case ...: | E.cs:90:17:90:27 | access to local variable switchguard | E.cs:95:18:95:27 | access to constant MY_CONST_C |
|
||||
| E.cs:90:17:90:27 | access to local variable switchguard | match case ...: | E.cs:90:17:90:27 | access to local variable switchguard | E.cs:97:18:97:27 | access to constant MY_CONST_B |
|
||||
| E.cs:126:21:126:29 | ... == ... | true | E.cs:126:21:126:24 | access to local variable step | E.cs:126:29:126:29 | 0 |
|
||||
| E.cs:126:21:126:29 | ... == ... | true | E.cs:126:29:126:29 | 0 | E.cs:126:21:126:24 | access to local variable step |
|
||||
| E.cs:153:13:153:24 | ... != ... | false | E.cs:153:13:153:16 | access to local variable obj2 | E.cs:153:21:153:24 | null |
|
||||
| E.cs:153:13:153:24 | ... != ... | false | E.cs:153:21:153:24 | null | E.cs:153:13:153:16 | access to local variable obj2 |
|
||||
| E.cs:164:17:164:25 | ... == ... | true | E.cs:164:17:164:17 | access to parameter a | E.cs:164:22:164:25 | null |
|
||||
| E.cs:164:17:164:25 | ... == ... | true | E.cs:164:22:164:25 | null | E.cs:164:17:164:17 | access to parameter a |
|
||||
| E.cs:175:19:175:29 | ... == ... | true | E.cs:175:19:175:21 | access to parameter obj | E.cs:175:26:175:29 | null |
|
||||
| E.cs:175:19:175:29 | ... == ... | true | E.cs:175:26:175:29 | null | E.cs:175:19:175:21 | access to parameter obj |
|
||||
| E.cs:176:13:176:22 | ... == ... | true | E.cs:176:13:176:14 | (...) ... | E.cs:176:19:176:22 | null |
|
||||
| E.cs:176:13:176:22 | ... == ... | true | E.cs:176:19:176:22 | null | E.cs:176:13:176:14 | (...) ... |
|
||||
| E.cs:180:13:180:23 | ... == ... | true | E.cs:180:13:180:15 | access to parameter obj | E.cs:180:20:180:23 | null |
|
||||
| E.cs:180:13:180:23 | ... == ... | true | E.cs:180:20:180:23 | null | E.cs:180:13:180:15 | access to parameter obj |
|
||||
| E.cs:184:13:184:22 | ... == ... | true | E.cs:184:13:184:14 | (...) ... | E.cs:184:19:184:22 | null |
|
||||
| E.cs:184:13:184:22 | ... == ... | true | E.cs:184:19:184:22 | null | E.cs:184:13:184:14 | (...) ... |
|
||||
| E.cs:252:13:252:21 | ... != ... | false | E.cs:252:13:252:13 | access to parameter i | E.cs:252:18:252:21 | null |
|
||||
| E.cs:252:13:252:21 | ... != ... | false | E.cs:252:18:252:21 | null | E.cs:252:13:252:13 | access to parameter i |
|
||||
| E.cs:259:13:259:21 | ... == ... | true | E.cs:259:13:259:13 | access to parameter i | E.cs:259:18:259:21 | null |
|
||||
| E.cs:259:13:259:21 | ... == ... | true | E.cs:259:18:259:21 | null | E.cs:259:13:259:13 | access to parameter i |
|
||||
| Forwarding.cs:59:13:59:21 | ... == ... | true | Forwarding.cs:59:13:59:13 | access to parameter o | Forwarding.cs:59:18:59:21 | null |
|
||||
| Forwarding.cs:59:13:59:21 | ... == ... | true | Forwarding.cs:59:18:59:21 | null | Forwarding.cs:59:13:59:13 | access to parameter o |
|
||||
| Forwarding.cs:78:16:78:39 | call to method ReferenceEquals | true | Forwarding.cs:78:32:78:32 | access to parameter o | Forwarding.cs:78:35:78:38 | null |
|
||||
| Forwarding.cs:78:16:78:39 | call to method ReferenceEquals | true | Forwarding.cs:78:35:78:38 | null | Forwarding.cs:78:32:78:32 | access to parameter o |
|
||||
| Forwarding.cs:83:16:83:24 | ... != ... | false | Forwarding.cs:83:16:83:16 | access to parameter o | Forwarding.cs:83:21:83:24 | null |
|
||||
| Forwarding.cs:83:16:83:24 | ... != ... | false | Forwarding.cs:83:21:83:24 | null | Forwarding.cs:83:16:83:16 | access to parameter o |
|
||||
| GuardedString.cs:19:13:19:26 | ... == ... | true | GuardedString.cs:19:15:19:21 | access to property Length | GuardedString.cs:19:26:19:26 | (...) ... |
|
||||
| GuardedString.cs:19:13:19:26 | ... == ... | true | GuardedString.cs:19:26:19:26 | (...) ... | GuardedString.cs:19:15:19:21 | access to property Length |
|
||||
| GuardedString.cs:34:13:34:26 | ... != ... | false | GuardedString.cs:34:15:34:21 | access to property Length | GuardedString.cs:34:26:34:26 | (...) ... |
|
||||
| GuardedString.cs:34:13:34:26 | ... != ... | false | GuardedString.cs:34:26:34:26 | (...) ... | GuardedString.cs:34:15:34:21 | access to property Length |
|
||||
| NullAlwaysBad.cs:9:17:9:25 | ... != ... | false | NullAlwaysBad.cs:9:17:9:17 | access to parameter s | NullAlwaysBad.cs:9:22:9:25 | null |
|
||||
| NullAlwaysBad.cs:9:17:9:25 | ... != ... | false | NullAlwaysBad.cs:9:22:9:25 | null | NullAlwaysBad.cs:9:17:9:17 | access to parameter s |
|
||||
| NullAlwaysGood.cs:9:17:9:25 | ... != ... | false | NullAlwaysGood.cs:9:17:9:17 | access to parameter s | NullAlwaysGood.cs:9:22:9:25 | null |
|
||||
| NullAlwaysGood.cs:9:17:9:25 | ... != ... | false | NullAlwaysGood.cs:9:22:9:25 | null | NullAlwaysGood.cs:9:17:9:17 | access to parameter s |
|
||||
| NullMaybeGood.cs:9:17:9:25 | ... != ... | false | NullMaybeGood.cs:9:17:9:17 | access to parameter o | NullMaybeGood.cs:9:22:9:25 | null |
|
||||
| NullMaybeGood.cs:9:17:9:25 | ... != ... | false | NullMaybeGood.cs:9:22:9:25 | null | NullMaybeGood.cs:9:17:9:17 | access to parameter o |
|
||||
| StringConcatenation.cs:15:16:15:22 | ... != ... | false | StringConcatenation.cs:15:16:15:16 | access to local variable s | StringConcatenation.cs:15:21:15:22 | "" |
|
||||
| StringConcatenation.cs:15:16:15:22 | ... != ... | false | StringConcatenation.cs:15:21:15:22 | "" | StringConcatenation.cs:15:16:15:16 | access to local variable s |
|
||||
| StringConcatenation.cs:22:16:22:22 | ... != ... | false | StringConcatenation.cs:22:16:22:16 | access to local variable s | StringConcatenation.cs:22:21:22:22 | "" |
|
||||
| StringConcatenation.cs:22:16:22:22 | ... != ... | false | StringConcatenation.cs:22:21:22:22 | "" | StringConcatenation.cs:22:16:22:16 | access to local variable s |
|
|
@ -0,0 +1,5 @@
|
|||
import csharp
|
||||
import semmle.code.csharp.controlflow.Guards
|
||||
|
||||
from Expr e1, AbstractValue v, Expr e2
|
||||
select Internal::getAnEqualityCheck(e1, v, e2), v, e1, e2
|
|
@ -8,36 +8,36 @@ class ForwardingTests
|
|||
|
||||
if (!s.IsNullOrEmpty())
|
||||
{
|
||||
Console.WriteLine(s.Length);
|
||||
Console.WriteLine(s.Length); // GOOD
|
||||
}
|
||||
|
||||
if (s.IsNotNullOrEmpty())
|
||||
{
|
||||
Console.WriteLine(s.Length);
|
||||
Console.WriteLine(s.Length); // GOOD
|
||||
}
|
||||
|
||||
if (!s.IsNull())
|
||||
{
|
||||
Console.WriteLine(s.Length);
|
||||
Console.WriteLine(s.Length); // GOOD
|
||||
}
|
||||
|
||||
if (s.IsNotNull())
|
||||
{
|
||||
Console.WriteLine(s.Length);
|
||||
Console.WriteLine(s.Length); // GOOD
|
||||
}
|
||||
|
||||
if (IsNotNull(s))
|
||||
{
|
||||
Console.WriteLine(s.Length);
|
||||
Console.WriteLine(s.Length); // GOOD
|
||||
}
|
||||
|
||||
if (IsNotNullWrong(s))
|
||||
{
|
||||
Console.WriteLine(s.Length); // maybe null
|
||||
Console.WriteLine(s.Length); // BAD (always)
|
||||
}
|
||||
|
||||
AssertIsNotNull(s);
|
||||
Console.WriteLine(s.Length); // FP; not currently handled
|
||||
Console.WriteLine(s.Length); // GOOD (false positive)
|
||||
}
|
||||
|
||||
bool IsNotNull(object o)
|
||||
|
|
|
@ -2,9 +2,9 @@ using System;
|
|||
|
||||
class GuardedStringTest
|
||||
{
|
||||
void Fn()
|
||||
void Fn(bool b)
|
||||
{
|
||||
string s = null;
|
||||
string s = b ? null : "";
|
||||
|
||||
if (!string.IsNullOrEmpty(s))
|
||||
{
|
||||
|
@ -17,23 +17,23 @@ class GuardedStringTest
|
|||
}
|
||||
|
||||
if (s?.Length == 0)
|
||||
Console.WriteLine(s.Length); // null guarded
|
||||
Console.WriteLine(s.Length); // GOOD
|
||||
|
||||
if (s?.Length > 0)
|
||||
Console.WriteLine(s.Length); // null guarded
|
||||
Console.WriteLine(s.Length); // GOOD
|
||||
|
||||
if (s?.Length >= 0)
|
||||
Console.WriteLine(s.Length); // null guarded
|
||||
Console.WriteLine(s.Length); // GOOD
|
||||
|
||||
if (s?.Length < 10)
|
||||
Console.WriteLine(s.Length); // null guarded
|
||||
Console.WriteLine(s.Length); // GOOD
|
||||
|
||||
if (s?.Length <= 10)
|
||||
Console.WriteLine(s.Length); // null guarded
|
||||
Console.WriteLine(s.Length); // GOOD
|
||||
|
||||
if (s?.Length != 0)
|
||||
Console.WriteLine(s.Length); // not null guarded
|
||||
Console.WriteLine(s.Length); // BAD (maybe)
|
||||
else
|
||||
Console.WriteLine(s.Length); // null guarded
|
||||
Console.WriteLine(s.Length); // GOOD
|
||||
}
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,6 @@
|
|||
import csharp
|
||||
import semmle.code.csharp.controlflow.Guards
|
||||
|
||||
query predicate impliesStep(Expr e1, AbstractValue v1, Expr e2, AbstractValue v2) {
|
||||
Internal::impliesStep(e1, v1, e2, v2)
|
||||
}
|
|
@ -1,17 +1,38 @@
|
|||
| A.cs:15:13:15:15 | access to local variable not | Variable $@ is always null here. | A.cs:12:16:12:18 | not | not |
|
||||
| A.cs:30:15:30:33 | access to local variable synchronized_always | Variable $@ is always null here. | A.cs:29:16:29:34 | synchronized_always | synchronized_always |
|
||||
| A.cs:77:31:77:39 | access to local variable do_always | Variable $@ is always null here. | A.cs:74:16:74:24 | do_always | do_always |
|
||||
| A.cs:111:31:111:42 | access to local variable while_always | Variable $@ is always null here. | A.cs:108:16:108:27 | while_always | while_always |
|
||||
| A.cs:129:9:129:18 | access to local variable array_null | Variable $@ is always null here. | A.cs:128:15:128:24 | array_null | array_null |
|
||||
| A.cs:149:31:149:39 | access to local variable if_always | Variable $@ is always null here. | A.cs:146:16:146:24 | if_always | if_always |
|
||||
| A.cs:169:27:169:32 | access to local variable for_ok | Variable $@ is always null here. | A.cs:163:16:163:21 | for_ok | for_ok |
|
||||
| A.cs:174:31:174:40 | access to local variable for_always | Variable $@ is always null here. | A.cs:172:21:172:30 | for_always | for_always |
|
||||
| A.cs:191:27:191:37 | access to local variable arrayaccess | Variable $@ is always null here. | A.cs:186:15:186:25 | arrayaccess | arrayaccess |
|
||||
| A.cs:192:27:192:37 | access to local variable fieldaccess | Variable $@ is always null here. | A.cs:187:18:187:28 | fieldaccess | fieldaccess |
|
||||
| A.cs:193:28:193:39 | access to local variable methodaccess | Variable $@ is always null here. | A.cs:188:16:188:27 | methodaccess | methodaccess |
|
||||
| A.cs:194:27:194:36 | access to local variable methodcall | Variable $@ is always null here. | A.cs:189:16:189:25 | methodcall | methodcall |
|
||||
| A.cs:247:31:247:44 | access to local variable eq_call_always | Variable $@ is always null here. | A.cs:241:11:241:24 | eq_call_always | eq_call_always |
|
||||
| A.cs:258:31:258:45 | access to local variable neq_call_always | Variable $@ is always null here. | A.cs:244:11:244:25 | neq_call_always | neq_call_always |
|
||||
| A.cs:8:15:8:32 | access to local variable synchronizedAlways | Variable $@ is always null here. | A.cs:7:16:7:33 | synchronizedAlways | synchronizedAlways |
|
||||
| A.cs:17:9:17:17 | access to local variable arrayNull | Variable $@ is always null here. | A.cs:16:15:16:23 | arrayNull | arrayNull |
|
||||
| A.cs:31:27:31:37 | access to local variable arrayAccess | Variable $@ is always null here. | A.cs:26:15:26:25 | arrayAccess | arrayAccess |
|
||||
| A.cs:32:27:32:37 | access to local variable fieldAccess | Variable $@ is always null here. | A.cs:27:18:27:28 | fieldAccess | fieldAccess |
|
||||
| A.cs:33:28:33:39 | access to local variable methodAccess | Variable $@ is always null here. | A.cs:28:16:28:27 | methodAccess | methodAccess |
|
||||
| A.cs:34:27:34:36 | access to local variable methodCall | Variable $@ is always null here. | A.cs:29:16:29:25 | methodCall | methodCall |
|
||||
| A.cs:50:9:50:14 | access to local variable varRef | Variable $@ is always null here. | A.cs:48:16:48:21 | varRef | varRef |
|
||||
| Assert.cs:15:27:15:27 | access to local variable s | Variable $@ is always null here. | Assert.cs:9:16:9:16 | s | s |
|
||||
| Assert.cs:23:27:23:27 | access to local variable s | Variable $@ is always null here. | Assert.cs:9:16:9:16 | s | s |
|
||||
| Assert.cs:31:27:31:27 | access to local variable s | Variable $@ is always null here. | Assert.cs:9:16:9:16 | s | s |
|
||||
| Assert.cs:47:27:47:27 | access to local variable s | Variable $@ is always null here. | Assert.cs:9:16:9:16 | s | s |
|
||||
| Assert.cs:51:27:51:27 | access to local variable s | Variable $@ is always null here. | Assert.cs:9:16:9:16 | s | s |
|
||||
| B.cs:13:13:13:24 | access to local variable eqCallAlways | Variable $@ is always null here. | B.cs:7:11:7:22 | eqCallAlways | eqCallAlways |
|
||||
| B.cs:24:13:24:25 | access to local variable neqCallAlways | Variable $@ is always null here. | B.cs:10:11:10:23 | neqCallAlways | neqCallAlways |
|
||||
| C.cs:18:13:18:13 | access to local variable o | Variable $@ is always null here. | C.cs:10:16:10:16 | o | o |
|
||||
| C.cs:42:9:42:9 | access to local variable s | Variable $@ is always null here. | C.cs:40:13:40:13 | s | s |
|
||||
| C.cs:57:9:57:10 | access to local variable o2 | Variable $@ is always null here. | C.cs:55:13:55:14 | o2 | o2 |
|
||||
| C.cs:163:13:163:13 | access to local variable s | Variable $@ is always null here. | C.cs:152:13:152:13 | s | s |
|
||||
| C.cs:171:13:171:13 | access to local variable s | Variable $@ is always null here. | C.cs:152:13:152:13 | s | s |
|
||||
| C.cs:197:13:197:13 | access to local variable s | Variable $@ is always null here. | C.cs:186:13:186:13 | s | s |
|
||||
| C.cs:219:13:219:13 | access to local variable s | Variable $@ is always null here. | C.cs:211:13:211:13 | s | s |
|
||||
| C.cs:234:9:234:9 | access to local variable s | Variable $@ is always null here. | C.cs:229:16:229:16 | s | s |
|
||||
| C.cs:238:13:238:13 | access to local variable s | Variable $@ is always null here. | C.cs:229:16:229:16 | s | s |
|
||||
| C.cs:250:9:250:9 | access to local variable a | Variable $@ is always null here. | C.cs:249:15:249:15 | a | a |
|
||||
| C.cs:261:9:261:10 | access to local variable ia | Variable $@ is always null here. | C.cs:258:15:258:16 | ia | ia |
|
||||
| C.cs:262:20:262:21 | access to local variable sa | Variable $@ is always null here. | C.cs:259:18:259:19 | sa | sa |
|
||||
| D.cs:120:13:120:13 | access to local variable x | Variable $@ is always null here. | D.cs:117:13:117:13 | x | x |
|
||||
| D.cs:197:13:197:13 | access to local variable o | Variable $@ is always null here. | D.cs:195:13:195:13 | o | o |
|
||||
| D.cs:207:17:207:17 | access to local variable e | Variable $@ is always null here. | D.cs:204:26:204:26 | e | e |
|
||||
| D.cs:217:13:217:14 | access to local variable o3 | Variable $@ is always null here. | D.cs:215:13:215:14 | o3 | o3 |
|
||||
| D.cs:222:13:222:14 | access to local variable o4 | Variable $@ is always null here. | D.cs:220:13:220:14 | o4 | o4 |
|
||||
| D.cs:385:13:385:15 | access to local variable ioe | Variable $@ is always null here. | D.cs:378:19:378:21 | ioe | ioe |
|
||||
| E.cs:210:16:210:16 | access to parameter s | Variable $@ is always null here. | E.cs:206:28:206:28 | s | s |
|
||||
| E.cs:220:13:220:13 | access to local variable x | Variable $@ is always null here. | E.cs:215:13:215:13 | x | x |
|
||||
| E.cs:229:13:229:13 | access to local variable x | Variable $@ is always null here. | E.cs:225:13:225:13 | x | x |
|
||||
| Forwarding.cs:36:31:36:31 | access to local variable s | Variable $@ is always null here. | Forwarding.cs:7:16:7:16 | s | s |
|
||||
| Forwarding.cs:40:27:40:27 | access to local variable s | Variable $@ is always null here. | Forwarding.cs:7:16:7:16 | s | s |
|
||||
| NullAlwaysBad.cs:9:30:9:30 | access to parameter s | Variable $@ is always null here. | NullAlwaysBad.cs:7:29:7:29 | s | s |
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
|
||||
namespace NullAlways
|
||||
{
|
||||
class Bad
|
||||
{
|
||||
void DoPrint(string s)
|
||||
{
|
||||
if (s != null || s.Length > 0)
|
||||
Console.WriteLine(s);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
|
||||
namespace NullAlways
|
||||
{
|
||||
class Good
|
||||
{
|
||||
void DoPrint(string s)
|
||||
{
|
||||
if (s != null && s.Length > 0)
|
||||
Console.WriteLine(s);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,245 @@
|
|||
| Assert.cs:10:22:10:30 | ... != ... | Assert.cs:10:22:10:22 | access to local variable s | false | true |
|
||||
| Assert.cs:10:22:10:30 | ... != ... | Assert.cs:10:22:10:22 | access to local variable s | true | false |
|
||||
| Assert.cs:22:23:22:31 | ... == ... | Assert.cs:22:23:22:23 | access to local variable s | false | false |
|
||||
| Assert.cs:22:23:22:31 | ... == ... | Assert.cs:22:23:22:23 | access to local variable s | true | true |
|
||||
| Assert.cs:26:23:26:31 | ... != ... | Assert.cs:26:23:26:23 | access to local variable s | false | true |
|
||||
| Assert.cs:26:23:26:31 | ... != ... | Assert.cs:26:23:26:23 | access to local variable s | true | false |
|
||||
| Assert.cs:30:24:30:32 | ... != ... | Assert.cs:30:24:30:24 | access to local variable s | false | true |
|
||||
| Assert.cs:30:24:30:32 | ... != ... | Assert.cs:30:24:30:24 | access to local variable s | true | false |
|
||||
| Assert.cs:34:24:34:32 | ... == ... | Assert.cs:34:24:34:24 | access to local variable s | false | false |
|
||||
| Assert.cs:34:24:34:32 | ... == ... | Assert.cs:34:24:34:24 | access to local variable s | true | true |
|
||||
| Assert.cs:38:23:38:31 | ... != ... | Assert.cs:38:23:38:23 | access to local variable s | false | true |
|
||||
| Assert.cs:38:23:38:31 | ... != ... | Assert.cs:38:23:38:23 | access to local variable s | true | false |
|
||||
| Assert.cs:42:24:42:32 | ... == ... | Assert.cs:42:24:42:24 | access to local variable s | false | false |
|
||||
| Assert.cs:42:24:42:32 | ... == ... | Assert.cs:42:24:42:24 | access to local variable s | true | true |
|
||||
| Assert.cs:46:23:46:31 | ... == ... | Assert.cs:46:23:46:23 | access to local variable s | false | false |
|
||||
| Assert.cs:46:23:46:31 | ... == ... | Assert.cs:46:23:46:23 | access to local variable s | true | true |
|
||||
| Assert.cs:50:24:50:32 | ... != ... | Assert.cs:50:24:50:24 | access to local variable s | false | true |
|
||||
| Assert.cs:50:24:50:32 | ... != ... | Assert.cs:50:24:50:24 | access to local variable s | true | false |
|
||||
| B.cs:12:13:12:32 | call to operator == | B.cs:12:13:12:24 | access to local variable eqCallAlways | false | false |
|
||||
| B.cs:12:13:12:32 | call to operator == | B.cs:12:13:12:24 | access to local variable eqCallAlways | true | true |
|
||||
| B.cs:15:13:15:22 | call to operator != | B.cs:15:13:15:14 | access to local variable b2 | false | true |
|
||||
| B.cs:15:13:15:22 | call to operator != | B.cs:15:13:15:14 | access to local variable b2 | true | false |
|
||||
| B.cs:18:13:18:22 | call to operator == | B.cs:18:13:18:14 | access to local variable b3 | false | false |
|
||||
| B.cs:18:13:18:22 | call to operator == | B.cs:18:13:18:14 | access to local variable b3 | true | true |
|
||||
| B.cs:22:13:22:33 | call to operator != | B.cs:22:13:22:25 | access to local variable neqCallAlways | false | true |
|
||||
| B.cs:22:13:22:33 | call to operator != | B.cs:22:13:22:25 | access to local variable neqCallAlways | true | false |
|
||||
| B.cs:53:17:53:33 | ... != ... | B.cs:53:17:53:25 | (...) ... | false | true |
|
||||
| B.cs:53:17:53:33 | ... != ... | B.cs:53:17:53:25 | (...) ... | true | false |
|
||||
| C.cs:11:19:11:27 | ... == ... | C.cs:11:19:11:19 | access to local variable o | false | false |
|
||||
| C.cs:11:19:11:27 | ... == ... | C.cs:11:19:11:19 | access to local variable o | true | true |
|
||||
| C.cs:16:15:16:23 | ... != ... | C.cs:16:15:16:15 | access to local variable o | false | true |
|
||||
| C.cs:16:15:16:23 | ... != ... | C.cs:16:15:16:15 | access to local variable o | true | false |
|
||||
| C.cs:24:13:24:21 | ... != ... | C.cs:24:13:24:13 | access to parameter o | false | true |
|
||||
| C.cs:24:13:24:21 | ... != ... | C.cs:24:13:24:13 | access to parameter o | true | false |
|
||||
| C.cs:28:37:28:45 | ... == ... | C.cs:28:37:28:37 | access to parameter o | false | false |
|
||||
| C.cs:28:37:28:45 | ... == ... | C.cs:28:37:28:37 | access to parameter o | true | true |
|
||||
| C.cs:30:40:30:48 | ... != ... | C.cs:30:40:30:40 | access to parameter o | false | true |
|
||||
| C.cs:30:40:30:48 | ... != ... | C.cs:30:40:30:40 | access to parameter o | true | false |
|
||||
| C.cs:34:13:34:21 | ... == ... | C.cs:34:13:34:13 | access to parameter o | false | false |
|
||||
| C.cs:34:13:34:21 | ... == ... | C.cs:34:13:34:13 | access to parameter o | true | true |
|
||||
| C.cs:41:22:41:30 | ... == ... | C.cs:41:22:41:22 | access to local variable s | false | false |
|
||||
| C.cs:41:22:41:30 | ... == ... | C.cs:41:22:41:22 | access to local variable s | true | true |
|
||||
| C.cs:45:22:45:30 | ... != ... | C.cs:45:22:45:22 | access to local variable s | false | true |
|
||||
| C.cs:45:22:45:30 | ... != ... | C.cs:45:22:45:22 | access to local variable s | true | false |
|
||||
| C.cs:78:13:78:24 | call to method IsNotNull | C.cs:78:23:78:23 | access to local variable o | false | true |
|
||||
| C.cs:78:13:78:24 | call to method IsNotNull | C.cs:78:23:78:23 | access to local variable o | true | false |
|
||||
| C.cs:82:14:82:22 | call to method IsNull | C.cs:82:21:82:21 | access to local variable o | false | false |
|
||||
| C.cs:82:14:82:22 | call to method IsNull | C.cs:82:21:82:21 | access to local variable o | true | true |
|
||||
| C.cs:89:13:89:23 | ... is ... | C.cs:89:13:89:13 | access to local variable o | true | false |
|
||||
| C.cs:114:22:114:36 | ... == ... | C.cs:114:22:114:28 | access to local variable colours | false | false |
|
||||
| C.cs:114:22:114:36 | ... == ... | C.cs:114:22:114:28 | access to local variable colours | true | true |
|
||||
| C.cs:121:13:121:28 | ... == ... | C.cs:121:13:121:20 | access to local variable children | false | false |
|
||||
| C.cs:121:13:121:28 | ... == ... | C.cs:121:13:121:20 | access to local variable children | true | true |
|
||||
| C.cs:130:13:130:38 | ... == ... | C.cs:130:14:130:29 | ... = ... | false | false |
|
||||
| C.cs:130:13:130:38 | ... == ... | C.cs:130:14:130:29 | ... = ... | true | true |
|
||||
| C.cs:146:13:146:39 | ... != ... | C.cs:146:14:146:30 | ... = ... | false | true |
|
||||
| C.cs:146:13:146:39 | ... != ... | C.cs:146:14:146:30 | ... = ... | true | false |
|
||||
| C.cs:158:16:158:24 | ... != ... | C.cs:158:16:158:16 | access to local variable s | false | true |
|
||||
| C.cs:158:16:158:24 | ... != ... | C.cs:158:16:158:16 | access to local variable s | true | false |
|
||||
| C.cs:166:16:166:24 | ... != ... | C.cs:166:16:166:16 | access to local variable s | false | true |
|
||||
| C.cs:166:16:166:24 | ... != ... | C.cs:166:16:166:16 | access to local variable s | true | false |
|
||||
| C.cs:173:16:173:24 | ... != ... | C.cs:173:16:173:16 | access to local variable s | false | true |
|
||||
| C.cs:173:16:173:24 | ... != ... | C.cs:173:16:173:16 | access to local variable s | true | false |
|
||||
| C.cs:187:16:187:24 | ... != ... | C.cs:187:16:187:16 | access to local variable s | false | true |
|
||||
| C.cs:187:16:187:24 | ... != ... | C.cs:187:16:187:16 | access to local variable s | true | false |
|
||||
| C.cs:212:13:212:21 | ... != ... | C.cs:212:13:212:13 | access to local variable s | false | true |
|
||||
| C.cs:212:13:212:21 | ... != ... | C.cs:212:13:212:13 | access to local variable s | true | false |
|
||||
| C.cs:218:13:218:21 | ... == ... | C.cs:218:13:218:13 | access to local variable s | false | false |
|
||||
| C.cs:218:13:218:21 | ... == ... | C.cs:218:13:218:13 | access to local variable s | true | true |
|
||||
| C.cs:222:13:222:21 | ... != ... | C.cs:222:13:222:13 | access to local variable s | false | true |
|
||||
| C.cs:222:13:222:21 | ... != ... | C.cs:222:13:222:13 | access to local variable s | true | false |
|
||||
| C.cs:230:22:230:30 | ... != ... | C.cs:230:22:230:22 | access to local variable s | false | true |
|
||||
| C.cs:230:22:230:30 | ... != ... | C.cs:230:22:230:22 | access to local variable s | true | false |
|
||||
| C.cs:236:24:236:32 | ... == ... | C.cs:236:24:236:24 | access to local variable s | false | false |
|
||||
| C.cs:236:24:236:32 | ... == ... | C.cs:236:24:236:24 | access to local variable s | true | true |
|
||||
| D.cs:28:13:28:25 | ... != ... | D.cs:28:13:28:17 | access to parameter param | false | true |
|
||||
| D.cs:28:13:28:25 | ... != ... | D.cs:28:13:28:17 | access to parameter param | true | false |
|
||||
| D.cs:37:13:37:23 | ... is ... | D.cs:37:13:37:13 | access to parameter x | true | false |
|
||||
| D.cs:38:13:38:21 | ... == ... | D.cs:38:13:38:13 | access to parameter x | false | false |
|
||||
| D.cs:38:13:38:21 | ... == ... | D.cs:38:13:38:13 | access to parameter x | true | true |
|
||||
| D.cs:39:16:39:24 | ... == ... | D.cs:39:16:39:16 | access to parameter x | false | false |
|
||||
| D.cs:39:16:39:24 | ... == ... | D.cs:39:16:39:16 | access to parameter x | true | true |
|
||||
| D.cs:45:13:45:22 | ... != ... | D.cs:45:13:45:14 | access to local variable o1 | false | true |
|
||||
| D.cs:45:13:45:22 | ... != ... | D.cs:45:13:45:14 | access to local variable o1 | true | false |
|
||||
| D.cs:48:13:48:24 | ... is ... | D.cs:48:13:48:14 | access to local variable o2 | false | true |
|
||||
| D.cs:48:13:48:24 | ... is ... | D.cs:48:13:48:14 | access to local variable o2 | true | false |
|
||||
| D.cs:51:13:51:44 | ... != ... | D.cs:51:14:51:35 | ... = ... | false | true |
|
||||
| D.cs:51:13:51:44 | ... != ... | D.cs:51:14:51:35 | ... = ... | true | false |
|
||||
| D.cs:55:23:55:32 | ... != ... | D.cs:55:23:55:24 | access to local variable o4 | false | true |
|
||||
| D.cs:55:23:55:32 | ... != ... | D.cs:55:23:55:24 | access to local variable o4 | true | false |
|
||||
| D.cs:58:19:58:28 | ... != ... | D.cs:58:19:58:20 | access to local variable o4 | false | true |
|
||||
| D.cs:58:19:58:28 | ... != ... | D.cs:58:19:58:20 | access to local variable o4 | true | false |
|
||||
| D.cs:59:13:59:22 | ... != ... | D.cs:59:13:59:14 | access to local variable o5 | false | true |
|
||||
| D.cs:59:13:59:22 | ... != ... | D.cs:59:13:59:14 | access to local variable o5 | true | false |
|
||||
| D.cs:61:13:61:22 | ... != ... | D.cs:61:13:61:14 | access to local variable o4 | false | true |
|
||||
| D.cs:61:13:61:22 | ... != ... | D.cs:61:13:61:14 | access to local variable o4 | true | false |
|
||||
| D.cs:65:14:65:29 | call to method CustomIsNull | D.cs:65:27:65:28 | access to local variable o6 | false | false |
|
||||
| D.cs:65:14:65:29 | call to method CustomIsNull | D.cs:65:27:65:28 | access to local variable o6 | true | true |
|
||||
| D.cs:69:18:69:27 | ... != ... | D.cs:69:18:69:19 | access to local variable o7 | false | true |
|
||||
| D.cs:69:18:69:27 | ... != ... | D.cs:69:18:69:19 | access to local variable o7 | true | false |
|
||||
| D.cs:76:21:76:30 | ... == ... | D.cs:76:21:76:22 | access to local variable o8 | false | false |
|
||||
| D.cs:76:21:76:30 | ... == ... | D.cs:76:21:76:22 | access to local variable o8 | true | true |
|
||||
| D.cs:110:26:110:35 | ... != ... | D.cs:110:26:110:27 | access to local variable xs | false | true |
|
||||
| D.cs:110:26:110:35 | ... != ... | D.cs:110:26:110:27 | access to local variable xs | true | false |
|
||||
| D.cs:118:13:118:21 | ... == ... | D.cs:118:13:118:13 | access to local variable x | false | false |
|
||||
| D.cs:118:13:118:21 | ... == ... | D.cs:118:13:118:13 | access to local variable x | true | true |
|
||||
| D.cs:119:13:119:21 | ... == ... | D.cs:119:13:119:13 | access to local variable x | false | false |
|
||||
| D.cs:119:13:119:21 | ... == ... | D.cs:119:13:119:13 | access to local variable x | true | true |
|
||||
| D.cs:127:20:127:28 | ... == ... | D.cs:127:20:127:20 | access to parameter a | false | false |
|
||||
| D.cs:127:20:127:28 | ... == ... | D.cs:127:20:127:20 | access to parameter a | true | true |
|
||||
| D.cs:128:20:128:28 | ... == ... | D.cs:128:20:128:20 | access to parameter b | false | false |
|
||||
| D.cs:128:20:128:28 | ... == ... | D.cs:128:20:128:20 | access to parameter b | true | true |
|
||||
| D.cs:139:13:139:21 | ... != ... | D.cs:139:13:139:13 | access to parameter a | false | true |
|
||||
| D.cs:139:13:139:21 | ... != ... | D.cs:139:13:139:13 | access to parameter a | true | false |
|
||||
| D.cs:152:17:152:27 | ... != ... | D.cs:152:17:152:19 | access to parameter obj | false | true |
|
||||
| D.cs:152:17:152:27 | ... != ... | D.cs:152:17:152:19 | access to parameter obj | true | false |
|
||||
| D.cs:196:13:196:21 | ... == ... | D.cs:196:13:196:13 | access to local variable o | false | false |
|
||||
| D.cs:196:13:196:21 | ... == ... | D.cs:196:13:196:13 | access to local variable o | true | true |
|
||||
| D.cs:206:17:206:25 | ... == ... | D.cs:206:17:206:17 | access to local variable e | false | false |
|
||||
| D.cs:206:17:206:25 | ... == ... | D.cs:206:17:206:17 | access to local variable e | true | true |
|
||||
| D.cs:212:18:212:26 | ... == ... | D.cs:212:18:212:18 | access to local variable n | false | false |
|
||||
| D.cs:212:18:212:26 | ... == ... | D.cs:212:18:212:18 | access to local variable n | true | true |
|
||||
| D.cs:216:13:216:22 | ... == ... | D.cs:216:13:216:14 | access to local variable o3 | false | false |
|
||||
| D.cs:216:13:216:22 | ... == ... | D.cs:216:13:216:14 | access to local variable o3 | true | true |
|
||||
| D.cs:221:13:221:22 | ... == ... | D.cs:221:13:221:14 | access to local variable o4 | false | false |
|
||||
| D.cs:221:13:221:22 | ... == ... | D.cs:221:13:221:14 | access to local variable o4 | true | true |
|
||||
| D.cs:242:13:242:25 | ... == ... | D.cs:242:13:242:17 | access to local variable other | false | false |
|
||||
| D.cs:242:13:242:25 | ... == ... | D.cs:242:13:242:17 | access to local variable other | true | true |
|
||||
| D.cs:244:13:244:25 | ... != ... | D.cs:244:13:244:17 | access to local variable other | false | true |
|
||||
| D.cs:244:13:244:25 | ... != ... | D.cs:244:13:244:17 | access to local variable other | true | false |
|
||||
| D.cs:266:13:266:27 | ... is ... | D.cs:266:13:266:17 | access to local variable other | true | false |
|
||||
| D.cs:336:13:336:23 | ... == ... | D.cs:336:13:336:15 | access to parameter obj | false | false |
|
||||
| D.cs:336:13:336:23 | ... == ... | D.cs:336:13:336:15 | access to parameter obj | true | true |
|
||||
| D.cs:341:13:341:23 | ... != ... | D.cs:341:13:341:15 | access to local variable msg | false | true |
|
||||
| D.cs:341:13:341:23 | ... != ... | D.cs:341:13:341:15 | access to local variable msg | true | false |
|
||||
| D.cs:367:27:367:35 | ... == ... | D.cs:367:27:367:27 | access to local variable b | false | false |
|
||||
| D.cs:367:27:367:35 | ... == ... | D.cs:367:27:367:27 | access to local variable b | true | true |
|
||||
| D.cs:382:13:382:23 | ... != ... | D.cs:382:13:382:15 | access to local variable ioe | false | true |
|
||||
| D.cs:382:13:382:23 | ... != ... | D.cs:382:13:382:15 | access to local variable ioe | true | false |
|
||||
| D.cs:390:20:390:28 | ... == ... | D.cs:390:20:390:20 | access to parameter a | false | false |
|
||||
| D.cs:390:20:390:28 | ... == ... | D.cs:390:20:390:20 | access to parameter a | true | true |
|
||||
| D.cs:397:20:397:28 | ... == ... | D.cs:397:20:397:20 | access to parameter b | false | false |
|
||||
| D.cs:397:20:397:28 | ... == ... | D.cs:397:20:397:20 | access to parameter b | true | true |
|
||||
| D.cs:407:14:407:22 | ... != ... | D.cs:407:14:407:14 | access to parameter x | false | true |
|
||||
| D.cs:407:14:407:22 | ... != ... | D.cs:407:14:407:14 | access to parameter x | true | false |
|
||||
| D.cs:407:27:407:35 | ... == ... | D.cs:407:27:407:27 | access to parameter y | false | false |
|
||||
| D.cs:407:27:407:35 | ... == ... | D.cs:407:27:407:27 | access to parameter y | true | true |
|
||||
| D.cs:407:42:407:50 | ... == ... | D.cs:407:42:407:42 | access to parameter x | false | false |
|
||||
| D.cs:407:42:407:50 | ... == ... | D.cs:407:42:407:42 | access to parameter x | true | true |
|
||||
| D.cs:407:55:407:63 | ... != ... | D.cs:407:55:407:55 | access to parameter y | false | true |
|
||||
| D.cs:407:55:407:63 | ... != ... | D.cs:407:55:407:55 | access to parameter y | true | false |
|
||||
| D.cs:409:13:409:21 | ... != ... | D.cs:409:13:409:13 | access to parameter x | false | true |
|
||||
| D.cs:409:13:409:21 | ... != ... | D.cs:409:13:409:13 | access to parameter x | true | false |
|
||||
| D.cs:411:13:411:21 | ... != ... | D.cs:411:13:411:13 | access to parameter y | false | true |
|
||||
| D.cs:411:13:411:21 | ... != ... | D.cs:411:13:411:13 | access to parameter y | true | false |
|
||||
| E.cs:10:34:10:54 | ... != ... | E.cs:10:35:10:45 | ... = ... | false | true |
|
||||
| E.cs:10:34:10:54 | ... != ... | E.cs:10:35:10:45 | ... = ... | true | false |
|
||||
| E.cs:12:32:12:52 | ... != ... | E.cs:12:33:12:43 | ... = ... | false | true |
|
||||
| E.cs:12:32:12:52 | ... != ... | E.cs:12:33:12:43 | ... = ... | true | false |
|
||||
| E.cs:20:19:20:28 | ... == ... | E.cs:20:19:20:20 | access to local variable s1 | false | false |
|
||||
| E.cs:20:19:20:28 | ... == ... | E.cs:20:19:20:20 | access to local variable s1 | true | true |
|
||||
| E.cs:21:13:21:22 | ... == ... | E.cs:21:13:21:14 | access to local variable s2 | false | false |
|
||||
| E.cs:21:13:21:22 | ... == ... | E.cs:21:13:21:14 | access to local variable s2 | true | true |
|
||||
| E.cs:24:19:24:28 | ... == ... | E.cs:24:19:24:20 | access to local variable s1 | false | false |
|
||||
| E.cs:24:19:24:28 | ... == ... | E.cs:24:19:24:20 | access to local variable s1 | true | true |
|
||||
| E.cs:26:13:26:22 | ... != ... | E.cs:26:13:26:14 | access to local variable s2 | false | true |
|
||||
| E.cs:26:13:26:22 | ... != ... | E.cs:26:13:26:14 | access to local variable s2 | true | false |
|
||||
| E.cs:70:22:70:32 | ... == ... | E.cs:70:22:70:24 | access to parameter arr | false | false |
|
||||
| E.cs:70:22:70:32 | ... == ... | E.cs:70:22:70:24 | access to parameter arr | true | true |
|
||||
| E.cs:83:13:83:24 | ... != ... | E.cs:83:13:83:16 | access to parameter vals | false | true |
|
||||
| E.cs:83:13:83:24 | ... != ... | E.cs:83:13:83:16 | access to parameter vals | true | false |
|
||||
| E.cs:85:18:85:29 | ... != ... | E.cs:85:18:85:21 | access to parameter vals | false | true |
|
||||
| E.cs:85:18:85:29 | ... != ... | E.cs:85:18:85:21 | access to parameter vals | true | false |
|
||||
| E.cs:153:13:153:24 | ... != ... | E.cs:153:13:153:16 | access to local variable obj2 | false | true |
|
||||
| E.cs:153:13:153:24 | ... != ... | E.cs:153:13:153:16 | access to local variable obj2 | true | false |
|
||||
| E.cs:164:17:164:25 | ... == ... | E.cs:164:17:164:17 | access to parameter a | false | false |
|
||||
| E.cs:164:17:164:25 | ... == ... | E.cs:164:17:164:17 | access to parameter a | true | true |
|
||||
| E.cs:175:19:175:29 | ... == ... | E.cs:175:19:175:21 | access to parameter obj | false | false |
|
||||
| E.cs:175:19:175:29 | ... == ... | E.cs:175:19:175:21 | access to parameter obj | true | true |
|
||||
| E.cs:176:13:176:22 | ... == ... | E.cs:176:13:176:14 | (...) ... | false | false |
|
||||
| E.cs:176:13:176:22 | ... == ... | E.cs:176:13:176:14 | (...) ... | true | true |
|
||||
| E.cs:180:13:180:23 | ... == ... | E.cs:180:13:180:15 | access to parameter obj | false | false |
|
||||
| E.cs:180:13:180:23 | ... == ... | E.cs:180:13:180:15 | access to parameter obj | true | true |
|
||||
| E.cs:184:13:184:22 | ... == ... | E.cs:184:13:184:14 | (...) ... | false | false |
|
||||
| E.cs:184:13:184:22 | ... == ... | E.cs:184:13:184:14 | (...) ... | true | true |
|
||||
| E.cs:193:17:193:17 | access to parameter o | E.cs:193:17:193:17 | access to parameter o | non-null | false |
|
||||
| E.cs:193:17:193:17 | access to parameter o | E.cs:193:17:193:17 | access to parameter o | null | true |
|
||||
| E.cs:208:13:208:23 | ... is ... | E.cs:208:13:208:13 | access to parameter s | false | true |
|
||||
| E.cs:208:13:208:23 | ... is ... | E.cs:208:13:208:13 | access to parameter s | true | false |
|
||||
| E.cs:245:13:245:22 | access to property HasValue | E.cs:245:13:245:13 | access to parameter i | false | true |
|
||||
| E.cs:245:13:245:22 | access to property HasValue | E.cs:245:13:245:13 | access to parameter i | true | false |
|
||||
| E.cs:252:13:252:21 | ... != ... | E.cs:252:13:252:13 | access to parameter i | false | true |
|
||||
| E.cs:252:13:252:21 | ... != ... | E.cs:252:13:252:13 | access to parameter i | true | false |
|
||||
| E.cs:259:13:259:21 | ... == ... | E.cs:259:13:259:13 | access to parameter i | false | false |
|
||||
| E.cs:259:13:259:21 | ... == ... | E.cs:259:13:259:13 | access to parameter i | true | true |
|
||||
| Forwarding.cs:9:14:9:30 | call to method IsNullOrEmpty | Forwarding.cs:9:14:9:14 | access to local variable s | false | false |
|
||||
| Forwarding.cs:14:13:14:32 | call to method IsNotNullOrEmpty | Forwarding.cs:14:13:14:13 | access to local variable s | true | false |
|
||||
| Forwarding.cs:19:14:19:23 | call to method IsNull | Forwarding.cs:19:14:19:14 | access to local variable s | false | false |
|
||||
| Forwarding.cs:19:14:19:23 | call to method IsNull | Forwarding.cs:19:14:19:14 | access to local variable s | true | true |
|
||||
| Forwarding.cs:24:13:24:25 | call to method IsNotNull | Forwarding.cs:24:13:24:13 | access to local variable s | false | true |
|
||||
| Forwarding.cs:24:13:24:25 | call to method IsNotNull | Forwarding.cs:24:13:24:13 | access to local variable s | true | false |
|
||||
| Forwarding.cs:29:13:29:24 | call to method IsNotNull | Forwarding.cs:29:23:29:23 | access to local variable s | true | false |
|
||||
| Forwarding.cs:34:13:34:29 | call to method IsNotNullWrong | Forwarding.cs:34:28:34:28 | access to local variable s | false | false |
|
||||
| Forwarding.cs:45:16:45:26 | ... is ... | Forwarding.cs:45:16:45:16 | access to parameter o | true | false |
|
||||
| Forwarding.cs:45:31:45:61 | call to method IsNullOrEmpty | Forwarding.cs:45:52:45:60 | (...) ... | false | false |
|
||||
| Forwarding.cs:45:66:45:75 | call to method IsNull | Forwarding.cs:45:66:45:66 | access to parameter o | false | false |
|
||||
| Forwarding.cs:45:66:45:75 | call to method IsNull | Forwarding.cs:45:66:45:66 | access to parameter o | true | true |
|
||||
| Forwarding.cs:50:13:50:23 | ... is ... | Forwarding.cs:50:13:50:13 | access to parameter o | true | false |
|
||||
| Forwarding.cs:52:21:52:51 | call to method IsNullOrEmpty | Forwarding.cs:52:42:52:50 | (...) ... | false | false |
|
||||
| Forwarding.cs:59:13:59:21 | ... == ... | Forwarding.cs:59:13:59:13 | access to parameter o | false | false |
|
||||
| Forwarding.cs:59:13:59:21 | ... == ... | Forwarding.cs:59:13:59:13 | access to parameter o | true | true |
|
||||
| Forwarding.cs:68:16:68:38 | call to method IsNullOrEmpty | Forwarding.cs:68:37:68:37 | access to parameter s | false | false |
|
||||
| Forwarding.cs:73:17:73:39 | call to method IsNullOrEmpty | Forwarding.cs:73:38:73:38 | access to parameter s | false | false |
|
||||
| Forwarding.cs:78:16:78:39 | call to method ReferenceEquals | Forwarding.cs:78:32:78:32 | access to parameter o | false | false |
|
||||
| Forwarding.cs:78:16:78:39 | call to method ReferenceEquals | Forwarding.cs:78:32:78:32 | access to parameter o | true | true |
|
||||
| Forwarding.cs:83:16:83:24 | ... != ... | Forwarding.cs:83:16:83:16 | access to parameter o | false | true |
|
||||
| Forwarding.cs:83:16:83:24 | ... != ... | Forwarding.cs:83:16:83:16 | access to parameter o | true | false |
|
||||
| GuardedString.cs:9:14:9:36 | call to method IsNullOrEmpty | GuardedString.cs:9:35:9:35 | access to local variable s | false | false |
|
||||
| GuardedString.cs:14:14:14:41 | call to method IsNullOrWhiteSpace | GuardedString.cs:14:40:14:40 | access to local variable s | false | false |
|
||||
| GuardedString.cs:19:13:19:13 | access to local variable s | GuardedString.cs:19:13:19:13 | access to local variable s | non-null | false |
|
||||
| GuardedString.cs:19:13:19:13 | access to local variable s | GuardedString.cs:19:13:19:13 | access to local variable s | null | true |
|
||||
| GuardedString.cs:19:13:19:26 | ... == ... | GuardedString.cs:19:15:19:21 | access to property Length | true | false |
|
||||
| GuardedString.cs:22:13:22:13 | access to local variable s | GuardedString.cs:22:13:22:13 | access to local variable s | non-null | false |
|
||||
| GuardedString.cs:22:13:22:13 | access to local variable s | GuardedString.cs:22:13:22:13 | access to local variable s | null | true |
|
||||
| GuardedString.cs:22:13:22:25 | ... > ... | GuardedString.cs:22:15:22:21 | access to property Length | true | false |
|
||||
| GuardedString.cs:25:13:25:13 | access to local variable s | GuardedString.cs:25:13:25:13 | access to local variable s | non-null | false |
|
||||
| GuardedString.cs:25:13:25:13 | access to local variable s | GuardedString.cs:25:13:25:13 | access to local variable s | null | true |
|
||||
| GuardedString.cs:25:13:25:26 | ... >= ... | GuardedString.cs:25:15:25:21 | access to property Length | true | false |
|
||||
| GuardedString.cs:28:13:28:13 | access to local variable s | GuardedString.cs:28:13:28:13 | access to local variable s | non-null | false |
|
||||
| GuardedString.cs:28:13:28:13 | access to local variable s | GuardedString.cs:28:13:28:13 | access to local variable s | null | true |
|
||||
| GuardedString.cs:28:13:28:26 | ... < ... | GuardedString.cs:28:15:28:21 | access to property Length | true | false |
|
||||
| GuardedString.cs:31:13:31:13 | access to local variable s | GuardedString.cs:31:13:31:13 | access to local variable s | non-null | false |
|
||||
| GuardedString.cs:31:13:31:13 | access to local variable s | GuardedString.cs:31:13:31:13 | access to local variable s | null | true |
|
||||
| GuardedString.cs:31:13:31:27 | ... <= ... | GuardedString.cs:31:15:31:21 | access to property Length | true | false |
|
||||
| GuardedString.cs:34:13:34:13 | access to local variable s | GuardedString.cs:34:13:34:13 | access to local variable s | non-null | false |
|
||||
| GuardedString.cs:34:13:34:13 | access to local variable s | GuardedString.cs:34:13:34:13 | access to local variable s | null | true |
|
||||
| GuardedString.cs:34:13:34:26 | ... != ... | GuardedString.cs:34:15:34:21 | access to property Length | false | false |
|
||||
| NullAlwaysBad.cs:9:17:9:25 | ... != ... | NullAlwaysBad.cs:9:17:9:17 | access to parameter s | false | true |
|
||||
| NullAlwaysBad.cs:9:17:9:25 | ... != ... | NullAlwaysBad.cs:9:17:9:17 | access to parameter s | true | false |
|
||||
| NullAlwaysGood.cs:9:17:9:25 | ... != ... | NullAlwaysGood.cs:9:17:9:17 | access to parameter s | false | true |
|
||||
| NullAlwaysGood.cs:9:17:9:25 | ... != ... | NullAlwaysGood.cs:9:17:9:17 | access to parameter s | true | false |
|
||||
| NullMaybeGood.cs:9:17:9:25 | ... != ... | NullMaybeGood.cs:9:17:9:17 | access to parameter o | false | true |
|
||||
| NullMaybeGood.cs:9:17:9:25 | ... != ... | NullMaybeGood.cs:9:17:9:17 | access to parameter o | true | false |
|
||||
| StringConcatenation.cs:15:16:15:22 | ... != ... | StringConcatenation.cs:15:16:15:16 | access to local variable s | false | false |
|
||||
| StringConcatenation.cs:22:16:22:22 | ... != ... | StringConcatenation.cs:22:16:22:16 | access to local variable s | false | false |
|
|
@ -0,0 +1,5 @@
|
|||
import csharp
|
||||
import semmle.code.csharp.controlflow.Guards
|
||||
|
||||
from DereferenceableExpr de, AbstractValue v, boolean isNull
|
||||
select de.getANullCheck(v, isNull), de, v, isNull
|
|
@ -1,9 +1,73 @@
|
|||
| A.cs:85:31:85:39 | access to local variable do_maybe1 | Variable $@ may be null here. | A.cs:82:16:82:24 | do_maybe1 | do_maybe1 |
|
||||
| A.cs:92:31:92:38 | access to local variable do_maybe | Variable $@ may be null here. | A.cs:89:16:89:23 | do_maybe | do_maybe |
|
||||
| A.cs:120:31:120:41 | access to local variable while_maybe | Variable $@ may be null here. | A.cs:117:16:117:26 | while_maybe | while_maybe |
|
||||
| A.cs:158:27:158:34 | access to local variable if_maybe | Variable $@ may be null here. | A.cs:153:16:153:23 | if_maybe | if_maybe |
|
||||
| A.cs:180:31:180:39 | access to local variable for_maybe | Variable $@ may be null here. | A.cs:178:21:178:29 | for_maybe | for_maybe |
|
||||
| Forwarding.cs:36:31:36:31 | access to local variable s | Variable $@ may be null here. | Forwarding.cs:7:16:7:16 | s | s |
|
||||
| Forwarding.cs:40:27:40:27 | access to local variable s | Variable $@ may be null here. | Forwarding.cs:7:16:7:16 | s | s |
|
||||
| GuardedString.cs:35:31:35:31 | access to local variable s | Variable $@ may be null here. | GuardedString.cs:7:16:7:16 | s | s |
|
||||
| StringConcatenation.cs:16:17:16:17 | access to local variable s | Variable $@ may be null here. | StringConcatenation.cs:14:16:14:16 | s | s |
|
||||
| C.cs:64:9:64:10 | access to local variable o1 | Variable $@ may be null here because of $@ assignment. | C.cs:62:13:62:14 | o1 | o1 | C.cs:62:13:62:46 | Object o1 = ... | this |
|
||||
| C.cs:68:9:68:10 | access to local variable o2 | Variable $@ may be null here because of $@ assignment. | C.cs:66:13:66:14 | o2 | o2 | C.cs:66:13:66:46 | Object o2 = ... | this |
|
||||
| C.cs:96:15:96:15 | access to local variable o | Variable $@ may be null here because of $@ assignment. | C.cs:95:13:95:13 | o | o | C.cs:95:13:95:45 | Object o = ... | this |
|
||||
| C.cs:104:27:104:30 | access to parameter list | Variable $@ may be null here because of $@ assignment. | C.cs:100:42:100:45 | list | list | C.cs:103:13:103:23 | ... = ... | this |
|
||||
| C.cs:178:13:178:13 | access to local variable s | Variable $@ may be null here because of $@ assignment. | C.cs:152:13:152:13 | s | s | C.cs:179:13:179:20 | ... = ... | this |
|
||||
| C.cs:204:13:204:13 | access to local variable s | Variable $@ may be null here because of $@ assignment. | C.cs:186:13:186:13 | s | s | C.cs:205:13:205:20 | ... = ... | this |
|
||||
| C.cs:224:9:224:9 | access to local variable s | Variable $@ may be null here because of $@ assignment. | C.cs:211:13:211:13 | s | s | C.cs:223:13:223:20 | ... = ... | this |
|
||||
| C.cs:243:13:243:13 | access to local variable s | Variable $@ may be null here because of $@ assignment. | C.cs:229:16:229:16 | s | s | C.cs:241:24:241:31 | ... = ... | this |
|
||||
| D.cs:23:9:23:13 | access to parameter param | Variable $@ may be null here because of $@ null argument. | D.cs:21:32:21:36 | param | param | D.cs:17:17:17:20 | null | this |
|
||||
| D.cs:32:9:32:13 | access to parameter param | Variable $@ may be null here as suggested by $@ null check. | D.cs:26:32:26:36 | param | param | D.cs:28:13:28:25 | ... != ... | this |
|
||||
| D.cs:62:13:62:14 | access to local variable o5 | Variable $@ may be null here because of $@ assignment. | D.cs:58:13:58:14 | o5 | o5 | D.cs:58:13:58:41 | String o5 = ... | this |
|
||||
| D.cs:73:13:73:14 | access to local variable o7 | Variable $@ may be null here because of $@ assignment. | D.cs:68:13:68:14 | o7 | o7 | D.cs:68:13:68:34 | String o7 = ... | this |
|
||||
| D.cs:82:13:82:14 | access to local variable o8 | Variable $@ may be null here because of $@ assignment. | D.cs:75:13:75:14 | o8 | o8 | D.cs:75:13:75:34 | String o8 = ... | this |
|
||||
| D.cs:84:13:84:14 | access to local variable o8 | Variable $@ may be null here because of $@ assignment. | D.cs:75:13:75:14 | o8 | o8 | D.cs:75:13:75:34 | String o8 = ... | this |
|
||||
| D.cs:91:13:91:14 | access to local variable xs | Variable $@ may be null here because of $@ assignment. | D.cs:89:15:89:16 | xs | xs | D.cs:89:15:89:44 | Int32[] xs = ... | this |
|
||||
| D.cs:94:21:94:22 | access to local variable xs | Variable $@ may be null here because of $@ assignment. | D.cs:89:15:89:16 | xs | xs | D.cs:89:15:89:44 | Int32[] xs = ... | this |
|
||||
| D.cs:98:21:98:22 | access to local variable xs | Variable $@ may be null here because of $@ assignment. | D.cs:89:15:89:16 | xs | xs | D.cs:89:15:89:44 | Int32[] xs = ... | this |
|
||||
| D.cs:102:31:102:32 | access to local variable xs | Variable $@ may be null here because of $@ assignment. | D.cs:89:15:89:16 | xs | xs | D.cs:89:15:89:44 | Int32[] xs = ... | this |
|
||||
| D.cs:105:19:105:20 | access to local variable xs | Variable $@ may be null here because of $@ assignment. | D.cs:89:15:89:16 | xs | xs | D.cs:89:15:89:44 | Int32[] xs = ... | this |
|
||||
| D.cs:134:24:134:24 | access to parameter a | Variable $@ may be null here as suggested by $@ null check. | D.cs:125:35:125:35 | a | a | D.cs:127:20:127:28 | ... == ... | this |
|
||||
| D.cs:134:24:134:24 | access to parameter a | Variable $@ may be null here as suggested by $@ null check. | D.cs:125:35:125:35 | a | a | D.cs:139:13:139:21 | ... != ... | this |
|
||||
| D.cs:135:24:135:24 | access to parameter b | Variable $@ may be null here as suggested by $@ null check. | D.cs:125:44:125:44 | b | b | D.cs:128:20:128:28 | ... == ... | this |
|
||||
| D.cs:145:20:145:20 | access to parameter a | Variable $@ may be null here as suggested by $@ null check. | D.cs:125:35:125:35 | a | a | D.cs:127:20:127:28 | ... == ... | this |
|
||||
| D.cs:145:20:145:20 | access to parameter a | Variable $@ may be null here as suggested by $@ null check. | D.cs:125:35:125:35 | a | a | D.cs:139:13:139:21 | ... != ... | this |
|
||||
| D.cs:151:9:151:11 | access to parameter obj | Variable $@ may be null here as suggested by $@ null check. | D.cs:149:36:149:38 | obj | obj | D.cs:152:17:152:27 | ... != ... | this |
|
||||
| D.cs:171:9:171:11 | access to local variable obj | Variable $@ may be null here because of $@ assignment. | D.cs:163:16:163:18 | obj | obj | D.cs:163:16:163:25 | Object obj = ... | this |
|
||||
| D.cs:245:13:245:13 | access to local variable o | Variable $@ may be null here because of $@ assignment. | D.cs:228:16:228:16 | o | o | D.cs:240:9:240:16 | ... = ... | this |
|
||||
| D.cs:247:13:247:13 | access to local variable o | Variable $@ may be null here because of $@ assignment. | D.cs:228:16:228:16 | o | o | D.cs:240:9:240:16 | ... = ... | this |
|
||||
| D.cs:253:13:253:14 | access to local variable o2 | Variable $@ may be null here because of $@ assignment. | D.cs:249:13:249:14 | o2 | o2 | D.cs:249:13:249:38 | String o2 = ... | this |
|
||||
| D.cs:267:13:267:13 | access to local variable o | Variable $@ may be null here because of $@ assignment. | D.cs:258:16:258:16 | o | o | D.cs:258:16:258:23 | Object o = ... | this |
|
||||
| D.cs:291:13:291:13 | access to local variable o | Variable $@ may be null here because of $@ assignment. | D.cs:258:16:258:16 | o | o | D.cs:269:9:269:16 | ... = ... | this |
|
||||
| D.cs:291:13:291:13 | access to local variable o | Variable $@ may be null here because of $@ assignment. | D.cs:258:16:258:16 | o | o | D.cs:283:17:283:24 | ... = ... | this |
|
||||
| D.cs:294:13:294:13 | access to local variable o | Variable $@ may be null here because of $@ assignment. | D.cs:258:16:258:16 | o | o | D.cs:269:9:269:16 | ... = ... | this |
|
||||
| D.cs:294:13:294:13 | access to local variable o | Variable $@ may be null here because of $@ assignment. | D.cs:258:16:258:16 | o | o | D.cs:283:17:283:24 | ... = ... | this |
|
||||
| D.cs:300:17:300:20 | access to local variable prev | Variable $@ may be null here because of $@ assignment. | D.cs:296:16:296:19 | prev | prev | D.cs:296:16:296:26 | Object prev = ... | this |
|
||||
| D.cs:313:17:313:17 | access to local variable s | Variable $@ may be null here because of $@ assignment. | D.cs:304:16:304:16 | s | s | D.cs:304:16:304:23 | String s = ... | this |
|
||||
| D.cs:324:9:324:9 | access to local variable r | Variable $@ may be null here because of $@ assignment. | D.cs:316:16:316:16 | r | r | D.cs:316:16:316:23 | Object r = ... | this |
|
||||
| D.cs:356:13:356:13 | access to local variable a | Variable $@ may be null here because of $@ assignment. | D.cs:351:15:351:15 | a | a | D.cs:351:15:351:22 | Int32[] a = ... | this |
|
||||
| D.cs:363:13:363:16 | access to local variable last | Variable $@ may be null here because of $@ assignment. | D.cs:360:20:360:23 | last | last | D.cs:360:20:360:30 | String last = ... | this |
|
||||
| D.cs:372:13:372:13 | access to local variable b | Variable $@ may be null here because of $@ assignment. | D.cs:366:15:366:15 | b | b | D.cs:366:15:366:47 | Int32[] b = ... | this |
|
||||
| D.cs:395:20:395:20 | access to parameter a | Variable $@ may be null here as suggested by $@ null check. | D.cs:388:36:388:36 | a | a | D.cs:390:20:390:28 | ... == ... | this |
|
||||
| D.cs:400:20:400:20 | access to parameter b | Variable $@ may be null here as suggested by $@ null check. | D.cs:388:45:388:45 | b | b | D.cs:397:20:397:28 | ... == ... | this |
|
||||
| D.cs:410:13:410:13 | access to parameter y | Variable $@ may be null here as suggested by $@ null check. | D.cs:405:45:405:45 | y | y | D.cs:407:27:407:35 | ... == ... | this |
|
||||
| D.cs:410:13:410:13 | access to parameter y | Variable $@ may be null here as suggested by $@ null check. | D.cs:405:45:405:45 | y | y | D.cs:407:55:407:63 | ... != ... | this |
|
||||
| D.cs:410:13:410:13 | access to parameter y | Variable $@ may be null here as suggested by $@ null check. | D.cs:405:45:405:45 | y | y | D.cs:411:13:411:21 | ... != ... | this |
|
||||
| D.cs:412:13:412:13 | access to parameter x | Variable $@ may be null here as suggested by $@ null check. | D.cs:405:35:405:35 | x | x | D.cs:407:14:407:22 | ... != ... | this |
|
||||
| D.cs:412:13:412:13 | access to parameter x | Variable $@ may be null here as suggested by $@ null check. | D.cs:405:35:405:35 | x | x | D.cs:407:42:407:50 | ... == ... | this |
|
||||
| D.cs:412:13:412:13 | access to parameter x | Variable $@ may be null here as suggested by $@ null check. | D.cs:405:35:405:35 | x | x | D.cs:409:13:409:21 | ... != ... | this |
|
||||
| E.cs:12:38:12:39 | access to local variable a2 | Variable $@ may be null here because of $@ assignment. | E.cs:9:18:9:19 | a2 | a2 | E.cs:9:18:9:26 | Int64[][] a2 = ... | this |
|
||||
| E.cs:14:13:14:14 | access to local variable a3 | Variable $@ may be null here because of $@ assignment. | E.cs:11:16:11:17 | a3 | a3 | E.cs:11:16:11:24 | Int64[] a3 = ... | this |
|
||||
| E.cs:27:13:27:14 | access to local variable s1 | Variable $@ may be null here because of $@ assignment. | E.cs:19:13:19:14 | s1 | s1 | E.cs:23:13:23:30 | ... = ... | this |
|
||||
| E.cs:35:9:35:12 | access to local variable last | Variable $@ may be null here because of $@ assignment. | E.cs:32:16:32:19 | last | last | E.cs:32:16:32:26 | String last = ... | this |
|
||||
| E.cs:43:13:43:16 | access to local variable last | Variable $@ may be null here because of $@ assignment. | E.cs:32:16:32:19 | last | last | E.cs:37:9:37:19 | ... = ... | this |
|
||||
| E.cs:61:13:61:17 | access to local variable slice | Variable $@ may be null here because of $@ assignment. | E.cs:51:22:51:26 | slice | slice | E.cs:51:22:51:33 | List<String> slice = ... | this |
|
||||
| E.cs:73:13:73:15 | access to parameter arr | Variable $@ may be null here as suggested by $@ null check. | E.cs:66:40:66:42 | arr | arr | E.cs:70:22:70:32 | ... == ... | this |
|
||||
| E.cs:112:13:112:16 | access to local variable arr2 | Variable $@ may be null here because of $@ assignment. | E.cs:107:15:107:18 | arr2 | arr2 | E.cs:107:15:107:25 | Int32[] arr2 = ... | this |
|
||||
| E.cs:125:33:125:35 | access to local variable obj | Variable $@ may be null here because of $@ assignment. | E.cs:119:13:119:15 | obj | obj | E.cs:137:25:137:34 | ... = ... | this |
|
||||
| E.cs:159:13:159:16 | access to local variable obj2 | Variable $@ may be null here as suggested by $@ null check. | E.cs:152:16:152:19 | obj2 | obj2 | E.cs:153:13:153:24 | ... != ... | this |
|
||||
| E.cs:167:21:167:21 | access to parameter a | Variable $@ may be null here as suggested by $@ null check. | E.cs:162:28:162:28 | a | a | E.cs:164:17:164:25 | ... == ... | this |
|
||||
| E.cs:178:13:178:15 | access to parameter obj | Variable $@ may be null here as suggested by $@ null check. | E.cs:173:29:173:31 | obj | obj | E.cs:175:19:175:29 | ... == ... | this |
|
||||
| E.cs:178:13:178:15 | access to parameter obj | Variable $@ may be null here as suggested by $@ null check. | E.cs:173:29:173:31 | obj | obj | E.cs:180:13:180:23 | ... == ... | this |
|
||||
| E.cs:186:13:186:15 | access to parameter obj | Variable $@ may be null here as suggested by $@ null check. | E.cs:173:29:173:31 | obj | obj | E.cs:175:19:175:29 | ... == ... | this |
|
||||
| E.cs:186:13:186:15 | access to parameter obj | Variable $@ may be null here as suggested by $@ null check. | E.cs:173:29:173:31 | obj | obj | E.cs:180:13:180:23 | ... == ... | this |
|
||||
| E.cs:192:17:192:17 | access to parameter o | Variable $@ may be null here as suggested by $@ null check. | E.cs:190:29:190:29 | o | o | E.cs:193:17:193:17 | access to parameter o | this |
|
||||
| E.cs:201:11:201:11 | access to local variable o | Variable $@ may be null here because of $@ assignment. | E.cs:198:13:198:13 | o | o | E.cs:198:13:198:29 | String o = ... | this |
|
||||
| E.cs:203:11:203:11 | access to local variable o | Variable $@ may be null here because of $@ assignment. | E.cs:198:13:198:13 | o | o | E.cs:198:13:198:29 | String o = ... | this |
|
||||
| E.cs:218:9:218:9 | access to local variable x | Variable $@ may be null here because of $@ assignment. | E.cs:215:13:215:13 | x | x | E.cs:217:13:217:20 | ... = ... | this |
|
||||
| E.cs:230:9:230:9 | access to local variable x | Variable $@ may be null here because of $@ assignment. | E.cs:225:13:225:13 | x | x | E.cs:227:13:227:20 | ... = ... | this |
|
||||
| E.cs:235:16:235:16 | access to parameter i | Variable $@ may be null here because it has a nullable type. | E.cs:233:26:233:26 | i | i | E.cs:233:26:233:26 | i | this |
|
||||
| E.cs:240:21:240:21 | access to parameter i | Variable $@ may be null here because it has a nullable type. | E.cs:238:26:238:26 | i | i | E.cs:238:26:238:26 | i | this |
|
||||
| GuardedString.cs:35:31:35:31 | access to local variable s | Variable $@ may be null here because of $@ assignment. | GuardedString.cs:7:16:7:16 | s | s | GuardedString.cs:7:16:7:32 | String s = ... | this |
|
||||
| NullMaybeBad.cs:9:31:9:31 | access to parameter o | Variable $@ may be null here because of $@ null argument. | NullMaybeBad.cs:7:29:7:29 | o | o | NullMaybeBad.cs:15:21:15:24 | null | this |
|
||||
| StringConcatenation.cs:16:17:16:17 | access to local variable s | Variable $@ may be null here because of $@ assignment. | StringConcatenation.cs:14:16:14:16 | s | s | StringConcatenation.cs:14:16:14:23 | String s = ... | this |
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
|
||||
namespace NullMaybe
|
||||
{
|
||||
class Bad
|
||||
{
|
||||
void DoPrint(object o)
|
||||
{
|
||||
Console.WriteLine(o.ToString());
|
||||
}
|
||||
|
||||
void M()
|
||||
{
|
||||
DoPrint("Hello");
|
||||
DoPrint(null);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
|
||||
namespace NullMaybe
|
||||
{
|
||||
class Good
|
||||
{
|
||||
void DoPrint(object o)
|
||||
{
|
||||
if (o != null)
|
||||
Console.WriteLine(o.ToString());
|
||||
}
|
||||
|
||||
void M()
|
||||
{
|
||||
DoPrint("Hello");
|
||||
DoPrint(null);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,14 +6,14 @@ class StringsTest
|
|||
{
|
||||
string s = null;
|
||||
s += "abc";
|
||||
s = s.Trim(); // OK
|
||||
s = s.Trim(); // GOOD
|
||||
}
|
||||
|
||||
void StringMaybeNull()
|
||||
{
|
||||
string s = null;
|
||||
while (s != "")
|
||||
s = s.Trim(); // Maybe null
|
||||
s = s.Trim(); // BAD (maybe)
|
||||
}
|
||||
|
||||
void StringNotNull()
|
||||
|
@ -21,13 +21,13 @@ class StringsTest
|
|||
string s = null;
|
||||
while (s != "")
|
||||
s += "abc";
|
||||
s = s.Trim(); // OK (s == "")
|
||||
s = s.Trim(); // GOOD
|
||||
}
|
||||
|
||||
void StringNotAssignedNull()
|
||||
{
|
||||
string s = "abc";
|
||||
s += null;
|
||||
s = s.Trim(); // OK
|
||||
s = s.Trim(); // GOOD
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче