diff --git a/csharp/ql/test/library-tests/dataflow/lambda/LambdaFlow.cs b/csharp/ql/test/library-tests/dataflow/lambda/LambdaFlow.cs new file mode 100644 index 00000000000..8d10f24b067 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/lambda/LambdaFlow.cs @@ -0,0 +1,190 @@ +using System; + +public class LambdaFlow +{ + /// + /// Flow into a normal method + /// + class Ex1 + { + void M1(string s) + { + Sink(s); // $ hasValueFlow=1 + } + + public void M2() + { + var source = Source(1); + M1(source); + } + } + + + + + + + + /// + /// Flow into a lambda + /// + class Ex2 + { + void M1(Action lambda) + { + var source = Source(2); + lambda(source); + } + + void M2() + { + Action lambda = x => Sink(x); // $ hasValueFlow=2 + M1(lambda); + } + } + + + + + + + + /// + /// Flow out of a lambda + /// + class Ex3 + { + Func M1() + { + return () => Source(3); + } + + void M2() + { + var lambda = M1(); + Sink(lambda()); // $ hasValueFlow=3 + } + } + + + + + + + + /// + /// Flow through a lambda + /// + class Ex4 + { + string M1(Func lambda, string input) + { + return lambda(input); + } + + void M2() + { + Func id = x => x; + var source = Source(4); + var output = M1(id, source); + Sink(output); // $ hasValueFlow=4 + } + } + + + + + + + + /// + /// No flow into lambda (call context sensitivity) + /// + class Ex5 + { + void M1(Action lambda, string input) + { + lambda(input); + } + + void M2(Action lambda, string input) + { + M1(lambda, input); + } + + void M3() + { + Action lambda1 = arg => Sink(arg); + Action lambda2 = arg => { }; + + var source = Source(5); + var nonSource = "non-source"; + + M1(lambda1, nonSource); + M1(lambda2, source); + + M2(lambda1, nonSource); + M2(lambda2, source); + } + } + + + + + + + + /// + /// Flow into a returned lambda + /// + class Ex6 + { + Action M1() + { + return x => Sink(x); // $ hasValueFlow=6 + } + + void M2() + { + var source = Source(6); + var lambda = M1(); + lambda(source); + } + } + + + + + + + + /// + /// No flow through lambda + /// + class Ex7 + { + void M1(Func lambda) + { + var source = Source(7); + lambda(source); + } + + void M2(Func lambda) + { + var nonSource = "non-source"; + var output = lambda(nonSource); + Sink(output); + } + + void M3() + { + Func id = x => x; + M1(id); + M2(id); + } + } + + static string Source(int source) => source.ToString(); + + static void Sink(string value) { } +} \ No newline at end of file diff --git a/csharp/ql/test/library-tests/dataflow/lambda/LambdaFlow.expected b/csharp/ql/test/library-tests/dataflow/lambda/LambdaFlow.expected new file mode 100644 index 00000000000..a24a0dd550e --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/lambda/LambdaFlow.expected @@ -0,0 +1,120 @@ +models +edges +| LambdaFlow.cs:10:24:10:24 | s : String | LambdaFlow.cs:12:18:12:18 | access to parameter s | provenance | | +| LambdaFlow.cs:17:17:17:22 | access to local variable source : String | LambdaFlow.cs:18:16:18:21 | access to local variable source : String | provenance | | +| LambdaFlow.cs:17:26:17:34 | call to method Source : String | LambdaFlow.cs:17:17:17:22 | access to local variable source : String | provenance | | +| LambdaFlow.cs:18:16:18:21 | access to local variable source : String | LambdaFlow.cs:10:24:10:24 | s : String | provenance | | +| LambdaFlow.cs:33:32:33:37 | lambda [Return] : Action [delegate argument at position 0] : String | LambdaFlow.cs:42:16:42:21 | [post] access to local variable lambda : Action [delegate argument at position 0] : String | provenance | | +| LambdaFlow.cs:35:17:35:22 | access to local variable source : String | LambdaFlow.cs:36:20:36:25 | access to local variable source : String | provenance | | +| LambdaFlow.cs:35:26:35:34 | call to method Source : String | LambdaFlow.cs:35:17:35:22 | access to local variable source : String | provenance | | +| LambdaFlow.cs:36:13:36:18 | [post] access to parameter lambda : Action [delegate argument at position 0] : String | LambdaFlow.cs:33:32:33:37 | lambda [Return] : Action [delegate argument at position 0] : String | provenance | | +| LambdaFlow.cs:36:20:36:25 | access to local variable source : String | LambdaFlow.cs:36:13:36:18 | [post] access to parameter lambda : Action [delegate argument at position 0] : String | provenance | | +| LambdaFlow.cs:41:37:41:37 | x : String | LambdaFlow.cs:41:47:41:47 | access to parameter x | provenance | | +| LambdaFlow.cs:42:16:42:21 | [post] access to local variable lambda : Action [delegate argument at position 0] : String | LambdaFlow.cs:41:37:41:37 | x : String | provenance | | +| LambdaFlow.cs:59:20:59:34 | (...) => ... : (...) => ... [delegate return] : String | LambdaFlow.cs:64:26:64:29 | call to method M1 : (...) => ... [delegate return] : String | provenance | | +| LambdaFlow.cs:59:26:59:34 | call to method Source : String | LambdaFlow.cs:59:20:59:34 | (...) => ... : (...) => ... [delegate return] : String | provenance | | +| LambdaFlow.cs:64:17:64:22 | access to local variable lambda : (...) => ... [delegate return] : String | LambdaFlow.cs:65:18:65:23 | access to local variable lambda : (...) => ... [delegate return] : String | provenance | | +| LambdaFlow.cs:64:26:64:29 | call to method M1 : (...) => ... [delegate return] : String | LambdaFlow.cs:64:17:64:22 | access to local variable lambda : (...) => ... [delegate return] : String | provenance | | +| LambdaFlow.cs:65:18:65:23 | access to local variable lambda : (...) => ... [delegate return] : String | LambdaFlow.cs:65:18:65:25 | delegate call | provenance | | +| LambdaFlow.cs:80:40:80:45 | lambda : (...) => ... [delegate return] : String | LambdaFlow.cs:82:20:82:25 | access to parameter lambda : (...) => ... [delegate return] : String | provenance | | +| LambdaFlow.cs:80:55:80:59 | input : String | LambdaFlow.cs:82:27:82:31 | access to parameter input : String | provenance | | +| LambdaFlow.cs:82:20:82:25 | [post] access to parameter lambda : Func [delegate argument at position 0] : String | LambdaFlow.cs:80:40:80:45 | lambda [Return] : Func [delegate argument at position 0] : String | provenance | | +| LambdaFlow.cs:82:20:82:25 | access to parameter lambda : (...) => ... [delegate return] : String | LambdaFlow.cs:82:20:82:32 | delegate call : String | provenance | | +| LambdaFlow.cs:82:27:82:31 | access to parameter input : String | LambdaFlow.cs:82:20:82:25 | [post] access to parameter lambda : Func [delegate argument at position 0] : String | provenance | | +| LambdaFlow.cs:87:34:87:35 | access to local variable id : (...) => ... [delegate return] : String | LambdaFlow.cs:89:29:89:30 | access to local variable id : (...) => ... [delegate return] : String | provenance | | +| LambdaFlow.cs:87:39:87:39 | x : String | LambdaFlow.cs:87:44:87:44 | access to parameter x : String | provenance | | +| LambdaFlow.cs:87:39:87:44 | (...) => ... : (...) => ... [delegate return] : String | LambdaFlow.cs:87:34:87:35 | access to local variable id : (...) => ... [delegate return] : String | provenance | | +| LambdaFlow.cs:88:17:88:22 | access to local variable source : String | LambdaFlow.cs:89:33:89:38 | access to local variable source : String | provenance | | +| LambdaFlow.cs:88:26:88:34 | call to method Source : String | LambdaFlow.cs:88:17:88:22 | access to local variable source : String | provenance | | +| LambdaFlow.cs:89:17:89:22 | access to local variable output : String | LambdaFlow.cs:90:18:90:23 | access to local variable output | provenance | | +| LambdaFlow.cs:89:26:89:39 | call to method M1 : String | LambdaFlow.cs:89:17:89:22 | access to local variable output : String | provenance | | +| LambdaFlow.cs:89:29:89:30 | [post] access to local variable id : Func [delegate argument at position 0] : String | LambdaFlow.cs:87:39:87:39 | x : String | provenance | | +| LambdaFlow.cs:89:29:89:30 | [post] access to local variable id : Func [delegate argument at position 0] : String | LambdaFlow.cs:87:39:87:44 | (...) => ... : (...) => ... [delegate return] : String | provenance | | +| LambdaFlow.cs:89:29:89:30 | access to local variable id : (...) => ... [delegate return] : String | LambdaFlow.cs:80:40:80:45 | lambda : (...) => ... [delegate return] : String | provenance | | +| LambdaFlow.cs:89:29:89:30 | access to local variable id : (...) => ... [delegate return] : String | LambdaFlow.cs:89:26:89:39 | call to method M1 : String | provenance | | +| LambdaFlow.cs:89:33:89:38 | access to local variable source : String | LambdaFlow.cs:80:55:80:59 | input : String | provenance | | +| LambdaFlow.cs:89:33:89:38 | access to local variable source : String | LambdaFlow.cs:89:29:89:30 | [post] access to local variable id : Func [delegate argument at position 0] : String | provenance | | +| LambdaFlow.cs:166:38:166:43 | lambda [Return] : Func [delegate argument at position 0] : String | LambdaFlow.cs:182:16:182:17 | [post] access to local variable id : Func [delegate argument at position 0] : String | provenance | | +| LambdaFlow.cs:168:17:168:22 | access to local variable source : String | LambdaFlow.cs:169:20:169:25 | access to local variable source : String | provenance | | +| LambdaFlow.cs:168:26:168:34 | call to method Source : String | LambdaFlow.cs:168:17:168:22 | access to local variable source : String | provenance | | +| LambdaFlow.cs:169:13:169:18 | [post] access to parameter lambda : Func [delegate argument at position 0] : String | LambdaFlow.cs:166:38:166:43 | lambda [Return] : Func [delegate argument at position 0] : String | provenance | | +| LambdaFlow.cs:169:20:169:25 | access to local variable source : String | LambdaFlow.cs:169:13:169:18 | [post] access to parameter lambda : Func [delegate argument at position 0] : String | provenance | | +| LambdaFlow.cs:172:38:172:43 | lambda : (...) => ... [delegate return] : String | LambdaFlow.cs:175:26:175:31 | access to parameter lambda : (...) => ... [delegate return] : String | provenance | | +| LambdaFlow.cs:175:17:175:22 | access to local variable output : String | LambdaFlow.cs:176:18:176:23 | access to local variable output | provenance | | +| LambdaFlow.cs:175:26:175:31 | access to parameter lambda : (...) => ... [delegate return] : String | LambdaFlow.cs:175:26:175:42 | delegate call : String | provenance | | +| LambdaFlow.cs:175:26:175:42 | delegate call : String | LambdaFlow.cs:175:17:175:22 | access to local variable output : String | provenance | | +| LambdaFlow.cs:181:34:181:35 | access to local variable id : (...) => ... [delegate return] : String | LambdaFlow.cs:183:16:183:17 | access to local variable id : (...) => ... [delegate return] : String | provenance | | +| LambdaFlow.cs:181:39:181:39 | x : String | LambdaFlow.cs:181:44:181:44 | access to parameter x : String | provenance | | +| LambdaFlow.cs:181:39:181:44 | (...) => ... : (...) => ... [delegate return] : String | LambdaFlow.cs:181:34:181:35 | access to local variable id : (...) => ... [delegate return] : String | provenance | | +| LambdaFlow.cs:182:16:182:17 | [post] access to local variable id : Func [delegate argument at position 0] : String | LambdaFlow.cs:181:39:181:39 | x : String | provenance | | +| LambdaFlow.cs:182:16:182:17 | [post] access to local variable id : Func [delegate argument at position 0] : String | LambdaFlow.cs:181:39:181:44 | (...) => ... : (...) => ... [delegate return] : String | provenance | | +| LambdaFlow.cs:183:16:183:17 | access to local variable id : (...) => ... [delegate return] : String | LambdaFlow.cs:172:38:172:43 | lambda : (...) => ... [delegate return] : String | provenance | | +nodes +| LambdaFlow.cs:10:24:10:24 | s : String | semmle.label | s : String | +| LambdaFlow.cs:12:18:12:18 | access to parameter s | semmle.label | access to parameter s | +| LambdaFlow.cs:17:17:17:22 | access to local variable source : String | semmle.label | access to local variable source : String | +| LambdaFlow.cs:17:26:17:34 | call to method Source : String | semmle.label | call to method Source : String | +| LambdaFlow.cs:18:16:18:21 | access to local variable source : String | semmle.label | access to local variable source : String | +| LambdaFlow.cs:33:32:33:37 | lambda [Return] : Action [delegate argument at position 0] : String | semmle.label | lambda [Return] : Action [delegate argument at position 0] : String | +| LambdaFlow.cs:35:17:35:22 | access to local variable source : String | semmle.label | access to local variable source : String | +| LambdaFlow.cs:35:26:35:34 | call to method Source : String | semmle.label | call to method Source : String | +| LambdaFlow.cs:36:13:36:18 | [post] access to parameter lambda : Action [delegate argument at position 0] : String | semmle.label | [post] access to parameter lambda : Action [delegate argument at position 0] : String | +| LambdaFlow.cs:36:20:36:25 | access to local variable source : String | semmle.label | access to local variable source : String | +| LambdaFlow.cs:41:37:41:37 | x : String | semmle.label | x : String | +| LambdaFlow.cs:41:47:41:47 | access to parameter x | semmle.label | access to parameter x | +| LambdaFlow.cs:42:16:42:21 | [post] access to local variable lambda : Action [delegate argument at position 0] : String | semmle.label | [post] access to local variable lambda : Action [delegate argument at position 0] : String | +| LambdaFlow.cs:59:20:59:34 | (...) => ... : (...) => ... [delegate return] : String | semmle.label | (...) => ... : (...) => ... [delegate return] : String | +| LambdaFlow.cs:59:26:59:34 | call to method Source : String | semmle.label | call to method Source : String | +| LambdaFlow.cs:64:17:64:22 | access to local variable lambda : (...) => ... [delegate return] : String | semmle.label | access to local variable lambda : (...) => ... [delegate return] : String | +| LambdaFlow.cs:64:26:64:29 | call to method M1 : (...) => ... [delegate return] : String | semmle.label | call to method M1 : (...) => ... [delegate return] : String | +| LambdaFlow.cs:65:18:65:23 | access to local variable lambda : (...) => ... [delegate return] : String | semmle.label | access to local variable lambda : (...) => ... [delegate return] : String | +| LambdaFlow.cs:65:18:65:25 | delegate call | semmle.label | delegate call | +| LambdaFlow.cs:80:40:80:45 | lambda : (...) => ... [delegate return] : String | semmle.label | lambda : (...) => ... [delegate return] : String | +| LambdaFlow.cs:80:40:80:45 | lambda [Return] : Func [delegate argument at position 0] : String | semmle.label | lambda [Return] : Func [delegate argument at position 0] : String | +| LambdaFlow.cs:80:55:80:59 | input : String | semmle.label | input : String | +| LambdaFlow.cs:82:20:82:25 | [post] access to parameter lambda : Func [delegate argument at position 0] : String | semmle.label | [post] access to parameter lambda : Func [delegate argument at position 0] : String | +| LambdaFlow.cs:82:20:82:25 | access to parameter lambda : (...) => ... [delegate return] : String | semmle.label | access to parameter lambda : (...) => ... [delegate return] : String | +| LambdaFlow.cs:82:20:82:32 | delegate call : String | semmle.label | delegate call : String | +| LambdaFlow.cs:82:27:82:31 | access to parameter input : String | semmle.label | access to parameter input : String | +| LambdaFlow.cs:87:34:87:35 | access to local variable id : (...) => ... [delegate return] : String | semmle.label | access to local variable id : (...) => ... [delegate return] : String | +| LambdaFlow.cs:87:39:87:39 | x : String | semmle.label | x : String | +| LambdaFlow.cs:87:39:87:44 | (...) => ... : (...) => ... [delegate return] : String | semmle.label | (...) => ... : (...) => ... [delegate return] : String | +| LambdaFlow.cs:87:44:87:44 | access to parameter x : String | semmle.label | access to parameter x : String | +| LambdaFlow.cs:88:17:88:22 | access to local variable source : String | semmle.label | access to local variable source : String | +| LambdaFlow.cs:88:26:88:34 | call to method Source : String | semmle.label | call to method Source : String | +| LambdaFlow.cs:89:17:89:22 | access to local variable output : String | semmle.label | access to local variable output : String | +| LambdaFlow.cs:89:26:89:39 | call to method M1 : String | semmle.label | call to method M1 : String | +| LambdaFlow.cs:89:29:89:30 | [post] access to local variable id : Func [delegate argument at position 0] : String | semmle.label | [post] access to local variable id : Func [delegate argument at position 0] : String | +| LambdaFlow.cs:89:29:89:30 | access to local variable id : (...) => ... [delegate return] : String | semmle.label | access to local variable id : (...) => ... [delegate return] : String | +| LambdaFlow.cs:89:33:89:38 | access to local variable source : String | semmle.label | access to local variable source : String | +| LambdaFlow.cs:90:18:90:23 | access to local variable output | semmle.label | access to local variable output | +| LambdaFlow.cs:166:38:166:43 | lambda [Return] : Func [delegate argument at position 0] : String | semmle.label | lambda [Return] : Func [delegate argument at position 0] : String | +| LambdaFlow.cs:168:17:168:22 | access to local variable source : String | semmle.label | access to local variable source : String | +| LambdaFlow.cs:168:26:168:34 | call to method Source : String | semmle.label | call to method Source : String | +| LambdaFlow.cs:169:13:169:18 | [post] access to parameter lambda : Func [delegate argument at position 0] : String | semmle.label | [post] access to parameter lambda : Func [delegate argument at position 0] : String | +| LambdaFlow.cs:169:20:169:25 | access to local variable source : String | semmle.label | access to local variable source : String | +| LambdaFlow.cs:172:38:172:43 | lambda : (...) => ... [delegate return] : String | semmle.label | lambda : (...) => ... [delegate return] : String | +| LambdaFlow.cs:175:17:175:22 | access to local variable output : String | semmle.label | access to local variable output : String | +| LambdaFlow.cs:175:26:175:31 | access to parameter lambda : (...) => ... [delegate return] : String | semmle.label | access to parameter lambda : (...) => ... [delegate return] : String | +| LambdaFlow.cs:175:26:175:42 | delegate call : String | semmle.label | delegate call : String | +| LambdaFlow.cs:176:18:176:23 | access to local variable output | semmle.label | access to local variable output | +| LambdaFlow.cs:181:34:181:35 | access to local variable id : (...) => ... [delegate return] : String | semmle.label | access to local variable id : (...) => ... [delegate return] : String | +| LambdaFlow.cs:181:39:181:39 | x : String | semmle.label | x : String | +| LambdaFlow.cs:181:39:181:44 | (...) => ... : (...) => ... [delegate return] : String | semmle.label | (...) => ... : (...) => ... [delegate return] : String | +| LambdaFlow.cs:181:44:181:44 | access to parameter x : String | semmle.label | access to parameter x : String | +| LambdaFlow.cs:182:16:182:17 | [post] access to local variable id : Func [delegate argument at position 0] : String | semmle.label | [post] access to local variable id : Func [delegate argument at position 0] : String | +| LambdaFlow.cs:183:16:183:17 | access to local variable id : (...) => ... [delegate return] : String | semmle.label | access to local variable id : (...) => ... [delegate return] : String | +subpaths +| LambdaFlow.cs:89:29:89:30 | [post] access to local variable id : Func [delegate argument at position 0] : String | LambdaFlow.cs:87:39:87:39 | x : String | LambdaFlow.cs:87:44:87:44 | access to parameter x : String | LambdaFlow.cs:87:39:87:44 | (...) => ... : (...) => ... [delegate return] : String | +| LambdaFlow.cs:89:29:89:30 | access to local variable id : (...) => ... [delegate return] : String | LambdaFlow.cs:80:40:80:45 | lambda : (...) => ... [delegate return] : String | LambdaFlow.cs:82:20:82:32 | delegate call : String | LambdaFlow.cs:89:26:89:39 | call to method M1 : String | +| LambdaFlow.cs:89:33:89:38 | access to local variable source : String | LambdaFlow.cs:80:55:80:59 | input : String | LambdaFlow.cs:80:40:80:45 | lambda [Return] : Func [delegate argument at position 0] : String | LambdaFlow.cs:89:29:89:30 | [post] access to local variable id : Func [delegate argument at position 0] : String | +| LambdaFlow.cs:182:16:182:17 | [post] access to local variable id : Func [delegate argument at position 0] : String | LambdaFlow.cs:181:39:181:39 | x : String | LambdaFlow.cs:181:44:181:44 | access to parameter x : String | LambdaFlow.cs:181:39:181:44 | (...) => ... : (...) => ... [delegate return] : String | +testFailures +| LambdaFlow.cs:144:34:144:52 | // ... | Missing result: hasValueFlow=6 | +| LambdaFlow.cs:176:18:176:23 | access to local variable output | Unexpected result: hasValueFlow=7 | +#select +| LambdaFlow.cs:12:18:12:18 | access to parameter s | LambdaFlow.cs:17:26:17:34 | call to method Source : String | LambdaFlow.cs:12:18:12:18 | access to parameter s | $@ | LambdaFlow.cs:17:26:17:34 | call to method Source : String | call to method Source : String | +| LambdaFlow.cs:41:47:41:47 | access to parameter x | LambdaFlow.cs:35:26:35:34 | call to method Source : String | LambdaFlow.cs:41:47:41:47 | access to parameter x | $@ | LambdaFlow.cs:35:26:35:34 | call to method Source : String | call to method Source : String | +| LambdaFlow.cs:65:18:65:25 | delegate call | LambdaFlow.cs:59:26:59:34 | call to method Source : String | LambdaFlow.cs:65:18:65:25 | delegate call | $@ | LambdaFlow.cs:59:26:59:34 | call to method Source : String | call to method Source : String | +| LambdaFlow.cs:90:18:90:23 | access to local variable output | LambdaFlow.cs:88:26:88:34 | call to method Source : String | LambdaFlow.cs:90:18:90:23 | access to local variable output | $@ | LambdaFlow.cs:88:26:88:34 | call to method Source : String | call to method Source : String | +| LambdaFlow.cs:176:18:176:23 | access to local variable output | LambdaFlow.cs:168:26:168:34 | call to method Source : String | LambdaFlow.cs:176:18:176:23 | access to local variable output | $@ | LambdaFlow.cs:168:26:168:34 | call to method Source : String | call to method Source : String | diff --git a/csharp/ql/test/library-tests/dataflow/lambda/LambdaFlow.ql b/csharp/ql/test/library-tests/dataflow/lambda/LambdaFlow.ql new file mode 100644 index 00000000000..f47c9f4e9a4 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/lambda/LambdaFlow.ql @@ -0,0 +1,12 @@ +/** + * @kind path-problem + */ + +import csharp +import TestUtilities.InlineFlowTest +import ValueFlowTest +import PathGraph + +from PathNode source, PathNode sink +where flowPath(source, sink) +select sink, source, sink, "$@", source, source.toString()