From ea1fc43732e8261651e7468de1b458a81f161533 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Fri, 27 Feb 2026 13:35:20 +0100 Subject: [PATCH 1/6] C#: Add data flow test for struct. --- .../dataflow/structs/StructFlow.expected | 61 +++++++++++++++++++ .../dataflow/structs/StructFlow.ql | 12 ++++ .../library-tests/dataflow/structs/structs.cs | 40 ++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 csharp/ql/test/library-tests/dataflow/structs/StructFlow.expected create mode 100644 csharp/ql/test/library-tests/dataflow/structs/StructFlow.ql create mode 100644 csharp/ql/test/library-tests/dataflow/structs/structs.cs diff --git a/csharp/ql/test/library-tests/dataflow/structs/StructFlow.expected b/csharp/ql/test/library-tests/dataflow/structs/StructFlow.expected new file mode 100644 index 000000000000..c0841982328a --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/structs/StructFlow.expected @@ -0,0 +1,61 @@ +models +edges +| structs.cs:10:27:10:30 | args : Object[] [element] : Object | structs.cs:12:25:12:28 | access to parameter args : Object[] [element] : Object | provenance | | +| structs.cs:10:27:10:30 | args : Object[] [element] : Object | structs.cs:12:25:12:28 | access to parameter args : Object[] [element] : Object | provenance | | +| structs.cs:12:13:12:16 | [post] this access : S [field args, element] : Object | structs.cs:10:16:10:16 | this [Return] : S [field args, element] : Object | provenance | | +| structs.cs:12:13:12:16 | [post] this access : S [field args, element] : Object | structs.cs:10:16:10:16 | this [Return] : S [field args, element] : Object | provenance | | +| structs.cs:12:25:12:28 | access to parameter args : Object[] [element] : Object | structs.cs:12:13:12:16 | [post] this access : S [field args, element] : Object | provenance | | +| structs.cs:12:25:12:28 | access to parameter args : Object[] [element] : Object | structs.cs:12:13:12:16 | [post] this access : S [field args, element] : Object | provenance | | +| structs.cs:24:13:24:13 | access to local variable o : Object | structs.cs:25:24:25:24 | access to local variable o : Object | provenance | | +| structs.cs:24:13:24:13 | access to local variable o : Object | structs.cs:25:24:25:24 | access to local variable o : Object | provenance | | +| structs.cs:24:17:24:33 | call to method Source : Object | structs.cs:24:13:24:13 | access to local variable o : Object | provenance | | +| structs.cs:24:17:24:33 | call to method Source : Object | structs.cs:24:13:24:13 | access to local variable o : Object | provenance | | +| structs.cs:25:13:25:13 | access to local variable s : S [field args, element] : Object | structs.cs:26:14:26:14 | access to local variable s : S [field args, element] : Object | provenance | | +| structs.cs:25:13:25:13 | access to local variable s : S [field args, element] : Object | structs.cs:26:14:26:14 | access to local variable s : S [field args, element] : Object | provenance | | +| structs.cs:25:17:25:26 | object creation of type S : S [field args, element] : Object | structs.cs:25:13:25:13 | access to local variable s : S [field args, element] : Object | provenance | | +| structs.cs:25:17:25:26 | object creation of type S : S [field args, element] : Object | structs.cs:25:13:25:13 | access to local variable s : S [field args, element] : Object | provenance | | +| structs.cs:25:23:25:25 | [...] : Object[] [element] : Object | structs.cs:10:27:10:30 | args : Object[] [element] : Object | provenance | | +| structs.cs:25:23:25:25 | [...] : Object[] [element] : Object | structs.cs:10:27:10:30 | args : Object[] [element] : Object | provenance | | +| structs.cs:25:23:25:25 | [...] : Object[] [element] : Object | structs.cs:25:17:25:26 | object creation of type S : S [field args, element] : Object | provenance | | +| structs.cs:25:23:25:25 | [...] : Object[] [element] : Object | structs.cs:25:17:25:26 | object creation of type S : S [field args, element] : Object | provenance | | +| structs.cs:25:24:25:24 | access to local variable o : Object | structs.cs:25:23:25:25 | [...] : Object[] [element] : Object | provenance | | +| structs.cs:25:24:25:24 | access to local variable o : Object | structs.cs:25:23:25:25 | [...] : Object[] [element] : Object | provenance | | +| structs.cs:26:14:26:14 | access to local variable s : S [field args, element] : Object | structs.cs:26:14:26:19 | access to field args : Object[] [element] : Object | provenance | | +| structs.cs:26:14:26:14 | access to local variable s : S [field args, element] : Object | structs.cs:26:14:26:19 | access to field args : Object[] [element] : Object | provenance | | +| structs.cs:26:14:26:19 | access to field args : Object[] [element] : Object | structs.cs:26:14:26:22 | access to array element | provenance | | +| structs.cs:26:14:26:19 | access to field args : Object[] [element] : Object | structs.cs:26:14:26:22 | access to array element | provenance | | +nodes +| structs.cs:10:16:10:16 | this [Return] : S [field args, element] : Object | semmle.label | this [Return] : S [field args, element] : Object | +| structs.cs:10:16:10:16 | this [Return] : S [field args, element] : Object | semmle.label | this [Return] : S [field args, element] : Object | +| structs.cs:10:27:10:30 | args : Object[] [element] : Object | semmle.label | args : Object[] [element] : Object | +| structs.cs:10:27:10:30 | args : Object[] [element] : Object | semmle.label | args : Object[] [element] : Object | +| structs.cs:12:13:12:16 | [post] this access : S [field args, element] : Object | semmle.label | [post] this access : S [field args, element] : Object | +| structs.cs:12:13:12:16 | [post] this access : S [field args, element] : Object | semmle.label | [post] this access : S [field args, element] : Object | +| structs.cs:12:25:12:28 | access to parameter args : Object[] [element] : Object | semmle.label | access to parameter args : Object[] [element] : Object | +| structs.cs:12:25:12:28 | access to parameter args : Object[] [element] : Object | semmle.label | access to parameter args : Object[] [element] : Object | +| structs.cs:24:13:24:13 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| structs.cs:24:13:24:13 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| structs.cs:24:17:24:33 | call to method Source : Object | semmle.label | call to method Source : Object | +| structs.cs:24:17:24:33 | call to method Source : Object | semmle.label | call to method Source : Object | +| structs.cs:25:13:25:13 | access to local variable s : S [field args, element] : Object | semmle.label | access to local variable s : S [field args, element] : Object | +| structs.cs:25:13:25:13 | access to local variable s : S [field args, element] : Object | semmle.label | access to local variable s : S [field args, element] : Object | +| structs.cs:25:17:25:26 | object creation of type S : S [field args, element] : Object | semmle.label | object creation of type S : S [field args, element] : Object | +| structs.cs:25:17:25:26 | object creation of type S : S [field args, element] : Object | semmle.label | object creation of type S : S [field args, element] : Object | +| structs.cs:25:23:25:25 | [...] : Object[] [element] : Object | semmle.label | [...] : Object[] [element] : Object | +| structs.cs:25:23:25:25 | [...] : Object[] [element] : Object | semmle.label | [...] : Object[] [element] : Object | +| structs.cs:25:24:25:24 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| structs.cs:25:24:25:24 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| structs.cs:26:14:26:14 | access to local variable s : S [field args, element] : Object | semmle.label | access to local variable s : S [field args, element] : Object | +| structs.cs:26:14:26:14 | access to local variable s : S [field args, element] : Object | semmle.label | access to local variable s : S [field args, element] : Object | +| structs.cs:26:14:26:19 | access to field args : Object[] [element] : Object | semmle.label | access to field args : Object[] [element] : Object | +| structs.cs:26:14:26:19 | access to field args : Object[] [element] : Object | semmle.label | access to field args : Object[] [element] : Object | +| structs.cs:26:14:26:22 | access to array element | semmle.label | access to array element | +| structs.cs:26:14:26:22 | access to array element | semmle.label | access to array element | +subpaths +| structs.cs:25:23:25:25 | [...] : Object[] [element] : Object | structs.cs:10:27:10:30 | args : Object[] [element] : Object | structs.cs:10:16:10:16 | this [Return] : S [field args, element] : Object | structs.cs:25:17:25:26 | object creation of type S : S [field args, element] : Object | +| structs.cs:25:23:25:25 | [...] : Object[] [element] : Object | structs.cs:10:27:10:30 | args : Object[] [element] : Object | structs.cs:10:16:10:16 | this [Return] : S [field args, element] : Object | structs.cs:25:17:25:26 | object creation of type S : S [field args, element] : Object | +testFailures +| structs.cs:33:26:33:44 | // ... | Missing result: hasValueFlow=2 | +#select +| structs.cs:26:14:26:22 | access to array element | structs.cs:24:17:24:33 | call to method Source : Object | structs.cs:26:14:26:22 | access to array element | $@ | structs.cs:24:17:24:33 | call to method Source : Object | call to method Source : Object | +| structs.cs:26:14:26:22 | access to array element | structs.cs:24:17:24:33 | call to method Source : Object | structs.cs:26:14:26:22 | access to array element | $@ | structs.cs:24:17:24:33 | call to method Source : Object | call to method Source : Object | diff --git a/csharp/ql/test/library-tests/dataflow/structs/StructFlow.ql b/csharp/ql/test/library-tests/dataflow/structs/StructFlow.ql new file mode 100644 index 000000000000..9ab95f59caf3 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/structs/StructFlow.ql @@ -0,0 +1,12 @@ +/** + * @kind path-problem + */ + +import csharp +import utils.test.InlineFlowTest +import DefaultFlowTest +import PathGraph + +from PathNode source, PathNode sink +where flowPath(source, sink) +select sink, source, sink, "$@", source, source.toString() diff --git a/csharp/ql/test/library-tests/dataflow/structs/structs.cs b/csharp/ql/test/library-tests/dataflow/structs/structs.cs new file mode 100644 index 000000000000..275e27512e42 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/structs/structs.cs @@ -0,0 +1,40 @@ +using System; + +public class Test +{ + public struct S + { + public int field; + public object[] args; + + public S(object[] args) + { + this.args = args; + } + } + + public void SetTainted(S s) + { + s.args[0] = Source(2); + s.field = Source(3); + } + + public void M1() + { + var o = Source(1); + var s = new S([o]); + Sink(s.args[0]); // $ hasValueFlow=1 + } + + public void M2() + { + var s = new S(new object[1]); + SetTainted(s); + Sink(s.args[0]); // $ hasValueFlow=2 + Sink(s.field); // $ no flow. + } + + public static void Sink(object o) { } + + static T Source(object source) => throw null; +} From 4e63b83fd321473aa5df629fcdc21aad716aa9d0 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Fri, 27 Feb 2026 13:08:28 +0100 Subject: [PATCH 2/6] C#: Add struct source model example. --- .../dataflow/external-models/Sources.cs | 6 ++++++ .../dataflow/external-models/srcs.expected | 12 ++++++------ .../dataflow/external-models/srcs.ext.yml | 1 + 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/csharp/ql/test/library-tests/dataflow/external-models/Sources.cs b/csharp/ql/test/library-tests/dataflow/external-models/Sources.cs index 6f73f096ef9c..10b8a37cc0f8 100644 --- a/csharp/ql/test/library-tests/dataflow/external-models/Sources.cs +++ b/csharp/ql/test/library-tests/dataflow/external-models/Sources.cs @@ -21,6 +21,9 @@ void Foo() x = TaggedSrcPropertyGetter; x = this[0]; + + S s; + StructSrc(s); } [SourceAttribute] @@ -65,7 +68,10 @@ void SrcArg(object src) { } [SourceAttribute] object this[int i] => null; + + void StructSrc(S s) { } } + struct S { } class SourceAttribute : System.Attribute { } } diff --git a/csharp/ql/test/library-tests/dataflow/external-models/srcs.expected b/csharp/ql/test/library-tests/dataflow/external-models/srcs.expected index 855e51fca562..d689f2b3f4c6 100644 --- a/csharp/ql/test/library-tests/dataflow/external-models/srcs.expected +++ b/csharp/ql/test/library-tests/dataflow/external-models/srcs.expected @@ -11,9 +11,9 @@ invalidModelRow | Sources.cs:20:17:20:33 | call to method SrcTwoArg | local | | Sources.cs:22:17:22:39 | access to property TaggedSrcPropertyGetter | local | | Sources.cs:23:17:23:23 | access to indexer | local | -| Sources.cs:27:14:27:20 | this | local | -| Sources.cs:27:29:27:45 | taggedMethodParam | local | -| Sources.cs:31:47:31:60 | taggedSrcParam | local | -| Sources.cs:43:45:43:45 | p | local | -| Sources.cs:50:50:50:50 | p | local | -| Sources.cs:56:16:56:30 | this | local | +| Sources.cs:30:14:30:20 | this | local | +| Sources.cs:30:29:30:45 | taggedMethodParam | local | +| Sources.cs:34:47:34:60 | taggedSrcParam | local | +| Sources.cs:46:45:46:45 | p | local | +| Sources.cs:53:50:53:50 | p | local | +| Sources.cs:59:16:59:30 | this | local | diff --git a/csharp/ql/test/library-tests/dataflow/external-models/srcs.ext.yml b/csharp/ql/test/library-tests/dataflow/external-models/srcs.ext.yml index ca5103b1cd5e..b4dcd75be26e 100644 --- a/csharp/ql/test/library-tests/dataflow/external-models/srcs.ext.yml +++ b/csharp/ql/test/library-tests/dataflow/external-models/srcs.ext.yml @@ -19,3 +19,4 @@ extensions: - ["My.Qltest", "SourceAttribute", false, "", "", "Attribute", "", "local", "manual"] - ["My.Qltest", "SourceAttribute", false, "", "", "Attribute.Getter", "ReturnValue", "local", "manual"] - ["My.Qltest", "A", false, "SrcTwoArg", "(System.String,System.String)", "", "ReturnValue", "local", "manual"] + - ["My.Qltest", "A", false, "StructSrc", "", "", "Argument[0]", "local", "manual"] From ec7e6e8e03aa635689daad6a982a2256c938d46a Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Fri, 27 Feb 2026 10:04:10 +0100 Subject: [PATCH 3/6] C#: Add post-update nodes for arguments of struct type. --- .../semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll index 1b3de63495f0..5f28c9da1964 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -6,6 +6,7 @@ private import ControlFlowReachability private import FlowSummaryImpl as FlowSummaryImpl private import semmle.code.csharp.dataflow.FlowSummary as FlowSummary private import semmle.code.csharp.dataflow.internal.ExternalFlow +private import semmle.code.csharp.commons.Collections private import semmle.code.csharp.Conversion private import semmle.code.csharp.dataflow.internal.SsaImpl as SsaImpl private import semmle.code.csharp.ExprOrStmtParent @@ -16,7 +17,6 @@ private import semmle.code.csharp.frameworks.EntityFramework private import semmle.code.csharp.frameworks.system.linq.Expressions private import semmle.code.csharp.frameworks.NHibernate private import semmle.code.csharp.frameworks.Razor -private import semmle.code.csharp.frameworks.system.Collections private import semmle.code.csharp.frameworks.system.threading.Tasks private import semmle.code.csharp.internal.Location private import codeql.util.Unit @@ -1087,7 +1087,7 @@ predicate exprMayHavePostUpdateNode(Expr e) { or t = any(TypeParameter tp | not tp.isValueType()) or - t.isRefLikeType() + t instanceof Struct ) } @@ -2545,6 +2545,7 @@ private predicate clearsCont(Node n, Content c) { a.getType() = s and f = s.getAField() and c.(FieldContent).getField() = f.getUnboundDeclaration() and + not f.getType() instanceof CollectionType and not f.isRef() ) or From a3d15dbaa302b16cca7d2fa7d5d953bbb7c9bddc Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Fri, 27 Feb 2026 13:43:32 +0100 Subject: [PATCH 4/6] C#: Update test expected output for new tests. --- .../dataflow/external-models/srcs.expected | 1 + .../dataflow/structs/StructFlow.expected | 33 ++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/csharp/ql/test/library-tests/dataflow/external-models/srcs.expected b/csharp/ql/test/library-tests/dataflow/external-models/srcs.expected index d689f2b3f4c6..063626c07265 100644 --- a/csharp/ql/test/library-tests/dataflow/external-models/srcs.expected +++ b/csharp/ql/test/library-tests/dataflow/external-models/srcs.expected @@ -11,6 +11,7 @@ invalidModelRow | Sources.cs:20:17:20:33 | call to method SrcTwoArg | local | | Sources.cs:22:17:22:39 | access to property TaggedSrcPropertyGetter | local | | Sources.cs:23:17:23:23 | access to indexer | local | +| Sources.cs:26:23:26:23 | [post] access to local variable s | local | | Sources.cs:30:14:30:20 | this | local | | Sources.cs:30:29:30:45 | taggedMethodParam | local | | Sources.cs:34:47:34:60 | taggedSrcParam | local | diff --git a/csharp/ql/test/library-tests/dataflow/structs/StructFlow.expected b/csharp/ql/test/library-tests/dataflow/structs/StructFlow.expected index c0841982328a..be27c832f117 100644 --- a/csharp/ql/test/library-tests/dataflow/structs/StructFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/structs/StructFlow.expected @@ -6,6 +6,14 @@ edges | structs.cs:12:13:12:16 | [post] this access : S [field args, element] : Object | structs.cs:10:16:10:16 | this [Return] : S [field args, element] : Object | provenance | | | structs.cs:12:25:12:28 | access to parameter args : Object[] [element] : Object | structs.cs:12:13:12:16 | [post] this access : S [field args, element] : Object | provenance | | | structs.cs:12:25:12:28 | access to parameter args : Object[] [element] : Object | structs.cs:12:13:12:16 | [post] this access : S [field args, element] : Object | provenance | | +| structs.cs:16:30:16:30 | s [Return] : S [field args, element] : Object | structs.cs:32:20:32:20 | [post] access to local variable s : S [field args, element] : Object | provenance | | +| structs.cs:16:30:16:30 | s [Return] : S [field args, element] : Object | structs.cs:32:20:32:20 | [post] access to local variable s : S [field args, element] : Object | provenance | | +| structs.cs:18:9:18:9 | [post] access to parameter s : S [field args, element] : Object | structs.cs:16:30:16:30 | s [Return] : S [field args, element] : Object | provenance | | +| structs.cs:18:9:18:9 | [post] access to parameter s : S [field args, element] : Object | structs.cs:16:30:16:30 | s [Return] : S [field args, element] : Object | provenance | | +| structs.cs:18:9:18:14 | [post] access to field args : Object[] [element] : Object | structs.cs:18:9:18:9 | [post] access to parameter s : S [field args, element] : Object | provenance | | +| structs.cs:18:9:18:14 | [post] access to field args : Object[] [element] : Object | structs.cs:18:9:18:9 | [post] access to parameter s : S [field args, element] : Object | provenance | | +| structs.cs:18:21:18:37 | call to method Source : Object | structs.cs:18:9:18:14 | [post] access to field args : Object[] [element] : Object | provenance | | +| structs.cs:18:21:18:37 | call to method Source : Object | structs.cs:18:9:18:14 | [post] access to field args : Object[] [element] : Object | provenance | | | structs.cs:24:13:24:13 | access to local variable o : Object | structs.cs:25:24:25:24 | access to local variable o : Object | provenance | | | structs.cs:24:13:24:13 | access to local variable o : Object | structs.cs:25:24:25:24 | access to local variable o : Object | provenance | | | structs.cs:24:17:24:33 | call to method Source : Object | structs.cs:24:13:24:13 | access to local variable o : Object | provenance | | @@ -24,6 +32,12 @@ edges | structs.cs:26:14:26:14 | access to local variable s : S [field args, element] : Object | structs.cs:26:14:26:19 | access to field args : Object[] [element] : Object | provenance | | | structs.cs:26:14:26:19 | access to field args : Object[] [element] : Object | structs.cs:26:14:26:22 | access to array element | provenance | | | structs.cs:26:14:26:19 | access to field args : Object[] [element] : Object | structs.cs:26:14:26:22 | access to array element | provenance | | +| structs.cs:32:20:32:20 | [post] access to local variable s : S [field args, element] : Object | structs.cs:33:14:33:14 | access to local variable s : S [field args, element] : Object | provenance | | +| structs.cs:32:20:32:20 | [post] access to local variable s : S [field args, element] : Object | structs.cs:33:14:33:14 | access to local variable s : S [field args, element] : Object | provenance | | +| structs.cs:33:14:33:14 | access to local variable s : S [field args, element] : Object | structs.cs:33:14:33:19 | access to field args : Object[] [element] : Object | provenance | | +| structs.cs:33:14:33:14 | access to local variable s : S [field args, element] : Object | structs.cs:33:14:33:19 | access to field args : Object[] [element] : Object | provenance | | +| structs.cs:33:14:33:19 | access to field args : Object[] [element] : Object | structs.cs:33:14:33:22 | access to array element | provenance | | +| structs.cs:33:14:33:19 | access to field args : Object[] [element] : Object | structs.cs:33:14:33:22 | access to array element | provenance | | nodes | structs.cs:10:16:10:16 | this [Return] : S [field args, element] : Object | semmle.label | this [Return] : S [field args, element] : Object | | structs.cs:10:16:10:16 | this [Return] : S [field args, element] : Object | semmle.label | this [Return] : S [field args, element] : Object | @@ -33,6 +47,14 @@ nodes | structs.cs:12:13:12:16 | [post] this access : S [field args, element] : Object | semmle.label | [post] this access : S [field args, element] : Object | | structs.cs:12:25:12:28 | access to parameter args : Object[] [element] : Object | semmle.label | access to parameter args : Object[] [element] : Object | | structs.cs:12:25:12:28 | access to parameter args : Object[] [element] : Object | semmle.label | access to parameter args : Object[] [element] : Object | +| structs.cs:16:30:16:30 | s [Return] : S [field args, element] : Object | semmle.label | s [Return] : S [field args, element] : Object | +| structs.cs:16:30:16:30 | s [Return] : S [field args, element] : Object | semmle.label | s [Return] : S [field args, element] : Object | +| structs.cs:18:9:18:9 | [post] access to parameter s : S [field args, element] : Object | semmle.label | [post] access to parameter s : S [field args, element] : Object | +| structs.cs:18:9:18:9 | [post] access to parameter s : S [field args, element] : Object | semmle.label | [post] access to parameter s : S [field args, element] : Object | +| structs.cs:18:9:18:14 | [post] access to field args : Object[] [element] : Object | semmle.label | [post] access to field args : Object[] [element] : Object | +| structs.cs:18:9:18:14 | [post] access to field args : Object[] [element] : Object | semmle.label | [post] access to field args : Object[] [element] : Object | +| structs.cs:18:21:18:37 | call to method Source : Object | semmle.label | call to method Source : Object | +| structs.cs:18:21:18:37 | call to method Source : Object | semmle.label | call to method Source : Object | | structs.cs:24:13:24:13 | access to local variable o : Object | semmle.label | access to local variable o : Object | | structs.cs:24:13:24:13 | access to local variable o : Object | semmle.label | access to local variable o : Object | | structs.cs:24:17:24:33 | call to method Source : Object | semmle.label | call to method Source : Object | @@ -51,11 +73,20 @@ nodes | structs.cs:26:14:26:19 | access to field args : Object[] [element] : Object | semmle.label | access to field args : Object[] [element] : Object | | structs.cs:26:14:26:22 | access to array element | semmle.label | access to array element | | structs.cs:26:14:26:22 | access to array element | semmle.label | access to array element | +| structs.cs:32:20:32:20 | [post] access to local variable s : S [field args, element] : Object | semmle.label | [post] access to local variable s : S [field args, element] : Object | +| structs.cs:32:20:32:20 | [post] access to local variable s : S [field args, element] : Object | semmle.label | [post] access to local variable s : S [field args, element] : Object | +| structs.cs:33:14:33:14 | access to local variable s : S [field args, element] : Object | semmle.label | access to local variable s : S [field args, element] : Object | +| structs.cs:33:14:33:14 | access to local variable s : S [field args, element] : Object | semmle.label | access to local variable s : S [field args, element] : Object | +| structs.cs:33:14:33:19 | access to field args : Object[] [element] : Object | semmle.label | access to field args : Object[] [element] : Object | +| structs.cs:33:14:33:19 | access to field args : Object[] [element] : Object | semmle.label | access to field args : Object[] [element] : Object | +| structs.cs:33:14:33:22 | access to array element | semmle.label | access to array element | +| structs.cs:33:14:33:22 | access to array element | semmle.label | access to array element | subpaths | structs.cs:25:23:25:25 | [...] : Object[] [element] : Object | structs.cs:10:27:10:30 | args : Object[] [element] : Object | structs.cs:10:16:10:16 | this [Return] : S [field args, element] : Object | structs.cs:25:17:25:26 | object creation of type S : S [field args, element] : Object | | structs.cs:25:23:25:25 | [...] : Object[] [element] : Object | structs.cs:10:27:10:30 | args : Object[] [element] : Object | structs.cs:10:16:10:16 | this [Return] : S [field args, element] : Object | structs.cs:25:17:25:26 | object creation of type S : S [field args, element] : Object | testFailures -| structs.cs:33:26:33:44 | // ... | Missing result: hasValueFlow=2 | #select | structs.cs:26:14:26:22 | access to array element | structs.cs:24:17:24:33 | call to method Source : Object | structs.cs:26:14:26:22 | access to array element | $@ | structs.cs:24:17:24:33 | call to method Source : Object | call to method Source : Object | | structs.cs:26:14:26:22 | access to array element | structs.cs:24:17:24:33 | call to method Source : Object | structs.cs:26:14:26:22 | access to array element | $@ | structs.cs:24:17:24:33 | call to method Source : Object | call to method Source : Object | +| structs.cs:33:14:33:22 | access to array element | structs.cs:18:21:18:37 | call to method Source : Object | structs.cs:33:14:33:22 | access to array element | $@ | structs.cs:18:21:18:37 | call to method Source : Object | call to method Source : Object | +| structs.cs:33:14:33:22 | access to array element | structs.cs:18:21:18:37 | call to method Source : Object | structs.cs:33:14:33:22 | access to array element | $@ | structs.cs:18:21:18:37 | call to method Source : Object | call to method Source : Object | From 8380474acdea48fb5a8909115ffaa238097b2d36 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Fri, 27 Feb 2026 13:46:46 +0100 Subject: [PATCH 5/6] C#: Update other test expected output. --- csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected | 1 + 1 file changed, 1 insertion(+) diff --git a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected index ebe04faf7258..b2094817cfb6 100644 --- a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected +++ b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected @@ -321,6 +321,7 @@ | CSharp7.cs:283:20:283:62 | call to method Select,(Int32,String)> | CSharp7.cs:283:13:283:16 | access to local variable list | | CSharp7.cs:283:32:283:35 | SSA param(item) | CSharp7.cs:283:41:283:44 | access to parameter item | | CSharp7.cs:283:32:283:35 | item | CSharp7.cs:283:32:283:35 | SSA param(item) | +| CSharp7.cs:283:41:283:44 | [post] access to parameter item | CSharp7.cs:283:51:283:54 | access to parameter item | | CSharp7.cs:283:41:283:44 | access to parameter item | CSharp7.cs:283:41:283:48 | access to property Key | | CSharp7.cs:283:41:283:44 | access to parameter item | CSharp7.cs:283:51:283:54 | access to parameter item | | CSharp7.cs:283:51:283:54 | access to parameter item | CSharp7.cs:283:51:283:60 | access to property Value | From 319e3d1ba4e277308ceb88b92cd76ffa33c7adea Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 2 Mar 2026 09:06:06 +0100 Subject: [PATCH 6/6] C#: Add change-note. --- csharp/ql/lib/change-notes/2026-03-02-post-update-nodes.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 csharp/ql/lib/change-notes/2026-03-02-post-update-nodes.md diff --git a/csharp/ql/lib/change-notes/2026-03-02-post-update-nodes.md b/csharp/ql/lib/change-notes/2026-03-02-post-update-nodes.md new file mode 100644 index 000000000000..d021cabf1a08 --- /dev/null +++ b/csharp/ql/lib/change-notes/2026-03-02-post-update-nodes.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added post-update nodes for struct-type arguments, allowing data flow out of method calls via those arguments.