Merge pull request #21383 from michaelnebel/csharp/postupdatenoderestriction

C#: Add post-update nodes for `struct` type argument nodes.
This commit is contained in:
Michael Nebel
2026-03-03 12:34:06 +01:00
committed by GitHub
9 changed files with 166 additions and 8 deletions

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added post-update nodes for struct-type arguments, allowing data flow out of method calls via those arguments.

View File

@@ -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

View File

@@ -321,6 +321,7 @@
| CSharp7.cs:283:20:283:62 | call to method Select<KeyValuePair<Int32,String>,(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 |

View File

@@ -21,6 +21,9 @@ namespace My.Qltest
x = TaggedSrcPropertyGetter;
x = this[0];
S s;
StructSrc(s);
}
[SourceAttribute]
@@ -65,7 +68,10 @@ namespace My.Qltest
[SourceAttribute]
object this[int i] => null;
void StructSrc(S s) { }
}
struct S { }
class SourceAttribute : System.Attribute { }
}

View File

@@ -11,9 +11,10 @@ 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: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 |
| Sources.cs:46:45:46:45 | p | local |
| Sources.cs:53:50:53:50 | p | local |
| Sources.cs:59:16:59:30 | this | local |

View File

@@ -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"]

View File

@@ -0,0 +1,92 @@
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: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> : 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> : 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> : 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> : 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 | |
| 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 |
| 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: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> : Object | semmle.label | call to method Source<Object> : Object |
| structs.cs:18:21:18:37 | call to method Source<Object> : Object | semmle.label | call to method Source<Object> : 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> : Object | semmle.label | call to method Source<Object> : Object |
| structs.cs:24:17:24:33 | call to method Source<Object> : Object | semmle.label | call to method Source<Object> : 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 |
| 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
#select
| structs.cs:26:14:26:22 | access to array element | structs.cs:24:17:24:33 | call to method Source<Object> : Object | structs.cs:26:14:26:22 | access to array element | $@ | structs.cs:24:17:24:33 | call to method Source<Object> : Object | call to method Source<Object> : Object |
| structs.cs:26:14:26:22 | access to array element | structs.cs:24:17:24:33 | call to method Source<Object> : Object | structs.cs:26:14:26:22 | access to array element | $@ | structs.cs:24:17:24:33 | call to method Source<Object> : Object | call to method Source<Object> : Object |
| structs.cs:33:14:33:22 | access to array element | structs.cs:18:21:18:37 | call to method Source<Object> : Object | structs.cs:33:14:33:22 | access to array element | $@ | structs.cs:18:21:18:37 | call to method Source<Object> : Object | call to method Source<Object> : Object |
| structs.cs:33:14:33:22 | access to array element | structs.cs:18:21:18:37 | call to method Source<Object> : Object | structs.cs:33:14:33:22 | access to array element | $@ | structs.cs:18:21:18:37 | call to method Source<Object> : Object | call to method Source<Object> : Object |

View File

@@ -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()

View File

@@ -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<object>(2);
s.field = Source<int>(3);
}
public void M1()
{
var o = Source<object>(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<T>(object source) => throw null;
}