Skip to content

Commit 3e0045f

Browse files
authored
Merge pull request #2308 from hvitved/csharp/dataflow/types
C#: Type-based pruning for data flow
2 parents 3049bf2 + abcb6b8 commit 3e0045f

51 files changed

Lines changed: 11693 additions & 9433 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

csharp/ql/src/semmle/code/csharp/Caching.qll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,9 @@ module Stages {
8989

9090
cached
9191
private predicate forceCachingInSameStageRev() {
92-
exists(CompoundTypeKind k)
92+
exists(Gvn::CompoundTypeKind k)
93+
or
94+
exists(any(Gvn::GvnType t).toString())
9395
or
9496
exists(Unification::UnconstrainedTypeParameter utp)
9597
or

csharp/ql/src/semmle/code/csharp/Conversion.qll

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,25 @@ private module Cached {
2424
*
2525
* 6.1: Implicit type conversions.
2626
*
27-
* The following conversions are classified as implicit conversions:
27+
* The following conversions are included:
2828
*
2929
* - Identity conversions
3030
* - Implicit numeric conversions
3131
* - Implicit nullable conversions
3232
* - Implicit reference conversions
3333
* - Boxing conversions
34-
* - User-defined implicit conversions
3534
*/
3635
cached
37-
predicate implicitConversion(Type fromType, Type toType) {
38-
implicitConversionNonNull(fromType, toType)
36+
predicate implicitConversionRestricted(Type fromType, Type toType) {
37+
convIdentity(fromType, toType)
3938
or
40-
defaultNullConversion(fromType, toType)
39+
convNumeric(fromType, toType)
40+
or
41+
convNullableType(fromType, toType)
42+
or
43+
convRefTypeNonNull(fromType, toType)
44+
or
45+
convBoxing(fromType, toType)
4146
}
4247

4348
/**
@@ -58,21 +63,36 @@ private module Cached {
5863
import Cached
5964

6065
private predicate implicitConversionNonNull(Type fromType, Type toType) {
61-
convIdentity(fromType, toType)
62-
or
63-
convNumeric(fromType, toType)
64-
or
65-
convNullableType(fromType, toType)
66-
or
67-
convRefTypeNonNull(fromType, toType)
68-
or
69-
convBoxing(fromType, toType)
66+
implicitConversionRestricted(fromType, toType)
7067
or
7168
convConversionOperator(fromType, toType)
7269
or
7370
fromType instanceof DynamicType // 6.1.8
7471
}
7572

73+
/**
74+
* INTERNAL: Do not use.
75+
*
76+
* Holds if there exists an implicit conversion from `fromType` to `toType`.
77+
*
78+
* 6.1: Implicit type conversions.
79+
*
80+
* The following conversions are classified as implicit conversions:
81+
*
82+
* - Identity conversions
83+
* - Implicit numeric conversions
84+
* - Implicit nullable conversions
85+
* - Implicit reference conversions
86+
* - Boxing conversions
87+
* - User-defined implicit conversions
88+
*/
89+
pragma[nomagic]
90+
predicate implicitConversion(Type fromType, Type toType) {
91+
implicitConversionNonNull(fromType, toType)
92+
or
93+
defaultNullConversion(fromType, toType)
94+
}
95+
7696
/**
7797
* A generic type. This includes both constructed generic types and unbound
7898
* generic types (which correspond to constructed generic types where the

csharp/ql/src/semmle/code/csharp/Implements.qll

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ private DeclarationWithAccessors getACompatibleInterfaceAccessorCandidate(Declar
130130
d.isPublic()
131131
}
132132

133-
pragma[noinline]
133+
pragma[nomagic]
134134
private predicate getACompatibleInterfaceAccessorAux(
135135
DeclarationWithAccessors d, ValueOrRefType t, string name
136136
) {
@@ -242,7 +242,7 @@ private Type getArgumentOrReturnType(Method m, int i) {
242242
* type parameters (at the same index).
243243
*/
244244
private module Gvn {
245-
private import semmle.code.csharp.Unification
245+
private import semmle.code.csharp.Unification::Gvn as Unification
246246

247247
private class MethodTypeParameter extends TypeParameter {
248248
MethodTypeParameter() { this = any(UnboundGenericMethod ugm).getATypeParameter() }
@@ -251,27 +251,26 @@ private module Gvn {
251251
private class LeafType extends Type {
252252
LeafType() {
253253
not exists(this.getAChild()) and
254-
not this instanceof MethodTypeParameter
254+
not this instanceof MethodTypeParameter and
255+
not this instanceof DynamicType
255256
}
256257
}
257258

258-
private predicate id(LeafType t, int i) = equivalenceRelation(convIdentity/2)(t, i)
259-
260259
private newtype TGvnType =
261-
TLeafGvnType(int i) { id(_, i) } or
260+
TLeafGvnType(LeafType t) or
262261
TMethodTypeParameterGvnType(int i) { i = any(MethodTypeParameter p).getIndex() } or
263262
TConstructedGvnType(ConstructedGvnTypeList l)
264263

265264
private newtype TConstructedGvnTypeList =
266-
TConstructedGvnTypeNil(CompoundTypeKind k) or
265+
TConstructedGvnTypeNil(Unification::CompoundTypeKind k) or
267266
TConstructedGvnTypeCons(GvnType head, ConstructedGvnTypeList tail) {
268267
gvnConstructedCons(_, _, _, head, tail)
269268
}
270269

271-
private ConstructedGvnTypeList gvnConstructed(Type t, CompoundTypeKind k, int i) {
270+
private ConstructedGvnTypeList gvnConstructed(Type t, Unification::CompoundTypeKind k, int i) {
272271
result = TConstructedGvnTypeNil(k) and
273272
i = -1 and
274-
k = getTypeKind(t)
273+
k = Unification::getTypeKind(t)
275274
or
276275
exists(GvnType head, ConstructedGvnTypeList tail | gvnConstructedCons(t, k, i, head, tail) |
277276
result = TConstructedGvnTypeCons(head, tail)
@@ -283,7 +282,7 @@ private module Gvn {
283282

284283
pragma[noinline]
285284
private predicate gvnConstructedCons(
286-
Type t, CompoundTypeKind k, int i, GvnType head, ConstructedGvnTypeList tail
285+
Type t, Unification::CompoundTypeKind k, int i, GvnType head, ConstructedGvnTypeList tail
287286
) {
288287
tail = gvnConstructed(t, k, i - 1) and
289288
head = gvnTypeChild(t, i)
@@ -292,11 +291,14 @@ private module Gvn {
292291
/** Gets the global value number for a given type. */
293292
pragma[nomagic]
294293
GvnType getGlobalValueNumber(Type t) {
295-
result = TLeafGvnType(any(int i | id(t, i)))
294+
result = TLeafGvnType(t)
295+
or
296+
t instanceof DynamicType and
297+
result = TLeafGvnType(any(ObjectType ot))
296298
or
297299
result = TMethodTypeParameterGvnType(t.(MethodTypeParameter).getIndex())
298300
or
299-
exists(ConstructedGvnTypeList l, CompoundTypeKind k, int i |
301+
exists(ConstructedGvnTypeList l, Unification::CompoundTypeKind k, int i |
300302
l = gvnConstructed(t, k, i) and
301303
i = k.getNumberOfTypeParameters() - 1 and
302304
result = TConstructedGvnType(l)
@@ -306,7 +308,7 @@ private module Gvn {
306308
/** A global value number for a type. */
307309
class GvnType extends TGvnType {
308310
string toString() {
309-
exists(int i | this = TLeafGvnType(i) | result = i.toString())
311+
exists(LeafType t | this = TLeafGvnType(t) | result = t.toString())
310312
or
311313
exists(int i | this = TMethodTypeParameterGvnType(i) | result = "M!" + i)
312314
or
@@ -338,12 +340,12 @@ private module Gvn {
338340

339341
language[monotonicAggregates]
340342
string toString() {
341-
exists(CompoundTypeKind k, string args |
343+
exists(Unification::CompoundTypeKind k, string args |
342344
this = gvnConstructed(_, k, _) and
343345
args = concat(int i |
344346
i in [0 .. k.getNumberOfTypeParameters() - 1]
345347
|
346-
this.getArg(i).toString(), ", " order by i
348+
this.getArg(i).toString(), "," order by i
347349
) and
348350
result = k.toString(args)
349351
)

csharp/ql/src/semmle/code/csharp/Type.qll

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -827,16 +827,13 @@ class ArrayType extends DotNet::ArrayType, RefType, @array_type {
827827
getRank() = that.getRank()
828828
}
829829

830-
private string getRankString(int i) {
831-
i in [0 .. getRank() - 1] and
832-
if i = getRank() - 1 then result = "" else result = "," + getRankString(i + 1)
833-
}
834-
835830
/**
836831
* INTERNAL: Do not use.
837832
* Gets a string representing the array suffix, for example `[,,,]`.
838833
*/
839-
string getArraySuffix() { result = "[" + getRankString(0) + "]" }
834+
string getArraySuffix() {
835+
result = "[" + concat(int i | i in [0 .. this.getRank() - 2] | ",") + "]"
836+
}
840837

841838
private string getDimensionString(Type elementType) {
842839
exists(Type et, string res |

csharp/ql/src/semmle/code/csharp/Unification.qll

Lines changed: 26 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,24 @@ import csharp
22
private import Conversion
33
private import Caching
44

5-
pragma[noinline]
6-
private Type getAProperSubType(Type t) {
7-
not result instanceof DynamicType and
8-
not result instanceof NullType and
9-
result.isImplicitlyConvertibleTo(t)
10-
}
11-
125
/**
6+
* INTERNAL: Do not use.
7+
*
138
* Provides an implementation of Global Value Numbering for types (see
149
* https://en.wikipedia.org/wiki/Global_value_numbering), where types are considered
1510
* equal modulo identity conversions and type parameters.
1611
*/
17-
private module Gvn {
12+
module Gvn {
1813
private class LeafType extends Type {
1914
LeafType() {
2015
not exists(this.getAChild()) and
21-
not this instanceof TypeParameter
16+
not this instanceof TypeParameter and
17+
not this instanceof DynamicType
2218
}
2319
}
2420

2521
/** A type kind for a compound type. */
26-
class CompoundTypeKindImpl extends TCompoundTypeKind {
22+
class CompoundTypeKind extends TCompoundTypeKind {
2723
/** Gets the number of type parameters for this kind. */
2824
int getNumberOfTypeParameters() {
2925
this = TPointerTypeKind() and result = 1
@@ -44,8 +40,8 @@ private module Gvn {
4440
or
4541
this = TNullableTypeKind() and result = args + "?"
4642
or
47-
exists(int dim, int rnk | this = TArrayTypeKind(dim, rnk) |
48-
result = args + "[" + dim + ", " + rnk + "]"
43+
exists(int rnk | this = TArrayTypeKind(_, rnk) |
44+
result = args + "[" + concat(int i | i in [0 .. rnk - 2] | ",") + "]"
4945
)
5046
or
5147
exists(UnboundGenericType ugt | this = TConstructedType(ugt) |
@@ -61,7 +57,7 @@ private module Gvn {
6157
}
6258

6359
/** Gets the type kind for type `t`, if any. */
64-
CompoundTypeKind getTypeKindImpl(Type t) {
60+
CompoundTypeKind getTypeKind(Type t) {
6561
result = TPointerTypeKind() and t instanceof PointerType
6662
or
6763
result = TNullableTypeKind() and t instanceof NullableType
@@ -86,11 +82,13 @@ private module Gvn {
8682
CompoundTypeKind getKind() { none() }
8783

8884
/** Gets a textual representation of this GVN. */
85+
cached
8986
string toString() {
90-
exists(int i | this = TLeafGvnType(i) | result = i.toString())
87+
Stages::UnificationStage::forceCachingInSameStage() and
88+
exists(LeafType t | this = TLeafGvnType(t) | result = t.toString())
9189
or
9290
this instanceof TTypeParameterGvnType and
93-
result = "<type parameter>"
91+
result = "T"
9492
or
9593
exists(ConstructedGvnTypeList l | this = TConstructedGvnType(l) | result = l.toString())
9694
}
@@ -99,6 +97,8 @@ private module Gvn {
9997
Location getLocation() { result instanceof EmptyLocation }
10098
}
10199

100+
class TypeParameterGvnType extends GvnType, TTypeParameterGvnType { }
101+
102102
class ConstructedGvnType extends GvnType, TConstructedGvnType {
103103
private ConstructedGvnTypeList l;
104104

@@ -157,7 +157,7 @@ private module Gvn {
157157
args = concat(int i |
158158
i in [0 .. k.getNumberOfTypeParameters() - 1]
159159
|
160-
this.getArg(i).toString(), ", " order by i
160+
this.getArg(i).toString(), "," order by i
161161
) and
162162
result = k.toString(args)
163163
)
@@ -356,8 +356,6 @@ private module Gvn {
356356
not result instanceof ConstructedGvnType
357357
}
358358

359-
private predicate id(LeafType t, int i) = equivalenceRelation(convIdentity/2)(t, i)
360-
361359
cached
362360
private module Cached {
363361
cached
@@ -367,11 +365,11 @@ private module Gvn {
367365
TArrayTypeKind(int dim, int rnk) {
368366
exists(ArrayType at | dim = at.getDimension() and rnk = at.getRank())
369367
} or
370-
TConstructedType(UnboundGenericType ugt)
368+
TConstructedType(UnboundGenericType ugt) { exists(ugt.getATypeParameter()) }
371369

372370
cached
373371
newtype TGvnType =
374-
TLeafGvnType(int i) { id(_, i) } or
372+
TLeafGvnType(LeafType t) or
375373
TTypeParameterGvnType() or
376374
TConstructedGvnType(ConstructedGvnTypeList l)
377375

@@ -385,7 +383,10 @@ private module Gvn {
385383
/** Gets the GVN for type `t`. */
386384
cached
387385
GvnType getGlobalValueNumber(Type t) {
388-
result = TLeafGvnType(any(int i | id(t, i)))
386+
result = TLeafGvnType(t)
387+
or
388+
t instanceof DynamicType and
389+
result = TLeafGvnType(any(ObjectType ot))
389390
or
390391
t instanceof TypeParameter and
391392
result = TTypeParameterGvnType()
@@ -430,10 +431,6 @@ private module Gvn {
430431
import Cached
431432
}
432433

433-
class CompoundTypeKind = Gvn::CompoundTypeKindImpl;
434-
435-
predicate getTypeKind = Gvn::getTypeKindImpl/1;
436-
437434
/** Provides definitions related to type unification. */
438435
module Unification {
439436
/** A type parameter that is compatible with any type. */
@@ -557,19 +554,19 @@ module Unification {
557554

558555
cached
559556
predicate typeConstraintUnifiable(TTypeConstraint ttc, Type t) {
560-
exists(Type t0 | ttc = TTypeConstraint(t0) | t = getAProperSubType(t0))
557+
exists(Type t0 | ttc = TTypeConstraint(t0) | implicitConversionRestricted(t, t0))
561558
or
562559
exists(Type t0, Type t1 | ttc = TTypeConstraint(t0) and unifiable(t0, t1) |
563-
t = getAProperSubType(t1)
560+
implicitConversionRestricted(t, t1)
564561
)
565562
}
566563

567564
cached
568565
predicate typeConstraintSubsumes(TTypeConstraint ttc, Type t) {
569-
exists(Type t0 | ttc = TTypeConstraint(t0) | t = getAProperSubType(t0))
566+
exists(Type t0 | ttc = TTypeConstraint(t0) | implicitConversionRestricted(t, t0))
570567
or
571568
exists(Type t0, Type t1 | ttc = TTypeConstraint(t0) and subsumes(t0, t1) |
572-
t = getAProperSubType(t1)
569+
implicitConversionRestricted(t, t1)
573570
)
574571
}
575572
}

0 commit comments

Comments
 (0)