Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit abcb6b8

Browse files
hvitvedTom Hvitved
authored andcommitted
C#: Type-based pruning for data flow
1 parent 5408824 commit abcb6b8

11 files changed

Lines changed: 749 additions & 1063 deletions

File tree

csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll

Lines changed: 89 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ private import DataFlowImplCommon::Public
77
private import ControlFlowReachability
88
private import DelegateDataFlow
99
private import semmle.code.csharp.Caching
10+
private import semmle.code.csharp.Conversion
1011
private import semmle.code.csharp.ExprOrStmtParent
1112
private import semmle.code.csharp.Unification
1213
private import semmle.code.csharp.controlflow.Guards
@@ -325,6 +326,23 @@ private Type getCSharpType(DotNet::Type t) {
325326
result.matchesHandle(t)
326327
}
327328

329+
pragma[noinline]
330+
private TypeParameter getATypeParameterSubType(DataFlowType t) {
331+
not t instanceof Gvn::TypeParameterGvnType and
332+
exists(Type t0 | t = Gvn::getGlobalValueNumber(t0) | implicitConversionRestricted(result, t0))
333+
}
334+
335+
pragma[noinline]
336+
private DataFlowType getANonTypeParameterSubType(DataFlowType t) {
337+
not t instanceof Gvn::TypeParameterGvnType and
338+
not result instanceof Gvn::TypeParameterGvnType and
339+
exists(Type t1, Type t2 |
340+
implicitConversionRestricted(t1, t2) and
341+
result = Gvn::getGlobalValueNumber(t1) and
342+
t = Gvn::getGlobalValueNumber(t2)
343+
)
344+
}
345+
328346
/** A collection of cached types and predicates to be evaluated in the same stage. */
329347
cached
330348
private module Cached {
@@ -486,6 +504,28 @@ private module Cached {
486504
t0 instanceof ObjectType
487505
)
488506
}
507+
508+
/**
509+
* Holds if GVNs `t1` and `t2` may have a common sub type. Neither `t1` nor
510+
* `t2` are allowed to be type parameters.
511+
*/
512+
cached
513+
predicate commonSubType(DataFlowType t1, DataFlowType t2) {
514+
not t1 instanceof Gvn::TypeParameterGvnType and
515+
t1 = t2
516+
or
517+
getATypeParameterSubType(t1) = getATypeParameterSubType(t2)
518+
or
519+
getANonTypeParameterSubType(t1) = getANonTypeParameterSubType(t2)
520+
}
521+
522+
cached
523+
predicate commonSubTypeUnifiableLeft(DataFlowType t1, DataFlowType t2) {
524+
exists(DataFlowType t |
525+
Gvn::unifiable(t1, t) and
526+
commonSubType(t, t2)
527+
)
528+
}
489529
}
490530

491531
import Cached
@@ -596,7 +636,11 @@ private module ParameterNodes {
596636
result = this.getUnderlyingNode().getEnclosingCallable()
597637
}
598638

599-
override Type getType() { result = this.getUnderlyingNode().getType() }
639+
override Type getType() {
640+
// Taint tracking steps are allowed to change the type of the tracked object,
641+
// so `result = this.getUnderlyingNode().getType()` is too restrictive
642+
result instanceof ObjectType
643+
}
600644

601645
override Location getLocation() { result = this.getUnderlyingNode().getLocation() }
602646

@@ -939,7 +983,9 @@ private module ReturnNodes {
939983
result = this.getUnderlyingNode().getEnclosingCallable()
940984
}
941985

942-
override Type getType() { result = this.getUnderlyingNode().getType() }
986+
override Type getType() {
987+
result = this.getUnderlyingNode().getEnclosingCallable().getReturnType()
988+
}
943989

944990
override Location getLocation() { result = this.getUnderlyingNode().getLocation() }
945991

