This commit is contained in:
Tom Hvitved 2019-06-25 14:08:34 +02:00
Родитель 946be967f8
Коммит 51d093add0
10 изменённых файлов: 108 добавлений и 5 удалений

Просмотреть файл

@ -661,11 +661,15 @@ module Internal {
e1 = e2.(AssignExpr).getRValue()
or
e1 = e2.(Cast).getExpr()
or
e2 = e1.(NullCoalescingExpr).getAnOperand()
}
/** Holds if expression `e3` is a `null` value whenever `e1` and `e2` are. */
predicate nullValueImpliedBinary(Expr e1, Expr e2, Expr e3) {
e3 = any(ConditionalExpr ce | e1 = ce.getThen() and e2 = ce.getElse())
or
e3 = any(NullCoalescingExpr nce | e1 = nce.getLeftOperand() and e2 = nce.getRightOperand())
}
/** A callable that always returns a non-`null` value. */
@ -684,11 +688,15 @@ module Internal {
e instanceof ArrayCreation
or
e.hasValue() and
not e instanceof NullLiteral and
not e instanceof DefaultValueExpr
exists(Expr stripped | stripped = e.stripCasts() |
not stripped instanceof NullLiteral and
not stripped instanceof DefaultValueExpr
)
or
e instanceof ThisAccess
or
// "In string concatenation operations, the C# compiler treats a null string the same as an empty string."
// (https://docs.microsoft.com/en-us/dotnet/csharp/how-to/concatenate-multiple-strings)
e instanceof AddExpr and
e.getType() instanceof StringType
or
@ -705,6 +713,8 @@ module Internal {
e1 = e2.(CastExpr).getExpr()
or
e1 = e2.(AssignExpr).getRValue()
or
e1 = e2.(NullCoalescingExpr).getAnOperand()
}
/**
@ -1405,6 +1415,10 @@ module Internal {
not preControlsDirect(g2, any(PreBasicBlocks::PreBasicBlock bb | g1 = bb.getAnElement()),
v2)
)
or
g2 = g1.(NullCoalescingExpr).getAnOperand() and
v1.(NullValue).isNull() and
v2 = v1
}
cached

Просмотреть файл

@ -35,11 +35,17 @@ class MaybeNullExpr extends Expr {
or
this instanceof AsExpr
or
exists(MaybeNullExpr e | G::Internal::nullValueImpliedUnary(e, this))
this.(AssignExpr).getRValue() instanceof MaybeNullExpr
or
exists(MaybeNullExpr e | G::Internal::nullValueImpliedBinary(e, _, this))
this.(Cast).getExpr() instanceof MaybeNullExpr
or
exists(MaybeNullExpr e | G::Internal::nullValueImpliedBinary(_, e, this))
this = any(ConditionalExpr ce |
ce.getThen() instanceof MaybeNullExpr
or
ce.getElse() instanceof MaybeNullExpr
)
or
this.(NullCoalescingExpr).getRightOperand() instanceof MaybeNullExpr
}
}

Просмотреть файл

@ -1,6 +1,7 @@
alwaysNull
| dataflow.cs:70:21:70:35 | default(...) |
| dataflow.cs:74:21:74:34 | call to method NullFunction |
| dataflow.cs:74:21:74:52 | ... ?? ... |
| dataflow.cs:74:39:74:52 | call to method IndirectNull |
| dataflow.cs:78:21:78:45 | call to method ReturnsNull |
| dataflow.cs:79:21:79:46 | call to method ReturnsNull2 |

Просмотреть файл

@ -257,10 +257,14 @@
| Guards.cs:108:27:108:36 | access to property Property | null | Guards.cs:106:22:106:25 | null | null |
| Guards.cs:113:13:114:38 | String dummy = ... | non-null | Guards.cs:113:13:113:17 | access to local variable dummy | non-null |
| Guards.cs:113:13:114:38 | String dummy = ... | null | Guards.cs:113:13:113:17 | access to local variable dummy | null |
| Guards.cs:113:21:114:38 | ... ?? ... | null | Guards.cs:113:21:113:45 | access to field Field | null |
| Guards.cs:113:21:114:38 | ... ?? ... | null | Guards.cs:114:14:114:38 | access to field Field | null |
| Guards.cs:115:9:115:55 | ... = ... | non-null | Guards.cs:115:9:115:13 | access to local variable dummy | non-null |
| Guards.cs:115:9:115:55 | ... = ... | non-null | Guards.cs:115:17:115:55 | ... ?? ... | non-null |
| Guards.cs:115:9:115:55 | ... = ... | null | Guards.cs:115:9:115:13 | access to local variable dummy | null |
| Guards.cs:115:9:115:55 | ... = ... | null | Guards.cs:115:17:115:55 | ... ?? ... | null |
| Guards.cs:115:17:115:55 | ... ?? ... | null | Guards.cs:115:17:115:41 | access to field Field | null |
| Guards.cs:115:17:115:55 | ... ?? ... | null | Guards.cs:115:46:115:55 | throw ... | null |
| Guards.cs:117:9:117:25 | ... = ... | non-null | Guards.cs:117:9:117:18 | access to property Property | non-null |
| Guards.cs:117:9:117:25 | ... = ... | non-null | Guards.cs:117:22:117:25 | null | non-null |
| Guards.cs:117:9:117:25 | ... = ... | null | Guards.cs:117:9:117:18 | access to property Property | null |

Просмотреть файл

@ -315,6 +315,33 @@ public class E
public bool Field;
string Make() => Field ? null : "";
static void Ex27(string s1, string s2)
{
if ((s1 ?? s2) is null)
{
s1.ToString(); // BAD (always)
s2.ToString(); // BAD (always)
}
}
static void Ex28()
{
var x = (string)null ?? null;
x.ToString(); // BAD (always)
}
static void Ex29(string s)
{
var x = s ?? "";
x.ToString(); // GOOD
}
static void Ex30(string s, object o)
{
var x = s ?? o as string;
x.ToString(); // BAD (maybe)
}
}
public static class Extensions

Просмотреть файл

@ -215,6 +215,7 @@
| E.cs:274:17:274:25 | ... != ... | false | E.cs:274:22:274:25 | null | E.cs:274:17:274:17 | access to local variable o |
| E.cs:293:13:293:24 | ... == ... | true | E.cs:293:15:293:19 | call to method M2 | E.cs:293:24:293:24 | (...) ... |
| E.cs:293:13:293:24 | ... == ... | true | E.cs:293:24:293:24 | (...) ... | E.cs:293:15:293:19 | call to method M2 |
| E.cs:321:13:321:30 | ... is ... | true | E.cs:321:14:321:21 | ... ?? ... | E.cs:321:27:321:30 | null |
| Forwarding.cs:59:13:59:21 | ... == ... | true | Forwarding.cs:59:13:59:13 | access to parameter o | Forwarding.cs:59:18:59:21 | null |
| Forwarding.cs:59:13:59:21 | ... == ... | true | Forwarding.cs:59:18:59:21 | null | Forwarding.cs:59:13:59:13 | access to parameter o |
| Forwarding.cs:78:16:78:39 | call to method ReferenceEquals | true | Forwarding.cs:78:32:78:32 | access to parameter o | Forwarding.cs:78:35:78:38 | null |

Просмотреть файл

@ -1488,6 +1488,30 @@
| E.cs:317:22:317:38 | ... ? ... : ... | non-null | E.cs:317:37:317:38 | "" | non-null |
| E.cs:317:22:317:38 | ... ? ... : ... | null | E.cs:317:22:317:26 | access to field Field | true |
| E.cs:317:22:317:38 | ... ? ... : ... | null | E.cs:317:30:317:33 | null | null |
| E.cs:321:13:321:30 | ... is ... | false | E.cs:321:14:321:21 | ... ?? ... | non-null |
| E.cs:321:13:321:30 | ... is ... | true | E.cs:321:14:321:21 | ... ?? ... | null |
| E.cs:321:14:321:21 | ... ?? ... | null | E.cs:321:14:321:15 | access to parameter s1 | null |
| E.cs:321:14:321:21 | ... ?? ... | null | E.cs:321:20:321:21 | access to parameter s2 | null |
| E.cs:330:13:330:36 | String x = ... | non-null | E.cs:330:13:330:13 | access to local variable x | non-null |
| E.cs:330:13:330:36 | String x = ... | null | E.cs:330:13:330:13 | access to local variable x | null |
| E.cs:330:17:330:28 | (...) ... | non-null | E.cs:330:25:330:28 | null | non-null |
| E.cs:330:17:330:28 | (...) ... | null | E.cs:330:25:330:28 | null | null |
| E.cs:330:17:330:36 | ... ?? ... | null | E.cs:330:17:330:28 | (...) ... | null |
| E.cs:330:17:330:36 | ... ?? ... | null | E.cs:330:33:330:36 | null | null |
| E.cs:331:9:331:9 | access to local variable x | non-null | E.cs:330:17:330:36 | ... ?? ... | non-null |
| E.cs:331:9:331:9 | access to local variable x | null | E.cs:330:17:330:36 | ... ?? ... | null |
| E.cs:336:13:336:23 | String x = ... | non-null | E.cs:336:13:336:13 | access to local variable x | non-null |
| E.cs:336:13:336:23 | String x = ... | null | E.cs:336:13:336:13 | access to local variable x | null |
| E.cs:336:17:336:23 | ... ?? ... | null | E.cs:336:17:336:17 | access to parameter s | null |
| E.cs:336:17:336:23 | ... ?? ... | null | E.cs:336:22:336:23 | "" | null |
| E.cs:337:9:337:9 | access to local variable x | non-null | E.cs:336:17:336:23 | ... ?? ... | non-null |
| E.cs:337:9:337:9 | access to local variable x | null | E.cs:336:17:336:23 | ... ?? ... | null |
| E.cs:342:13:342:32 | String x = ... | non-null | E.cs:342:13:342:13 | access to local variable x | non-null |
| E.cs:342:13:342:32 | String x = ... | null | E.cs:342:13:342:13 | access to local variable x | null |
| E.cs:342:17:342:32 | ... ?? ... | null | E.cs:342:17:342:17 | access to parameter s | null |
| E.cs:342:17:342:32 | ... ?? ... | null | E.cs:342:22:342:32 | ... as ... | null |
| E.cs:343:9:343:9 | access to local variable x | non-null | E.cs:342:17:342:32 | ... ?? ... | non-null |
| E.cs:343:9:343:9 | access to local variable x | null | E.cs:342:17:342:32 | ... ?? ... | null |
| Forwarding.cs:7:16:7:23 | String s = ... | non-null | Forwarding.cs:7:16:7:16 | access to local variable s | non-null |
| Forwarding.cs:7:16:7:23 | String s = ... | null | Forwarding.cs:7:16:7:16 | access to local variable s | null |
| Forwarding.cs:9:13:9:30 | !... | false | Forwarding.cs:9:14:9:30 | call to method IsNullOrEmpty | true |

Просмотреть файл

@ -33,6 +33,9 @@
| E.cs:210:16:210:16 | access to parameter s | Variable $@ is always null here. | E.cs:206:28:206:28 | s | s |
| E.cs:220:13:220:13 | access to local variable x | Variable $@ is always null here. | E.cs:215:13:215:13 | x | x |
| E.cs:229:13:229:13 | access to local variable x | Variable $@ is always null here. | E.cs:225:13:225:13 | x | x |
| E.cs:323:13:323:14 | access to parameter s1 | Variable $@ is always null here. | E.cs:319:29:319:30 | s1 | s1 |
| E.cs:324:13:324:14 | access to parameter s2 | Variable $@ is always null here. | E.cs:319:40:319:41 | s2 | s2 |
| E.cs:331:9:331:9 | access to local variable x | Variable $@ is always null here. | E.cs:330:13:330:13 | x | x |
| Forwarding.cs:36:31:36:31 | access to local variable s | Variable $@ is always null here. | Forwarding.cs:7:16:7:16 | s | s |
| Forwarding.cs:40:27:40:27 | access to local variable s | Variable $@ is always null here. | Forwarding.cs:7:16:7:16 | s | s |
| NullAlwaysBad.cs:9:30:9:30 | access to parameter s | Variable $@ is always null here. | NullAlwaysBad.cs:7:29:7:29 | s | s |

Просмотреть файл

@ -208,6 +208,15 @@
| E.cs:306:31:306:31 | access to field l | E.cs:306:31:306:31 | access to field l | null | true |
| E.cs:309:13:309:22 | access to property HasValue | E.cs:309:13:309:13 | access to field l | false | true |
| E.cs:309:13:309:22 | access to property HasValue | E.cs:309:13:309:13 | access to field l | true | false |
| E.cs:321:13:321:30 | ... is ... | E.cs:321:14:321:21 | ... ?? ... | false | false |
| E.cs:321:13:321:30 | ... is ... | E.cs:321:14:321:21 | ... ?? ... | true | true |
| E.cs:321:14:321:15 | access to parameter s1 | E.cs:321:14:321:15 | access to parameter s1 | non-null | false |
| E.cs:321:14:321:15 | access to parameter s1 | E.cs:321:14:321:15 | access to parameter s1 | null | true |
| E.cs:330:17:330:28 | (...) ... | E.cs:330:17:330:28 | (...) ... | null | true |
| E.cs:336:17:336:17 | access to parameter s | E.cs:336:17:336:17 | access to parameter s | non-null | false |
| E.cs:336:17:336:17 | access to parameter s | E.cs:336:17:336:17 | access to parameter s | null | true |
| E.cs:342:17:342:17 | access to parameter s | E.cs:342:17:342:17 | access to parameter s | non-null | false |
| E.cs:342:17:342:17 | access to parameter s | E.cs:342:17:342:17 | access to parameter s | null | true |
| Forwarding.cs:9:14:9:30 | call to method IsNullOrEmpty | Forwarding.cs:9:14:9:14 | access to local variable s | false | false |
| Forwarding.cs:14:13:14:32 | call to method IsNotNullOrEmpty | Forwarding.cs:14:13:14:13 | access to local variable s | true | false |
| Forwarding.cs:19:14:19:23 | call to method IsNull | Forwarding.cs:19:14:19:14 | access to local variable s | false | false |

Просмотреть файл

@ -348,6 +348,14 @@ nodes
| E.cs:285:9:285:9 | access to local variable o |
| E.cs:301:13:301:27 | SSA def(s) |
| E.cs:302:9:302:9 | access to local variable s |
| E.cs:319:29:319:30 | SSA param(s1) |
| E.cs:321:20:321:21 | access to parameter s2 |
| E.cs:321:27:321:30 | null |
| E.cs:323:13:323:14 | access to parameter s1 |
| E.cs:330:13:330:36 | SSA def(x) |
| E.cs:331:9:331:9 | access to local variable x |
| E.cs:342:13:342:32 | SSA def(x) |
| E.cs:343:9:343:9 | access to local variable x |
| Forwarding.cs:7:16:7:23 | SSA def(s) |
| Forwarding.cs:14:9:17:9 | if (...) ... |
| Forwarding.cs:19:9:22:9 | if (...) ... |
@ -678,6 +686,11 @@ edges
| E.cs:283:13:283:22 | [b (line 279): false] SSA def(o) | E.cs:285:9:285:9 | access to local variable o |
| E.cs:283:13:283:22 | [b (line 279): true] SSA def(o) | E.cs:285:9:285:9 | access to local variable o |
| E.cs:301:13:301:27 | SSA def(s) | E.cs:302:9:302:9 | access to local variable s |
| E.cs:319:29:319:30 | SSA param(s1) | E.cs:321:20:321:21 | access to parameter s2 |
| E.cs:321:20:321:21 | access to parameter s2 | E.cs:321:27:321:30 | null |
| E.cs:321:27:321:30 | null | E.cs:323:13:323:14 | access to parameter s1 |
| E.cs:330:13:330:36 | SSA def(x) | E.cs:331:9:331:9 | access to local variable x |
| E.cs:342:13:342:32 | SSA def(x) | E.cs:343:9:343:9 | access to local variable x |
| Forwarding.cs:7:16:7:23 | SSA def(s) | Forwarding.cs:14:9:17:9 | if (...) ... |
| Forwarding.cs:14:9:17:9 | if (...) ... | Forwarding.cs:19:9:22:9 | if (...) ... |
| Forwarding.cs:19:9:22:9 | if (...) ... | Forwarding.cs:24:9:27:9 | if (...) ... |
@ -778,6 +791,7 @@ edges
| E.cs:285:9:285:9 | access to local variable o | E.cs:283:13:283:22 | [b (line 279): false] SSA def(o) | E.cs:285:9:285:9 | access to local variable o | Variable $@ may be null here as suggested by $@ null check. | E.cs:283:13:283:13 | o | o | E.cs:284:9:284:9 | access to local variable o | this |
| E.cs:285:9:285:9 | access to local variable o | E.cs:283:13:283:22 | [b (line 279): true] SSA def(o) | E.cs:285:9:285:9 | access to local variable o | Variable $@ may be null here as suggested by $@ null check. | E.cs:283:13:283:13 | o | o | E.cs:284:9:284:9 | access to local variable o | this |
| E.cs:302:9:302:9 | access to local variable s | E.cs:301:13:301:27 | SSA def(s) | E.cs:302:9:302:9 | access to local variable s | Variable $@ may be null here because of $@ assignment. | E.cs:301:13:301:13 | s | s | E.cs:301:13:301:27 | String s = ... | this |
| E.cs:343:9:343:9 | access to local variable x | E.cs:342:13:342:32 | SSA def(x) | E.cs:343:9:343:9 | access to local variable x | Variable $@ may be null here because of $@ assignment. | E.cs:342:13:342:13 | x | x | E.cs:342:13:342:32 | String x = ... | this |
| GuardedString.cs:35:31:35:31 | access to local variable s | GuardedString.cs:7:16:7:32 | SSA def(s) | GuardedString.cs:35:31:35:31 | access to local variable s | Variable $@ may be null here because of $@ assignment. | GuardedString.cs:7:16:7:16 | s | s | GuardedString.cs:7:16:7:32 | String s = ... | this |
| NullMaybeBad.cs:7:27:7:27 | access to parameter o | NullMaybeBad.cs:13:17:13:20 | null | NullMaybeBad.cs:7:27:7:27 | access to parameter o | Variable $@ may be null here because of $@ null argument. | NullMaybeBad.cs:5:25:5:25 | o | o | NullMaybeBad.cs:13:17:13:20 | null | this |
| StringConcatenation.cs:16:17:16:17 | access to local variable s | StringConcatenation.cs:14:16:14:23 | SSA def(s) | StringConcatenation.cs:16:17:16:17 | access to local variable s | Variable $@ may be null here because of $@ assignment. | StringConcatenation.cs:14:16:14:16 | s | s | StringConcatenation.cs:14:16:14:23 | String s = ... | this |