From 34d90b426c22141a96b154b4bb0902137b237ca0 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 11 May 2026 15:10:16 +0200 Subject: [PATCH 1/5] C#: Update the mutation definition assignable definition logic to account for implicit assignment of built and user-definied static operator calls. --- .../ql/lib/semmle/code/csharp/Assignable.qll | 84 +++++++++++++++++-- 1 file changed, 76 insertions(+), 8 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/Assignable.qll b/csharp/ql/lib/semmle/code/csharp/Assignable.qll index 7bd432d48ce4..38bcedeeadb7 100644 --- a/csharp/ql/lib/semmle/code/csharp/Assignable.qll +++ b/csharp/ql/lib/semmle/code/csharp/Assignable.qll @@ -117,6 +117,62 @@ class AssignableRead extends AssignableAccess { AssignableRead getANextRead() { result.getControlFlowNode() = this.getAnAdjacentReadSameVar() } } +private newtype TMutationOperationAssignment = + TBuiltInMutationOperation(MutatorOperation mo) or + TUserMutatorOperatorCall(MutatorOperatorCall moc) { + not moc instanceof InstanceMutatorOperatorCall + } + +/** + * A mutation operation that implicitly assigns the result to its operand. For example, `a++` in + * line 7 in + * + * ```csharp + * class A { + * public static A operator ++(A a) { + * return a; + * } + * + * public static void Increment(A a) { + * a++; + * } + * } + * ``` + */ +private class MutationOperationAssignment extends TMutationOperationAssignment { + string toString() { none() } + + Expr getOperand() { none() } + + Expr getMutationOperation() { none() } +} + +private class BuiltInMutationOperation extends MutationOperationAssignment, + TBuiltInMutationOperation +{ + private MutatorOperation mo; + + BuiltInMutationOperation() { this = TBuiltInMutationOperation(mo) } + + override string toString() { result = mo.toString() } + + override Expr getOperand() { result = mo.getOperand() } + + override Expr getMutationOperation() { result = mo } +} + +private class UserMutatorOperatorCall extends MutationOperationAssignment, TUserMutatorOperatorCall { + private MutatorOperatorCall moc; + + UserMutatorOperatorCall() { this = TUserMutatorOperatorCall(moc) } + + override string toString() { result = moc.toString() } + + override Expr getOperand() { result = moc.getArgument(0) } + + override Expr getMutationOperation() { result = moc } +} + /** * An access to an assignable that updates the underlying value. Either a * variable write (`VariableWrite`), a property write (`PropertyWrite`), @@ -262,7 +318,8 @@ module AssignableInternal { or def = TOutRefDefinition(any(AssignableAccess aa | result = aa.getParent())) or - def = TMutationDefinition(result) + def = + TMutationDefinition(any(MutationOperationAssignment moa | result = moa.getMutationOperation())) or def = TLocalVariableDefinition(result) or @@ -299,7 +356,7 @@ module AssignableInternal { or aa.(RefArg).isPotentialAssignment() } or - TMutationDefinition(MutatorOperation mo) or + TMutationDefinition(MutationOperationAssignment mo) or TLocalVariableDefinition(LocalVariableDeclExpr lvde) { not lvde.hasInitializer() and not exists(getTupleSource(TTupleAssignmentDefinition(_, lvde))) and @@ -372,7 +429,7 @@ module AssignableInternal { or def = TOutRefDefinition(result) or - def = TMutationDefinition(any(MutatorOperation mo | mo.getOperand() = result)) + def = TMutationDefinition(any(MutationOperationAssignment mo | mo.getOperand() = result)) or def = TAddressOfDefinition(any(AddressOfExpr aoe | aoe.getOperand() = result)) or @@ -645,14 +702,25 @@ module AssignableDefinitions { * A definition by mutation, for example `x++`. */ class MutationDefinition extends AssignableDefinition, TMutationDefinition { - MutatorOperation mo; + MutationOperationAssignment moa; + + MutationDefinition() { this = TMutationDefinition(moa) } + + /** + * DEPRECATED: Use `getMutationOperation()` instead. + * + * Gets the underlying mutator operation. + */ + deprecated MutatorOperation getMutatorOperation() { moa = TBuiltInMutationOperation(result) } - MutationDefinition() { this = TMutationDefinition(mo) } + /** + * Gets the underlying mutation operation. + */ + Expr getMutationOperation() { result = moa.getMutationOperation() } - /** Gets the underlying mutator operation. */ - MutatorOperation getMutatorOperation() { result = mo } + override Expr getSource() { result = this.getMutationOperation() } - override string toString() { result = mo.toString() } + override string toString() { result = moa.toString() } } /** From a986a22919e64a8b5e8ac64bbde7500416de7da8 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 12 May 2026 15:10:04 +0200 Subject: [PATCH 2/5] C#: Do not use the SSA definition expression for sign of increment and decrement (only use the specialized code, which is already present). --- .../dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll index 48ed00858a0d..be2a1294ccfd 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll @@ -125,7 +125,9 @@ private module Impl { SsaExplicitWrite getExplicitSsaAssignment(SsaExplicitWrite v) { result = v } /** Returns the assignment of the variable update `def`. */ - ExprNode getExprFromSsaAssignment(SsaExplicitWrite def) { result.getExpr() = def.getValue() } + ExprNode getExprFromSsaAssignment(SsaExplicitWrite def) { + result.getExpr() = def.getValue() and not def.getDefiningExpr() instanceof MutatorOperation + } /** Holds if `def` can have any sign. */ predicate explicitSsaDefWithAnySign(SsaExplicitWrite def) { From da4097bf0af6d310263f04704a9b182e8fda1010 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 11 May 2026 15:12:34 +0200 Subject: [PATCH 3/5] C#: Add data flow testcases for mutation operators. --- .../dataflow/operators/Operator.cs | 42 ++++++++++ .../dataflow/operators/operatorFlow.expected | 82 +++++++++++++++++++ 2 files changed, 124 insertions(+) diff --git a/csharp/ql/test/library-tests/dataflow/operators/Operator.cs b/csharp/ql/test/library-tests/dataflow/operators/Operator.cs index 5db1a82b9a4b..c279ff8a33e4 100644 --- a/csharp/ql/test/library-tests/dataflow/operators/Operator.cs +++ b/csharp/ql/test/library-tests/dataflow/operators/Operator.cs @@ -120,3 +120,45 @@ public void M1() Sink(x.Field); // $ hasValueFlow=1 } } + +public class MutatorOperators +{ + static void Sink(object o) { } + static T Source(object source) => throw null; + + public class C1 + { + public object Field { get; private set; } + + public C1() + { + Field = new object(); + } + + public C1(object o) + { + Field = o; + } + + public static C1 operator --(C1 x) + { + var f = Source(2); + return new C1(f); + } + + public void M2() + { + var x = new C1(); + x--; + Sink(x.Field); // $ hasValueFlow=2 + } + + public void M3() + { + var x = new C1(); + var y = x--; + Sink(x.Field); // $ hasValueFlow=2 + Sink(y.Field); // $ hasValueFlow=2 + } + } +} diff --git a/csharp/ql/test/library-tests/dataflow/operators/operatorFlow.expected b/csharp/ql/test/library-tests/dataflow/operators/operatorFlow.expected index 8fd12f1c2a8f..ca0bad4e0a55 100644 --- a/csharp/ql/test/library-tests/dataflow/operators/operatorFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/operators/operatorFlow.expected @@ -130,6 +130,42 @@ edges | Operator.cs:119:14:119:14 | access to local variable y : C [property Field] : Object | Operator.cs:119:9:119:9 | [post] access to local variable x : C [property Field] : Object | provenance | | | Operator.cs:120:14:120:14 | access to local variable x : C [property Field] : Object | Operator.cs:120:14:120:20 | access to property Field | provenance | | | Operator.cs:120:14:120:14 | access to local variable x : C [property Field] : Object | Operator.cs:120:14:120:20 | access to property Field | provenance | | +| Operator.cs:138:26:138:26 | o : Object | Operator.cs:140:21:140:21 | access to parameter o : Object | provenance | | +| Operator.cs:138:26:138:26 | o : Object | Operator.cs:140:21:140:21 | access to parameter o : Object | provenance | | +| Operator.cs:140:13:140:17 | [post] this access : C1 [property Field] : Object | Operator.cs:138:16:138:17 | this [Return] : C1 [property Field] : Object | provenance | | +| Operator.cs:140:13:140:17 | [post] this access : C1 [property Field] : Object | Operator.cs:138:16:138:17 | this [Return] : C1 [property Field] : Object | provenance | | +| Operator.cs:140:21:140:21 | access to parameter o : Object | Operator.cs:140:13:140:17 | [post] this access : C1 [property Field] : Object | provenance | | +| Operator.cs:140:21:140:21 | access to parameter o : Object | Operator.cs:140:13:140:17 | [post] this access : C1 [property Field] : Object | provenance | | +| Operator.cs:145:17:145:17 | access to local variable f : Object | Operator.cs:146:27:146:27 | access to local variable f : Object | provenance | | +| Operator.cs:145:17:145:17 | access to local variable f : Object | Operator.cs:146:27:146:27 | access to local variable f : Object | provenance | | +| Operator.cs:145:21:145:37 | call to method Source : Object | Operator.cs:145:17:145:17 | access to local variable f : Object | provenance | | +| Operator.cs:145:21:145:37 | call to method Source : Object | Operator.cs:145:17:145:17 | access to local variable f : Object | provenance | | +| Operator.cs:146:20:146:28 | object creation of type C1 : C1 [property Field] : Object | Operator.cs:152:13:152:15 | call to operator -- : C1 [property Field] : Object | provenance | | +| Operator.cs:146:20:146:28 | object creation of type C1 : C1 [property Field] : Object | Operator.cs:152:13:152:15 | call to operator -- : C1 [property Field] : Object | provenance | | +| Operator.cs:146:20:146:28 | object creation of type C1 : C1 [property Field] : Object | Operator.cs:159:21:159:23 | call to operator -- : C1 [property Field] : Object | provenance | | +| Operator.cs:146:20:146:28 | object creation of type C1 : C1 [property Field] : Object | Operator.cs:159:21:159:23 | call to operator -- : C1 [property Field] : Object | provenance | | +| Operator.cs:146:27:146:27 | access to local variable f : Object | Operator.cs:138:26:138:26 | o : Object | provenance | | +| Operator.cs:146:27:146:27 | access to local variable f : Object | Operator.cs:138:26:138:26 | o : Object | provenance | | +| Operator.cs:146:27:146:27 | access to local variable f : Object | Operator.cs:146:20:146:28 | object creation of type C1 : C1 [property Field] : Object | provenance | | +| Operator.cs:146:27:146:27 | access to local variable f : Object | Operator.cs:146:20:146:28 | object creation of type C1 : C1 [property Field] : Object | provenance | | +| Operator.cs:152:13:152:13 | access to local variable x : C1 [property Field] : Object | Operator.cs:153:18:153:18 | access to local variable x : C1 [property Field] : Object | provenance | | +| Operator.cs:152:13:152:13 | access to local variable x : C1 [property Field] : Object | Operator.cs:153:18:153:18 | access to local variable x : C1 [property Field] : Object | provenance | | +| Operator.cs:152:13:152:15 | call to operator -- : C1 [property Field] : Object | Operator.cs:152:13:152:13 | access to local variable x : C1 [property Field] : Object | provenance | | +| Operator.cs:152:13:152:15 | call to operator -- : C1 [property Field] : Object | Operator.cs:152:13:152:13 | access to local variable x : C1 [property Field] : Object | provenance | | +| Operator.cs:153:18:153:18 | access to local variable x : C1 [property Field] : Object | Operator.cs:153:18:153:24 | access to property Field | provenance | | +| Operator.cs:153:18:153:18 | access to local variable x : C1 [property Field] : Object | Operator.cs:153:18:153:24 | access to property Field | provenance | | +| Operator.cs:159:17:159:17 | access to local variable y : C1 [property Field] : Object | Operator.cs:161:18:161:18 | access to local variable y : C1 [property Field] : Object | provenance | | +| Operator.cs:159:17:159:17 | access to local variable y : C1 [property Field] : Object | Operator.cs:161:18:161:18 | access to local variable y : C1 [property Field] : Object | provenance | | +| Operator.cs:159:21:159:21 | access to local variable x : C1 [property Field] : Object | Operator.cs:160:18:160:18 | access to local variable x : C1 [property Field] : Object | provenance | | +| Operator.cs:159:21:159:21 | access to local variable x : C1 [property Field] : Object | Operator.cs:160:18:160:18 | access to local variable x : C1 [property Field] : Object | provenance | | +| Operator.cs:159:21:159:23 | call to operator -- : C1 [property Field] : Object | Operator.cs:159:17:159:17 | access to local variable y : C1 [property Field] : Object | provenance | | +| Operator.cs:159:21:159:23 | call to operator -- : C1 [property Field] : Object | Operator.cs:159:17:159:17 | access to local variable y : C1 [property Field] : Object | provenance | | +| Operator.cs:159:21:159:23 | call to operator -- : C1 [property Field] : Object | Operator.cs:159:21:159:21 | access to local variable x : C1 [property Field] : Object | provenance | | +| Operator.cs:159:21:159:23 | call to operator -- : C1 [property Field] : Object | Operator.cs:159:21:159:21 | access to local variable x : C1 [property Field] : Object | provenance | | +| Operator.cs:160:18:160:18 | access to local variable x : C1 [property Field] : Object | Operator.cs:160:18:160:24 | access to property Field | provenance | | +| Operator.cs:160:18:160:18 | access to local variable x : C1 [property Field] : Object | Operator.cs:160:18:160:24 | access to property Field | provenance | | +| Operator.cs:161:18:161:18 | access to local variable y : C1 [property Field] : Object | Operator.cs:161:18:161:24 | access to property Field | provenance | | +| Operator.cs:161:18:161:18 | access to local variable y : C1 [property Field] : Object | Operator.cs:161:18:161:24 | access to property Field | provenance | | nodes | Operator.cs:9:39:9:39 | x : C | semmle.label | x : C | | Operator.cs:9:39:9:39 | x : C | semmle.label | x : C | @@ -275,6 +311,44 @@ nodes | Operator.cs:120:14:120:14 | access to local variable x : C [property Field] : Object | semmle.label | access to local variable x : C [property Field] : Object | | Operator.cs:120:14:120:20 | access to property Field | semmle.label | access to property Field | | Operator.cs:120:14:120:20 | access to property Field | semmle.label | access to property Field | +| Operator.cs:138:16:138:17 | this [Return] : C1 [property Field] : Object | semmle.label | this [Return] : C1 [property Field] : Object | +| Operator.cs:138:16:138:17 | this [Return] : C1 [property Field] : Object | semmle.label | this [Return] : C1 [property Field] : Object | +| Operator.cs:138:26:138:26 | o : Object | semmle.label | o : Object | +| Operator.cs:138:26:138:26 | o : Object | semmle.label | o : Object | +| Operator.cs:140:13:140:17 | [post] this access : C1 [property Field] : Object | semmle.label | [post] this access : C1 [property Field] : Object | +| Operator.cs:140:13:140:17 | [post] this access : C1 [property Field] : Object | semmle.label | [post] this access : C1 [property Field] : Object | +| Operator.cs:140:21:140:21 | access to parameter o : Object | semmle.label | access to parameter o : Object | +| Operator.cs:140:21:140:21 | access to parameter o : Object | semmle.label | access to parameter o : Object | +| Operator.cs:145:17:145:17 | access to local variable f : Object | semmle.label | access to local variable f : Object | +| Operator.cs:145:17:145:17 | access to local variable f : Object | semmle.label | access to local variable f : Object | +| Operator.cs:145:21:145:37 | call to method Source : Object | semmle.label | call to method Source : Object | +| Operator.cs:145:21:145:37 | call to method Source : Object | semmle.label | call to method Source : Object | +| Operator.cs:146:20:146:28 | object creation of type C1 : C1 [property Field] : Object | semmle.label | object creation of type C1 : C1 [property Field] : Object | +| Operator.cs:146:20:146:28 | object creation of type C1 : C1 [property Field] : Object | semmle.label | object creation of type C1 : C1 [property Field] : Object | +| Operator.cs:146:27:146:27 | access to local variable f : Object | semmle.label | access to local variable f : Object | +| Operator.cs:146:27:146:27 | access to local variable f : Object | semmle.label | access to local variable f : Object | +| Operator.cs:152:13:152:13 | access to local variable x : C1 [property Field] : Object | semmle.label | access to local variable x : C1 [property Field] : Object | +| Operator.cs:152:13:152:13 | access to local variable x : C1 [property Field] : Object | semmle.label | access to local variable x : C1 [property Field] : Object | +| Operator.cs:152:13:152:15 | call to operator -- : C1 [property Field] : Object | semmle.label | call to operator -- : C1 [property Field] : Object | +| Operator.cs:152:13:152:15 | call to operator -- : C1 [property Field] : Object | semmle.label | call to operator -- : C1 [property Field] : Object | +| Operator.cs:153:18:153:18 | access to local variable x : C1 [property Field] : Object | semmle.label | access to local variable x : C1 [property Field] : Object | +| Operator.cs:153:18:153:18 | access to local variable x : C1 [property Field] : Object | semmle.label | access to local variable x : C1 [property Field] : Object | +| Operator.cs:153:18:153:24 | access to property Field | semmle.label | access to property Field | +| Operator.cs:153:18:153:24 | access to property Field | semmle.label | access to property Field | +| Operator.cs:159:17:159:17 | access to local variable y : C1 [property Field] : Object | semmle.label | access to local variable y : C1 [property Field] : Object | +| Operator.cs:159:17:159:17 | access to local variable y : C1 [property Field] : Object | semmle.label | access to local variable y : C1 [property Field] : Object | +| Operator.cs:159:21:159:21 | access to local variable x : C1 [property Field] : Object | semmle.label | access to local variable x : C1 [property Field] : Object | +| Operator.cs:159:21:159:21 | access to local variable x : C1 [property Field] : Object | semmle.label | access to local variable x : C1 [property Field] : Object | +| Operator.cs:159:21:159:23 | call to operator -- : C1 [property Field] : Object | semmle.label | call to operator -- : C1 [property Field] : Object | +| Operator.cs:159:21:159:23 | call to operator -- : C1 [property Field] : Object | semmle.label | call to operator -- : C1 [property Field] : Object | +| Operator.cs:160:18:160:18 | access to local variable x : C1 [property Field] : Object | semmle.label | access to local variable x : C1 [property Field] : Object | +| Operator.cs:160:18:160:18 | access to local variable x : C1 [property Field] : Object | semmle.label | access to local variable x : C1 [property Field] : Object | +| Operator.cs:160:18:160:24 | access to property Field | semmle.label | access to property Field | +| Operator.cs:160:18:160:24 | access to property Field | semmle.label | access to property Field | +| Operator.cs:161:18:161:18 | access to local variable y : C1 [property Field] : Object | semmle.label | access to local variable y : C1 [property Field] : Object | +| Operator.cs:161:18:161:18 | access to local variable y : C1 [property Field] : Object | semmle.label | access to local variable y : C1 [property Field] : Object | +| Operator.cs:161:18:161:24 | access to property Field | semmle.label | access to property Field | +| Operator.cs:161:18:161:24 | access to property Field | semmle.label | access to property Field | subpaths | Operator.cs:29:17:29:17 | access to local variable x : C | Operator.cs:16:38:16:38 | x : C | Operator.cs:16:49:16:49 | access to parameter x : C | Operator.cs:29:17:29:21 | call to operator + : C | | Operator.cs:29:17:29:17 | access to local variable x : C | Operator.cs:16:38:16:38 | x : C | Operator.cs:16:49:16:49 | access to parameter x : C | Operator.cs:29:17:29:21 | call to operator + : C | @@ -292,6 +366,8 @@ subpaths | Operator.cs:118:23:118:29 | access to local variable tainted : Object | Operator.cs:103:25:103:25 | o : Object | Operator.cs:103:16:103:16 | this [Return] : C [property Field] : Object | Operator.cs:118:17:118:30 | object creation of type C : C [property Field] : Object | | Operator.cs:119:14:119:14 | access to local variable y : C [property Field] : Object | Operator.cs:108:35:108:35 | x : C [property Field] : Object | Operator.cs:108:30:108:31 | this [Return] : C [property Field] : Object | Operator.cs:119:9:119:9 | [post] access to local variable x : C [property Field] : Object | | Operator.cs:119:14:119:14 | access to local variable y : C [property Field] : Object | Operator.cs:108:35:108:35 | x : C [property Field] : Object | Operator.cs:108:30:108:31 | this [Return] : C [property Field] : Object | Operator.cs:119:9:119:9 | [post] access to local variable x : C [property Field] : Object | +| Operator.cs:146:27:146:27 | access to local variable f : Object | Operator.cs:138:26:138:26 | o : Object | Operator.cs:138:16:138:17 | this [Return] : C1 [property Field] : Object | Operator.cs:146:20:146:28 | object creation of type C1 : C1 [property Field] : Object | +| Operator.cs:146:27:146:27 | access to local variable f : Object | Operator.cs:138:26:138:26 | o : Object | Operator.cs:138:16:138:17 | this [Return] : C1 [property Field] : Object | Operator.cs:146:20:146:28 | object creation of type C1 : C1 [property Field] : Object | testFailures #select | Operator.cs:30:14:30:14 | access to local variable z | Operator.cs:27:17:27:28 | call to method Source : C | Operator.cs:30:14:30:14 | access to local variable z | $@ | Operator.cs:27:17:27:28 | call to method Source : C | call to method Source : C | @@ -308,3 +384,9 @@ testFailures | Operator.cs:78:14:78:14 | (...) ... | Operator.cs:84:17:84:29 | call to method Source : C | Operator.cs:78:14:78:14 | (...) ... | $@ | Operator.cs:84:17:84:29 | call to method Source : C | call to method Source : C | | Operator.cs:120:14:120:20 | access to property Field | Operator.cs:116:23:116:39 | call to method Source : Object | Operator.cs:120:14:120:20 | access to property Field | $@ | Operator.cs:116:23:116:39 | call to method Source : Object | call to method Source : Object | | Operator.cs:120:14:120:20 | access to property Field | Operator.cs:116:23:116:39 | call to method Source : Object | Operator.cs:120:14:120:20 | access to property Field | $@ | Operator.cs:116:23:116:39 | call to method Source : Object | call to method Source : Object | +| Operator.cs:153:18:153:24 | access to property Field | Operator.cs:145:21:145:37 | call to method Source : Object | Operator.cs:153:18:153:24 | access to property Field | $@ | Operator.cs:145:21:145:37 | call to method Source : Object | call to method Source : Object | +| Operator.cs:153:18:153:24 | access to property Field | Operator.cs:145:21:145:37 | call to method Source : Object | Operator.cs:153:18:153:24 | access to property Field | $@ | Operator.cs:145:21:145:37 | call to method Source : Object | call to method Source : Object | +| Operator.cs:160:18:160:24 | access to property Field | Operator.cs:145:21:145:37 | call to method Source : Object | Operator.cs:160:18:160:24 | access to property Field | $@ | Operator.cs:145:21:145:37 | call to method Source : Object | call to method Source : Object | +| Operator.cs:160:18:160:24 | access to property Field | Operator.cs:145:21:145:37 | call to method Source : Object | Operator.cs:160:18:160:24 | access to property Field | $@ | Operator.cs:145:21:145:37 | call to method Source : Object | call to method Source : Object | +| Operator.cs:161:18:161:24 | access to property Field | Operator.cs:145:21:145:37 | call to method Source : Object | Operator.cs:161:18:161:24 | access to property Field | $@ | Operator.cs:145:21:145:37 | call to method Source : Object | call to method Source : Object | +| Operator.cs:161:18:161:24 | access to property Field | Operator.cs:145:21:145:37 | call to method Source : Object | Operator.cs:161:18:161:24 | access to property Field | $@ | Operator.cs:145:21:145:37 | call to method Source : Object | call to method Source : Object | From 1c018c787989c11af90ad4ba9c6aa3c594b87159 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 13 May 2026 14:08:26 +0200 Subject: [PATCH 4/5] C#: Update expected test output for other tests. --- .../assignables/AssignableDefinition.expected | 10 +++++----- .../assignables/GetAnAssignedValue.expected | 5 +++++ .../test/library-tests/csharp7/LocalTaintFlow.expected | 1 + .../library-tests/dataflow/local/DataFlowStep.expected | 2 ++ .../dataflow/local/TaintTrackingStep.expected | 2 ++ csharp/ql/test/library-tests/fields/Fields11.expected | 1 + 6 files changed, 16 insertions(+), 5 deletions(-) diff --git a/csharp/ql/test/library-tests/assignables/AssignableDefinition.expected b/csharp/ql/test/library-tests/assignables/AssignableDefinition.expected index a2f6e34e4ea1..23823a8f277e 100644 --- a/csharp/ql/test/library-tests/assignables/AssignableDefinition.expected +++ b/csharp/ql/test/library-tests/assignables/AssignableDefinition.expected @@ -1,6 +1,6 @@ | Assignables.cs:5:9:5:13 | Field | Assignables.cs:5:9:5:17 | ... = ... | Assignables.cs:5:9:5:13 | access to field Field | Assignables.cs:5:17:5:17 | 0 | certain | | Assignables.cs:5:9:5:13 | Field | Assignables.cs:18:9:18:24 | ... = ... | Assignables.cs:18:9:18:13 | access to field Field | Assignables.cs:18:17:18:24 | access to property Property | certain | -| Assignables.cs:5:9:5:13 | Field | Assignables.cs:19:9:19:15 | ...-- | Assignables.cs:19:9:19:13 | access to field Field | Assignables.cs:19:9:19:15 | | certain | +| Assignables.cs:5:9:5:13 | Field | Assignables.cs:19:9:19:15 | ...-- | Assignables.cs:19:9:19:13 | access to field Field | Assignables.cs:19:9:19:15 | ...-- | certain | | Assignables.cs:5:9:5:13 | Field | Assignables.cs:29:17:29:21 | access to field Field | Assignables.cs:29:17:29:21 | access to field Field | Assignables.cs:29:17:29:21 | | certain | | Assignables.cs:5:9:5:13 | Field | Assignables.cs:30:34:30:38 | access to field Field | Assignables.cs:30:34:30:38 | access to field Field | Assignables.cs:30:34:30:38 | | certain | | Assignables.cs:5:9:5:13 | Field | Assignables.cs:31:36:31:40 | access to field Field | Assignables.cs:31:36:31:40 | access to field Field | Assignables.cs:31:36:31:40 | | uncertain | @@ -9,22 +9,22 @@ | Assignables.cs:5:9:5:13 | Field | Assignables.cs:34:40:34:44 | access to field Field | Assignables.cs:34:40:34:44 | access to field Field | Assignables.cs:34:40:34:44 | | uncertain | | Assignables.cs:6:9:6:16 | Property | Assignables.cs:6:32:6:34 | ... = ... | Assignables.cs:6:9:6:16 | access to property Property | Assignables.cs:6:34:6:34 | 1 | certain | | Assignables.cs:6:9:6:16 | Property | Assignables.cs:20:9:20:33 | ... = ... | Assignables.cs:20:9:20:16 | access to property Property | Assignables.cs:20:20:20:33 | access to indexer | certain | -| Assignables.cs:6:9:6:16 | Property | Assignables.cs:21:9:21:18 | ...++ | Assignables.cs:21:9:21:16 | access to property Property | Assignables.cs:21:9:21:18 | | certain | +| Assignables.cs:6:9:6:16 | Property | Assignables.cs:21:9:21:18 | ...++ | Assignables.cs:21:9:21:16 | access to property Property | Assignables.cs:21:9:21:18 | ...++ | certain | | Assignables.cs:6:9:6:16 | Property | Assignables.cs:96:9:96:36 | ... = ... | Assignables.cs:96:10:96:17 | access to property Property | Assignables.cs:96:32:96:32 | 2 | certain | | Assignables.cs:8:24:8:28 | Event | Assignables.cs:23:9:23:25 | ... += ... | Assignables.cs:23:9:23:13 | access to event Event | Assignables.cs:23:9:23:25 | | certain | | Assignables.cs:8:24:8:28 | Event | Assignables.cs:25:9:25:25 | ... -= ... | Assignables.cs:25:9:25:13 | access to event Event | Assignables.cs:25:9:25:25 | | certain | | Assignables.cs:9:9:9:12 | Item | Assignables.cs:26:9:26:33 | ... = ... | Assignables.cs:26:9:26:22 | access to indexer | Assignables.cs:26:26:26:33 | access to local variable variable | certain | -| Assignables.cs:9:9:9:12 | Item | Assignables.cs:27:9:27:21 | ...++ | Assignables.cs:27:9:27:19 | access to indexer | Assignables.cs:27:9:27:21 | | certain | +| Assignables.cs:9:9:9:12 | Item | Assignables.cs:27:9:27:21 | ...++ | Assignables.cs:27:9:27:19 | access to indexer | Assignables.cs:27:9:27:21 | ...++ | certain | | Assignables.cs:9:9:9:12 | Item | Assignables.cs:96:9:96:36 | ... = ... | Assignables.cs:96:20:96:26 | access to indexer | Assignables.cs:96:35:96:35 | 3 | certain | | Assignables.cs:9:18:9:18 | i | Assignables.cs:9:18:9:18 | i | Assignables.cs:9:18:9:18 | | Assignables.cs:9:18:9:18 | | certain | | Assignables.cs:9:18:9:18 | i | Assignables.cs:9:18:9:18 | i | Assignables.cs:9:18:9:18 | | Assignables.cs:9:18:9:18 | | certain | | Assignables.cs:9:41:9:43 | value | Assignables.cs:9:41:9:43 | value | Assignables.cs:9:41:9:43 | | Assignables.cs:9:41:9:43 | | certain | | Assignables.cs:11:16:11:24 | parameter | Assignables.cs:11:16:11:24 | parameter | Assignables.cs:11:16:11:24 | | Assignables.cs:11:16:11:24 | | certain | | Assignables.cs:11:16:11:24 | parameter | Assignables.cs:16:9:16:25 | ... = ... | Assignables.cs:16:9:16:17 | access to parameter parameter | Assignables.cs:16:21:16:25 | access to field Field | certain | -| Assignables.cs:11:16:11:24 | parameter | Assignables.cs:17:9:17:19 | ...++ | Assignables.cs:17:9:17:17 | access to parameter parameter | Assignables.cs:17:9:17:19 | | certain | +| Assignables.cs:11:16:11:24 | parameter | Assignables.cs:17:9:17:19 | ...++ | Assignables.cs:17:9:17:17 | access to parameter parameter | Assignables.cs:17:9:17:19 | ...++ | certain | | Assignables.cs:13:13:13:20 | variable | Assignables.cs:13:13:13:24 | Int32 variable = ... | Assignables.cs:13:13:13:20 | access to local variable variable | Assignables.cs:13:24:13:24 | 0 | certain | | Assignables.cs:13:13:13:20 | variable | Assignables.cs:14:9:14:28 | ... = ... | Assignables.cs:14:9:14:16 | access to local variable variable | Assignables.cs:14:20:14:28 | access to parameter parameter | certain | -| Assignables.cs:13:13:13:20 | variable | Assignables.cs:15:9:15:18 | ...-- | Assignables.cs:15:9:15:16 | access to local variable variable | Assignables.cs:15:9:15:18 | | certain | +| Assignables.cs:13:13:13:20 | variable | Assignables.cs:15:9:15:18 | ...-- | Assignables.cs:15:9:15:16 | access to local variable variable | Assignables.cs:15:9:15:18 | ...-- | certain | | Assignables.cs:13:13:13:20 | variable | Assignables.cs:28:17:28:24 | access to local variable variable | Assignables.cs:28:17:28:24 | access to local variable variable | Assignables.cs:28:17:28:24 | | certain | | Assignables.cs:22:22:22:29 | callback | Assignables.cs:22:22:22:50 | EventHandler callback = ... | Assignables.cs:22:22:22:29 | access to local variable callback | Assignables.cs:22:33:22:50 | (...) => ... | certain | | Assignables.cs:22:34:22:39 | sender | Assignables.cs:22:34:22:39 | sender | Assignables.cs:22:34:22:39 | | Assignables.cs:22:34:22:39 | | certain | diff --git a/csharp/ql/test/library-tests/assignables/GetAnAssignedValue.expected b/csharp/ql/test/library-tests/assignables/GetAnAssignedValue.expected index af8396de8f54..5d0db173b4d0 100644 --- a/csharp/ql/test/library-tests/assignables/GetAnAssignedValue.expected +++ b/csharp/ql/test/library-tests/assignables/GetAnAssignedValue.expected @@ -1,13 +1,18 @@ | Assignables.cs:5:9:5:13 | Field | Assignables.cs:5:17:5:17 | 0 | | Assignables.cs:5:9:5:13 | Field | Assignables.cs:18:17:18:24 | access to property Property | +| Assignables.cs:5:9:5:13 | Field | Assignables.cs:19:9:19:15 | ...-- | | Assignables.cs:6:9:6:16 | Property | Assignables.cs:6:34:6:34 | 1 | | Assignables.cs:6:9:6:16 | Property | Assignables.cs:20:20:20:33 | access to indexer | +| Assignables.cs:6:9:6:16 | Property | Assignables.cs:21:9:21:18 | ...++ | | Assignables.cs:6:9:6:16 | Property | Assignables.cs:96:32:96:32 | 2 | | Assignables.cs:9:9:9:12 | Item | Assignables.cs:26:26:26:33 | access to local variable variable | +| Assignables.cs:9:9:9:12 | Item | Assignables.cs:27:9:27:21 | ...++ | | Assignables.cs:9:9:9:12 | Item | Assignables.cs:96:35:96:35 | 3 | | Assignables.cs:11:16:11:24 | parameter | Assignables.cs:16:21:16:25 | access to field Field | +| Assignables.cs:11:16:11:24 | parameter | Assignables.cs:17:9:17:19 | ...++ | | Assignables.cs:13:13:13:20 | variable | Assignables.cs:13:24:13:24 | 0 | | Assignables.cs:13:13:13:20 | variable | Assignables.cs:14:20:14:28 | access to parameter parameter | +| Assignables.cs:13:13:13:20 | variable | Assignables.cs:15:9:15:18 | ...-- | | Assignables.cs:22:22:22:29 | callback | Assignables.cs:22:33:22:50 | (...) => ... | | Assignables.cs:37:22:37:22 | o | Assignables.cs:39:13:39:13 | 0 | | Assignables.cs:42:35:42:35 | y | Assignables.cs:45:17:45:17 | access to parameter x | diff --git a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected index e2d3b18e0366..65e3c32e52a0 100644 --- a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected +++ b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected @@ -334,5 +334,6 @@ | CSharp7.cs:297:35:297:44 | ... is ... | CSharp7.cs:297:25:297:44 | ... && ... | | CSharp7.cs:297:40:297:44 | Int32 y | CSharp7.cs:297:40:297:44 | SSA def(y) | | CSharp7.cs:297:40:297:44 | SSA def(y) | CSharp7.cs:299:31:299:31 | access to local variable y | +| CSharp7.cs:297:47:297:49 | ++... | CSharp7.cs:297:49:297:49 | access to local variable x | | CSharp7.cs:297:47:297:49 | SSA def(x) | CSharp7.cs:297:25:297:25 | access to local variable x | | CSharp7.cs:297:49:297:49 | access to local variable x | CSharp7.cs:297:47:297:49 | SSA def(x) | diff --git a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected index 2a88f163a3aa..3e889672c1aa 100644 --- a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected @@ -886,6 +886,7 @@ | SSA.cs:170:16:170:28 | SSA def(ssaSink5) | SSA.cs:180:15:180:22 | access to local variable ssaSink5 | | SSA.cs:170:27:170:28 | "" | SSA.cs:170:16:170:23 | access to local variable ssaSink5 | | SSA.cs:171:13:171:13 | access to parameter i | SSA.cs:171:13:171:15 | SSA def(i) | +| SSA.cs:171:13:171:15 | ...-- | SSA.cs:171:13:171:13 | access to parameter i | | SSA.cs:171:13:171:15 | SSA def(i) | SSA.cs:174:20:174:20 | access to parameter i | | SSA.cs:172:9:179:9 | [input] SSA phi(ssaSink5) | SSA.cs:180:15:180:22 | access to local variable ssaSink5 | | SSA.cs:173:13:173:20 | access to local variable ssaSink5 | SSA.cs:173:13:173:30 | SSA def(ssaSink5) | @@ -894,6 +895,7 @@ | SSA.cs:174:13:178:13 | SSA phi read(ssaSink5) | SSA.cs:172:9:179:9 | [input] SSA phi(ssaSink5) | | SSA.cs:174:13:178:13 | SSA phi read(ssaSink5) | SSA.cs:176:21:176:28 | access to local variable ssaSink5 | | SSA.cs:174:20:174:20 | access to parameter i | SSA.cs:174:20:174:22 | SSA def(i) | +| SSA.cs:174:20:174:22 | ...-- | SSA.cs:174:20:174:20 | access to parameter i | | SSA.cs:174:20:174:22 | SSA def(i) | SSA.cs:174:20:174:20 | access to parameter i | | SSA.cs:176:21:176:28 | [post] access to local variable ssaSink5 | SSA.cs:177:21:177:28 | access to local variable ssaSink5 | | SSA.cs:176:21:176:28 | access to local variable ssaSink5 | SSA.cs:177:21:177:28 | access to local variable ssaSink5 | diff --git a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected index 8f059acc6caa..218c36bb2f40 100644 --- a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected @@ -1014,6 +1014,7 @@ | SSA.cs:170:16:170:28 | SSA def(ssaSink5) | SSA.cs:180:15:180:22 | access to local variable ssaSink5 | | SSA.cs:170:27:170:28 | "" | SSA.cs:170:16:170:23 | access to local variable ssaSink5 | | SSA.cs:171:13:171:13 | access to parameter i | SSA.cs:171:13:171:15 | SSA def(i) | +| SSA.cs:171:13:171:15 | ...-- | SSA.cs:171:13:171:13 | access to parameter i | | SSA.cs:171:13:171:15 | ...-- | SSA.cs:171:13:171:19 | ... > ... | | SSA.cs:171:13:171:15 | SSA def(i) | SSA.cs:174:20:174:20 | access to parameter i | | SSA.cs:172:9:179:9 | [input] SSA phi(ssaSink5) | SSA.cs:180:15:180:22 | access to local variable ssaSink5 | @@ -1023,6 +1024,7 @@ | SSA.cs:174:13:178:13 | SSA phi read(ssaSink5) | SSA.cs:172:9:179:9 | [input] SSA phi(ssaSink5) | | SSA.cs:174:13:178:13 | SSA phi read(ssaSink5) | SSA.cs:176:21:176:28 | access to local variable ssaSink5 | | SSA.cs:174:20:174:20 | access to parameter i | SSA.cs:174:20:174:22 | SSA def(i) | +| SSA.cs:174:20:174:22 | ...-- | SSA.cs:174:20:174:20 | access to parameter i | | SSA.cs:174:20:174:22 | ...-- | SSA.cs:174:20:174:26 | ... > ... | | SSA.cs:174:20:174:22 | SSA def(i) | SSA.cs:174:20:174:20 | access to parameter i | | SSA.cs:176:21:176:28 | [post] access to local variable ssaSink5 | SSA.cs:177:21:177:28 | access to local variable ssaSink5 | diff --git a/csharp/ql/test/library-tests/fields/Fields11.expected b/csharp/ql/test/library-tests/fields/Fields11.expected index 62898bc07a7e..a1f5afb67082 100644 --- a/csharp/ql/test/library-tests/fields/Fields11.expected +++ b/csharp/ql/test/library-tests/fields/Fields11.expected @@ -3,6 +3,7 @@ | fields.cs:15:27:15:27 | X | fields.cs:15:31:15:31 | 1 | | fields.cs:17:27:17:27 | Z | fields.cs:17:31:17:33 | 100 | | fields.cs:23:20:23:24 | count | fields.cs:23:28:23:28 | 0 | +| fields.cs:23:20:23:24 | count | fields.cs:25:22:25:28 | ...++ | | fields.cs:35:23:35:23 | x | fields.cs:35:27:35:40 | call to method Sqrt | | fields.cs:36:13:36:13 | i | fields.cs:36:17:36:19 | 100 | | fields.cs:37:16:37:16 | s | fields.cs:37:20:37:26 | "Hello" | From 78ff6ae3e46f5980956c3da4f298069bce3d660c Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 12 May 2026 15:08:46 +0200 Subject: [PATCH 5/5] REMOVE AGAIN WHEN OTHER PR IS MERGED. --- csharp/ql/lib/semmle/code/csharp/Assignable.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/csharp/ql/lib/semmle/code/csharp/Assignable.qll b/csharp/ql/lib/semmle/code/csharp/Assignable.qll index 38bcedeeadb7..862b0a44162f 100644 --- a/csharp/ql/lib/semmle/code/csharp/Assignable.qll +++ b/csharp/ql/lib/semmle/code/csharp/Assignable.qll @@ -120,7 +120,8 @@ class AssignableRead extends AssignableAccess { private newtype TMutationOperationAssignment = TBuiltInMutationOperation(MutatorOperation mo) or TUserMutatorOperatorCall(MutatorOperatorCall moc) { - not moc instanceof InstanceMutatorOperatorCall + any() + // not moc instanceof InstanceMutatorOperatorCall } /**