@@ -1130,7 +1176,11 @@ private module OutNodes {
11301176

11311177
override Callable getEnclosingCallable() { result = cfn.getEnclosingCallable() }
11321178

1133-
override Type getType() { result = cfn.getElement().(Expr).getType() }
1179+
override Type getType() {
1180+
exists(ImplicitDelegateDataFlowCall c | c.getNode() = this |
1181+
result = c.getDelegateReturnType()
1182+
)
1183+
}
11341184

11351185
override Location getLocation() { result = cfn.getLocation() }
11361186

@@ -1329,15 +1379,34 @@ predicate readStep = readStepImpl/3;
13291379
/** Gets a string representation of a type returned by `getErasedRepr`. */
13301380
string ppReprType(DataFlowType t) { result = t.toString() }
13311381

1382+
private class DataFlowNullType extends DataFlowType {
1383+
DataFlowNullType() { this = Gvn::getGlobalValueNumber(any(NullType nt)) }
1384+
1385+
pragma[noinline]
1386+
predicate isConvertibleTo(DataFlowType t) {
1387+
defaultNullConversion(_, any(Type t0 | t = Gvn::getGlobalValueNumber(t0)))
1388+
}
1389+
}
1390+
13321391
/**
13331392
* Holds if `t1` and `t2` are compatible, that is, whether data can flow from
13341393
* a node of type `t1` to a node of type `t2`.
1335-
*
1336-
* Type-based pruning is disabled for now, so this is a stub implementation.
13371394
*/
1338-
bindingset[t1, t2]
1395+
pragma[inline]
13391396
predicate compatibleTypes(DataFlowType t1, DataFlowType t2) {
1340-
any() // stub implementation
1397+
commonSubType(t1, t2)
1398+
or
1399+
commonSubTypeUnifiableLeft(t1, t2)
1400+
or
1401+
commonSubTypeUnifiableLeft(t2, t1)
1402+
or
1403+
t1.(DataFlowNullType).isConvertibleTo(t2)
1404+
or
1405+
t2.(DataFlowNullType).isConvertibleTo(t1)
1406+
or
1407+
t1 instanceof Gvn::TypeParameterGvnType
1408+
or
1409+
t2 instanceof Gvn::TypeParameterGvnType
13411410
}
13421411

13431412
/**
@@ -1384,8 +1453,19 @@ private module PostUpdateNodes {
13841453
private import PostUpdateNodes
13851454

13861455
/** A node that performs a type cast. */
1387-
class CastNode extends ExprNode {
1388-
CastNode() { this.getExpr() instanceof CastExpr }
1456+
class CastNode extends Node {
1457+
CastNode() {
1458+
this.asExpr() instanceof Cast
1459+
or
1460+
exists(Ssa::ExplicitDefinition def |
1461+
def = this.(SsaDefinitionNode).getDefinition() and
1462+
def.getADefinition() instanceof AssignableDefinitions::PatternDefinition
1463+
)
1464+
or
1465+
readStep(_, _, this)
1466+
or
1467+
storeStep(this, _, _)
1468+
}
13891469
}
13901470

13911471
class DataFlowExpr = DotNet::Expr;

csharp/ql/test/library-tests/dataflow/fields/A.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public void M6(C c)
7474
}
7575
if (cc is C1)
7676
{
77-
Sink(((C1)cc).a); // no flow, stopped by cast to C2 (FALSE POSITIVE, no type pruning yet)
77+
Sink(((C1)cc).a); // no flow, stopped by cast to C2
7878
}
7979
}
8080

csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,7 @@ edges
1919
| A.cs:57:16:57:16 | access to local variable a : A | A.cs:57:9:57:10 | [post] access to local variable c1 [a] : A |
2020
| A.cs:58:12:58:13 | access to local variable c1 [a] : A | A.cs:60:22:60:22 | c [a] : A |
2121
| A.cs:60:22:60:22 | c [a] : A | A.cs:64:19:64:23 | (...) ... [a] : A |
22-
| A.cs:60:22:60:22 | c [a] : A | A.cs:69:18:69:22 | (...) ... [a] : A |
2322
| A.cs:64:19:64:23 | (...) ... [a] : A | A.cs:64:18:64:26 | access to field a |
24-
| A.cs:69:18:69:22 | (...) ... [a] : A | A.cs:77:19:77:24 | (...) ... [a] : A |
25-
| A.cs:77:19:77:24 | (...) ... [a] : A | A.cs:77:18:77:27 | access to field a |
2623
| A.cs:83:9:83:9 | [post] access to parameter b [c] : C | A.cs:88:12:88:12 | [post] access to local variable b [c] : C |
2724
| A.cs:83:15:83:21 | object creation of type C : C | A.cs:83:9:83:9 | [post] access to parameter b [c] : C |
2825
| A.cs:88:12:88:12 | [post] access to local variable b [c] : C | A.cs:89:14:89:14 | access to local variable b [c] : C |
@@ -131,7 +128,6 @@ edges
131128
| F.cs:10:17:10:28 | object creation of type Object : Object | F.cs:11:24:11:24 | access to local variable o : Object |
132129
| F.cs:10:17:10:28 | object creation of type Object : Object | F.cs:15:26:15:26 | access to local variable o : Object |
133130
| F.cs:10:17:10:28 | object creation of type Object : Object | F.cs:19:32:19:32 | access to local variable o : Object |
134-
| F.cs:10:17:10:28 | object creation of type Object : Object | F.cs:23:32:23:32 | access to local variable o : Object |
135131
| F.cs:11:17:11:31 | call to method Create [Field1] : Object | F.cs:12:14:12:14 | access to local variable f [Field1] : Object |
136132
| F.cs:11:24:11:24 | access to local variable o : Object | F.cs:11:17:11:31 | call to method Create [Field1] : Object |
137133
| F.cs:12:14:12:14 | access to local variable f [Field1] : Object | F.cs:12:14:12:21 | access to field Field1 |
@@ -140,6 +136,7 @@ edges
140136
| F.cs:17:14:17:14 | access to local variable f [Field2] : Object | F.cs:17:14:17:21 | access to field Field2 |
141137
| F.cs:19:13:19:34 | object creation of type F [Field1] : Object | F.cs:20:14:20:14 | access to local variable f [Field1] : Object |
142138
| F.cs:19:32:19:32 | access to local variable o : Object | F.cs:19:13:19:34 | object creation of type F [Field1] : Object |
139+
| F.cs:19:32:19:32 | access to local variable o : Object | F.cs:23:32:23:32 | access to local variable o : Object |
143140
| F.cs:20:14:20:14 | access to local variable f [Field1] : Object | F.cs:20:14:20:21 | access to field Field1 |
144141
| F.cs:23:13:23:34 | object creation of type F [Field2] : Object | F.cs:25:14:25:14 | access to local variable f [Field2] : Object |
145142
| F.cs:23:32:23:32 | access to local variable o : Object | F.cs:23:13:23:34 | object creation of type F [Field2] : Object |
@@ -205,9 +202,6 @@ nodes
205202
| A.cs:60:22:60:22 | c [a] : A | semmle.label | c [a] : A |
206203
| A.cs:64:18:64:26 | access to field a | semmle.label | access to field a |
207204
| A.cs:64:19:64:23 | (...) ... [a] : A | semmle.label | (...) ... [a] : A |
208-
| A.cs:69:18:69:22 | (...) ... [a] : A | semmle.label | (...) ... [a] : A |
209-
| A.cs:77:18:77:27 | access to field a | semmle.label | access to field a |
210-
| A.cs:77:19:77:24 | (...) ... [a] : A | semmle.label | (...) ... [a] : A |
211205
| A.cs:83:9:83:9 | [post] access to parameter b [c] : C | semmle.label | [post] access to parameter b [c] : C |
212206
| A.cs:83:15:83:21 | object creation of type C : C | semmle.label | object creation of type C : C |
213207
| A.cs:88:12:88:12 | [post] access to local variable b [c] : C | semmle.label | [post] access to local variable b [c] : C |
@@ -384,7 +378,6 @@ nodes
384378
| A.cs:24:14:24:17 | access to field c | A.cs:22:25:22:32 | object creation of type C2 : C2 | A.cs:24:14:24:17 | access to field c | $@ | A.cs:22:25:22:32 | object creation of type C2 : C2 | object creation of type C2 : C2 |
385379
| A.cs:33:14:33:17 | access to field c | A.cs:31:29:31:36 | object creation of type C2 : C2 | A.cs:33:14:33:17 | access to field c | $@ | A.cs:31:29:31:36 | object creation of type C2 : C2 | object creation of type C2 : C2 |
386380
| A.cs:64:18:64:26 | access to field a | A.cs:55:17:55:23 | object creation of type A : A | A.cs:64:18:64:26 | access to field a | $@ | A.cs:55:17:55:23 | object creation of type A : A | object creation of type A : A |
387-
| A.cs:77:18:77:27 | access to field a | A.cs:55:17:55:23 | object creation of type A : A | A.cs:77:18:77:27 | access to field a | $@ | A.cs:55:17:55:23 | object creation of type A : A | object creation of type A : A |
388381
| A.cs:89:14:89:16 | access to field c | A.cs:83:15:83:21 | object creation of type C : C | A.cs:89:14:89:16 | access to field c | $@ | A.cs:83:15:83:21 | object creation of type C : C | object creation of type C : C |
389382
| A.cs:106:14:106:16 | access to field b | A.cs:98:30:98:36 | object creation of type B : B | A.cs:106:14:106:16 | access to field b | $@ | A.cs:98:30:98:36 | object creation of type B : B | object creation of type B : B |
390383
| A.cs:106:14:106:16 | access to field b | A.cs:104:17:104:23 | object creation of type B : B | A.cs:106:14:106:16 | access to field b | $@ | A.cs:104:17:104:23 | object creation of type B : B | object creation of type B : B |

0 commit comments

Comments
 (0)