mirror of
https://github.com/github/codeql.git
synced 2026-05-02 04:05:14 +02:00
C#: Teach guards library about assertions
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
|
||||
import csharp
|
||||
private import ControlFlow::SuccessorTypes
|
||||
private import semmle.code.csharp.commons.Assertions
|
||||
private import semmle.code.csharp.commons.ComparisonTest
|
||||
private import semmle.code.csharp.commons.StructuralComparison::Internal
|
||||
private import semmle.code.csharp.controlflow.BasicBlocks
|
||||
@@ -472,30 +473,69 @@ module Internal {
|
||||
pragma [noinline]
|
||||
private predicate candidateAux(AccessOrCallExpr e, Declaration target, BasicBlock bb) {
|
||||
target = e.getTarget() and
|
||||
controls(bb, _, e, _)
|
||||
exists(Expr e0 |
|
||||
e = e0.getAChildExpr*() |
|
||||
controls(bb, e0, _)
|
||||
or
|
||||
controlsNode(bb.getANode(), e0, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if basic block `bb` only is reached when `e` has abstract value `v`.
|
||||
* SSA qualified expression `sub` is a sub expression of `e`.
|
||||
*/
|
||||
private predicate controls(BasicBlock bb, Expr e, AccessOrCallExpr sub, AbstractValue v) {
|
||||
/** Holds if basic block `bb` only is reached when `e` has abstract value `v`. */
|
||||
private predicate controls(BasicBlock bb, Expr e, AbstractValue v) {
|
||||
exists(ConditionBlock cb, ConditionalSuccessor s, AbstractValue v0, Expr cond |
|
||||
cb.controls(bb, s) |
|
||||
v0.branchImplies(cb.getLastNode().getElement(), s, cond) and
|
||||
impliesSteps(cond, v0, e, v) and
|
||||
sub = e.getAChildExpr*()
|
||||
impliesSteps(cond, v0, e, v)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if assertion `a` directly asserts that expression `e` evaluates to
|
||||
* value `v`.
|
||||
*/
|
||||
predicate asserts(Assertion a, Expr e, AbstractValue v) {
|
||||
e = a.getExpr() and
|
||||
(
|
||||
a.getAssertMethod() instanceof AssertTrueMethod and
|
||||
v.(BooleanValue).getValue() = true
|
||||
or
|
||||
a.getAssertMethod() instanceof AssertFalseMethod and
|
||||
v.(BooleanValue).getValue() = false
|
||||
or
|
||||
a.getAssertMethod() instanceof AssertNullMethod and
|
||||
v.(NullValue).isNull()
|
||||
or
|
||||
a.getAssertMethod() instanceof AssertNonNullMethod and
|
||||
v = any(NullValue nv | not nv.isNull())
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if control flow node `cfn` only is reached when `e` evaluates to `v`. */
|
||||
private predicate controlsNode(ControlFlow::Node cfn, Expr e, AbstractValue v) {
|
||||
exists(Assertion a, Expr e0, AbstractValue v0 |
|
||||
a.getAControlFlowNode().dominates(cfn) |
|
||||
asserts(a, e0, v0) and
|
||||
impliesSteps(e0, v0, e, v)
|
||||
)
|
||||
}
|
||||
|
||||
private cached module Cached {
|
||||
pragma[noinline]
|
||||
private predicate isGuardedBy0(AccessOrCallExpr guarded, Expr e, AccessOrCallExpr sub, AbstractValue v) {
|
||||
exists(ControlFlow::Node cfn |
|
||||
(controls(cfn.getBasicBlock(), e, v) or controlsNode(cfn, e, v)) and
|
||||
cfn = guarded.getAControlFlowNode() and
|
||||
exists(ConditionOnExprComparisonConfig c | c.same(sub, guarded))
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate isGuardedBy(AccessOrCallExpr guarded, Expr e, AccessOrCallExpr sub, AbstractValue v) {
|
||||
exists(BasicBlock bb |
|
||||
controls(bb, e, sub, v) and
|
||||
bb = guarded.getAControlFlowNode().getBasicBlock() and
|
||||
exists(ConditionOnExprComparisonConfig c | c.same(sub, guarded)) |
|
||||
isGuardedBy0(guarded, e, sub, v) and
|
||||
sub = e.getAChildExpr*() and
|
||||
(
|
||||
not guarded.hasSsaQualifier() and not sub.hasSsaQualifier()
|
||||
or
|
||||
guarded.getSsaQualifier() = sub.getSsaQualifier()
|
||||
@@ -647,6 +687,13 @@ module Internal {
|
||||
e2 = e1 and
|
||||
v2 = v1
|
||||
or
|
||||
exists(Assertion a |
|
||||
e1 = a.getExpr() |
|
||||
asserts(a, e1, v1) and
|
||||
e2 = e1 and
|
||||
v2 = v1
|
||||
)
|
||||
or
|
||||
exists(Expr mid, AbstractValue vMid |
|
||||
impliesSteps(e1, v1, mid, vMid) |
|
||||
impliesStep(mid, vMid, e2, v2)
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
| Assert.cs:11:27:11:27 | access to local variable s | Assert.cs:10:22:10:30 | ... != ... | Assert.cs:10:22:10:22 | access to local variable s | true |
|
||||
| Assert.cs:32:27:32:27 | access to local variable s | Assert.cs:31:23:31:31 | ... == ... | Assert.cs:31:23:31:23 | access to local variable s | true |
|
||||
| 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: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: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: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: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:13:10:25 | !... | Guards.cs:10:16:10:16 | access to parameter s | false |
|
||||
| Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:14:10:25 | !... | Guards.cs:10:16:10:16 | access to parameter s | true |
|
||||
| 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 |
|
||||
|
||||
@@ -1,7 +1,31 @@
|
||||
| Assert.cs:11:27:11:27 | access to local variable s | Assert.cs:10:22:10:22 | access to local variable s | Assert.cs:10:22:10:22 | access to local variable s | non-null |
|
||||
| Assert.cs:11:27:11:27 | access to local variable s | Assert.cs:10:22:10:30 | ... != ... | Assert.cs:10:22:10:22 | access to local variable s | true |
|
||||
| Assert.cs:18:27:18:27 | access to local variable s | Assert.cs:17:23:17:23 | access to local variable s | Assert.cs:17:23:17:23 | access to local variable s | null |
|
||||
| Assert.cs:25:27:25:27 | access to local variable s | Assert.cs:24:26:24:26 | access to local variable s | Assert.cs:24:26:24:26 | access to local variable s | non-null |
|
||||
| Assert.cs:32:27:32:27 | access to local variable s | Assert.cs:31:23:31:23 | access to local variable s | Assert.cs:31:23:31:23 | access to local variable s | null |
|
||||
| Assert.cs:32:27:32:27 | access to local variable s | Assert.cs:31:23:31:31 | ... == ... | Assert.cs:31:23:31:23 | access to local variable s | true |
|
||||
| Assert.cs:39:27:39:27 | access to local variable s | Assert.cs:38:23:38:23 | access to local variable s | Assert.cs:38:23:38:23 | access to local variable s | non-null |
|
||||
| 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:24 | access to local variable s | Assert.cs:45:24:45:24 | access to local variable s | null |
|
||||
| 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: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: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: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: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 |
|
||||
| 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:13:10:25 | !... | Guards.cs:10:16:10:16 | access to parameter s | false |
|
||||
| Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:14:10:25 | !... | Guards.cs:10:16:10:16 | access to parameter s | true |
|
||||
| Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | non-null |
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
| Assert.cs:11:27:11:27 | access to local variable s |
|
||||
| Assert.cs:25:27:25:27 | access to local variable s |
|
||||
| Assert.cs:39:27:39:27 | access to local variable s |
|
||||
| Assert.cs:53:27:53:27 | access to local variable s |
|
||||
| Assert.cs:60:27:60:27 | access to local variable s |
|
||||
| Assert.cs:67:27:67:27 | access to local variable s |
|
||||
| Guards.cs:12:13:12:13 | access to parameter s |
|
||||
| Guards.cs:14:31:14:31 | access to parameter s |
|
||||
| Guards.cs:26:31:26:31 | access to parameter s |
|
||||
|
||||
@@ -10,21 +10,27 @@ class AssertTests
|
||||
Debug.Assert(s != null);
|
||||
Console.WriteLine(s.Length);
|
||||
|
||||
s = null;
|
||||
Assert.IsNull(s);
|
||||
Console.WriteLine(s.Length); // always null
|
||||
|
||||
s = null;
|
||||
Assert.IsNotNull(s);
|
||||
Console.WriteLine(s.Length);
|
||||
|
||||
s = null;
|
||||
Assert.IsTrue(s == null);
|
||||
Console.WriteLine(s.Length); // always null
|
||||
|
||||
s = null;
|
||||
Assert.IsTrue(s != null);
|
||||
Console.WriteLine(s.Length);
|
||||
|
||||
s = null;
|
||||
Assert.IsFalse(s != null);
|
||||
Console.WriteLine(s.Length); // always null
|
||||
|
||||
s = null;
|
||||
Assert.IsFalse(s == null);
|
||||
Console.WriteLine(s.Length);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,6 @@
|
||||
| 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 |
|
||||
| Assert.cs:14:27:14:27 | access to local variable s | Variable $@ is always null here. | Assert.cs:9:16:9:16 | s | s |
|
||||
| Assert.cs:20:27:20:27 | access to local variable s | Variable $@ is always null here. | Assert.cs:9:16:9:16 | s | s |
|
||||
| Assert.cs:26:27:26:27 | access to local variable s | Variable $@ is always null here. | Assert.cs:9:16:9:16 | s | s |
|
||||
| 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 |
|
||||
|
||||
Reference in New Issue
Block a user