Merge pull request #4378 from tamasvajk/feature/flow-summary-nullable

Flow summary nullable
This commit is contained in:
Tamás Vajk
2020-10-06 11:45:41 +02:00
committed by GitHub
4 changed files with 112 additions and 5 deletions

View File

@@ -347,7 +347,7 @@ abstract class LibraryTypeDataFlow extends Type {
* Holds if data may flow from `source` to `sink` when calling callable `c`.
*
* `sourceAp` describes the contents of `source` that flows to `sink`
* (if any), and `sinkContent` describes the contents of `sink` that it
* (if any), and `sinkAp` describes the contents of `sink` that it
* flows to (if any).
*/
pragma[nomagic]
@@ -736,6 +736,49 @@ class SystemLazyFlow extends LibraryTypeDataFlow, SystemLazyClass {
}
}
/** Data flow for `System.Nullable<>`. */
class SystemNullableFlow extends LibraryTypeDataFlow, SystemNullableStruct {
override predicate callableFlow(
CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp,
SourceDeclarationCallable c, boolean preservesValue
) {
preservesValue = true and
c.(Constructor).getDeclaringType() = this and
source = getFlowSourceArg(c, 0, sourceAp) and
sourceAp = AccessPath::empty() and
sink = TCallableFlowSinkReturn() and
sinkAp = AccessPath::property(this.getValueProperty())
or
preservesValue = true and
c = this.getAGetValueOrDefaultMethod() and
source = TCallableFlowSourceQualifier() and
sourceAp = AccessPath::property(this.getValueProperty()) and
sink = TCallableFlowSinkReturn() and
sinkAp = AccessPath::empty()
or
preservesValue = false and
c = this.getHasValueProperty().getGetter() and
source = TCallableFlowSourceQualifier() and
sourceAp = AccessPath::property(this.getValueProperty()) and
sink = TCallableFlowSinkReturn() and
sinkAp = AccessPath::empty()
or
preservesValue = true and
c = this.getAGetValueOrDefaultMethod() and
source = getFlowSourceArg(c, 0, _) and
sourceAp = AccessPath::empty() and
sink = TCallableFlowSinkReturn() and
sinkAp = AccessPath::empty()
or
preservesValue = false and
c = this.getValueProperty().getGetter() and
source = TCallableFlowSourceQualifier() and
sourceAp = AccessPath::empty() and
sink = TCallableFlowSinkReturn() and
sinkAp = AccessPath::empty()
}
}
/** Data flow for `System.Collections.IEnumerable` (and sub types). */
class IEnumerableFlow extends LibraryTypeDataFlow, RefType {
IEnumerableFlow() { this.getABaseType*() instanceof SystemCollectionsIEnumerableInterface }

View File

@@ -21,6 +21,11 @@ class SystemUnboundGenericClass extends UnboundGenericClass {
SystemUnboundGenericClass() { this.getNamespace() instanceof SystemNamespace }
}
/** An unbound generic struct in the `System` namespace. */
class SystemUnboundGenericStruct extends UnboundGenericStruct {
SystemUnboundGenericStruct() { this.getNamespace() instanceof SystemNamespace }
}
/** An interface in the `System` namespace. */
class SystemInterface extends Interface {
SystemInterface() { this.getNamespace() instanceof SystemNamespace }
@@ -215,6 +220,35 @@ class SystemLazyClass extends SystemUnboundGenericClass {
}
}
/** The `System.Nullable<T>` struct. */
class SystemNullableStruct extends SystemUnboundGenericStruct {
SystemNullableStruct() {
this.hasName("Nullable<>") and
this.getNumberOfTypeParameters() = 1
}
/** Gets the `Value` property. */
Property getValueProperty() {
result.getDeclaringType() = this and
result.hasName("Value") and
result.getType() = getTypeParameter(0)
}
/** Gets the `HasValue` property. */
Property getHasValueProperty() {
result.getDeclaringType() = this and
result.hasName("HasValue") and
result.getType() instanceof BoolType
}
/** Gets a `GetValueOrDefault()` method. */
Method getAGetValueOrDefaultMethod() {
result.getDeclaringType() = this and
result.hasName("GetValueOrDefault") and
result.getReturnType() = getTypeParameter(0)
}
}
/** The `System.NullReferenceException` class. */
class SystemNullReferenceExceptionClass extends SystemClass {
SystemNullReferenceExceptionClass() { this.hasName("NullReferenceException") }

View File

@@ -1,20 +1,29 @@
using System;
using System.Runtime.Serialization;
class C
{
sbyte x1;
sbyte? x2;
int x1;
int? x2;
Nullable<int> x3;
Nullable<char> x4;
// Verify conversions
void M()
{
x2 = x1;
x3 = x4;
x2 = x1; // T -> T? conversion: implicit, nullable -> implicit cast
x3 = x4; // T1? -> T2? conversion: implicit, nullable -> implicit cast
x12 = x1; // T1 -> T2? conversion: implicit, nullable -> implicit cast
x12 = null; // null -> T? conversion: implicit, null literal -> no cast
x3 = x2; // T? -> T? no conversion
x14 = x15; // T1? -> T2? conversion: implicit, user defined -> implicit cast
}
// Cause the following types to exist in the database:
sbyte? x0;
byte? x5;
short? x6;
ushort? x7;
@@ -24,4 +33,19 @@ class C
double? x11;
long? x12;
float? x13;
A? x14;
B? x15;
struct A
{
}
struct B
{
public static implicit operator A(B value)
{
return new A();
}
}
}

View File

@@ -494,6 +494,8 @@ callableFlow
| System.Net.WebUtility.HtmlEncode(string) | argument 0 -> return | false |
| System.Net.WebUtility.HtmlEncode(string, TextWriter) | argument 0 -> return | false |
| System.Net.WebUtility.UrlEncode(string) | argument 0 -> return | false |
| System.Nullable<>.GetValueOrDefault(T) | argument 0 -> return | true |
| System.Nullable<>.get_Value() | qualifier -> return | false |
| System.Security.Cryptography.CryptoStream.BeginRead(Byte[], int, int, AsyncCallback, object) | qualifier -> argument 0 | false |
| System.Security.Cryptography.CryptoStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> qualifier | false |
| System.Security.Cryptography.CryptoStream.Read(Byte[], int, int) | qualifier -> argument 0 | false |
@@ -1767,6 +1769,10 @@ callableFlowAccessPath
| System.Net.NetworkInformation.IPAddressCollection.Add(IPAddress) | argument 0 [<empty>] -> qualifier [[]] | true |
| System.Net.NetworkInformation.IPAddressCollection.CopyTo(IPAddress[], int) | qualifier [[]] -> argument 0 [[]] | true |
| System.Net.NetworkInformation.IPAddressCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true |
| System.Nullable<>.GetValueOrDefault() | qualifier [Value] -> return [<empty>] | true |
| System.Nullable<>.GetValueOrDefault(T) | qualifier [Value] -> return [<empty>] | true |
| System.Nullable<>.Nullable(T) | argument 0 [<empty>] -> return [Value] | true |
| System.Nullable<>.get_HasValue() | qualifier [Value] -> return [<empty>] | false |
| System.Resources.ResourceReader.GetEnumerator() | qualifier [[]] -> return [Current] | true |
| System.Resources.ResourceSet.GetEnumerator() | qualifier [[]] -> return [Current] | true |
| System.Runtime.CompilerServices.ConditionalWeakTable<,>.GetEnumerator() | qualifier [[]] -> return [Current] | true |