Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion csharp/ql/test/TestUtilities/InlineFlowTest.qll
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ private module FlowTestImpl implements InputSig<CsharpDataFlow> {
}

string getArgString(DataFlow::Node src, DataFlow::Node sink) {
(if exists(getSourceArgString(src)) then result = getSourceArgString(src) else result = "") and
(
result = getSourceArgString(src)
or
not exists(getSourceArgString(src)) and result = "line:" + src.getLocation().getStartLine()
) and
exists(sink)
}
}
Expand Down
48 changes: 35 additions & 13 deletions csharp/ql/test/library-tests/dataflow/types/Types.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class C : B<int> { }

class D : B<string>
{
public override void M() => Sink(this);
public override void M() => Sink(this); // $ hasValueFlow=line:32 $ hasValueFlow=line:33 $ hasValueFlow=line:40
}

static void M1()
Expand Down Expand Up @@ -41,32 +41,32 @@ static void M1()
M9(new D()); // no flow

object o = null; // flow
Sink(o);
Sink(o); // $ hasValueFlow=line:43
}

static void M2(A a)
{
if (a is C c)
Sink(c);
Sink(c); // $ hasValueFlow=line:23
}

static void M3(A a)
{
switch (a)
{
case D d:
Sink(d);
Sink(d); // $ hasValueFlow=line:35
break;
}
}

static void M4(A a) => Sink((C)a);
static void M4(A a) => Sink((C)a); // $ hasValueFlow=line:25

static void M5<T>(T x) => Sink(x);
static void M5<T>(T x) => Sink(x); // $ hasValueFlow=line:26 $ hasValueFlow=line:37

static void M6<T>(T x) where T : A => Sink(x);
static void M6<T>(T x) where T : A => Sink(x); // $ hasValueFlow=line:27 $ hasValueFlow=line:38

static void M7<T>(T x) where T : class => Sink(x);
static void M7<T>(T x) where T : class => Sink(x); // $ hasValueFlow=line:28 $ hasValueFlow=line:39

