Skip to content

Commit 2d25a04

Browse files
committed
C#: Add test for guard implications logic
1 parent f5e6b79 commit 2d25a04

File tree

3 files changed

+136
-4
lines changed

3 files changed

+136
-4
lines changed

csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,10 +138,11 @@ class DereferenceableExpr extends Expr {
138138
exists(boolean branch |
139139
branch = v.getValue() |
140140
// Comparison with `null`, for example `x != null`
141-
exists(ComparisonTest ct, ComparisonKind ck |
141+
exists(ComparisonTest ct, ComparisonKind ck, NullLiteral nl |
142142
ct.getExpr() = result and
143143
ct.getAnArgument() = this and
144-
ct.getAnArgument() instanceof NullLiteral and
144+
ct.getAnArgument() = nl and
145+
this != nl and
145146
ck = ct.getComparisonKind() |
146147
ck.isEquality() and isNull = branch
147148
or
@@ -609,7 +610,8 @@ module Internal {
609610
or
610611
exists(boolean isNull |
611612
v2 = any(NullValue nv | if nv.isNull() then isNull = true else isNull = false) |
612-
e1 = e2.(DereferenceableExpr).getANullCheck(v1, isNull)
613+
e1 = e2.(DereferenceableExpr).getANullCheck(v1, isNull) and
614+
(e1 != e2 or v1 != v2)
613615
)
614616
or
615617
e1 instanceof DereferenceableExpr and
@@ -624,7 +626,7 @@ module Internal {
624626
* Holds if `e1` having some abstract value, `v`, implies that `e2` has the same
625627
* abstract value `v`.
626628
*/
627-
private predicate impliesStepIdentity(Expr e1, Expr e2) {
629+
predicate impliesStepIdentity(Expr e1, Expr e2) {
628630
exists(PreSsa::Definition def |
629631
def.getDefinition().getSource() = e2 |
630632
e1 = def.getARead()
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
impliesStep
2+
| Guards.cs:10:13:10:25 | !... | false | Guards.cs:10:14:10:25 | !... | true |
3+
| Guards.cs:10:13:10:25 | !... | true | Guards.cs:10:14:10:25 | !... | false |
4+
| Guards.cs:10:14:10:25 | !... | false | Guards.cs:10:13:10:25 | !... | true |
5+
| Guards.cs:10:14:10:25 | !... | false | Guards.cs:10:16:10:24 | ... == ... | true |
6+
| Guards.cs:10:14:10:25 | !... | true | Guards.cs:10:13:10:25 | !... | false |
7+
| Guards.cs:10:14:10:25 | !... | true | Guards.cs:10:16:10:24 | ... == ... | false |
8+
| Guards.cs:10:16:10:24 | ... == ... | false | Guards.cs:10:14:10:25 | !... | true |
9+
| Guards.cs:10:16:10:24 | ... == ... | false | Guards.cs:10:16:10:16 | access to parameter s | non-null |
10+
| Guards.cs:10:16:10:24 | ... == ... | true | Guards.cs:10:14:10:25 | !... | false |
11+
| Guards.cs:10:16:10:24 | ... == ... | true | Guards.cs:10:16:10:16 | access to parameter s | null |
12+
| Guards.cs:24:13:24:21 | ... != ... | false | Guards.cs:24:13:24:13 | access to parameter s | null |
13+
| Guards.cs:24:13:24:21 | ... != ... | true | Guards.cs:24:13:24:13 | access to parameter s | non-null |
14+
| Guards.cs:32:13:32:36 | !... | false | Guards.cs:32:13:32:51 | ... & ... | false |
15+
| Guards.cs:32:13:32:36 | !... | false | Guards.cs:32:14:32:36 | call to method IsNullOrEmpty | true |
16+
| Guards.cs:32:13:32:36 | !... | true | Guards.cs:32:14:32:36 | call to method IsNullOrEmpty | false |
17+
| Guards.cs:32:13:32:51 | ... & ... | true | Guards.cs:32:13:32:36 | !... | true |
18+
| Guards.cs:32:13:32:51 | ... & ... | true | Guards.cs:32:40:32:51 | !... | true |
19+
| Guards.cs:32:14:32:36 | call to method IsNullOrEmpty | false | Guards.cs:32:13:32:36 | !... | true |
20+
| Guards.cs:32:14:32:36 | call to method IsNullOrEmpty | false | Guards.cs:32:35:32:35 | access to parameter x | non-null |
21+
| Guards.cs:32:14:32:36 | call to method IsNullOrEmpty | true | Guards.cs:32:13:32:36 | !... | false |
22+
| Guards.cs:32:40:32:51 | !... | false | Guards.cs:32:13:32:51 | ... & ... | false |
23+
| Guards.cs:32:40:32:51 | !... | false | Guards.cs:32:42:32:50 | ... == ... | true |
24+
| Guards.cs:32:40:32:51 | !... | true | Guards.cs:32:42:32:50 | ... == ... | false |
25+
| Guards.cs:32:42:32:50 | ... == ... | false | Guards.cs:32:40:32:51 | !... | true |
26+
| Guards.cs:32:42:32:50 | ... == ... | false | Guards.cs:32:42:32:42 | access to parameter y | non-null |
27+
| Guards.cs:32:42:32:50 | ... == ... | true | Guards.cs:32:40:32:51 | !... | false |
28+
| Guards.cs:32:42:32:50 | ... == ... | true | Guards.cs:32:42:32:42 | access to parameter y | null |
29+
| Guards.cs:35:13:35:21 | ... == ... | false | Guards.cs:35:13:35:13 | access to parameter x | non-null |
30+
| Guards.cs:35:13:35:21 | ... == ... | true | Guards.cs:35:13:35:13 | access to parameter x | null |
31+
| Guards.cs:35:13:35:21 | ... == ... | true | Guards.cs:35:13:35:34 | ... \|\| ... | true |
32+
| Guards.cs:35:13:35:34 | ... \|\| ... | false | Guards.cs:35:13:35:21 | ... == ... | false |
33+
| Guards.cs:35:13:35:34 | ... \|\| ... | false | Guards.cs:35:26:35:34 | ... == ... | false |
34+
| Guards.cs:35:26:35:34 | ... == ... | false | Guards.cs:35:26:35:26 | access to parameter y | non-null |
35+
| Guards.cs:35:26:35:34 | ... == ... | true | Guards.cs:35:13:35:34 | ... \|\| ... | true |
36+
| Guards.cs:35:26:35:34 | ... == ... | true | Guards.cs:35:26:35:26 | access to parameter y | null |
37+
| Guards.cs:38:13:38:37 | !... | false | Guards.cs:38:15:38:36 | ... \|\| ... | true |
38+
| Guards.cs:38:13:38:37 | !... | true | Guards.cs:38:15:38:36 | ... \|\| ... | false |
39+
| Guards.cs:38:15:38:23 | ... == ... | false | Guards.cs:38:15:38:15 | access to parameter x | non-null |
40+
| Guards.cs:38:15:38:23 | ... == ... | true | Guards.cs:38:15:38:15 | access to parameter x | null |
41+
| Guards.cs:38:15:38:23 | ... == ... | true | Guards.cs:38:15:38:36 | ... \|\| ... | true |
42+
| Guards.cs:38:15:38:36 | ... \|\| ... | false | Guards.cs:38:13:38:37 | !... | true |
43+
| Guards.cs:38:15:38:36 | ... \|\| ... | false | Guards.cs:38:15:38:23 | ... == ... | false |
44+
| Guards.cs:38:15:38:36 | ... \|\| ... | false | Guards.cs:38:28:38:36 | ... == ... | false |
45+
| Guards.cs:38:15:38:36 | ... \|\| ... | true | Guards.cs:38:13:38:37 | !... | false |
46+
| Guards.cs:38:28:38:36 | ... == ... | false | Guards.cs:38:28:38:28 | access to parameter y | non-null |
47+
| Guards.cs:38:28:38:36 | ... == ... | true | Guards.cs:38:15:38:36 | ... \|\| ... | true |
48+
| Guards.cs:38:28:38:36 | ... == ... | true | Guards.cs:38:28:38:28 | access to parameter y | null |
49+
| Guards.cs:41:13:41:39 | !... | false | Guards.cs:41:14:41:39 | !... | true |
50+
| Guards.cs:41:13:41:39 | !... | true | Guards.cs:41:14:41:39 | !... | false |
51+
| Guards.cs:41:14:41:39 | !... | false | Guards.cs:41:13:41:39 | !... | true |
52+
| Guards.cs:41:14:41:39 | !... | false | Guards.cs:41:15:41:39 | !... | true |
53+
| Guards.cs:41:14:41:39 | !... | true | Guards.cs:41:13:41:39 | !... | false |
54+
| Guards.cs:41:14:41:39 | !... | true | Guards.cs:41:15:41:39 | !... | false |
55+
| Guards.cs:41:15:41:39 | !... | false | Guards.cs:41:14:41:39 | !... | true |
56+
| Guards.cs:41:15:41:39 | !... | false | Guards.cs:41:17:41:38 | ... && ... | true |
57+
| Guards.cs:41:15:41:39 | !... | true | Guards.cs:41:14:41:39 | !... | false |
58+
| Guards.cs:41:15:41:39 | !... | true | Guards.cs:41:17:41:38 | ... && ... | false |
59+
| Guards.cs:41:17:41:25 | ... != ... | false | Guards.cs:41:17:41:17 | access to parameter x | null |
60+
| Guards.cs:41:17:41:25 | ... != ... | false | Guards.cs:41:17:41:38 | ... && ... | false |
61+
| Guards.cs:41:17:41:25 | ... != ... | true | Guards.cs:41:17:41:17 | access to parameter x | non-null |
62+
| Guards.cs:41:17:41:38 | ... && ... | false | Guards.cs:41:15:41:39 | !... | true |
63+
| Guards.cs:41:17:41:38 | ... && ... | true | Guards.cs:41:15:41:39 | !... | false |
64+
| Guards.cs:41:17:41:38 | ... && ... | true | Guards.cs:41:17:41:25 | ... != ... | true |
65+
| Guards.cs:41:17:41:38 | ... && ... | true | Guards.cs:41:30:41:38 | ... != ... | true |
66+
| Guards.cs:41:30:41:38 | ... != ... | false | Guards.cs:41:17:41:38 | ... && ... | false |
67+
| Guards.cs:41:30:41:38 | ... != ... | false | Guards.cs:41:30:41:30 | access to parameter y | null |
68+
| Guards.cs:41:30:41:38 | ... != ... | true | Guards.cs:41:30:41:30 | access to parameter y | non-null |
69+
| Guards.cs:44:13:44:25 | ... != ... | false | Guards.cs:44:13:44:17 | access to field Field | null |
70+
| Guards.cs:44:13:44:25 | ... != ... | true | Guards.cs:44:13:44:17 | access to field Field | non-null |
71+
| Guards.cs:47:13:47:25 | ... != ... | false | Guards.cs:47:13:47:17 | access to field Field | null |
72+
| Guards.cs:47:13:47:25 | ... != ... | true | Guards.cs:47:13:47:17 | access to field Field | non-null |
73+
| Guards.cs:53:13:53:27 | ... == ... | false | Guards.cs:53:13:53:19 | access to field Field | non-null |
74+
| Guards.cs:53:13:53:27 | ... == ... | true | Guards.cs:53:13:53:19 | access to field Field | null |
75+
| Guards.cs:60:13:60:45 | ... == ... | false | Guards.cs:60:13:60:37 | access to field Field | non-null |
76+
| Guards.cs:60:13:60:45 | ... == ... | true | Guards.cs:60:13:60:37 | access to field Field | null |
77+
| Guards.cs:68:16:68:24 | ... != ... | false | Guards.cs:68:16:68:16 | access to parameter s | null |
78+
| Guards.cs:68:16:68:24 | ... != ... | true | Guards.cs:68:16:68:16 | access to parameter s | non-null |
79+
| Guards.cs:78:13:78:26 | ... == ... | true | Guards.cs:78:15:78:21 | access to property Length | non-null |
80+
| Guards.cs:78:15:78:21 | access to property Length | non-null | Guards.cs:78:13:78:13 | access to parameter s | non-null |
81+
| Guards.cs:78:15:78:21 | access to property Length | null | Guards.cs:78:13:78:13 | access to parameter s | null |
82+
| Guards.cs:80:13:80:25 | ... > ... | true | Guards.cs:80:15:80:21 | access to property Length | non-null |
83+
| Guards.cs:80:15:80:21 | access to property Length | non-null | Guards.cs:80:13:80:13 | access to parameter s | non-null |
84+
| Guards.cs:80:15:80:21 | access to property Length | null | Guards.cs:80:13:80:13 | access to parameter s | null |
85+
| Guards.cs:82:13:82:26 | ... >= ... | true | Guards.cs:82:15:82:21 | access to property Length | non-null |
86+
| Guards.cs:82:15:82:21 | access to property Length | non-null | Guards.cs:82:13:82:13 | access to parameter s | non-null |
87+
| Guards.cs:82:15:82:21 | access to property Length | null | Guards.cs:82:13:82:13 | access to parameter s | null |
88+
| Guards.cs:84:13:84:26 | ... < ... | true | Guards.cs:84:15:84:21 | access to property Length | non-null |
89+
| Guards.cs:84:15:84:21 | access to property Length | non-null | Guards.cs:84:13:84:13 | access to parameter s | non-null |
90+
| Guards.cs:84:15:84:21 | access to property Length | null | Guards.cs:84:13:84:13 | access to parameter s | null |
91+
| Guards.cs:86:13:86:27 | ... <= ... | true | Guards.cs:86:15:86:21 | access to property Length | non-null |
92+
| Guards.cs:86:15:86:21 | access to property Length | non-null | Guards.cs:86:13:86:13 | access to parameter s | non-null |
93+
| Guards.cs:86:15:86:21 | access to property Length | null | Guards.cs:86:13:86:13 | access to parameter s | null |
94+
| Guards.cs:88:13:88:29 | ... != ... | false | Guards.cs:88:15:88:21 | access to property Length | null |
95+
| Guards.cs:88:13:88:29 | ... != ... | true | Guards.cs:88:15:88:21 | access to property Length | non-null |
96+
| Guards.cs:88:15:88:21 | access to property Length | non-null | Guards.cs:88:13:88:13 | access to parameter s | non-null |
97+
| Guards.cs:88:15:88:21 | access to property Length | null | Guards.cs:88:13:88:13 | access to parameter s | null |
98+
| Guards.cs:92:13:92:25 | ... - ... | non-null | Guards.cs:92:15:92:21 | access to property Length | non-null |
99+
| Guards.cs:92:13:92:25 | ... - ... | null | Guards.cs:92:15:92:21 | access to property Length | null |
100+
| Guards.cs:92:13:92:30 | ... != ... | false | Guards.cs:92:13:92:25 | ... - ... | non-null |
101+
| Guards.cs:92:15:92:21 | access to property Length | non-null | Guards.cs:92:13:92:13 | access to parameter s | non-null |
102+
| Guards.cs:92:15:92:21 | access to property Length | null | Guards.cs:92:13:92:13 | access to parameter s | null |
103+
| Guards.cs:96:13:96:19 | ... == ... | true | Guards.cs:96:13:96:13 | access to parameter s | non-null |
104+
| Guards.cs:104:13:104:45 | ... == ... | false | Guards.cs:104:13:104:37 | access to field Field | non-null |
105+
| Guards.cs:104:13:104:45 | ... == ... | true | Guards.cs:104:13:104:37 | access to field Field | null |
106+
| Guards.cs:125:21:125:31 | call to method Equals | non-null | Guards.cs:125:18:125:19 | access to parameter s1 | non-null |
107+
| Guards.cs:125:21:125:31 | call to method Equals | null | Guards.cs:125:18:125:19 | access to parameter s1 | null |
108+
| Guards.cs:130:13:130:21 | ... is ... | false | Guards.cs:130:13:130:13 | access to parameter s | non-null |
109+
| Guards.cs:130:13:130:21 | ... is ... | true | Guards.cs:130:13:130:13 | access to parameter s | null |
110+
| Guards.cs:137:13:137:23 | ... is ... | true | Guards.cs:137:13:137:13 | access to parameter s | non-null |
111+
| Guards.cs:144:13:144:25 | ... is ... | true | Guards.cs:144:13:144:13 | access to parameter o | non-null |
112+
| Guards.cs:151:17:151:17 | access to parameter o | match case ...: | Guards.cs:151:17:151:17 | access to parameter o | non-null |
113+
| Guards.cs:151:17:151:17 | access to parameter o | match case ...: | Guards.cs:151:17:151:17 | access to parameter o | null |
114+
| Guards.cs:151:17:151:17 | access to parameter o | match case Action<Object>: | Guards.cs:151:17:151:17 | access to parameter o | non-null |
115+
| Guards.cs:151:17:151:17 | access to parameter o | match case Action<String> a: | Guards.cs:151:17:151:17 | access to parameter o | non-null |
116+
| Guards.cs:151:17:151:17 | access to parameter o | non-match case ...: | Guards.cs:151:17:151:17 | access to parameter o | non-null |
117+
impliesStepIdentity
118+
| Guards.cs:72:31:72:31 | access to parameter s | Guards.cs:71:17:71:20 | null |
119+
| Guards.cs:145:20:145:20 | access to local variable s | Guards.cs:144:13:144:13 | access to parameter o |
120+
| Guards.cs:156:24:156:24 | access to local variable a | Guards.cs:151:17:151:17 | access to parameter o |
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import csharp
2+
import semmle.code.csharp.controlflow.Guards
3+
4+
query predicate impliesStep(Expr e1, AbstractValue v1, Expr e2, AbstractValue v2) {
5+
Internal::impliesStep(e1, v1, e2, v2)
6+
}
7+
8+
query predicate impliesStepIdentity(Expr e1, Expr e2) {
9+
Internal::impliesStepIdentity(e1, e2)
10+
}

0 commit comments

Comments
 (0)