mirror of
https://github.com/github/codeql.git
synced 2026-04-28 02:05:14 +02:00
@@ -79,7 +79,7 @@ class ConstantNullnessCondition extends ConstantCondition {
|
||||
cfn = this.getAControlFlowNode() |
|
||||
exists(ControlFlow::SuccessorTypes::NullnessSuccessor t |
|
||||
exists(cfn.getASuccessorByType(t)) |
|
||||
if t.isNull() then b = true else b = false
|
||||
b = t.getValue()
|
||||
) and
|
||||
strictcount(ControlFlow::SuccessorType t | exists(cfn.getASuccessorByType(t))) = 1
|
||||
)
|
||||
@@ -102,7 +102,7 @@ class ConstantMatchingCondition extends ConstantCondition {
|
||||
cfn = this.getAControlFlowNode() |
|
||||
exists(ControlFlow::SuccessorTypes::MatchingSuccessor t |
|
||||
exists(cfn.getASuccessorByType(t)) |
|
||||
if t.isMatch() then b = true else b = false
|
||||
b = t.getValue()
|
||||
) and
|
||||
strictcount(ControlFlow::SuccessorType t | exists(cfn.getASuccessorByType(t))) = 1
|
||||
)
|
||||
|
||||
@@ -17,10 +17,10 @@ variables in the same sequence.</p>
|
||||
<p>The following example shows a program running two threads, which deadlocks because <code>thread1</code> holds <code>lock1</code> and
|
||||
is waiting to acquire <code>lock2</code>, whilst <code>thread2</code> holds <code>lock2</code> and is waiting to acquire <code>lock1</code>.</p>
|
||||
|
||||
<sample src="LockOrder.cs" />
|
||||
<sample src="LockOrderBad.cs" />
|
||||
|
||||
<p>This problem is resolved by reordering the <code>lock</code> variables as shown below.</p>
|
||||
<sample src="LockOrderFix.cs" />
|
||||
<sample src="LockOrderGood.cs" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
|
||||
@@ -13,13 +13,50 @@
|
||||
|
||||
import csharp
|
||||
|
||||
from LockStmt l1, LockStmt l2, LockStmt l3, LockStmt l4, Variable v1, Variable v2
|
||||
where l1.getALockedStmt()=l2
|
||||
and l3.getALockedStmt()=l4
|
||||
and l1.getLockVariable()=v1
|
||||
and l2.getLockVariable()=v2
|
||||
and l3.getLockVariable()=v2
|
||||
and l4.getLockVariable()=v1
|
||||
and v1!=v2
|
||||
select l4, "Inconsistent lock sequence. The locks " + v1 + " and " + v2 + " are locked in a different sequence $@.",
|
||||
l2, "here"
|
||||
/**
|
||||
* Gets a call target conservatively only when there is
|
||||
* one runtime target.
|
||||
*/
|
||||
Callable getCallTarget(Call c) {
|
||||
count(c.getARuntimeTarget()) = 1 and
|
||||
result = c.getARuntimeTarget()
|
||||
}
|
||||
|
||||
/** Gets a lock statement reachable from a callable. */
|
||||
LockStmt getAReachableLockStmt(Callable callable) {
|
||||
result.getEnclosingCallable() = callable
|
||||
or
|
||||
exists(Call call | call.getEnclosingCallable() = callable |
|
||||
result = getAReachableLockStmt(getCallTarget(call))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is nested pairs of lock statements, either
|
||||
* inter-procedurally or intra-procedurally.
|
||||
*/
|
||||
predicate nestedLocks(Variable outerVariable, Variable innerVariable, LockStmt outer, LockStmt inner) {
|
||||
outerVariable = outer.getLockVariable() and
|
||||
innerVariable = inner.getLockVariable() and
|
||||
outerVariable != innerVariable and (
|
||||
inner = outer.getALockedStmt()
|
||||
or
|
||||
exists(Call call | call.getEnclosingStmt() = outer.getALockedStmt() |
|
||||
inner = getAReachableLockStmt(getCallTarget(call))
|
||||
) and
|
||||
outerVariable.(Modifiable).isStatic() and
|
||||
innerVariable.(Modifiable).isStatic()
|
||||
)
|
||||
}
|
||||
|
||||
from LockStmt outer1, LockStmt inner1, LockStmt outer2, LockStmt inner2, Variable v1, Variable v2
|
||||
where
|
||||
nestedLocks(v1, v2, outer1, inner1) and
|
||||
nestedLocks(v2, v1, outer2, inner2) and
|
||||
v1.getName() <= v2.getName()
|
||||
select v1, "Inconsistent lock sequence with $@. Lock sequences $@, $@ and $@, $@ found.",
|
||||
v2, v2.getName(),
|
||||
outer1, v1.getName(),
|
||||
inner1, v2.getName(),
|
||||
outer2, v2.getName(),
|
||||
inner2, v1.getName()
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
class Deadlock
|
||||
{
|
||||
private readonly Object lock1 = new Object();
|
||||
@@ -1,3 +1,6 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
class DeadlockFixed
|
||||
{
|
||||
private readonly Object lock1 = new Object();
|
||||
@@ -85,6 +85,7 @@ abstract class StructuralComparisonConfiguration extends string {
|
||||
value = x.getValue()
|
||||
}
|
||||
|
||||
pragma [nomagic]
|
||||
private predicate sameByStructure(Element x, Element y) {
|
||||
// At least one of `x` and `y` must not have a value, they must have
|
||||
// the same kind, and the same number of children
|
||||
@@ -121,6 +122,7 @@ abstract class StructuralComparisonConfiguration extends string {
|
||||
not (x.(Expr).hasValue() and y.(Expr).hasValue())
|
||||
}
|
||||
|
||||
pragma [nomagic]
|
||||
private predicate sameInternal(Element x, Element y) {
|
||||
sameByValue(x, y)
|
||||
or
|
||||
@@ -210,6 +212,7 @@ module Internal {
|
||||
value = x.getValue()
|
||||
}
|
||||
|
||||
pragma [nomagic]
|
||||
private predicate sameByStructure(Element x, Element y) {
|
||||
// At least one of `x` and `y` must not have a value, they must have
|
||||
// the same kind, and the same number of children
|
||||
@@ -246,6 +249,7 @@ module Internal {
|
||||
not (x.(Expr).hasValue() and y.(Expr).hasValue())
|
||||
}
|
||||
|
||||
pragma [nomagic]
|
||||
private predicate sameInternal(Element x, Element y) {
|
||||
sameByValue(x, y)
|
||||
or
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
private import ControlFlow::SuccessorTypes
|
||||
|
||||
/**
|
||||
* A basic block, that is, a maximal straight-line sequence of control flow nodes
|
||||
@@ -14,6 +15,11 @@ class BasicBlock extends TBasicBlockStart {
|
||||
result.getFirstNode() = getLastNode().getASuccessor()
|
||||
}
|
||||
|
||||
/** Gets an immediate successor of this basic block of a given flow type, if any. */
|
||||
BasicBlock getASuccessorByType(ControlFlow::SuccessorType t) {
|
||||
result.getFirstNode() = this.getLastNode().getASuccessorByType(t)
|
||||
}
|
||||
|
||||
/** Gets an immediate predecessor of this basic block, if any. */
|
||||
BasicBlock getAPredecessor() {
|
||||
result.getASuccessor() = this
|
||||
@@ -75,6 +81,7 @@ class BasicBlock extends TBasicBlockStart {
|
||||
* The node on line 2 is an immediate `null` successor of the node
|
||||
* `x` on line 1.
|
||||
*/
|
||||
deprecated
|
||||
BasicBlock getANullSuccessor() {
|
||||
result.getFirstNode() = getLastNode().getANullSuccessor()
|
||||
}
|
||||
@@ -94,6 +101,7 @@ class BasicBlock extends TBasicBlockStart {
|
||||
* The node `x?.M()`, representing the call to `M`, is a non-`null` successor
|
||||
* of the node `x`.
|
||||
*/
|
||||
deprecated
|
||||
BasicBlock getANonNullSuccessor() {
|
||||
result.getFirstNode() = getLastNode().getANonNullSuccessor()
|
||||
}
|
||||
@@ -430,7 +438,7 @@ class ConditionBlock extends BasicBlock {
|
||||
* the callable entry point by going via the true edge (`testIsTrue = true`)
|
||||
* or false edge (`testIsTrue = false`) out of this basic block.
|
||||
*/
|
||||
predicate controls(BasicBlock controlled, boolean testIsTrue) {
|
||||
predicate controls(BasicBlock controlled, ConditionalSuccessor s) {
|
||||
/*
|
||||
* For this block to control the block `controlled` with `testIsTrue` the following must be true:
|
||||
* Execution must have passed through the test i.e. `this` must strictly dominate `controlled`.
|
||||
@@ -465,7 +473,7 @@ class ConditionBlock extends BasicBlock {
|
||||
* directly.
|
||||
*/
|
||||
exists(BasicBlock succ |
|
||||
isCandidateSuccessor(succ, testIsTrue) |
|
||||
isCandidateSuccessor(succ, s) |
|
||||
succ.dominates(controlled)
|
||||
)
|
||||
}
|
||||
@@ -476,11 +484,9 @@ class ConditionBlock extends BasicBlock {
|
||||
* the callable entry point by going via the `null` edge (`isNull = true`)
|
||||
* or non-`null` edge (`isNull = false`) out of this basic block.
|
||||
*/
|
||||
deprecated
|
||||
predicate controlsNullness(BasicBlock controlled, boolean isNull) {
|
||||
exists(BasicBlock succ |
|
||||
isCandidateSuccessorNullness(succ, isNull) |
|
||||
succ.dominates(controlled)
|
||||
)
|
||||
this.controls(controlled, any(NullnessSuccessor s | s.getValue() = isNull))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -520,29 +526,11 @@ class ConditionBlock extends BasicBlock {
|
||||
// only `x & y` controls `A` if we do not take sub conditions into account.
|
||||
predicate controlsSubCond(BasicBlock controlled, boolean testIsTrue, Expr cond, boolean condIsTrue) {
|
||||
impliesSub(getLastNode().getElement(), cond, testIsTrue, condIsTrue) and
|
||||
controls(controlled, testIsTrue)
|
||||
controls(controlled, any(BooleanSuccessor s | s.getValue() = testIsTrue))
|
||||
}
|
||||
|
||||
private predicate isCandidateSuccessor(BasicBlock succ, boolean testIsTrue) {
|
||||
(
|
||||
testIsTrue = true and succ = this.getATrueSuccessor()
|
||||
or
|
||||
testIsTrue = false and succ = this.getAFalseSuccessor()
|
||||
)
|
||||
and
|
||||
forall(BasicBlock pred |
|
||||
pred = succ.getAPredecessor() and pred != this |
|
||||
succ.dominates(pred)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isCandidateSuccessorNullness(BasicBlock succ, boolean isNull) {
|
||||
(
|
||||
isNull = true and succ = this.getANullSuccessor()
|
||||
or
|
||||
isNull = false and succ = this.getANonNullSuccessor()
|
||||
)
|
||||
and
|
||||
private predicate isCandidateSuccessor(BasicBlock succ, ConditionalSuccessor s) {
|
||||
succ = this.getASuccessorByType(s) and
|
||||
forall(BasicBlock pred |
|
||||
pred = succ.getAPredecessor() and pred != this |
|
||||
succ.dominates(pred)
|
||||
|
||||
@@ -401,10 +401,21 @@ private predicate inNullnessContext(Expr e, boolean isNullnessCompletionForParen
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `cfe` is the element inside case statement `cs`, belonging to `switch`
|
||||
* statement `ss`, that has the matching completion.
|
||||
*/
|
||||
predicate switchMatching(SwitchStmt ss, CaseStmt cs, ControlFlowElement cfe) {
|
||||
ss.getACase() = cs and
|
||||
(
|
||||
cfe = cs.(ConstCase).getExpr()
|
||||
or
|
||||
cfe = cs.(TypeCase).getTypeAccess() // use type access to represent the type test
|
||||
)
|
||||
}
|
||||
|
||||
private predicate mustHaveMatchingCompletion(SwitchStmt ss, ControlFlowElement cfe) {
|
||||
cfe = ss.getAConstCase().getExpr()
|
||||
or
|
||||
cfe = ss.getATypeCase().getTypeAccess() // use type access to represent the type test
|
||||
switchMatching(ss, _, cfe)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -255,6 +255,7 @@ module ControlFlow {
|
||||
* The node on line 2 is an immediate `null` successor of the node
|
||||
* `x` on line 1.
|
||||
*/
|
||||
deprecated
|
||||
Node getANullSuccessor() {
|
||||
result = getASuccessorByType(any(NullnessSuccessor t | t.isNull()))
|
||||
}
|
||||
@@ -274,6 +275,7 @@ module ControlFlow {
|
||||
* The node `x?.M()`, representing the call to `M`, is a non-`null` successor
|
||||
* of the node `x`.
|
||||
*/
|
||||
deprecated
|
||||
Node getANonNullSuccessor() {
|
||||
result = getASuccessorByType(any(NullnessSuccessor t | not t.isNull()))
|
||||
}
|
||||
@@ -400,7 +402,10 @@ module ControlFlow {
|
||||
* a nullness successor (`NullnessSuccessor`), a matching successor (`MatchingSuccessor`),
|
||||
* or an emptiness successor (`EmptinessSuccessor`).
|
||||
*/
|
||||
abstract class ConditionalSuccessor extends SuccessorType { }
|
||||
abstract class ConditionalSuccessor extends SuccessorType {
|
||||
/** Gets the Boolean value of this successor. */
|
||||
abstract boolean getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* A Boolean control flow successor.
|
||||
@@ -429,8 +434,7 @@ module ControlFlow {
|
||||
* ```
|
||||
*/
|
||||
class BooleanSuccessor extends ConditionalSuccessor, TBooleanSuccessor {
|
||||
/** Gets the value of this Boolean successor. */
|
||||
boolean getValue() { this = TBooleanSuccessor(result) }
|
||||
override boolean getValue() { this = TBooleanSuccessor(result) }
|
||||
|
||||
override string toString() { result = getValue().toString() }
|
||||
|
||||
@@ -469,6 +473,8 @@ module ControlFlow {
|
||||
/** Holds if this is a `null` successor. */
|
||||
predicate isNull() { this = TNullnessSuccessor(true) }
|
||||
|
||||
override boolean getValue() { this = TNullnessSuccessor(result) }
|
||||
|
||||
override string toString() {
|
||||
if this.isNull() then
|
||||
result = "null"
|
||||
@@ -520,6 +526,8 @@ module ControlFlow {
|
||||
/** Holds if this is a match successor. */
|
||||
predicate isMatch() { this = TMatchingSuccessor(true) }
|
||||
|
||||
override boolean getValue() { this = TMatchingSuccessor(result) }
|
||||
|
||||
override string toString() {
|
||||
if this.isMatch() then
|
||||
result = "match"
|
||||
@@ -571,6 +579,8 @@ module ControlFlow {
|
||||
/** Holds if this is an empty successor. */
|
||||
predicate isEmpty() { this = TEmptinessSuccessor(true) }
|
||||
|
||||
override boolean getValue() { this = TEmptinessSuccessor(result) }
|
||||
|
||||
override string toString() {
|
||||
if this.isEmpty() then
|
||||
result = "empty"
|
||||
|
||||
@@ -10,14 +10,12 @@ private import semmle.code.csharp.frameworks.System
|
||||
|
||||
/** An expression that accesses/calls a declaration. */
|
||||
class AccessOrCallExpr extends Expr {
|
||||
AccessOrCallExpr() {
|
||||
exists(getDeclarationTarget(this))
|
||||
}
|
||||
private Declaration target;
|
||||
|
||||
AccessOrCallExpr() { target = getDeclarationTarget(this) }
|
||||
|
||||
/** Gets the target of this expression. */
|
||||
Declaration getTarget() {
|
||||
result = getDeclarationTarget(this)
|
||||
}
|
||||
Declaration getTarget() { result = target }
|
||||
|
||||
/**
|
||||
* Gets the (non-trivial) SSA definition corresponding to the longest
|
||||
@@ -35,16 +33,12 @@ class AccessOrCallExpr extends Expr {
|
||||
* x; // SSA qualifier: SSA definition for `x`
|
||||
* ```
|
||||
*/
|
||||
Ssa::Definition getSsaQualifier() {
|
||||
result = getSsaQualifier(this)
|
||||
}
|
||||
Ssa::Definition getSsaQualifier() { result = getSsaQualifier(this) }
|
||||
|
||||
/**
|
||||
* Holds if this expression has an SSA qualifier.
|
||||
*/
|
||||
predicate hasSsaQualifier() {
|
||||
exists(getSsaQualifier())
|
||||
}
|
||||
predicate hasSsaQualifier() { exists(this.getSsaQualifier()) }
|
||||
}
|
||||
|
||||
private Declaration getDeclarationTarget(Expr e) {
|
||||
@@ -103,8 +97,12 @@ private AssignableRead getATrackedRead(Ssa::Definition def) {
|
||||
* definition).
|
||||
*/
|
||||
class GuardedExpr extends AccessOrCallExpr {
|
||||
private Expr cond0;
|
||||
private AccessOrCallExpr e0;
|
||||
private boolean b0;
|
||||
|
||||
GuardedExpr() {
|
||||
Internal::isGuardedBy(this, _, _, _)
|
||||
Internal::isGuardedBy(this, cond0, e0, b0)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,14 +115,16 @@ class GuardedExpr extends AccessOrCallExpr {
|
||||
* variable).
|
||||
*/
|
||||
predicate isGuardedBy(Expr cond, Expr e, boolean b) {
|
||||
Internal::isGuardedBy(this, cond, e, b)
|
||||
cond = cond0 and
|
||||
e = e0 and
|
||||
b = b0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A nullness guarded expression.
|
||||
*
|
||||
* A nullness guarded expression is an access or a call that is reached only
|
||||
* A nullness guarded expression is an access or a call that is reached only
|
||||
* when a nullness condition containing a structurally equal expression
|
||||
* evaluates to one of `null` or non-`null`.
|
||||
*
|
||||
@@ -136,8 +136,11 @@ class GuardedExpr extends AccessOrCallExpr {
|
||||
* ```
|
||||
*/
|
||||
class NullnessGuardedExpr extends AccessOrCallExpr {
|
||||
private Expr e0;
|
||||
private boolean isNull0;
|
||||
|
||||
NullnessGuardedExpr() {
|
||||
Internal::isGuardedByNullness(this, _, _)
|
||||
Internal::isGuardedByNullness(this, e0, isNull0)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -150,13 +153,64 @@ class NullnessGuardedExpr extends AccessOrCallExpr {
|
||||
* variable).
|
||||
*/
|
||||
predicate isGuardedBy(Expr e, boolean isNull) {
|
||||
Internal::isGuardedByNullness(this, e, isNull)
|
||||
e = e0 and
|
||||
isNull = isNull0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A matching guarded expression.
|
||||
*
|
||||
* A matching guarded expression is an access or a call that is reached only
|
||||
* when a pattern, matching against a structurally equal expression, matches
|
||||
* or non-matches.
|
||||
*
|
||||
* For example, the access to `o` on line 8 is only evaluated when `case null`
|
||||
* does not match.
|
||||
*
|
||||
* ```
|
||||
* string M(object o)
|
||||
* {
|
||||
* switch (o)
|
||||
* {
|
||||
* case null:
|
||||
* return "";
|
||||
* default:
|
||||
* return o.ToString();
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class MatchingGuardedExpr extends AccessOrCallExpr {
|
||||
private AccessOrCallExpr e0;
|
||||
private CaseStmt cs0;
|
||||
private boolean isMatch0;
|
||||
|
||||
MatchingGuardedExpr() {
|
||||
Internal::isGuardedByMatching(this, e0, cs0, isMatch0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this expression is guarded by case statement `cs` matching
|
||||
* (`isMatch = true`) or non-matching (`isMatch = false`). The expression
|
||||
* `e` is structurally equal to this expression being matched against in
|
||||
* `cs`.
|
||||
*
|
||||
* In case this expression or `e` accesses an SSA variable in its
|
||||
* left-most qualifier, then so must the other (accessing the same SSA
|
||||
* variable).
|
||||
*/
|
||||
predicate isGuardedBy(AccessOrCallExpr e, CaseStmt cs, boolean isMatch) {
|
||||
e = e0 and
|
||||
cs0 = cs and
|
||||
isMatch0 = isMatch
|
||||
}
|
||||
}
|
||||
|
||||
/** An expression guarded by a `null` check. */
|
||||
class NullGuardedExpr extends AccessOrCallExpr {
|
||||
NullGuardedExpr() {
|
||||
this.getType() instanceof RefType and
|
||||
exists(Expr cond, Expr sub, boolean b |
|
||||
this.(GuardedExpr).isGuardedBy(cond, sub, b) |
|
||||
// Comparison with `null`, for example `x != null`
|
||||
@@ -182,19 +236,47 @@ class NullGuardedExpr extends AccessOrCallExpr {
|
||||
)
|
||||
or
|
||||
// Call to `string.IsNullOrEmpty()`
|
||||
exists(MethodCall mc |
|
||||
mc = cond and
|
||||
cond = any(MethodCall mc |
|
||||
mc.getTarget() = any(SystemStringClass c).getIsNullOrEmptyMethod() and
|
||||
mc.getArgument(0) = sub and
|
||||
b = false
|
||||
)
|
||||
or
|
||||
cond = any(IsExpr ie |
|
||||
ie.getExpr() = sub and
|
||||
if ie.(IsConstantExpr).getConstant() instanceof NullLiteral then
|
||||
// E.g. `x is null`
|
||||
b = false
|
||||
else
|
||||
// E.g. `x is string`
|
||||
b = true
|
||||
)
|
||||
)
|
||||
or
|
||||
this.(NullnessGuardedExpr).isGuardedBy(_, false)
|
||||
or
|
||||
exists(CaseStmt cs, boolean isMatch |
|
||||
this.(MatchingGuardedExpr).isGuardedBy(_, cs, isMatch) |
|
||||
// E.g. `case string`
|
||||
cs instanceof TypeCase and
|
||||
isMatch = true
|
||||
or
|
||||
cs = any(ConstCase cc |
|
||||
if cc.getExpr() instanceof NullLiteral then
|
||||
// `case null`
|
||||
isMatch = false
|
||||
else
|
||||
// E.g. `case ""`
|
||||
isMatch = true
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private module Internal {
|
||||
private import semmle.code.csharp.controlflow.Completion
|
||||
private import ControlFlow::SuccessorTypes
|
||||
|
||||
private cached module Cached {
|
||||
cached predicate isGuardedBy(AccessOrCallExpr guarded, Expr cond, AccessOrCallExpr e, boolean b) {
|
||||
exists(BasicBlock bb |
|
||||
@@ -217,6 +299,17 @@ private module Internal {
|
||||
guarded.getSsaQualifier() = e.getSsaQualifier()
|
||||
)
|
||||
}
|
||||
|
||||
cached predicate isGuardedByMatching(AccessOrCallExpr guarded, AccessOrCallExpr e, CaseStmt cs, boolean isMatch) {
|
||||
exists(BasicBlock bb |
|
||||
controlsMatching(e, cs, bb, isMatch) and
|
||||
bb = guarded.getAControlFlowNode().getBasicBlock() and
|
||||
exists(ConditionOnExprComparisonConfig c | c.same(e, guarded)) |
|
||||
not guarded.hasSsaQualifier() and not e.hasSsaQualifier()
|
||||
or
|
||||
guarded.getSsaQualifier() = e.getSsaQualifier()
|
||||
)
|
||||
}
|
||||
}
|
||||
import Cached
|
||||
|
||||
@@ -263,12 +356,27 @@ private module Internal {
|
||||
* (`isNull = true`) or when `e` evaluates to non-`null` (`isNull = false`).
|
||||
*/
|
||||
private predicate controlsNullness(Expr e, BasicBlock bb, boolean isNull) {
|
||||
exists(ConditionBlock cb |
|
||||
cb.controlsNullness(bb, isNull) |
|
||||
exists(ConditionBlock cb, NullnessSuccessor s |
|
||||
cb.controls(bb, s) |
|
||||
isNull = s.getValue() and
|
||||
e = cb.getLastNode().getElement()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if basic block `bb` only is reached when `e` matches case `cs`
|
||||
* (`isMatch = true`) or when `e` does not match `cs` (`isMatch = false`).
|
||||
*/
|
||||
private predicate controlsMatching(Expr e, CaseStmt cs, BasicBlock bb, boolean isMatch) {
|
||||
exists(ConditionBlock cb, SwitchStmt ss, ControlFlowElement cfe, MatchingSuccessor s |
|
||||
cb.controls(bb, s) |
|
||||
cfe = cb.getLastNode().getElement() and
|
||||
switchMatching(ss, cs, cfe) and
|
||||
e = ss.getCondition() and
|
||||
isMatch = s.getValue()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper class for calculating structurally equal access/call expressions.
|
||||
*/
|
||||
@@ -280,7 +388,10 @@ private module Internal {
|
||||
override predicate candidate(Element x, Element y) {
|
||||
exists(BasicBlock bb, Declaration d |
|
||||
candidateAux(x, d, bb) and
|
||||
y = any(AccessOrCallExpr e | e.getAControlFlowNode().getBasicBlock() = bb and e.getTarget() = d)
|
||||
y = any(AccessOrCallExpr e |
|
||||
e.getAControlFlowNode().getBasicBlock() = bb and
|
||||
e.getTarget() = d
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -289,10 +400,16 @@ private module Internal {
|
||||
* is a sub expression of a condition that controls whether basic block
|
||||
* `bb` is reached.
|
||||
*/
|
||||
pragma [noinline] // predicate folding for proper join-order
|
||||
pragma [noinline]
|
||||
private predicate candidateAux(AccessOrCallExpr e, Declaration target, BasicBlock bb) {
|
||||
(controls(_, e, bb, _) or controlsNullness(e, bb, _)) and
|
||||
target = e.getTarget()
|
||||
target = e.getTarget() and
|
||||
(
|
||||
controls(_, e, bb, _)
|
||||
or
|
||||
controlsNullness(e, bb, _)
|
||||
or
|
||||
controlsMatching(e, _, bb, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,14 +73,20 @@ module UserControlledBypassOfSensitiveMethod {
|
||||
* on the given expression.
|
||||
*/
|
||||
predicate conditionControlsMethod(MethodCall call, Expr e) {
|
||||
exists (ConditionBlock cb, SensitiveExecutionMethod def, boolean cond |
|
||||
cb.controls(call.getAControlFlowNode().getBasicBlock(), cond) and
|
||||
exists(ConditionBlock cb, SensitiveExecutionMethod def, boolean cond |
|
||||
exists(ControlFlow::SuccessorTypes::BooleanSuccessor s |
|
||||
cond = s.getValue() |
|
||||
cb.controls(call.getAControlFlowNode().getBasicBlock(), s)
|
||||
) and
|
||||
def = call.getTarget() and
|
||||
/*
|
||||
* Exclude this condition if the other branch also contains a call to the same security
|
||||
* sensitive method.
|
||||
*/
|
||||
not cb.controls(def.getACall().getAControlFlowNode().getBasicBlock(), cond.booleanNot()) and
|
||||
not exists(ControlFlow::SuccessorTypes::BooleanSuccessor s |
|
||||
cond = s.getValue().booleanNot() |
|
||||
cb.controls(def.getACall().getAControlFlowNode().getBasicBlock(), s)
|
||||
) and
|
||||
e = cb.getLastNode().getElement()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
| BreakInTry.cs:7:13:11:13 | foreach (... ... in ...) ... | BreakInTry.cs:7:26:7:28 | String arg | false |
|
||||
| BreakInTry.cs:7:13:11:13 | foreach (... ... in ...) ... | BreakInTry.cs:10:21:10:26 | break; | false |
|
||||
| BreakInTry.cs:9:21:9:31 | ... == ... | BreakInTry.cs:10:21:10:26 | break; | true |
|
||||
| BreakInTry.cs:15:17:15:28 | ... == ... | BreakInTry.cs:16:17:16:17 | ; | true |
|
||||
| BreakInTry.cs:22:9:34:9 | foreach (... ... in ...) ... | BreakInTry.cs:22:22:22:24 | String arg | false |
|
||||
| BreakInTry.cs:22:9:34:9 | foreach (... ... in ...) ... | BreakInTry.cs:27:21:27:26 | break; | false |
|
||||
| BreakInTry.cs:22:9:34:9 | foreach (... ... in ...) ... | BreakInTry.cs:30:13:33:13 | {...} | false |
|
||||
| BreakInTry.cs:22:9:34:9 | foreach (... ... in ...) ... | BreakInTry.cs:32:21:32:21 | ; | false |
|
||||
| BreakInTry.cs:22:9:34:9 | foreach (... ... in ...) ... | BreakInTry.cs:32:21:32:21 | [finally: break] ; | false |
|
||||
| BreakInTry.cs:26:21:26:31 | ... == ... | BreakInTry.cs:27:21:27:26 | break; | true |
|
||||
| BreakInTry.cs:26:21:26:31 | ... == ... | BreakInTry.cs:30:13:33:13 | {...} | false |
|
||||
| BreakInTry.cs:26:21:26:31 | ... == ... | BreakInTry.cs:32:21:32:21 | ; | false |
|
||||
@@ -15,6 +22,10 @@
|
||||
| BreakInTry.cs:42:17:42:28 | ... == ... | BreakInTry.cs:50:21:50:26 | [finally: return] break; | true |
|
||||
| BreakInTry.cs:42:17:42:28 | ... == ... | BreakInTry.cs:50:21:50:26 | break; | false |
|
||||
| BreakInTry.cs:42:17:42:28 | ... == ... | BreakInTry.cs:53:7:53:7 | ; | false |
|
||||
| BreakInTry.cs:47:13:51:13 | [finally: return] foreach (... ... in ...) ... | BreakInTry.cs:47:26:47:28 | [finally: return] String arg | false |
|
||||
| BreakInTry.cs:47:13:51:13 | [finally: return] foreach (... ... in ...) ... | BreakInTry.cs:50:21:50:26 | [finally: return] break; | false |
|
||||
| BreakInTry.cs:47:13:51:13 | foreach (... ... in ...) ... | BreakInTry.cs:47:26:47:28 | String arg | false |
|
||||
| BreakInTry.cs:47:13:51:13 | foreach (... ... in ...) ... | BreakInTry.cs:50:21:50:26 | break; | false |
|
||||
| BreakInTry.cs:49:21:49:31 | ... == ... | BreakInTry.cs:50:21:50:26 | break; | true |
|
||||
| BreakInTry.cs:49:21:49:31 | [finally: return] ... == ... | BreakInTry.cs:50:21:50:26 | [finally: return] break; | true |
|
||||
| BreakInTry.cs:60:17:60:28 | ... == ... | BreakInTry.cs:61:17:61:23 | return ...; | true |
|
||||
@@ -25,6 +36,10 @@
|
||||
| BreakInTry.cs:60:17:60:28 | ... == ... | BreakInTry.cs:65:26:65:28 | [finally: return] String arg | true |
|
||||
| BreakInTry.cs:60:17:60:28 | ... == ... | BreakInTry.cs:68:21:68:26 | [finally: return] break; | true |
|
||||
| BreakInTry.cs:60:17:60:28 | ... == ... | BreakInTry.cs:68:21:68:26 | break; | false |
|
||||
| BreakInTry.cs:65:13:69:13 | [finally: return] foreach (... ... in ...) ... | BreakInTry.cs:65:26:65:28 | [finally: return] String arg | false |
|
||||
| BreakInTry.cs:65:13:69:13 | [finally: return] foreach (... ... in ...) ... | BreakInTry.cs:68:21:68:26 | [finally: return] break; | false |
|
||||
| BreakInTry.cs:65:13:69:13 | foreach (... ... in ...) ... | BreakInTry.cs:65:26:65:28 | String arg | false |
|
||||
| BreakInTry.cs:65:13:69:13 | foreach (... ... in ...) ... | BreakInTry.cs:68:21:68:26 | break; | false |
|
||||
| BreakInTry.cs:67:21:67:31 | ... == ... | BreakInTry.cs:68:21:68:26 | break; | true |
|
||||
| BreakInTry.cs:67:21:67:31 | [finally: return] ... == ... | BreakInTry.cs:68:21:68:26 | [finally: return] break; | true |
|
||||
| CatchInFinally.cs:9:17:9:28 | ... == ... | CatchInFinally.cs:10:17:10:50 | throw ...; | true |
|
||||
@@ -58,8 +73,16 @@
|
||||
| CatchInFinally.cs:16:21:16:36 | [finally: exception(ArgumentNullException)] ... == ... | CatchInFinally.cs:17:41:17:43 | [finally: exception(ArgumentNullException)] "1" | true |
|
||||
| CatchInFinally.cs:16:21:16:36 | [finally: exception(Exception)] ... == ... | CatchInFinally.cs:17:21:17:45 | [finally: exception(Exception)] throw ...; | true |
|
||||
| CatchInFinally.cs:16:21:16:36 | [finally: exception(Exception)] ... == ... | CatchInFinally.cs:17:41:17:43 | [finally: exception(Exception)] "1" | true |
|
||||
| ConditionalAccess.cs:3:26:3:26 | access to parameter i | ConditionalAccess.cs:3:28:3:38 | call to method ToString | false |
|
||||
| ConditionalAccess.cs:3:26:3:26 | access to parameter i | ConditionalAccess.cs:3:40:3:49 | call to method ToLower | false |
|
||||
| ConditionalAccess.cs:3:28:3:38 | call to method ToString | ConditionalAccess.cs:3:40:3:49 | call to method ToLower | false |
|
||||
| ConditionalAccess.cs:5:26:5:26 | access to parameter s | ConditionalAccess.cs:5:28:5:34 | access to property Length | false |
|
||||
| ConditionalAccess.cs:7:39:7:40 | access to parameter s1 | ConditionalAccess.cs:7:45:7:46 | access to parameter s2 | true |
|
||||
| ConditionalAccess.cs:9:25:9:25 | access to parameter s | ConditionalAccess.cs:9:27:9:33 | access to property Length | false |
|
||||
| ConditionalAccess.cs:13:13:13:13 | access to parameter s | ConditionalAccess.cs:13:15:13:21 | access to property Length | false |
|
||||
| ConditionalAccess.cs:13:13:13:25 | ... > ... | ConditionalAccess.cs:14:20:14:20 | 0 | true |
|
||||
| ConditionalAccess.cs:13:13:13:25 | ... > ... | ConditionalAccess.cs:16:20:16:20 | 1 | false |
|
||||
| ConditionalAccess.cs:19:40:19:41 | access to parameter s1 | ConditionalAccess.cs:19:58:19:59 | access to parameter s2 | false |
|
||||
| Conditions.cs:5:13:5:15 | access to parameter inc | Conditions.cs:6:13:6:16 | [inc (line 3): true] ...; | true |
|
||||
| Conditions.cs:5:13:5:15 | access to parameter inc | Conditions.cs:7:9:8:16 | [inc (line 3): false] if (...) ... | false |
|
||||
| Conditions.cs:14:13:14:13 | access to parameter b | Conditions.cs:15:13:15:16 | [b (line 11): true] ...; | true |
|
||||
@@ -106,9 +129,23 @@
|
||||
| Conditions.cs:62:17:62:17 | access to parameter b | Conditions.cs:63:17:63:20 | [b (line 57): true] ...; | true |
|
||||
| Conditions.cs:62:17:62:17 | access to parameter b | Conditions.cs:65:9:66:16 | [b (line 57): false] if (...) ... | false |
|
||||
| Conditions.cs:62:17:62:17 | access to parameter b | Conditions.cs:65:9:66:16 | [b (line 57): true] if (...) ... | true |
|
||||
| Conditions.cs:74:9:80:9 | foreach (... ... in ...) ... | Conditions.cs:75:9:80:9 | {...} | false |
|
||||
| Conditions.cs:74:9:80:9 | foreach (... ... in ...) ... | Conditions.cs:77:17:77:20 | ...; | false |
|
||||
| Conditions.cs:74:9:80:9 | foreach (... ... in ...) ... | Conditions.cs:78:13:79:26 | if (...) ... | false |
|
||||
| Conditions.cs:74:9:80:9 | foreach (... ... in ...) ... | Conditions.cs:79:17:79:26 | ...; | false |
|
||||
| Conditions.cs:74:9:80:9 | foreach (... ... in ...) ... | Conditions.cs:81:9:82:16 | if (...) ... | true |
|
||||
| Conditions.cs:74:9:80:9 | foreach (... ... in ...) ... | Conditions.cs:82:13:82:16 | ...; | true |
|
||||
| Conditions.cs:74:9:80:9 | foreach (... ... in ...) ... | Conditions.cs:83:16:83:16 | access to local variable x | true |
|
||||
| Conditions.cs:76:17:76:17 | access to local variable b | Conditions.cs:77:17:77:20 | ...; | true |
|
||||
| Conditions.cs:78:17:78:21 | ... > ... | Conditions.cs:79:17:79:26 | ...; | true |
|
||||
| Conditions.cs:81:12:81:12 | access to local variable b | Conditions.cs:82:13:82:16 | ...; | true |
|
||||
| Conditions.cs:90:9:98:9 | foreach (... ... in ...) ... | Conditions.cs:91:9:98:9 | {...} | false |
|
||||
| Conditions.cs:90:9:98:9 | foreach (... ... in ...) ... | Conditions.cs:93:17:93:20 | ...; | false |
|
||||
| Conditions.cs:90:9:98:9 | foreach (... ... in ...) ... | Conditions.cs:94:13:95:26 | if (...) ... | false |
|
||||
| Conditions.cs:90:9:98:9 | foreach (... ... in ...) ... | Conditions.cs:95:17:95:26 | ...; | false |
|
||||
| Conditions.cs:90:9:98:9 | foreach (... ... in ...) ... | Conditions.cs:96:13:97:20 | if (...) ... | false |
|
||||
| Conditions.cs:90:9:98:9 | foreach (... ... in ...) ... | Conditions.cs:97:17:97:20 | ...; | false |
|
||||
| Conditions.cs:90:9:98:9 | foreach (... ... in ...) ... | Conditions.cs:99:16:99:16 | access to local variable x | true |
|
||||
| Conditions.cs:92:17:92:17 | access to local variable b | Conditions.cs:93:17:93:20 | ...; | true |
|
||||
| Conditions.cs:94:17:94:21 | ... > ... | Conditions.cs:95:17:95:26 | ...; | true |
|
||||
| Conditions.cs:96:17:96:17 | access to local variable b | Conditions.cs:97:17:97:20 | ...; | true |
|
||||
@@ -118,6 +155,7 @@
|
||||
| Conditions.cs:105:13:105:13 | access to parameter b | Conditions.cs:108:13:109:24 | [b (line 102): true] if (...) ... | true |
|
||||
| Conditions.cs:107:13:107:24 | [b (line 102): false] ... > ... | Conditions.cs:108:13:109:24 | [b (line 102): false] if (...) ... | true |
|
||||
| Conditions.cs:107:13:107:24 | [b (line 102): true] ... > ... | Conditions.cs:108:13:109:24 | [b (line 102): true] if (...) ... | true |
|
||||
| ExitMethods.cs:42:9:45:9 | [exception: Exception] catch (...) {...} | ExitMethods.cs:46:9:49:9 | [exception: Exception] catch (...) {...} | false |
|
||||
| ExitMethods.cs:54:13:54:13 | access to parameter b | ExitMethods.cs:55:19:55:33 | object creation of type Exception | true |
|
||||
| ExitMethods.cs:60:13:60:13 | access to parameter b | ExitMethods.cs:61:19:61:33 | object creation of type Exception | true |
|
||||
| ExitMethods.cs:60:13:60:13 | access to parameter b | ExitMethods.cs:63:41:63:43 | "b" | false |
|
||||
@@ -125,9 +163,23 @@
|
||||
| ExitMethods.cs:78:16:78:25 | ... != ... | ExitMethods.cs:78:69:78:75 | "input" | false |
|
||||
| ExitMethods.cs:83:16:83:30 | call to method Contains | ExitMethods.cs:83:34:83:34 | 0 | true |
|
||||
| ExitMethods.cs:83:16:83:30 | call to method Contains | ExitMethods.cs:83:38:83:38 | 1 | false |
|
||||
| Foreach.cs:8:9:9:13 | foreach (... ... in ...) ... | Foreach.cs:6:10:6:11 | exit M1 | true |
|
||||
| Foreach.cs:8:9:9:13 | foreach (... ... in ...) ... | Foreach.cs:8:22:8:24 | String arg | false |
|
||||
| Foreach.cs:14:9:15:13 | foreach (... ... in ...) ... | Foreach.cs:12:10:12:11 | exit M2 | true |
|
||||
| Foreach.cs:14:9:15:13 | foreach (... ... in ...) ... | Foreach.cs:15:13:15:13 | ; | false |
|
||||
| Foreach.cs:20:9:21:11 | foreach (... ... in ...) ... | Foreach.cs:18:10:18:11 | exit M3 | true |
|
||||
| Foreach.cs:20:9:21:11 | foreach (... ... in ...) ... | Foreach.cs:20:22:20:22 | String x | false |
|
||||
| Foreach.cs:20:27:20:27 | access to parameter e | Foreach.cs:20:29:20:38 | call to method ToArray | false |
|
||||
| NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:28:3:28 | 0 | true |
|
||||
| NullCoalescing.cs:5:25:5:25 | access to parameter b | NullCoalescing.cs:5:30:5:34 | false | true |
|
||||
| NullCoalescing.cs:5:25:5:25 | access to parameter b | NullCoalescing.cs:5:39:5:39 | 0 | true |
|
||||
| NullCoalescing.cs:7:40:7:41 | access to parameter s1 | NullCoalescing.cs:7:46:7:53 | ... ?? ... | true |
|
||||
| NullCoalescing.cs:7:40:7:41 | access to parameter s1 | NullCoalescing.cs:7:52:7:53 | "" | true |
|
||||
| NullCoalescing.cs:7:46:7:47 | access to parameter s2 | NullCoalescing.cs:7:52:7:53 | "" | true |
|
||||
| NullCoalescing.cs:9:37:9:37 | access to parameter b | NullCoalescing.cs:9:41:9:41 | access to parameter s | true |
|
||||
| NullCoalescing.cs:9:37:9:37 | access to parameter b | NullCoalescing.cs:9:45:9:45 | access to parameter s | false |
|
||||
| NullCoalescing.cs:11:44:11:45 | access to parameter b1 | NullCoalescing.cs:11:51:11:58 | ... && ... | true |
|
||||
| NullCoalescing.cs:11:44:11:45 | access to parameter b1 | NullCoalescing.cs:11:57:11:58 | access to parameter b3 | true |
|
||||
| NullCoalescing.cs:11:51:11:52 | access to parameter b2 | NullCoalescing.cs:11:57:11:58 | access to parameter b3 | true |
|
||||
| Patterns.cs:8:13:8:23 | ... is ... | Patterns.cs:9:9:11:9 | {...} | true |
|
||||
| Patterns.cs:8:13:8:23 | ... is ... | Patterns.cs:12:14:18:9 | if (...) ... | false |
|
||||
@@ -138,16 +190,123 @@
|
||||
| Patterns.cs:12:18:12:31 | ... is ... | Patterns.cs:16:14:18:9 | if (...) ... | false |
|
||||
| Patterns.cs:12:18:12:31 | ... is ... | Patterns.cs:17:9:18:9 | {...} | false |
|
||||
| Patterns.cs:16:18:16:28 | ... is ... | Patterns.cs:17:9:18:9 | {...} | true |
|
||||
| Patterns.cs:22:18:22:22 | "xyz" | Patterns.cs:23:17:23:22 | break; | true |
|
||||
| Patterns.cs:22:18:22:22 | "xyz" | Patterns.cs:24:13:24:36 | case Int32 i2: | false |
|
||||
| Patterns.cs:22:18:22:22 | "xyz" | Patterns.cs:24:18:24:23 | Int32 i2 | false |
|
||||
| Patterns.cs:22:18:22:22 | "xyz" | Patterns.cs:25:17:25:52 | ...; | false |
|
||||
| Patterns.cs:22:18:22:22 | "xyz" | Patterns.cs:27:13:27:24 | case Int32 i3: | false |
|
||||
| Patterns.cs:22:18:22:22 | "xyz" | Patterns.cs:27:18:27:23 | Int32 i3 | false |
|
||||
| Patterns.cs:22:18:22:22 | "xyz" | Patterns.cs:30:13:30:27 | case String s2: | false |
|
||||
| Patterns.cs:22:18:22:22 | "xyz" | Patterns.cs:30:18:30:26 | String s2 | false |
|
||||
| Patterns.cs:22:18:22:22 | "xyz" | Patterns.cs:33:13:33:24 | case Object v2: | false |
|
||||
| Patterns.cs:22:18:22:22 | "xyz" | Patterns.cs:33:18:33:23 | Object v2 | false |
|
||||
| Patterns.cs:22:18:22:22 | "xyz" | Patterns.cs:35:13:35:20 | default: | false |
|
||||
| Patterns.cs:24:18:24:20 | access to type Int32 | Patterns.cs:24:18:24:23 | Int32 i2 | true |
|
||||
| Patterns.cs:24:18:24:20 | access to type Int32 | Patterns.cs:25:17:25:52 | ...; | true |
|
||||
| Patterns.cs:24:30:24:35 | ... > ... | Patterns.cs:25:17:25:52 | ...; | true |
|
||||
| Patterns.cs:27:18:27:20 | access to type Int32 | Patterns.cs:27:18:27:23 | Int32 i3 | true |
|
||||
| Patterns.cs:27:18:27:20 | access to type Int32 | Patterns.cs:30:13:30:27 | case String s2: | false |
|
||||
| Patterns.cs:27:18:27:20 | access to type Int32 | Patterns.cs:30:18:30:26 | String s2 | false |
|
||||
| Patterns.cs:27:18:27:20 | access to type Int32 | Patterns.cs:33:13:33:24 | case Object v2: | false |
|
||||
| Patterns.cs:27:18:27:20 | access to type Int32 | Patterns.cs:33:18:33:23 | Object v2 | false |
|
||||
| Patterns.cs:27:18:27:20 | access to type Int32 | Patterns.cs:35:13:35:20 | default: | false |
|
||||
| Patterns.cs:30:18:30:23 | access to type String | Patterns.cs:30:18:30:26 | String s2 | true |
|
||||
| Patterns.cs:30:18:30:23 | access to type String | Patterns.cs:33:13:33:24 | case Object v2: | false |
|
||||
| Patterns.cs:30:18:30:23 | access to type String | Patterns.cs:33:18:33:23 | Object v2 | false |
|
||||
| Patterns.cs:30:18:30:23 | access to type String | Patterns.cs:35:13:35:20 | default: | false |
|
||||
| Patterns.cs:33:18:33:20 | access to type Object | Patterns.cs:33:18:33:23 | Object v2 | true |
|
||||
| Patterns.cs:33:18:33:20 | access to type Object | Patterns.cs:35:13:35:20 | default: | false |
|
||||
| Switch.cs:14:18:14:20 | "a" | Switch.cs:15:17:15:23 | return ...; | true |
|
||||
| Switch.cs:14:18:14:20 | "a" | Switch.cs:16:13:16:19 | case ...: | false |
|
||||
| Switch.cs:14:18:14:20 | "a" | Switch.cs:17:23:17:37 | object creation of type Exception | false |
|
||||
| Switch.cs:14:18:14:20 | "a" | Switch.cs:18:13:18:22 | case ...: | false |
|
||||
| Switch.cs:14:18:14:20 | "a" | Switch.cs:19:17:19:29 | goto default; | false |
|
||||
| Switch.cs:14:18:14:20 | "a" | Switch.cs:20:13:20:23 | case Int32 i: | false |
|
||||
| Switch.cs:14:18:14:20 | "a" | Switch.cs:20:18:20:22 | Int32 i | false |
|
||||
| Switch.cs:14:18:14:20 | "a" | Switch.cs:22:21:22:27 | return ...; | false |
|
||||
| Switch.cs:14:18:14:20 | "a" | Switch.cs:23:27:23:27 | 0 | false |
|
||||
| Switch.cs:14:18:14:20 | "a" | Switch.cs:24:13:24:56 | case String s: | false |
|
||||
| Switch.cs:14:18:14:20 | "a" | Switch.cs:24:18:24:25 | String s | false |
|
||||
| Switch.cs:14:18:14:20 | "a" | Switch.cs:24:48:24:48 | access to local variable s | false |
|
||||
| Switch.cs:14:18:14:20 | "a" | Switch.cs:25:17:25:37 | ...; | false |
|
||||
| Switch.cs:14:18:14:20 | "a" | Switch.cs:27:13:27:39 | case Double d: | false |
|
||||
| Switch.cs:14:18:14:20 | "a" | Switch.cs:27:18:27:25 | Double d | false |
|
||||
| Switch.cs:14:18:14:20 | "a" | Switch.cs:30:13:30:20 | default: | false |
|
||||
| Switch.cs:16:18:16:18 | 0 | Switch.cs:18:13:18:22 | case ...: | false |
|
||||
| Switch.cs:16:18:16:18 | 0 | Switch.cs:19:17:19:29 | goto default; | false |
|
||||
| Switch.cs:16:18:16:18 | 0 | Switch.cs:20:13:20:23 | case Int32 i: | false |
|
||||
| Switch.cs:16:18:16:18 | 0 | Switch.cs:20:18:20:22 | Int32 i | false |
|
||||
| Switch.cs:16:18:16:18 | 0 | Switch.cs:22:21:22:27 | return ...; | false |
|
||||
| Switch.cs:16:18:16:18 | 0 | Switch.cs:23:27:23:27 | 0 | false |
|
||||
| Switch.cs:16:18:16:18 | 0 | Switch.cs:24:13:24:56 | case String s: | false |
|
||||
| Switch.cs:16:18:16:18 | 0 | Switch.cs:24:18:24:25 | String s | false |
|
||||
| Switch.cs:16:18:16:18 | 0 | Switch.cs:24:48:24:48 | access to local variable s | false |
|
||||
| Switch.cs:16:18:16:18 | 0 | Switch.cs:25:17:25:37 | ...; | false |
|
||||
| Switch.cs:16:18:16:18 | 0 | Switch.cs:27:13:27:39 | case Double d: | false |
|
||||
| Switch.cs:16:18:16:18 | 0 | Switch.cs:27:18:27:25 | Double d | false |
|
||||
| Switch.cs:16:18:16:18 | 0 | Switch.cs:30:13:30:20 | default: | false |
|
||||
| Switch.cs:18:18:18:21 | null | Switch.cs:19:17:19:29 | goto default; | true |
|
||||
| Switch.cs:18:18:18:21 | null | Switch.cs:20:13:20:23 | case Int32 i: | false |
|
||||
| Switch.cs:18:18:18:21 | null | Switch.cs:20:18:20:22 | Int32 i | false |
|
||||
| Switch.cs:18:18:18:21 | null | Switch.cs:22:21:22:27 | return ...; | false |
|
||||
| Switch.cs:18:18:18:21 | null | Switch.cs:23:27:23:27 | 0 | false |
|
||||
| Switch.cs:18:18:18:21 | null | Switch.cs:24:13:24:56 | case String s: | false |
|
||||
| Switch.cs:18:18:18:21 | null | Switch.cs:24:18:24:25 | String s | false |
|
||||
| Switch.cs:18:18:18:21 | null | Switch.cs:24:48:24:48 | access to local variable s | false |
|
||||
| Switch.cs:18:18:18:21 | null | Switch.cs:25:17:25:37 | ...; | false |
|
||||
| Switch.cs:18:18:18:21 | null | Switch.cs:27:13:27:39 | case Double d: | false |
|
||||
| Switch.cs:18:18:18:21 | null | Switch.cs:27:18:27:25 | Double d | false |
|
||||
| Switch.cs:20:18:20:20 | access to type Int32 | Switch.cs:20:18:20:22 | Int32 i | true |
|
||||
| Switch.cs:20:18:20:20 | access to type Int32 | Switch.cs:22:21:22:27 | return ...; | true |
|
||||
| Switch.cs:20:18:20:20 | access to type Int32 | Switch.cs:23:27:23:27 | 0 | true |
|
||||
| Switch.cs:20:18:20:20 | access to type Int32 | Switch.cs:24:13:24:56 | case String s: | false |
|
||||
| Switch.cs:20:18:20:20 | access to type Int32 | Switch.cs:24:18:24:25 | String s | false |
|
||||
| Switch.cs:20:18:20:20 | access to type Int32 | Switch.cs:24:48:24:48 | access to local variable s | false |
|
||||
| Switch.cs:20:18:20:20 | access to type Int32 | Switch.cs:25:17:25:37 | ...; | false |
|
||||
| Switch.cs:20:18:20:20 | access to type Int32 | Switch.cs:27:13:27:39 | case Double d: | false |
|
||||
| Switch.cs:20:18:20:20 | access to type Int32 | Switch.cs:27:18:27:25 | Double d | false |
|
||||
| Switch.cs:21:21:21:29 | ... == ... | Switch.cs:22:21:22:27 | return ...; | true |
|
||||
| Switch.cs:21:21:21:29 | ... == ... | Switch.cs:23:27:23:27 | 0 | false |
|
||||
| Switch.cs:24:18:24:23 | access to type String | Switch.cs:24:18:24:25 | String s | true |
|
||||
| Switch.cs:24:18:24:23 | access to type String | Switch.cs:24:48:24:48 | access to local variable s | true |
|
||||
| Switch.cs:24:18:24:23 | access to type String | Switch.cs:25:17:25:37 | ...; | true |
|
||||
| Switch.cs:24:32:24:43 | ... > ... | Switch.cs:24:48:24:48 | access to local variable s | true |
|
||||
| Switch.cs:24:32:24:43 | ... > ... | Switch.cs:25:17:25:37 | ...; | true |
|
||||
| Switch.cs:24:48:24:55 | ... != ... | Switch.cs:25:17:25:37 | ...; | true |
|
||||
| Switch.cs:27:18:27:23 | access to type Double | Switch.cs:27:18:27:25 | Double d | true |
|
||||
| Switch.cs:48:18:48:20 | access to type Int32 | Switch.cs:49:17:49:22 | break; | true |
|
||||
| Switch.cs:48:18:48:20 | access to type Int32 | Switch.cs:50:13:50:39 | case Boolean: | false |
|
||||
| Switch.cs:48:18:48:20 | access to type Int32 | Switch.cs:50:30:50:30 | access to parameter o | false |
|
||||
| Switch.cs:48:18:48:20 | access to type Int32 | Switch.cs:51:17:51:22 | break; | false |
|
||||
| Switch.cs:50:18:50:21 | access to type Boolean | Switch.cs:50:30:50:30 | access to parameter o | true |
|
||||
| Switch.cs:50:18:50:21 | access to type Boolean | Switch.cs:51:17:51:22 | break; | true |
|
||||
| Switch.cs:50:30:50:38 | ... != ... | Switch.cs:51:17:51:22 | break; | true |
|
||||
| Switch.cs:72:18:72:19 | "" | Switch.cs:73:15:73:20 | break; | true |
|
||||
| Switch.cs:81:18:81:18 | 1 | Switch.cs:82:22:82:25 | true | true |
|
||||
| Switch.cs:81:18:81:18 | 1 | Switch.cs:83:13:83:20 | case ...: | false |
|
||||
| Switch.cs:81:18:81:18 | 1 | Switch.cs:84:15:85:22 | if (...) ... | false |
|
||||
| Switch.cs:81:18:81:18 | 1 | Switch.cs:85:17:85:22 | break; | false |
|
||||
| Switch.cs:81:18:81:18 | 1 | Switch.cs:86:22:86:25 | true | false |
|
||||
| Switch.cs:81:18:81:18 | 1 | Switch.cs:88:16:88:20 | false | false |
|
||||
| Switch.cs:83:18:83:18 | 2 | Switch.cs:84:15:85:22 | if (...) ... | true |
|
||||
| Switch.cs:83:18:83:18 | 2 | Switch.cs:85:17:85:22 | break; | true |
|
||||
| Switch.cs:83:18:83:18 | 2 | Switch.cs:86:22:86:25 | true | true |
|
||||
| Switch.cs:84:19:84:23 | ... > ... | Switch.cs:85:17:85:22 | break; | true |
|
||||
| Switch.cs:84:19:84:23 | ... > ... | Switch.cs:86:22:86:25 | true | false |
|
||||
| Switch.cs:95:18:95:20 | access to type Int32 | Switch.cs:96:22:96:25 | true | true |
|
||||
| Switch.cs:95:18:95:20 | access to type Int32 | Switch.cs:98:16:98:20 | false | false |
|
||||
| Switch.cs:103:17:103:17 | access to parameter s | Switch.cs:103:19:103:25 | access to property Length | false |
|
||||
| Switch.cs:105:18:105:18 | 0 | Switch.cs:105:29:105:29 | 0 | true |
|
||||
| Switch.cs:105:18:105:18 | 0 | Switch.cs:106:13:106:20 | case ...: | false |
|
||||
| Switch.cs:105:18:105:18 | 0 | Switch.cs:106:29:106:29 | 1 | false |
|
||||
| Switch.cs:105:18:105:18 | 0 | Switch.cs:108:17:108:17 | 1 | false |
|
||||
| Switch.cs:106:18:106:18 | 1 | Switch.cs:106:29:106:29 | 1 | true |
|
||||
| Switch.cs:106:18:106:18 | 1 | Switch.cs:108:17:108:17 | 1 | false |
|
||||
| Switch.cs:117:18:117:18 | 3 | Switch.cs:117:25:117:25 | access to parameter s | true |
|
||||
| Switch.cs:117:18:117:18 | 3 | Switch.cs:117:43:117:43 | 1 | true |
|
||||
| Switch.cs:117:25:117:32 | ... == ... | Switch.cs:117:43:117:43 | 1 | true |
|
||||
| Switch.cs:118:18:118:18 | 2 | Switch.cs:118:25:118:25 | access to parameter s | true |
|
||||
| Switch.cs:118:18:118:18 | 2 | Switch.cs:118:42:118:42 | 2 | true |
|
||||
| Switch.cs:118:25:118:31 | ... == ... | Switch.cs:118:42:118:42 | 2 | true |
|
||||
| TypeAccesses.cs:7:13:7:22 | ... is ... | TypeAccesses.cs:7:25:7:25 | ; | true |
|
||||
| VarDecls.cs:25:20:25:20 | access to parameter b | VarDecls.cs:25:24:25:24 | access to local variable x | true |
|
||||
@@ -199,6 +358,35 @@
|
||||
| cflow.cs:28:22:28:31 | ... == ... | cflow.cs:33:17:33:37 | ...; | false |
|
||||
| cflow.cs:30:22:30:31 | ... == ... | cflow.cs:31:17:31:42 | ...; | true |
|
||||
| cflow.cs:30:22:30:31 | ... == ... | cflow.cs:33:17:33:37 | ...; | false |
|
||||
| cflow.cs:41:18:41:18 | 1 | cflow.cs:37:17:37:22 | exit Switch | false |
|
||||
| cflow.cs:41:18:41:18 | 1 | cflow.cs:44:13:44:19 | case ...: | false |
|
||||
| cflow.cs:41:18:41:18 | 1 | cflow.cs:47:13:47:19 | case ...: | false |
|
||||
| cflow.cs:41:18:41:18 | 1 | cflow.cs:48:17:48:39 | ...; | false |
|
||||
| cflow.cs:41:18:41:18 | 1 | cflow.cs:51:9:59:9 | switch (...) {...} | false |
|
||||
| cflow.cs:41:18:41:18 | 1 | cflow.cs:54:17:54:48 | ...; | false |
|
||||
| cflow.cs:41:18:41:18 | 1 | cflow.cs:56:13:56:20 | default: | false |
|
||||
| cflow.cs:41:18:41:18 | 1 | cflow.cs:60:9:66:9 | switch (...) {...} | false |
|
||||
| cflow.cs:41:18:41:18 | 1 | cflow.cs:63:17:64:55 | if (...) ... | false |
|
||||
| cflow.cs:41:18:41:18 | 1 | cflow.cs:64:27:64:54 | object creation of type NullReferenceException | false |
|
||||
| cflow.cs:41:18:41:18 | 1 | cflow.cs:65:17:65:22 | break; | false |
|
||||
| cflow.cs:41:18:41:18 | 1 | cflow.cs:67:16:67:16 | access to parameter a | false |
|
||||
| cflow.cs:44:18:44:18 | 2 | cflow.cs:37:17:37:22 | exit Switch | false |
|
||||
| cflow.cs:44:18:44:18 | 2 | cflow.cs:47:13:47:19 | case ...: | false |
|
||||
| cflow.cs:44:18:44:18 | 2 | cflow.cs:48:17:48:39 | ...; | false |
|
||||
| cflow.cs:44:18:44:18 | 2 | cflow.cs:51:9:59:9 | switch (...) {...} | false |
|
||||
| cflow.cs:44:18:44:18 | 2 | cflow.cs:54:17:54:48 | ...; | false |
|
||||
| cflow.cs:44:18:44:18 | 2 | cflow.cs:56:13:56:20 | default: | false |
|
||||
| cflow.cs:44:18:44:18 | 2 | cflow.cs:60:9:66:9 | switch (...) {...} | false |
|
||||
| cflow.cs:44:18:44:18 | 2 | cflow.cs:63:17:64:55 | if (...) ... | false |
|
||||
| cflow.cs:44:18:44:18 | 2 | cflow.cs:64:27:64:54 | object creation of type NullReferenceException | false |
|
||||
| cflow.cs:44:18:44:18 | 2 | cflow.cs:65:17:65:22 | break; | false |
|
||||
| cflow.cs:44:18:44:18 | 2 | cflow.cs:67:16:67:16 | access to parameter a | false |
|
||||
| cflow.cs:47:18:47:18 | 3 | cflow.cs:48:17:48:39 | ...; | true |
|
||||
| cflow.cs:53:18:53:19 | 42 | cflow.cs:54:17:54:48 | ...; | true |
|
||||
| cflow.cs:53:18:53:19 | 42 | cflow.cs:56:13:56:20 | default: | false |
|
||||
| cflow.cs:62:18:62:18 | 0 | cflow.cs:63:17:64:55 | if (...) ... | true |
|
||||
| cflow.cs:62:18:62:18 | 0 | cflow.cs:64:27:64:54 | object creation of type NullReferenceException | true |
|
||||
| cflow.cs:62:18:62:18 | 0 | cflow.cs:65:17:65:22 | break; | true |
|
||||
| cflow.cs:63:23:63:33 | ... == ... | cflow.cs:64:27:64:54 | object creation of type NullReferenceException | false |
|
||||
| cflow.cs:63:23:63:33 | ... == ... | cflow.cs:65:17:65:22 | break; | true |
|
||||
| cflow.cs:72:13:72:21 | ... == ... | cflow.cs:73:13:73:19 | return ...; | true |
|
||||
@@ -225,6 +413,15 @@
|
||||
| cflow.cs:108:13:108:21 | ... != ... | cflow.cs:116:9:116:29 | ...; | false |
|
||||
| cflow.cs:127:32:127:44 | ... == ... | cflow.cs:127:48:127:49 | "" | true |
|
||||
| cflow.cs:127:32:127:44 | ... == ... | cflow.cs:127:53:127:57 | this access | false |
|
||||
| cflow.cs:162:9:165:9 | [exception: Exception] catch (...) {...} | cflow.cs:162:38:162:39 | [exception: Exception] IOException ex | true |
|
||||
| cflow.cs:162:9:165:9 | [exception: Exception] catch (...) {...} | cflow.cs:166:9:176:9 | [exception: Exception] catch (...) {...} | false |
|
||||
| cflow.cs:162:9:165:9 | [exception: Exception] catch (...) {...} | cflow.cs:166:41:166:42 | [exception: Exception] ArgumentException ex | false |
|
||||
| cflow.cs:162:9:165:9 | [exception: Exception] catch (...) {...} | cflow.cs:177:9:179:9 | [exception: Exception] catch (...) {...} | false |
|
||||
| cflow.cs:166:9:176:9 | [exception: Exception] catch (...) {...} | cflow.cs:166:41:166:42 | [exception: Exception] ArgumentException ex | true |
|
||||
| cflow.cs:166:9:176:9 | [exception: Exception] catch (...) {...} | cflow.cs:177:9:179:9 | [exception: Exception] catch (...) {...} | false |
|
||||
| cflow.cs:194:9:197:9 | [exception: Exception] catch (...) {...} | cflow.cs:194:38:194:39 | [exception: Exception] IOException ex | true |
|
||||
| cflow.cs:194:9:197:9 | [exception: Exception] catch (...) {...} | cflow.cs:198:9:200:9 | [exception: Exception] catch (...) {...} | false |
|
||||
| cflow.cs:194:9:197:9 | [exception: Exception] catch (...) {...} | cflow.cs:202:9:204:9 | [finally: exception(Exception)] {...} | false |
|
||||
| cflow.cs:207:16:207:20 | ... > ... | cflow.cs:208:9:230:9 | {...} | true |
|
||||
| cflow.cs:207:16:207:20 | ... > ... | cflow.cs:212:21:212:27 | return ...; | true |
|
||||
| cflow.cs:207:16:207:20 | ... > ... | cflow.cs:213:17:214:29 | if (...) ... | true |
|
||||
@@ -383,6 +580,10 @@
|
||||
| cflow.cs:315:17:315:32 | ... > ... | cflow.cs:319:13:322:13 | if (...) ... | false |
|
||||
| cflow.cs:315:17:315:32 | ... > ... | cflow.cs:320:13:322:13 | {...} | false |
|
||||
| cflow.cs:319:17:319:32 | ... < ... | cflow.cs:320:13:322:13 | {...} | true |
|
||||
| cflow.cs:328:9:339:9 | foreach (... ... in ...) ... | cflow.cs:328:22:328:22 | String x | false |
|
||||
| cflow.cs:328:9:339:9 | foreach (... ... in ...) ... | cflow.cs:332:13:334:13 | {...} | false |
|
||||
| cflow.cs:328:9:339:9 | foreach (... ... in ...) ... | cflow.cs:335:13:338:13 | if (...) ... | false |
|
||||
| cflow.cs:328:9:339:9 | foreach (... ... in ...) ... | cflow.cs:336:13:338:13 | {...} | false |
|
||||
| cflow.cs:331:17:331:32 | ... > ... | cflow.cs:332:13:334:13 | {...} | true |
|
||||
| cflow.cs:331:17:331:32 | ... > ... | cflow.cs:335:13:338:13 | if (...) ... | false |
|
||||
| cflow.cs:331:17:331:32 | ... > ... | cflow.cs:336:13:338:13 | {...} | false |
|
||||
@@ -397,6 +598,15 @@
|
||||
| cflow.cs:346:13:346:28 | ... > ... | cflow.cs:355:13:355:19 | case ...: | false |
|
||||
| cflow.cs:346:13:346:28 | ... > ... | cflow.cs:356:17:356:27 | goto ...; | false |
|
||||
| cflow.cs:346:13:346:28 | ... > ... | cflow.cs:357:13:357:20 | default: | false |
|
||||
| cflow.cs:350:18:350:18 | 0 | cflow.cs:351:17:351:29 | goto default; | true |
|
||||
| cflow.cs:350:18:350:18 | 0 | cflow.cs:352:13:352:19 | case ...: | false |
|
||||
| cflow.cs:350:18:350:18 | 0 | cflow.cs:353:17:353:37 | ...; | false |
|
||||
| cflow.cs:350:18:350:18 | 0 | cflow.cs:355:13:355:19 | case ...: | false |
|
||||
| cflow.cs:350:18:350:18 | 0 | cflow.cs:356:17:356:27 | goto ...; | false |
|
||||
| cflow.cs:352:18:352:18 | 1 | cflow.cs:353:17:353:37 | ...; | true |
|
||||
| cflow.cs:352:18:352:18 | 1 | cflow.cs:355:13:355:19 | case ...: | false |
|
||||
| cflow.cs:352:18:352:18 | 1 | cflow.cs:356:17:356:27 | goto ...; | false |
|
||||
| cflow.cs:355:18:355:18 | 2 | cflow.cs:356:17:356:27 | goto ...; | true |
|
||||
| cflow.cs:366:25:366:30 | ... < ... | cflow.cs:367:9:369:9 | {...} | true |
|
||||
| cflow.cs:366:25:366:30 | ... < ... | cflow.cs:370:9:378:9 | try {...} ... | false |
|
||||
| cflow.cs:419:46:419:50 | ... > ... | cflow.cs:419:56:419:56 | access to parameter s | false |
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import csharp
|
||||
import ControlFlow
|
||||
|
||||
from ControlFlow::BasicBlocks::ConditionBlock cb, ControlFlow::BasicBlock controlled, boolean testIsTrue
|
||||
where cb.controls(controlled, testIsTrue)
|
||||
from BasicBlocks::ConditionBlock cb, BasicBlock controlled, boolean testIsTrue
|
||||
where cb.controls(controlled,any(SuccessorTypes::ConditionalSuccessor s | testIsTrue = s.getValue()))
|
||||
select cb.getLastNode(), controlled.getFirstNode(), testIsTrue
|
||||
|
||||
@@ -34,3 +34,8 @@
|
||||
| Guards.cs:106:9:106:9 | access to parameter g | Guards.cs:104:13:104:45 | ... == ... | Guards.cs:104:13:104:13 | access to parameter g | false |
|
||||
| Guards.cs:107:27:107:27 | access to parameter g | Guards.cs:104:13:104:45 | ... == ... | Guards.cs:104:13:104:13 | access to parameter g | false |
|
||||
| Guards.cs:108:27:108:27 | access to parameter g | Guards.cs:104:13:104:45 | ... == ... | Guards.cs:104:13:104:13 | access to parameter g | false |
|
||||
| Guards.cs:131:20:131:20 | access to parameter s | Guards.cs:130:13:130:21 | ... is ... | Guards.cs:130:13:130:13 | access to parameter s | true |
|
||||
| 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: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: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 |
|
||||
|
||||
@@ -124,4 +124,42 @@ public class Guards
|
||||
var b1 = s1.Equals(s2); // not null guarded
|
||||
var b2 = s1?.Equals(s1); // null guarded
|
||||
}
|
||||
|
||||
int M11(string s)
|
||||
{
|
||||
if (s is null)
|
||||
return s.Length; // not null guarded
|
||||
return s.Length; // null guarded
|
||||
}
|
||||
|
||||
int M12(string s)
|
||||
{
|
||||
if (s is string)
|
||||
return s.Length; // null guarded
|
||||
return s.Length; // not null guarded
|
||||
}
|
||||
|
||||
string M13(object o)
|
||||
{
|
||||
if (o is string s)
|
||||
return s; // not null (but not a guard)
|
||||
return o.ToString(); // not null guarded
|
||||
}
|
||||
|
||||
string M14(object o)
|
||||
{
|
||||
switch (o)
|
||||
{
|
||||
case Action<object> _:
|
||||
return o.ToString(); // null guarded
|
||||
case Action<string> a:
|
||||
return a.ToString(); // not null (but not a guard)
|
||||
case "":
|
||||
return o.ToString(); // null guarded
|
||||
case null:
|
||||
return o.ToString(); // not null guarded
|
||||
default:
|
||||
return o.ToString(); // null guarded
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
| Guards.cs:154:24:154:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:153:13:153:34 | case Action<Object>: | true |
|
||||
| Guards.cs:158:24:158:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:153:13:153:34 | case Action<Object>: | false |
|
||||
| Guards.cs:158:24:158:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:155:13:155:34 | case Action<String> a: | false |
|
||||
| Guards.cs:158:24:158:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:157:13:157:20 | case ...: | true |
|
||||
| Guards.cs:160:24:160:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:153:13:153:34 | case Action<Object>: | false |
|
||||
| Guards.cs:160:24:160:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:155:13:155:34 | case Action<String> a: | false |
|
||||
| Guards.cs:160:24:160:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:157:13:157:20 | case ...: | false |
|
||||
| Guards.cs:160:24:160:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:159:13:159:22 | case ...: | true |
|
||||
| Guards.cs:162:24:162:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:153:13:153:34 | case Action<Object>: | false |
|
||||
| Guards.cs:162:24:162:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:155:13:155:34 | case Action<String> a: | false |
|
||||
| Guards.cs:162:24:162:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:157:13:157:20 | case ...: | false |
|
||||
| Guards.cs:162:24:162:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:159:13:159:22 | case ...: | false |
|
||||
@@ -0,0 +1,6 @@
|
||||
import csharp
|
||||
import semmle.code.csharp.controlflow.Guards
|
||||
|
||||
from MatchingGuardedExpr mge, Expr e, CaseStmt cs, boolean isMatch
|
||||
where mge.isGuardedBy(e, cs, isMatch)
|
||||
select mge, e, cs, isMatch
|
||||
@@ -23,3 +23,8 @@
|
||||
| Guards.cs:97:31:97:31 | access to parameter s |
|
||||
| Guards.cs:116:27:116:51 | access to field Field |
|
||||
| Guards.cs:125:29:125:30 | access to parameter s1 |
|
||||
| Guards.cs:132:16:132:16 | access to parameter s |
|
||||
| Guards.cs:138:20:138:20 | access to parameter s |
|
||||
| Guards.cs:154:24:154:24 | access to parameter o |
|
||||
| Guards.cs:158:24:158:24 | access to parameter o |
|
||||
| Guards.cs:162:24:162:24 | access to parameter o |
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
| Guards.cs:114:14:114:38 | access to field Field | Guards.cs:113:21:113:45 | access to field Field | true |
|
||||
| Guards.cs:116:27:116:51 | access to field Field | Guards.cs:115:17:115:41 | access to field Field | false |
|
||||
| Guards.cs:125:29:125:30 | access to parameter s1 | Guards.cs:125:18:125:19 | access to parameter s1 | false |
|
||||
@@ -0,0 +1,6 @@
|
||||
import csharp
|
||||
import semmle.code.csharp.controlflow.Guards
|
||||
|
||||
from NullnessGuardedExpr nge, Expr e, boolean isNull
|
||||
where nge.isGuardedBy(e, isNull)
|
||||
select nge, e, isNull
|
||||
@@ -1,18 +1,66 @@
|
||||
using System;
|
||||
|
||||
class Foo
|
||||
class LocalTest
|
||||
{
|
||||
// BAD: b is flagged.
|
||||
Object a, b, c;
|
||||
|
||||
void f()
|
||||
void F()
|
||||
{
|
||||
lock (a) lock (b) { }
|
||||
lock (b) lock (a) { }
|
||||
lock (b) lock (a) { }
|
||||
lock (a) lock (b) { }
|
||||
lock (b) lock (c) { }
|
||||
lock (c) lock (b) { }
|
||||
lock (a) lock (a) { }
|
||||
lock (a) lock (a) { }
|
||||
lock (a) lock (b) lock(c) { }
|
||||
}
|
||||
|
||||
void G()
|
||||
{
|
||||
lock (a) lock (c) lock(b) { }
|
||||
}
|
||||
|
||||
void H()
|
||||
{
|
||||
lock (a) lock(c) { }
|
||||
}
|
||||
}
|
||||
|
||||
class GlobalTest
|
||||
{
|
||||
// BAD: b is flagged.
|
||||
static Object a, b, c;
|
||||
|
||||
void F()
|
||||
{
|
||||
lock (a) G();
|
||||
}
|
||||
|
||||
void G()
|
||||
{
|
||||
lock (b) H();
|
||||
lock (c) I();
|
||||
}
|
||||
|
||||
void H()
|
||||
{
|
||||
lock (c) { }
|
||||
}
|
||||
|
||||
void I()
|
||||
{
|
||||
lock (b) { }
|
||||
}
|
||||
}
|
||||
|
||||
class LambdaTest
|
||||
{
|
||||
// BAD: a is flagged.
|
||||
static Object a, b;
|
||||
|
||||
void F()
|
||||
{
|
||||
Action lock_a = () => { lock(a) { } };
|
||||
Action lock_b = () => { lock(b) { } };
|
||||
|
||||
lock(a) lock_b();
|
||||
lock(b) lock_a();
|
||||
}
|
||||
}
|
||||
|
||||
// semmle-extractor-options: /r:System.Runtime.Extensions.dll /r:System.Threading.dll /r:System.Threading.Thread.dll
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
| LockOrder.cs:9:18:9:29 | lock (...) {...} | Inconsistent lock sequence. The locks b and a are locked in a different sequence $@. | LockOrder.cs:10:18:10:29 | lock (...) {...} | here |
|
||||
| LockOrder.cs:9:18:9:29 | lock (...) {...} | Inconsistent lock sequence. The locks b and a are locked in a different sequence $@. | LockOrder.cs:11:18:11:29 | lock (...) {...} | here |
|
||||
| LockOrder.cs:10:18:10:29 | lock (...) {...} | Inconsistent lock sequence. The locks a and b are locked in a different sequence $@. | LockOrder.cs:9:18:9:29 | lock (...) {...} | here |
|
||||
| LockOrder.cs:10:18:10:29 | lock (...) {...} | Inconsistent lock sequence. The locks a and b are locked in a different sequence $@. | LockOrder.cs:12:18:12:29 | lock (...) {...} | here |
|
||||
| LockOrder.cs:11:18:11:29 | lock (...) {...} | Inconsistent lock sequence. The locks a and b are locked in a different sequence $@. | LockOrder.cs:9:18:9:29 | lock (...) {...} | here |
|
||||
| LockOrder.cs:11:18:11:29 | lock (...) {...} | Inconsistent lock sequence. The locks a and b are locked in a different sequence $@. | LockOrder.cs:12:18:12:29 | lock (...) {...} | here |
|
||||
| LockOrder.cs:12:18:12:29 | lock (...) {...} | Inconsistent lock sequence. The locks b and a are locked in a different sequence $@. | LockOrder.cs:10:18:10:29 | lock (...) {...} | here |
|
||||
| LockOrder.cs:12:18:12:29 | lock (...) {...} | Inconsistent lock sequence. The locks b and a are locked in a different sequence $@. | LockOrder.cs:11:18:11:29 | lock (...) {...} | here |
|
||||
| LockOrder.cs:13:18:13:29 | lock (...) {...} | Inconsistent lock sequence. The locks c and b are locked in a different sequence $@. | LockOrder.cs:14:18:14:29 | lock (...) {...} | here |
|
||||
| LockOrder.cs:14:18:14:29 | lock (...) {...} | Inconsistent lock sequence. The locks b and c are locked in a different sequence $@. | LockOrder.cs:13:18:13:29 | lock (...) {...} | here |
|
||||
| LockOrder.cs:6:15:6:15 | b | Inconsistent lock sequence with $@. Lock sequences $@, $@ and $@, $@ found. | LockOrder.cs:6:18:6:18 | c | c | LockOrder.cs:10:18:10:37 | lock (...) {...} | b | LockOrder.cs:10:27:10:37 | lock (...) {...} | c | LockOrder.cs:15:18:15:37 | lock (...) {...} | c | LockOrder.cs:15:27:15:37 | lock (...) {...} | b |
|
||||
| LockOrder.cs:27:22:27:22 | b | Inconsistent lock sequence with $@. Lock sequences $@, $@ and $@, $@ found. | LockOrder.cs:27:25:27:25 | c | c | LockOrder.cs:36:8:36:20 | lock (...) {...} | b | LockOrder.cs:42:9:42:20 | lock (...) {...} | c | LockOrder.cs:37:8:37:20 | lock (...) {...} | c | LockOrder.cs:47:9:47:20 | lock (...) {...} | b |
|
||||
| LockOrder.cs:54:19:54:19 | a | Inconsistent lock sequence with $@. Lock sequences $@, $@ and $@, $@ found. | LockOrder.cs:54:22:54:22 | b | b | LockOrder.cs:61:9:61:25 | lock (...) {...} | a | LockOrder.cs:59:33:59:43 | lock (...) {...} | b | LockOrder.cs:62:9:62:25 | lock (...) {...} | b | LockOrder.cs:58:33:58:43 | lock (...) {...} | a |
|
||||
| LockOrderBad.cs:6:29:6:33 | lock1 | Inconsistent lock sequence with $@. Lock sequences $@, $@ and $@, $@ found. | LockOrderBad.cs:7:29:7:33 | lock2 | lock2 | LockOrderBad.cs:11:9:19:9 | lock (...) {...} | lock1 | LockOrderBad.cs:16:13:18:13 | lock (...) {...} | lock2 | LockOrderBad.cs:24:9:32:9 | lock (...) {...} | lock2 | LockOrderBad.cs:29:13:31:13 | lock (...) {...} | lock1 |
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
class Deadlock
|
||||
{
|
||||
private readonly Object lock1 = new Object();
|
||||
private readonly Object lock2 = new Object();
|
||||
|
||||
public void thread1()
|
||||
{
|
||||
lock (lock1)
|
||||
{
|
||||
Console.Out.WriteLine("Thread 1 acquired lock1");
|
||||
Thread.Sleep(10);
|
||||
Console.Out.WriteLine("Thread 1 waiting on lock2");
|
||||
lock (lock2) // Deadlock here
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void thread2()
|
||||
{
|
||||
lock (lock2)
|
||||
{
|
||||
Console.Out.WriteLine("Thread 2 acquired lock2");
|
||||
Thread.Sleep(10);
|
||||
Console.Out.WriteLine("Thread 2 waiting on lock1");
|
||||
lock (lock1) // Deadlock here
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
class DeadlockFixed
|
||||
{
|
||||
private readonly Object lock1 = new Object();
|
||||
private readonly Object lock2 = new Object();
|
||||
|
||||
public void thread1()
|
||||
{
|
||||
lock (lock1)
|
||||
{
|
||||
Console.Out.WriteLine("Thread 1 acquired lock1");
|
||||
Thread.Sleep(10);
|
||||
Console.Out.WriteLine("Thread 1 waiting on lock2");
|
||||
lock (lock2)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void thread2()
|
||||
{
|
||||
lock (lock1) // Fixed
|
||||
{
|
||||
Console.Out.WriteLine("Thread 2 acquired lock1");
|
||||
Thread.Sleep(10);
|
||||
Console.Out.WriteLine("Thread 2 waiting on lock2");
|
||||
lock (lock2) // Fixed
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user