static void M8<T>(T x)
{
Expand All @@ -77,7 +77,7 @@ static void M8<T>(T x)
static void M9(A a)
{
if (a is B<int> b)
Sink(b);
Sink(b); // $ hasValueFlow=line:30
}

static void Sink<T>(T x) { }
Expand Down Expand Up @@ -112,15 +112,15 @@ void M3()

public override void M()
{
Sink(this.Field);
Sink(this.Field); // $ hasValueFlow=line:110
}

void M10()
{
var a = new A();
var e2 = new E2();
Sink(Through(a)); // flow
Sink(Through(e2)); // flow
Sink(Through(a)); // $ hasValueFlow=line:120
Sink(Through(e2)); // $ hasValueFlow=line:121
Sink((E2)Through(a)); // no flow
Sink((A)Through(e2)); // no flow
}
Expand Down Expand Up @@ -150,6 +150,28 @@ class FieldB : FieldA { }

class FieldC : FieldA
{
public override void M() => Sink(this.Field);
public override void M() => Sink(this.Field); // $ hasValueFlow=line:144
}

class F
{
public virtual void M() { }

class F1<T> : F
{
public override void M() => Sink(this); // $ hasValueFlow=line:167
}

class F2 : F { }

F GetF1() => new F1<int>();

F GetF2() => new F2();

private void M2()
{
GetF1().M();
GetF2().M();
}
}
}
9 changes: 9 additions & 0 deletions csharp/ql/test/library-tests/dataflow/types/Types.expected
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
testFailures
edges
| Types.cs:7:21:7:25 | this : D | Types.cs:7:32:7:35 | this access : D |
| Types.cs:7:32:7:35 | this access : D | Types.cs:16:30:16:30 | this : D |
Expand Down Expand Up @@ -54,6 +55,9 @@ edges
| Types.cs:145:13:145:13 | access to parameter c : FieldC [field Field] : Object | Types.cs:138:21:138:25 | this : FieldC [field Field] : Object |
| Types.cs:153:30:153:30 | this : FieldC [field Field] : Object | Types.cs:153:42:153:45 | this access : FieldC [field Field] : Object |
| Types.cs:153:42:153:45 | this access : FieldC [field Field] : Object | Types.cs:153:42:153:51 | access to field Field |
| Types.cs:162:34:162:34 | this : Types+F+F1<Int32> | Types.cs:162:46:162:49 | this access |
| Types.cs:167:22:167:34 | object creation of type F1<Int32> : Types+F+F1<Int32> | Types.cs:173:13:173:19 | call to method GetF1 : Types+F+F1<Int32> |
| Types.cs:173:13:173:19 | call to method GetF1 : Types+F+F1<Int32> | Types.cs:162:34:162:34 | this : Types+F+F1<Int32> |
nodes
| Types.cs:7:21:7:25 | this : D | semmle.label | this : D |
| Types.cs:7:32:7:35 | this access : D | semmle.label | this access : D |
Expand Down Expand Up @@ -123,6 +127,10 @@ nodes
| Types.cs:153:30:153:30 | this : FieldC [field Field] : Object | semmle.label | this : FieldC [field Field] : Object |
| Types.cs:153:42:153:45 | this access : FieldC [field Field] : Object | semmle.label | this access : FieldC [field Field] : Object |
| Types.cs:153:42:153:51 | access to field Field | semmle.label | access to field Field |
| Types.cs:162:34:162:34 | this : Types+F+F1<Int32> | semmle.label | this : Types+F+F1<Int32> |
| Types.cs:162:46:162:49 | this access | semmle.label | this access |
| Types.cs:167:22:167:34 | object creation of type F1<Int32> : Types+F+F1<Int32> | semmle.label | object creation of type F1<Int32> : Types+F+F1<Int32> |
| Types.cs:173:13:173:19 | call to method GetF1 : Types+F+F1<Int32> | semmle.label | call to method GetF1 : Types+F+F1<Int32> |
subpaths
| Types.cs:122:30:122:30 | access to local variable a : A | Types.cs:130:34:130:34 | x : A | Types.cs:130:40:130:40 | access to parameter x : A | Types.cs:122:22:122:31 | call to method Through |
| Types.cs:123:30:123:31 | access to local variable e2 : Types+E<D>.E2 | Types.cs:130:34:130:34 | x : Types+E<D>.E2 | Types.cs:130:40:130:40 | access to parameter x : Types+E<D>.E2 | Types.cs:123:22:123:32 | call to method Through |
Expand All @@ -145,3 +153,4 @@ subpaths
| Types.cs:120:25:120:31 | object creation of type A : A | Types.cs:120:25:120:31 | object creation of type A : A | Types.cs:122:22:122:31 | call to method Through | $@ | Types.cs:122:22:122:31 | call to method Through | call to method Through |
| Types.cs:121:26:121:33 | object creation of type E2 : Types+E<D>.E2 | Types.cs:121:26:121:33 | object creation of type E2 : Types+E<D>.E2 | Types.cs:123:22:123:32 | call to method Through | $@ | Types.cs:123:22:123:32 | call to method Through | call to method Through |
| Types.cs:144:23:144:34 | object creation of type Object : Object | Types.cs:144:23:144:34 | object creation of type Object : Object | Types.cs:153:42:153:51 | access to field Field | $@ | Types.cs:153:42:153:51 | access to field Field | access to field Field |
| Types.cs:167:22:167:34 | object creation of type F1<Int32> : Types+F+F1<Int32> | Types.cs:167:22:167:34 | object creation of type F1<Int32> : Types+F+F1<Int32> | Types.cs:162:46:162:49 | this access | $@ | Types.cs:162:46:162:49 | this access | this access |
11 changes: 7 additions & 4 deletions csharp/ql/test/library-tests/dataflow/types/Types.ql
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
*/

import csharp
import Types::PathGraph
import TestUtilities.InlineFlowTest
import PathGraph

module TypesConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) {
Expand All @@ -17,10 +18,12 @@ module TypesConfig implements DataFlow::ConfigSig {
mc.getAnArgument() = sink.asExpr()
)
}

int fieldFlowBranchLimit() { result = 1000 }
}

module Types = DataFlow::Global<TypesConfig>;
import ValueFlowTest<TypesConfig>

from Types::PathNode source, Types::PathNode sink
where Types::flowPath(source, sink)
from PathNode source, PathNode sink
where flowPath(source, sink)
select source, source, sink, "$@", sink, sink.toString()