From 5591e48c49a06f94b8b20d41908b907139a26db5 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Fri, 14 Feb 2025 10:28:47 +0100 Subject: [PATCH 01/12] C#: Basic pattern match data flow support. --- .../ql/lib/semmle/code/csharp/Assignable.qll | 33 +++++--- .../dataflow/internal/DataFlowPrivate.qll | 78 +++++++++++++++---- .../ql/lib/semmle/code/csharp/exprs/Expr.qll | 7 ++ 3 files changed, 91 insertions(+), 27 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/Assignable.qll b/csharp/ql/lib/semmle/code/csharp/Assignable.qll index d4f8d9974f08..bcc592bf91bd 100644 --- a/csharp/ql/lib/semmle/code/csharp/Assignable.qll +++ b/csharp/ql/lib/semmle/code/csharp/Assignable.qll @@ -273,12 +273,20 @@ module AssignableInternal { def = TPatternDefinition(result) } - /** A local variable declaration at the top-level of a pattern. */ - class TopLevelPatternDecl extends LocalVariableDeclExpr { + /** A pattern containing a local variable declaration. */ + class LocalVariablePatternDecl extends LocalVariableDeclExpr { private PatternMatch pm; - TopLevelPatternDecl() { this = pm.getPattern().(BindingPatternExpr).getVariableDeclExpr() } + LocalVariablePatternDecl() { + exists(BindingPatternExpr bpe | + this = bpe.getVariableDeclExpr() and pm = bpe.getPatternMatch() + ) + } + /** Holds if the local variable definition is at the top level of the pattern. */ + predicate isTopLevel() { this = pm.getPattern().(BindingPatternExpr).getVariableDeclExpr() } + + /** Gets the pattern match that this local variable declaration (pattern) belongs to. */ PatternMatch getMatch() { result = pm } } @@ -297,7 +305,7 @@ module AssignableInternal { TLocalVariableDefinition(LocalVariableDeclExpr lvde) { not lvde.hasInitializer() and not exists(getTupleSource(TTupleAssignmentDefinition(_, lvde))) and - not lvde instanceof TopLevelPatternDecl and + not lvde instanceof LocalVariablePatternDecl and not lvde.isOutArgument() } or TImplicitParameterDefinition(Parameter p) { @@ -309,7 +317,7 @@ module AssignableInternal { ) } or TAddressOfDefinition(AddressOfExpr aoe) or - TPatternDefinition(TopLevelPatternDecl tlpd) + TPatternDefinition(LocalVariablePatternDecl lvpd) /** * Gets the source expression assigned in tuple definition `def`, if any. @@ -699,22 +707,25 @@ module AssignableDefinitions { } /** - * A local variable definition in a pattern, for example `x is int i`. + * A local variable definition in a pattern, for example `int i` in `x is int i`. */ class PatternDefinition extends AssignableDefinition, TPatternDefinition { - TopLevelPatternDecl tlpd; + LocalVariablePatternDecl lvpd; - PatternDefinition() { this = TPatternDefinition(tlpd) } + PatternDefinition() { this = TPatternDefinition(lvpd) } /** Gets the element matches against this pattern. */ - PatternMatch getMatch() { result = tlpd.getMatch() } + PatternMatch getMatch() { result = lvpd.getMatch() } /** Gets the underlying local variable declaration. */ - LocalVariableDeclExpr getDeclaration() { result = tlpd } + LocalVariableDeclExpr getDeclaration() { result = lvpd } - override Expr getSource() { result = this.getMatch().getExpr() } + override Expr getSource() { this.isTopLevel() and result = this.getMatch().getExpr() } override string toString() { result = this.getDeclaration().toString() } + + /** Holds if the local variable definition is at the top level of the pattern. */ + predicate isTopLevel() { lvpd.isTopLevel() } } /** 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 d8c57d4a3c16..e26ba2a7a185 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -605,7 +605,7 @@ module LocalFlow { isSuccessor = false or isSuccessor = true and - exists(ControlFlowElement cfe | cfe = e2.(TupleExpr).(PatternExpr).getPatternMatch() | + exists(ControlFlowElement cfe | cfe = e2.(TuplePatternExpr).getPatternMatch() | cfe.(IsExpr).getExpr() = e1 and scope = cfe or exists(Switch sw | sw.getACase() = cfe and sw.getExpr() = e1 and scope = sw) @@ -624,18 +624,29 @@ module LocalFlow { scope = def.getExpr() and isSuccessor = true or - scope = def.(AssignableDefinitions::PatternDefinition).getMatch().(IsExpr) and - isSuccessor = false - or - exists(Switch s | - s.getACase() = def.(AssignableDefinitions::PatternDefinition).getMatch() and - isSuccessor = true - | - scope = s.getExpr() + exists(AssignableDefinitions::PatternDefinition def0 | def = def0 and def0.isTopLevel() | + scope = def0.getMatch().(IsExpr) and + isSuccessor = false or - scope = s.getACase() + exists(Switch s | + s.getACase() = def0.getMatch() and + isSuccessor = true + | + scope = s.getExpr() + or + scope = s.getACase() + ) ) ) + or + // Needed for read steps for pattern matching involving properties. + scope = def.getExpr() and + exactScope = false and + isSuccessor = false and + def = + any(AssignableDefinitions::PatternDefinition apd | + e = apd.getDeclaration() and not apd.isTopLevel() + ) } } @@ -896,6 +907,30 @@ private predicate fieldOrPropertyStore(Expr e, ContentSet c, Expr src, Expr q, b ) } +private predicate patternPropertyRead0(RecursivePatternExpr rpe, ContentSet c, VariablePatternExpr e) { + exists(TypeAccess ta, Property prop | + ta = rpe.getTypeAccess() and + e = rpe.getPropertyPatterns().getPattern(_) and + prop.getDeclaringType() = ta.getType() and + prop.getName() = e.(LabeledPatternExpr).getLabel() and + c.isProperty(prop) + ) +} + +private predicate patternPropertyRead(Expr e1, ContentSet c, VariablePatternExpr e2) { + exists(IsExpr ie, RecursivePatternExpr rpe | + e1 = ie.getExpr() and + rpe = ie.getPattern() and + patternPropertyRead0(rpe, c, e2) + ) + or + exists(Switch sw, RecursivePatternExpr rpe | + e1 = sw.getExpr() and + rpe = sw.getACase().getPattern() and + patternPropertyRead0(rpe, c, e2) + ) +} + /** * Holds if `e2` is an expression that reads field or property `c` from * expression `e1`. @@ -1124,6 +1159,8 @@ private module Cached { or dynamicPropertyRead(e, _, read) or + patternPropertyRead(e, _, read) + or arrayRead(e, read) ) ) @@ -2415,6 +2452,11 @@ private class ReadStepConfiguration extends ControlFlowReachabilityConfiguration e2 = e1.(TupleExpr).getAnArgument() and scope = e1 and isSuccessor = false + or + exactScope = false and + isSuccessor = true and + patternPropertyRead(e1, _, e2) and + scope = e1 } override predicate candidateDef( @@ -2446,8 +2488,8 @@ private class ReadStepConfiguration extends ControlFlowReachabilityConfiguration ) or scope = - any(TupleExpr te | - te.getAnArgument() = defTo.(AssignableDefinitions::LocalVariableDefinition).getDeclaration() and + any(TuplePatternExpr te | + te.getAnArgument() = defTo.(AssignableDefinitions::PatternDefinition).getDeclaration() and e = te and exactScope = false and isSuccessor = false @@ -2496,8 +2538,8 @@ private predicate readContentStep(Node node1, Content c, Node node2) { ) or // item = variable in node1 = (..., variable, ...) in a case/is var (..., ...) - te = any(PatternExpr pe).getAChildExpr*() and - exists(AssignableDefinitions::LocalVariableDefinition lvd | + te = any(TuplePatternExpr pe).getAChildExpr*() and + exists(AssignableDefinitions::PatternDefinition lvd | node2.(AssignableDefinitionNode).getDefinition() = lvd and lvd.getDeclaration() = item and hasNodePath(x, node1, node2) @@ -2537,6 +2579,8 @@ predicate readStep(Node node1, ContentSet c, Node node2) { or dynamicPropertyRead(node1.asExpr(), c, node2.asExpr()) or + patternPropertyRead(node1.asExpr(), c, node2.asExpr()) + or node2.asExpr().(AwaitExpr).getExpr() = node1.asExpr() and c = getResultContent() ) @@ -2927,8 +2971,10 @@ class CastNode extends Node { CastNode() { this.asExpr() instanceof Cast or - this.(AssignableDefinitionNode).getDefinition() instanceof - AssignableDefinitions::PatternDefinition + this.(AssignableDefinitionNode) + .getDefinition() + .(AssignableDefinitions::PatternDefinition) + .isTopLevel() } } diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll index 85676bbd2701..c3011ac7850f 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll @@ -531,6 +531,13 @@ class LabeledPatternExpr extends PatternExpr { override string getAPrimaryQlClass() { result = "LabeledPatternExpr" } } +/** + * A tuple pattern. For example, `var (x, y)`. + */ +class TuplePatternExpr extends TupleExpr, PatternExpr { + override string getAPrimaryQlClass() { result = "TuplePatternExpr" } +} + /** A positional pattern. For example, `(int x, int y)`. */ class PositionalPatternExpr extends PatternExpr, @positional_pattern_expr { override string toString() { result = "( ... )" } From 262e6329a8dbfe8e024dc1a2172d4d9072861f7e Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 17 Feb 2025 13:02:37 +0100 Subject: [PATCH 02/12] C#: Update data flow patterns test expected file. --- .../dataflow/patterns/PatternFlow.expected | 78 +++++++++++++++++++ .../dataflow/patterns/Patterns.cs | 4 +- 2 files changed, 80 insertions(+), 2 deletions(-) diff --git a/csharp/ql/test/library-tests/dataflow/patterns/PatternFlow.expected b/csharp/ql/test/library-tests/dataflow/patterns/PatternFlow.expected index 4e4a41dfc62c..6878a0a21638 100644 --- a/csharp/ql/test/library-tests/dataflow/patterns/PatternFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/patterns/PatternFlow.expected @@ -1,6 +1,84 @@ models edges +| Patterns.cs:3:41:3:44 | Prop : Object | Patterns.cs:3:21:3:32 | this [Return] : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:3:41:3:44 | Prop : Object | Patterns.cs:3:21:3:32 | this [Return] : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:11:13:11:13 | access to local variable o : Object | Patterns.cs:12:34:12:34 | access to local variable o : Object | provenance | | +| Patterns.cs:11:13:11:13 | access to local variable o : Object | Patterns.cs:12:34:12:34 | access to local variable o : Object | provenance | | +| Patterns.cs:11:17:11:33 | call to method Source : Object | Patterns.cs:11:13:11:13 | access to local variable o : Object | provenance | | +| Patterns.cs:11:17:11:33 | call to method Source : Object | Patterns.cs:11:13:11:13 | access to local variable o : Object | provenance | | +| Patterns.cs:12:13:12:13 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:13:13:13:13 | access to local variable r : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:12:13:12:13 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:13:13:13:13 | access to local variable r : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:12:17:12:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | Patterns.cs:12:13:12:13 | access to local variable r : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:12:17:12:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | Patterns.cs:12:13:12:13 | access to local variable r : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:12:34:12:34 | access to local variable o : Object | Patterns.cs:3:41:3:44 | Prop : Object | provenance | | +| Patterns.cs:12:34:12:34 | access to local variable o : Object | Patterns.cs:3:41:3:44 | Prop : Object | provenance | | +| Patterns.cs:12:34:12:34 | access to local variable o : Object | Patterns.cs:12:17:12:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:12:34:12:34 | access to local variable o : Object | Patterns.cs:12:17:12:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:13:13:13:13 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:13:39:13:46 | Object p : Object | provenance | | +| Patterns.cs:13:13:13:13 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:13:39:13:46 | Object p : Object | provenance | | +| Patterns.cs:13:39:13:46 | Object p : Object | Patterns.cs:15:18:15:18 | access to local variable p | provenance | | +| Patterns.cs:13:39:13:46 | Object p : Object | Patterns.cs:15:18:15:18 | access to local variable p | provenance | | +| Patterns.cs:21:13:21:13 | access to local variable o : Object | Patterns.cs:22:34:22:34 | access to local variable o : Object | provenance | | +| Patterns.cs:21:13:21:13 | access to local variable o : Object | Patterns.cs:22:34:22:34 | access to local variable o : Object | provenance | | +| Patterns.cs:21:17:21:33 | call to method Source : Object | Patterns.cs:21:13:21:13 | access to local variable o : Object | provenance | | +| Patterns.cs:21:17:21:33 | call to method Source : Object | Patterns.cs:21:13:21:13 | access to local variable o : Object | provenance | | +| Patterns.cs:22:13:22:13 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:23:17:23:17 | access to local variable r : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:22:13:22:13 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:23:17:23:17 | access to local variable r : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:22:17:22:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | Patterns.cs:22:13:22:13 | access to local variable r : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:22:17:22:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | Patterns.cs:22:13:22:13 | access to local variable r : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:22:34:22:34 | access to local variable o : Object | Patterns.cs:3:41:3:44 | Prop : Object | provenance | | +| Patterns.cs:22:34:22:34 | access to local variable o : Object | Patterns.cs:3:41:3:44 | Prop : Object | provenance | | +| Patterns.cs:22:34:22:34 | access to local variable o : Object | Patterns.cs:22:17:22:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:22:34:22:34 | access to local variable o : Object | Patterns.cs:22:17:22:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:23:17:23:17 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:25:39:25:46 | Object p : Object | provenance | | +| Patterns.cs:23:17:23:17 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:25:39:25:46 | Object p : Object | provenance | | +| Patterns.cs:25:39:25:46 | Object p : Object | Patterns.cs:26:22:26:22 | access to local variable p | provenance | | +| Patterns.cs:25:39:25:46 | Object p : Object | Patterns.cs:26:22:26:22 | access to local variable p | provenance | | nodes +| Patterns.cs:3:21:3:32 | this [Return] : RecordClass2 [property Prop] : Object | semmle.label | this [Return] : RecordClass2 [property Prop] : Object | +| Patterns.cs:3:21:3:32 | this [Return] : RecordClass2 [property Prop] : Object | semmle.label | this [Return] : RecordClass2 [property Prop] : Object | +| Patterns.cs:3:41:3:44 | Prop : Object | semmle.label | Prop : Object | +| Patterns.cs:3:41:3:44 | Prop : Object | semmle.label | Prop : Object | +| Patterns.cs:11:13:11:13 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| Patterns.cs:11:13:11:13 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| Patterns.cs:11:17:11:33 | call to method Source : Object | semmle.label | call to method Source : Object | +| Patterns.cs:11:17:11:33 | call to method Source : Object | semmle.label | call to method Source : Object | +| Patterns.cs:12:13:12:13 | access to local variable r : RecordClass2 [property Prop] : Object | semmle.label | access to local variable r : RecordClass2 [property Prop] : Object | +| Patterns.cs:12:13:12:13 | access to local variable r : RecordClass2 [property Prop] : Object | semmle.label | access to local variable r : RecordClass2 [property Prop] : Object | +| Patterns.cs:12:17:12:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | semmle.label | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | +| Patterns.cs:12:17:12:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | semmle.label | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | +| Patterns.cs:12:34:12:34 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| Patterns.cs:12:34:12:34 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| Patterns.cs:13:13:13:13 | access to local variable r : RecordClass2 [property Prop] : Object | semmle.label | access to local variable r : RecordClass2 [property Prop] : Object | +| Patterns.cs:13:13:13:13 | access to local variable r : RecordClass2 [property Prop] : Object | semmle.label | access to local variable r : RecordClass2 [property Prop] : Object | +| Patterns.cs:13:39:13:46 | Object p : Object | semmle.label | Object p : Object | +| Patterns.cs:13:39:13:46 | Object p : Object | semmle.label | Object p : Object | +| Patterns.cs:15:18:15:18 | access to local variable p | semmle.label | access to local variable p | +| Patterns.cs:15:18:15:18 | access to local variable p | semmle.label | access to local variable p | +| Patterns.cs:21:13:21:13 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| Patterns.cs:21:13:21:13 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| Patterns.cs:21:17:21:33 | call to method Source : Object | semmle.label | call to method Source : Object | +| Patterns.cs:21:17:21:33 | call to method Source : Object | semmle.label | call to method Source : Object | +| Patterns.cs:22:13:22:13 | access to local variable r : RecordClass2 [property Prop] : Object | semmle.label | access to local variable r : RecordClass2 [property Prop] : Object | +| Patterns.cs:22:13:22:13 | access to local variable r : RecordClass2 [property Prop] : Object | semmle.label | access to local variable r : RecordClass2 [property Prop] : Object | +| Patterns.cs:22:17:22:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | semmle.label | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | +| Patterns.cs:22:17:22:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | semmle.label | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | +| Patterns.cs:22:34:22:34 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| Patterns.cs:22:34:22:34 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| Patterns.cs:23:17:23:17 | access to local variable r : RecordClass2 [property Prop] : Object | semmle.label | access to local variable r : RecordClass2 [property Prop] : Object | +| Patterns.cs:23:17:23:17 | access to local variable r : RecordClass2 [property Prop] : Object | semmle.label | access to local variable r : RecordClass2 [property Prop] : Object | +| Patterns.cs:25:39:25:46 | Object p : Object | semmle.label | Object p : Object | +| Patterns.cs:25:39:25:46 | Object p : Object | semmle.label | Object p : Object | +| Patterns.cs:26:22:26:22 | access to local variable p | semmle.label | access to local variable p | +| Patterns.cs:26:22:26:22 | access to local variable p | semmle.label | access to local variable p | subpaths +| Patterns.cs:12:34:12:34 | access to local variable o : Object | Patterns.cs:3:41:3:44 | Prop : Object | Patterns.cs:3:21:3:32 | this [Return] : RecordClass2 [property Prop] : Object | Patterns.cs:12:17:12:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | +| Patterns.cs:12:34:12:34 | access to local variable o : Object | Patterns.cs:3:41:3:44 | Prop : Object | Patterns.cs:3:21:3:32 | this [Return] : RecordClass2 [property Prop] : Object | Patterns.cs:12:17:12:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | +| Patterns.cs:22:34:22:34 | access to local variable o : Object | Patterns.cs:3:41:3:44 | Prop : Object | Patterns.cs:3:21:3:32 | this [Return] : RecordClass2 [property Prop] : Object | Patterns.cs:22:17:22:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | +| Patterns.cs:22:34:22:34 | access to local variable o : Object | Patterns.cs:3:41:3:44 | Prop : Object | Patterns.cs:3:21:3:32 | this [Return] : RecordClass2 [property Prop] : Object | Patterns.cs:22:17:22:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | testFailures #select +| Patterns.cs:15:18:15:18 | access to local variable p | Patterns.cs:11:17:11:33 | call to method Source : Object | Patterns.cs:15:18:15:18 | access to local variable p | $@ | Patterns.cs:11:17:11:33 | call to method Source : Object | call to method Source : Object | +| Patterns.cs:15:18:15:18 | access to local variable p | Patterns.cs:11:17:11:33 | call to method Source : Object | Patterns.cs:15:18:15:18 | access to local variable p | $@ | Patterns.cs:11:17:11:33 | call to method Source : Object | call to method Source : Object | +| Patterns.cs:26:22:26:22 | access to local variable p | Patterns.cs:21:17:21:33 | call to method Source : Object | Patterns.cs:26:22:26:22 | access to local variable p | $@ | Patterns.cs:21:17:21:33 | call to method Source : Object | call to method Source : Object | +| Patterns.cs:26:22:26:22 | access to local variable p | Patterns.cs:21:17:21:33 | call to method Source : Object | Patterns.cs:26:22:26:22 | access to local variable p | $@ | Patterns.cs:21:17:21:33 | call to method Source : Object | call to method Source : Object | diff --git a/csharp/ql/test/library-tests/dataflow/patterns/Patterns.cs b/csharp/ql/test/library-tests/dataflow/patterns/Patterns.cs index d3247e1351b8..9b760eee90f0 100644 --- a/csharp/ql/test/library-tests/dataflow/patterns/Patterns.cs +++ b/csharp/ql/test/library-tests/dataflow/patterns/Patterns.cs @@ -12,7 +12,7 @@ private void M1() var r = new RecordClass2(o); if (r is RecordClass2 { Prop: object p }) { - Sink(p); // $ MISSING: hasValueFlow=1 + Sink(p); // $ hasValueFlow=1 } } @@ -23,7 +23,7 @@ private void M2() switch (r) { case RecordClass2 { Prop: object p }: - Sink(p); // $ MISSING: hasValueFlow=2 + Sink(p); // $ hasValueFlow=2 break; } } From 2a5c794adcb568bd9d03ea30c6758ecf09e4bf6d Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 17 Feb 2025 13:14:38 +0100 Subject: [PATCH 03/12] C#: Update other test expected output files. --- .../ql/test/library-tests/csharp8/PrintAst.expected | 4 ++-- .../dataflow/tuples/DataFlowStep.expected | 11 +++++++++++ .../library-tests/dataflow/tuples/PrintAst.expected | 12 ++++++------ 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/csharp/ql/test/library-tests/csharp8/PrintAst.expected b/csharp/ql/test/library-tests/csharp8/PrintAst.expected index c33374e4761d..7ef3580298a1 100644 --- a/csharp/ql/test/library-tests/csharp8/PrintAst.expected +++ b/csharp/ql/test/library-tests/csharp8/PrintAst.expected @@ -927,7 +927,7 @@ patterns.cs: # 57| 1: [ConstantPatternExpr,IntLiteral] 2 # 58| 10: [BreakStmt] break; # 59| 11: [CaseStmt] case ...: -# 59| 0: [TupleExpr] (..., ...) +# 59| 0: [TuplePatternExpr] (..., ...) # 59| 0: [VariablePatternExpr] Int32 x # 59| 1: [VariablePatternExpr] Int32 y # 60| 12: [BreakStmt] break; @@ -1154,7 +1154,7 @@ patterns.cs: # 130| 1: [ConstantPatternExpr,IntLiteral] 2 # 130| 2: [IntLiteral] 2 # 131| 3: [SwitchCaseExpr] ... => ... -# 131| 0: [TupleExpr] (..., ...) +# 131| 0: [TuplePatternExpr] (..., ...) # 131| 0: [VariablePatternExpr] Int32 x # 131| 1: [DiscardPatternExpr] _ # 131| 2: [IntLiteral] 3 diff --git a/csharp/ql/test/library-tests/dataflow/tuples/DataFlowStep.expected b/csharp/ql/test/library-tests/dataflow/tuples/DataFlowStep.expected index 73b0a757b5a3..2ad11331e908 100644 --- a/csharp/ql/test/library-tests/dataflow/tuples/DataFlowStep.expected +++ b/csharp/ql/test/library-tests/dataflow/tuples/DataFlowStep.expected @@ -126,10 +126,13 @@ | Tuples.cs:65:22:65:34 | access to field Item1 | Tuples.cs:65:22:65:34 | (...) ... | | Tuples.cs:67:23:67:23 | SSA def(a) | Tuples.cs:68:22:68:22 | access to local variable a | | Tuples.cs:67:23:67:23 | String a | Tuples.cs:67:23:67:23 | SSA def(a) | +| Tuples.cs:67:23:67:23 | String a | Tuples.cs:67:23:67:23 | String a | +| Tuples.cs:67:27:67:27 | Int32 b | Tuples.cs:67:27:67:27 | Int32 b | | Tuples.cs:67:27:67:27 | Int32 b | Tuples.cs:67:27:67:27 | SSA def(b) | | Tuples.cs:67:27:67:27 | SSA def(b) | Tuples.cs:70:22:70:22 | access to local variable b | | Tuples.cs:67:30:67:30 | SSA def(c) | Tuples.cs:69:22:69:22 | access to local variable c | | Tuples.cs:67:30:67:30 | String c | Tuples.cs:67:30:67:30 | SSA def(c) | +| Tuples.cs:67:30:67:30 | String c | Tuples.cs:67:30:67:30 | String c | | Tuples.cs:70:22:70:22 | access to local variable b | Tuples.cs:70:22:70:22 | (...) ... | | Tuples.cs:74:13:74:14 | access to local variable o3 | Tuples.cs:74:13:74:34 | SSA def(o3) | | Tuples.cs:74:13:74:34 | SSA def(o3) | Tuples.cs:78:51:78:52 | access to local variable o3 | @@ -147,10 +150,13 @@ | Tuples.cs:76:17:76:17 | access to local variable y | Tuples.cs:79:22:79:22 | access to local variable y | | Tuples.cs:78:19:78:23 | SSA def(a) | Tuples.cs:78:46:78:46 | access to local variable a | | Tuples.cs:78:19:78:23 | String a | Tuples.cs:78:19:78:23 | SSA def(a) | +| Tuples.cs:78:19:78:23 | String a | Tuples.cs:78:19:78:23 | String a | +| Tuples.cs:78:31:78:31 | Int32 b | Tuples.cs:78:31:78:31 | Int32 b | | Tuples.cs:78:31:78:31 | Int32 b | Tuples.cs:78:31:78:31 | SSA def(b) | | Tuples.cs:78:31:78:31 | SSA def(b) | Tuples.cs:83:22:83:22 | access to local variable b | | Tuples.cs:78:34:78:34 | SSA def(c) | Tuples.cs:81:22:81:22 | access to local variable c | | Tuples.cs:78:34:78:34 | String c | Tuples.cs:78:34:78:34 | SSA def(c) | +| Tuples.cs:78:34:78:34 | String c | Tuples.cs:78:34:78:34 | String c | | Tuples.cs:79:22:79:22 | [post] access to local variable y | Tuples.cs:80:22:80:22 | access to local variable y | | Tuples.cs:79:22:79:22 | access to local variable y | Tuples.cs:80:22:80:22 | access to local variable y | | Tuples.cs:80:22:80:22 | [post] access to local variable y | Tuples.cs:82:22:82:22 | access to local variable y | @@ -163,10 +169,13 @@ | Tuples.cs:87:13:87:13 | access to local variable x | Tuples.cs:87:18:87:35 | (..., ...) | | Tuples.cs:87:23:87:23 | SSA def(p) | Tuples.cs:89:18:89:18 | access to local variable p | | Tuples.cs:87:23:87:23 | String p | Tuples.cs:87:23:87:23 | SSA def(p) | +| Tuples.cs:87:23:87:23 | String p | Tuples.cs:87:23:87:23 | String p | +| Tuples.cs:87:27:87:27 | Int32 q | Tuples.cs:87:27:87:27 | Int32 q | | Tuples.cs:87:27:87:27 | Int32 q | Tuples.cs:87:27:87:27 | SSA def(q) | | Tuples.cs:87:27:87:27 | SSA def(q) | Tuples.cs:91:18:91:18 | access to local variable q | | Tuples.cs:87:30:87:30 | SSA def(r) | Tuples.cs:90:18:90:18 | access to local variable r | | Tuples.cs:87:30:87:30 | String r | Tuples.cs:87:30:87:30 | SSA def(r) | +| Tuples.cs:87:30:87:30 | String r | Tuples.cs:87:30:87:30 | String r | | Tuples.cs:91:18:91:18 | access to local variable q | Tuples.cs:91:18:91:18 | (...) ... | | Tuples.cs:95:12:95:13 | this | Tuples.cs:95:22:95:22 | this | | Tuples.cs:95:22:95:22 | [post] this | Tuples.cs:95:29:95:29 | this | @@ -191,6 +200,8 @@ | Tuples.cs:107:17:107:17 | access to local variable r | Tuples.cs:109:18:109:27 | (..., ...) | | Tuples.cs:109:23:109:23 | SSA def(x) | Tuples.cs:110:22:110:22 | access to local variable x | | Tuples.cs:109:23:109:23 | String x | Tuples.cs:109:23:109:23 | SSA def(x) | +| Tuples.cs:109:23:109:23 | String x | Tuples.cs:109:23:109:23 | String x | +| Tuples.cs:109:26:109:26 | Int32 y | Tuples.cs:109:26:109:26 | Int32 y | | Tuples.cs:109:26:109:26 | Int32 y | Tuples.cs:109:26:109:26 | SSA def(y) | | Tuples.cs:109:26:109:26 | SSA def(y) | Tuples.cs:111:22:111:22 | access to local variable y | | Tuples.cs:111:22:111:22 | access to local variable y | Tuples.cs:111:22:111:22 | (...) ... | diff --git a/csharp/ql/test/library-tests/dataflow/tuples/PrintAst.expected b/csharp/ql/test/library-tests/dataflow/tuples/PrintAst.expected index 7cbddb9d3d57..aea9c5fa1f00 100644 --- a/csharp/ql/test/library-tests/dataflow/tuples/PrintAst.expected +++ b/csharp/ql/test/library-tests/dataflow/tuples/PrintAst.expected @@ -262,9 +262,9 @@ Tuples.cs: # 65| -1: [LocalVariableAccess] access to local variable t # 66| 4: [BreakStmt] break; # 67| 5: [CaseStmt] case ...: -# 67| 0: [TupleExpr] (..., ...) +# 67| 0: [TuplePatternExpr] (..., ...) # 67| 0: [VariablePatternExpr] String a -# 67| 1: [TupleExpr] (..., ...) +# 67| 1: [TuplePatternExpr] (..., ...) # 67| 0: [VariablePatternExpr] Int32 b # 67| 1: [VariablePatternExpr] String c # 67| 2: [DiscardPatternExpr] _ @@ -302,7 +302,7 @@ Tuples.cs: # 78| 0: [RecursivePatternExpr] { ... } # 78| 2: [PositionalPatternExpr] ( ... ) # 78| 0: [VariablePatternExpr] String a -# 78| 1: [TupleExpr] (..., ...) +# 78| 1: [TuplePatternExpr] (..., ...) # 78| 0: [VariablePatternExpr] Int32 b # 78| 1: [VariablePatternExpr] String c # 78| 2: [DiscardPatternExpr] _ @@ -335,9 +335,9 @@ Tuples.cs: # 87| 7: [IfStmt] if (...) ... # 87| 0: [IsExpr] ... is ... # 87| 0: [LocalVariableAccess] access to local variable x -# 87| 1: [TupleExpr] (..., ...) +# 87| 1: [TuplePatternExpr] (..., ...) # 87| 0: [VariablePatternExpr] String p -# 87| 1: [TupleExpr] (..., ...) +# 87| 1: [TuplePatternExpr] (..., ...) # 87| 0: [VariablePatternExpr] Int32 q # 87| 1: [VariablePatternExpr] String r # 87| 2: [DiscardPatternExpr] _ @@ -417,7 +417,7 @@ Tuples.cs: # 107| 6: [SwitchStmt] switch (...) {...} # 107| 0: [LocalVariableAccess] access to local variable r # 109| 0: [CaseStmt] case ...: -# 109| 0: [TupleExpr] (..., ...) +# 109| 0: [TuplePatternExpr] (..., ...) # 109| 0: [VariablePatternExpr] String x # 109| 1: [VariablePatternExpr] Int32 y # 110| 1: [ExprStmt] ...; From 425f0faaee2bc60990a9b99e9d140560736f5f2a Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 18 Feb 2025 08:59:35 +0100 Subject: [PATCH 04/12] C#: Split pattern reads into multiple steps steps. --- .../dataflow/internal/DataFlowPrivate.qll | 57 ++++++++++++------- 1 file changed, 38 insertions(+), 19 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 e26ba2a7a185..0bb1472ccc1d 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -610,6 +610,24 @@ module LocalFlow { or exists(Switch sw | sw.getACase() = cfe and sw.getExpr() = e1 and scope = sw) ) + or + isSuccessor = true and + scope = + any(IsExpr ie | + e1 = ie.getExpr() and + e2 = ie.getPattern() + ) + or + isSuccessor = true and + scope = + any(Switch e | + e1 = e.getExpr() and + e2 = e.getACase().getPattern() + ) + or + isSuccessor = false and + e2 = e1.(RecursivePatternExpr).getPropertyPatterns() and + scope = e1 ) } @@ -907,27 +925,28 @@ private predicate fieldOrPropertyStore(Expr e, ContentSet c, Expr src, Expr q, b ) } -private predicate patternPropertyRead0(RecursivePatternExpr rpe, ContentSet c, VariablePatternExpr e) { - exists(TypeAccess ta, Property prop | - ta = rpe.getTypeAccess() and - e = rpe.getPropertyPatterns().getPattern(_) and - prop.getDeclaringType() = ta.getType() and - prop.getName() = e.(LabeledPatternExpr).getLabel() and - c.isProperty(prop) +/** + * TODO: Should we consider to override getType on pattern expressions? + */ +private Type getPatternType(PatternExpr pe) { + result = pe.(RecursivePatternExpr).getTypeAccess().getType() + or + not pe instanceof LabeledPatternExpr and + result = getPatternType(pe.getParent()) + or + exists(Property p | + result = p.getType() and + p.getDeclaringType() = getPatternType(pe.getParent()) and + p.getName() = pe.(LabeledPatternExpr).getLabel() ) } -private predicate patternPropertyRead(Expr e1, ContentSet c, VariablePatternExpr e2) { - exists(IsExpr ie, RecursivePatternExpr rpe | - e1 = ie.getExpr() and - rpe = ie.getPattern() and - patternPropertyRead0(rpe, c, e2) - ) - or - exists(Switch sw, RecursivePatternExpr rpe | - e1 = sw.getExpr() and - rpe = sw.getACase().getPattern() and - patternPropertyRead0(rpe, c, e2) +private predicate patternPropertyRead(PropertyPatternExpr pe, ContentSet c, LabeledPatternExpr e) { + exists(Property prop | + e = pe.getPattern(_) and + prop.getDeclaringType() = getPatternType(pe) and + prop.getName() = e.getLabel() and + c.isProperty(prop) ) } @@ -2454,7 +2473,7 @@ private class ReadStepConfiguration extends ControlFlowReachabilityConfiguration isSuccessor = false or exactScope = false and - isSuccessor = true and + isSuccessor = false and patternPropertyRead(e1, _, e2) and scope = e1 } From c6ae475764c3e41655e7dd0f5af479a573b397e4 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 18 Feb 2025 11:34:28 +0100 Subject: [PATCH 05/12] C#: Update patterns flow test expected output (as nested pattern matching is now supported). --- .../dataflow/patterns/PatternFlow.expected | 166 ++++++++++++++++-- .../dataflow/patterns/Patterns.cs | 4 +- 2 files changed, 156 insertions(+), 14 deletions(-) diff --git a/csharp/ql/test/library-tests/dataflow/patterns/PatternFlow.expected b/csharp/ql/test/library-tests/dataflow/patterns/PatternFlow.expected index 6878a0a21638..c1fed9d0ce54 100644 --- a/csharp/ql/test/library-tests/dataflow/patterns/PatternFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/patterns/PatternFlow.expected @@ -2,43 +2,117 @@ models edges | Patterns.cs:3:41:3:44 | Prop : Object | Patterns.cs:3:21:3:32 | this [Return] : RecordClass2 [property Prop] : Object | provenance | | | Patterns.cs:3:41:3:44 | Prop : Object | Patterns.cs:3:21:3:32 | this [Return] : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:5:41:5:46 | Record : RecordClass2 [property Prop] : Object | Patterns.cs:5:21:5:26 | this [Return] : Nested [property Record, property Prop] : Object | provenance | | +| Patterns.cs:5:41:5:46 | Record : RecordClass2 [property Prop] : Object | Patterns.cs:5:21:5:26 | this [Return] : Nested [property Record, property Prop] : Object | provenance | | | Patterns.cs:11:13:11:13 | access to local variable o : Object | Patterns.cs:12:34:12:34 | access to local variable o : Object | provenance | | | Patterns.cs:11:13:11:13 | access to local variable o : Object | Patterns.cs:12:34:12:34 | access to local variable o : Object | provenance | | | Patterns.cs:11:17:11:33 | call to method Source : Object | Patterns.cs:11:13:11:13 | access to local variable o : Object | provenance | | | Patterns.cs:11:17:11:33 | call to method Source : Object | Patterns.cs:11:13:11:13 | access to local variable o : Object | provenance | | -| Patterns.cs:12:13:12:13 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:13:13:13:13 | access to local variable r : RecordClass2 [property Prop] : Object | provenance | | -| Patterns.cs:12:13:12:13 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:13:13:13:13 | access to local variable r : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:12:13:12:13 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:13:31:13:48 | [match] { ... } : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:12:13:12:13 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:13:31:13:48 | [match] { ... } : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:12:13:12:13 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:13:31:13:48 | [no-match] { ... } : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:12:13:12:13 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:13:31:13:48 | [no-match] { ... } : RecordClass2 [property Prop] : Object | provenance | | | Patterns.cs:12:17:12:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | Patterns.cs:12:13:12:13 | access to local variable r : RecordClass2 [property Prop] : Object | provenance | | | Patterns.cs:12:17:12:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | Patterns.cs:12:13:12:13 | access to local variable r : RecordClass2 [property Prop] : Object | provenance | | | Patterns.cs:12:34:12:34 | access to local variable o : Object | Patterns.cs:3:41:3:44 | Prop : Object | provenance | | | Patterns.cs:12:34:12:34 | access to local variable o : Object | Patterns.cs:3:41:3:44 | Prop : Object | provenance | | | Patterns.cs:12:34:12:34 | access to local variable o : Object | Patterns.cs:12:17:12:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | provenance | | | Patterns.cs:12:34:12:34 | access to local variable o : Object | Patterns.cs:12:17:12:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | provenance | | -| Patterns.cs:13:13:13:13 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:13:39:13:46 | Object p : Object | provenance | | -| Patterns.cs:13:13:13:13 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:13:39:13:46 | Object p : Object | provenance | | +| Patterns.cs:13:31:13:48 | [match] { ... } : RecordClass2 [property Prop] : Object | Patterns.cs:13:39:13:46 | Object p : Object | provenance | | +| Patterns.cs:13:31:13:48 | [match] { ... } : RecordClass2 [property Prop] : Object | Patterns.cs:13:39:13:46 | Object p : Object | provenance | | +| Patterns.cs:13:31:13:48 | [no-match] { ... } : RecordClass2 [property Prop] : Object | Patterns.cs:13:39:13:46 | Object p : Object | provenance | | +| Patterns.cs:13:31:13:48 | [no-match] { ... } : RecordClass2 [property Prop] : Object | Patterns.cs:13:39:13:46 | Object p : Object | provenance | | | Patterns.cs:13:39:13:46 | Object p : Object | Patterns.cs:15:18:15:18 | access to local variable p | provenance | | | Patterns.cs:13:39:13:46 | Object p : Object | Patterns.cs:15:18:15:18 | access to local variable p | provenance | | | Patterns.cs:21:13:21:13 | access to local variable o : Object | Patterns.cs:22:34:22:34 | access to local variable o : Object | provenance | | | Patterns.cs:21:13:21:13 | access to local variable o : Object | Patterns.cs:22:34:22:34 | access to local variable o : Object | provenance | | | Patterns.cs:21:17:21:33 | call to method Source : Object | Patterns.cs:21:13:21:13 | access to local variable o : Object | provenance | | | Patterns.cs:21:17:21:33 | call to method Source : Object | Patterns.cs:21:13:21:13 | access to local variable o : Object | provenance | | -| Patterns.cs:22:13:22:13 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:23:17:23:17 | access to local variable r : RecordClass2 [property Prop] : Object | provenance | | -| Patterns.cs:22:13:22:13 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:23:17:23:17 | access to local variable r : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:22:13:22:13 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:25:31:25:48 | [match] { ... } : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:22:13:22:13 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:25:31:25:48 | [match] { ... } : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:22:13:22:13 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:25:31:25:48 | [no-match] { ... } : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:22:13:22:13 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:25:31:25:48 | [no-match] { ... } : RecordClass2 [property Prop] : Object | provenance | | | Patterns.cs:22:17:22:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | Patterns.cs:22:13:22:13 | access to local variable r : RecordClass2 [property Prop] : Object | provenance | | | Patterns.cs:22:17:22:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | Patterns.cs:22:13:22:13 | access to local variable r : RecordClass2 [property Prop] : Object | provenance | | | Patterns.cs:22:34:22:34 | access to local variable o : Object | Patterns.cs:3:41:3:44 | Prop : Object | provenance | | | Patterns.cs:22:34:22:34 | access to local variable o : Object | Patterns.cs:3:41:3:44 | Prop : Object | provenance | | | Patterns.cs:22:34:22:34 | access to local variable o : Object | Patterns.cs:22:17:22:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | provenance | | | Patterns.cs:22:34:22:34 | access to local variable o : Object | Patterns.cs:22:17:22:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | provenance | | -| Patterns.cs:23:17:23:17 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:25:39:25:46 | Object p : Object | provenance | | -| Patterns.cs:23:17:23:17 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:25:39:25:46 | Object p : Object | provenance | | +| Patterns.cs:25:31:25:48 | [match] { ... } : RecordClass2 [property Prop] : Object | Patterns.cs:25:39:25:46 | Object p : Object | provenance | | +| Patterns.cs:25:31:25:48 | [match] { ... } : RecordClass2 [property Prop] : Object | Patterns.cs:25:39:25:46 | Object p : Object | provenance | | +| Patterns.cs:25:31:25:48 | [no-match] { ... } : RecordClass2 [property Prop] : Object | Patterns.cs:25:39:25:46 | Object p : Object | provenance | | +| Patterns.cs:25:31:25:48 | [no-match] { ... } : RecordClass2 [property Prop] : Object | Patterns.cs:25:39:25:46 | Object p : Object | provenance | | | Patterns.cs:25:39:25:46 | Object p : Object | Patterns.cs:26:22:26:22 | access to local variable p | provenance | | | Patterns.cs:25:39:25:46 | Object p : Object | Patterns.cs:26:22:26:22 | access to local variable p | provenance | | +| Patterns.cs:33:13:33:13 | access to local variable o : Object | Patterns.cs:34:45:34:45 | access to local variable o : Object | provenance | | +| Patterns.cs:33:13:33:13 | access to local variable o : Object | Patterns.cs:34:45:34:45 | access to local variable o : Object | provenance | | +| Patterns.cs:33:17:33:33 | call to method Source : Object | Patterns.cs:33:13:33:13 | access to local variable o : Object | provenance | | +| Patterns.cs:33:17:33:33 | call to method Source : Object | Patterns.cs:33:13:33:13 | access to local variable o : Object | provenance | | +| Patterns.cs:34:13:34:13 | access to local variable s : Nested [property Record, property Prop] : Object | Patterns.cs:35:25:35:54 | [match] { ... } : Nested [property Record, property Prop] : Object | provenance | | +| Patterns.cs:34:13:34:13 | access to local variable s : Nested [property Record, property Prop] : Object | Patterns.cs:35:25:35:54 | [match] { ... } : Nested [property Record, property Prop] : Object | provenance | | +| Patterns.cs:34:13:34:13 | access to local variable s : Nested [property Record, property Prop] : Object | Patterns.cs:35:25:35:54 | [no-match] { ... } : Nested [property Record, property Prop] : Object | provenance | | +| Patterns.cs:34:13:34:13 | access to local variable s : Nested [property Record, property Prop] : Object | Patterns.cs:35:25:35:54 | [no-match] { ... } : Nested [property Record, property Prop] : Object | provenance | | +| Patterns.cs:34:17:34:47 | object creation of type Nested : Nested [property Record, property Prop] : Object | Patterns.cs:34:13:34:13 | access to local variable s : Nested [property Record, property Prop] : Object | provenance | | +| Patterns.cs:34:17:34:47 | object creation of type Nested : Nested [property Record, property Prop] : Object | Patterns.cs:34:13:34:13 | access to local variable s : Nested [property Record, property Prop] : Object | provenance | | +| Patterns.cs:34:28:34:46 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | Patterns.cs:5:41:5:46 | Record : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:34:28:34:46 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | Patterns.cs:5:41:5:46 | Record : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:34:28:34:46 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | Patterns.cs:34:17:34:47 | object creation of type Nested : Nested [property Record, property Prop] : Object | provenance | | +| Patterns.cs:34:28:34:46 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | Patterns.cs:34:17:34:47 | object creation of type Nested : Nested [property Record, property Prop] : Object | provenance | | +| Patterns.cs:34:45:34:45 | access to local variable o : Object | Patterns.cs:3:41:3:44 | Prop : Object | provenance | | +| Patterns.cs:34:45:34:45 | access to local variable o : Object | Patterns.cs:3:41:3:44 | Prop : Object | provenance | | +| Patterns.cs:34:45:34:45 | access to local variable o : Object | Patterns.cs:34:28:34:46 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:34:45:34:45 | access to local variable o : Object | Patterns.cs:34:28:34:46 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:35:25:35:54 | [match] { ... } : Nested [property Record, property Prop] : Object | Patterns.cs:35:35:35:52 | [match] { ... } : null [property Prop] : Object | provenance | | +| Patterns.cs:35:25:35:54 | [match] { ... } : Nested [property Record, property Prop] : Object | Patterns.cs:35:35:35:52 | [match] { ... } : null [property Prop] : Object | provenance | | +| Patterns.cs:35:25:35:54 | [no-match] { ... } : Nested [property Record, property Prop] : Object | Patterns.cs:35:35:35:52 | [no-match] { ... } : null [property Prop] : Object | provenance | | +| Patterns.cs:35:25:35:54 | [no-match] { ... } : Nested [property Record, property Prop] : Object | Patterns.cs:35:35:35:52 | [no-match] { ... } : null [property Prop] : Object | provenance | | +| Patterns.cs:35:35:35:52 | [match] { ... } : null [property Prop] : Object | Patterns.cs:35:35:35:52 | [match] { ... } : null [property Prop] : Object | provenance | | +| Patterns.cs:35:35:35:52 | [match] { ... } : null [property Prop] : Object | Patterns.cs:35:35:35:52 | [match] { ... } : null [property Prop] : Object | provenance | | +| Patterns.cs:35:35:35:52 | [match] { ... } : null [property Prop] : Object | Patterns.cs:35:43:35:50 | Object p : Object | provenance | | +| Patterns.cs:35:35:35:52 | [match] { ... } : null [property Prop] : Object | Patterns.cs:35:43:35:50 | Object p : Object | provenance | | +| Patterns.cs:35:35:35:52 | [no-match] { ... } : null [property Prop] : Object | Patterns.cs:35:35:35:52 | [no-match] { ... } : null [property Prop] : Object | provenance | | +| Patterns.cs:35:35:35:52 | [no-match] { ... } : null [property Prop] : Object | Patterns.cs:35:35:35:52 | [no-match] { ... } : null [property Prop] : Object | provenance | | +| Patterns.cs:35:35:35:52 | [no-match] { ... } : null [property Prop] : Object | Patterns.cs:35:43:35:50 | Object p : Object | provenance | | +| Patterns.cs:35:35:35:52 | [no-match] { ... } : null [property Prop] : Object | Patterns.cs:35:43:35:50 | Object p : Object | provenance | | +| Patterns.cs:35:43:35:50 | Object p : Object | Patterns.cs:37:18:37:18 | access to local variable p | provenance | | +| Patterns.cs:35:43:35:50 | Object p : Object | Patterns.cs:37:18:37:18 | access to local variable p | provenance | | +| Patterns.cs:43:13:43:13 | access to local variable o : Object | Patterns.cs:44:45:44:45 | access to local variable o : Object | provenance | | +| Patterns.cs:43:13:43:13 | access to local variable o : Object | Patterns.cs:44:45:44:45 | access to local variable o : Object | provenance | | +| Patterns.cs:43:17:43:33 | call to method Source : Object | Patterns.cs:43:13:43:13 | access to local variable o : Object | provenance | | +| Patterns.cs:43:17:43:33 | call to method Source : Object | Patterns.cs:43:13:43:13 | access to local variable o : Object | provenance | | +| Patterns.cs:44:13:44:13 | access to local variable s : Nested [property Record, property Prop] : Object | Patterns.cs:45:25:45:49 | [match] { ... } : Nested [property Record, property Prop] : Object | provenance | | +| Patterns.cs:44:13:44:13 | access to local variable s : Nested [property Record, property Prop] : Object | Patterns.cs:45:25:45:49 | [match] { ... } : Nested [property Record, property Prop] : Object | provenance | | +| Patterns.cs:44:13:44:13 | access to local variable s : Nested [property Record, property Prop] : Object | Patterns.cs:45:25:45:49 | [no-match] { ... } : Nested [property Record, property Prop] : Object | provenance | | +| Patterns.cs:44:13:44:13 | access to local variable s : Nested [property Record, property Prop] : Object | Patterns.cs:45:25:45:49 | [no-match] { ... } : Nested [property Record, property Prop] : Object | provenance | | +| Patterns.cs:44:17:44:47 | object creation of type Nested : Nested [property Record, property Prop] : Object | Patterns.cs:44:13:44:13 | access to local variable s : Nested [property Record, property Prop] : Object | provenance | | +| Patterns.cs:44:17:44:47 | object creation of type Nested : Nested [property Record, property Prop] : Object | Patterns.cs:44:13:44:13 | access to local variable s : Nested [property Record, property Prop] : Object | provenance | | +| Patterns.cs:44:28:44:46 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | Patterns.cs:5:41:5:46 | Record : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:44:28:44:46 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | Patterns.cs:5:41:5:46 | Record : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:44:28:44:46 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | Patterns.cs:44:17:44:47 | object creation of type Nested : Nested [property Record, property Prop] : Object | provenance | | +| Patterns.cs:44:28:44:46 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | Patterns.cs:44:17:44:47 | object creation of type Nested : Nested [property Record, property Prop] : Object | provenance | | +| Patterns.cs:44:45:44:45 | access to local variable o : Object | Patterns.cs:3:41:3:44 | Prop : Object | provenance | | +| Patterns.cs:44:45:44:45 | access to local variable o : Object | Patterns.cs:3:41:3:44 | Prop : Object | provenance | | +| Patterns.cs:44:45:44:45 | access to local variable o : Object | Patterns.cs:44:28:44:46 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:44:45:44:45 | access to local variable o : Object | Patterns.cs:44:28:44:46 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | provenance | | +| Patterns.cs:45:25:45:49 | [match] { ... } : Nested [property Record, property Prop] : Object | Patterns.cs:45:27:45:32 | [match] { ... } : null [property Prop] : Object | provenance | | +| Patterns.cs:45:25:45:49 | [match] { ... } : Nested [property Record, property Prop] : Object | Patterns.cs:45:27:45:32 | [match] { ... } : null [property Prop] : Object | provenance | | +| Patterns.cs:45:25:45:49 | [no-match] { ... } : Nested [property Record, property Prop] : Object | Patterns.cs:45:27:45:32 | [no-match] { ... } : null [property Prop] : Object | provenance | | +| Patterns.cs:45:25:45:49 | [no-match] { ... } : Nested [property Record, property Prop] : Object | Patterns.cs:45:27:45:32 | [no-match] { ... } : null [property Prop] : Object | provenance | | +| Patterns.cs:45:27:45:32 | [match] { ... } : null [property Prop] : Object | Patterns.cs:45:40:45:47 | Object p : Object | provenance | | +| Patterns.cs:45:27:45:32 | [match] { ... } : null [property Prop] : Object | Patterns.cs:45:40:45:47 | Object p : Object | provenance | | +| Patterns.cs:45:27:45:32 | [no-match] { ... } : null [property Prop] : Object | Patterns.cs:45:40:45:47 | Object p : Object | provenance | | +| Patterns.cs:45:27:45:32 | [no-match] { ... } : null [property Prop] : Object | Patterns.cs:45:40:45:47 | Object p : Object | provenance | | +| Patterns.cs:45:40:45:47 | Object p : Object | Patterns.cs:47:18:47:18 | access to local variable p | provenance | | +| Patterns.cs:45:40:45:47 | Object p : Object | Patterns.cs:47:18:47:18 | access to local variable p | provenance | | nodes | Patterns.cs:3:21:3:32 | this [Return] : RecordClass2 [property Prop] : Object | semmle.label | this [Return] : RecordClass2 [property Prop] : Object | | Patterns.cs:3:21:3:32 | this [Return] : RecordClass2 [property Prop] : Object | semmle.label | this [Return] : RecordClass2 [property Prop] : Object | | Patterns.cs:3:41:3:44 | Prop : Object | semmle.label | Prop : Object | | Patterns.cs:3:41:3:44 | Prop : Object | semmle.label | Prop : Object | +| Patterns.cs:5:21:5:26 | this [Return] : Nested [property Record, property Prop] : Object | semmle.label | this [Return] : Nested [property Record, property Prop] : Object | +| Patterns.cs:5:21:5:26 | this [Return] : Nested [property Record, property Prop] : Object | semmle.label | this [Return] : Nested [property Record, property Prop] : Object | +| Patterns.cs:5:41:5:46 | Record : RecordClass2 [property Prop] : Object | semmle.label | Record : RecordClass2 [property Prop] : Object | +| Patterns.cs:5:41:5:46 | Record : RecordClass2 [property Prop] : Object | semmle.label | Record : RecordClass2 [property Prop] : Object | | Patterns.cs:11:13:11:13 | access to local variable o : Object | semmle.label | access to local variable o : Object | | Patterns.cs:11:13:11:13 | access to local variable o : Object | semmle.label | access to local variable o : Object | | Patterns.cs:11:17:11:33 | call to method Source : Object | semmle.label | call to method Source : Object | @@ -49,8 +123,10 @@ nodes | Patterns.cs:12:17:12:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | semmle.label | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | | Patterns.cs:12:34:12:34 | access to local variable o : Object | semmle.label | access to local variable o : Object | | Patterns.cs:12:34:12:34 | access to local variable o : Object | semmle.label | access to local variable o : Object | -| Patterns.cs:13:13:13:13 | access to local variable r : RecordClass2 [property Prop] : Object | semmle.label | access to local variable r : RecordClass2 [property Prop] : Object | -| Patterns.cs:13:13:13:13 | access to local variable r : RecordClass2 [property Prop] : Object | semmle.label | access to local variable r : RecordClass2 [property Prop] : Object | +| Patterns.cs:13:31:13:48 | [match] { ... } : RecordClass2 [property Prop] : Object | semmle.label | [match] { ... } : RecordClass2 [property Prop] : Object | +| Patterns.cs:13:31:13:48 | [match] { ... } : RecordClass2 [property Prop] : Object | semmle.label | [match] { ... } : RecordClass2 [property Prop] : Object | +| Patterns.cs:13:31:13:48 | [no-match] { ... } : RecordClass2 [property Prop] : Object | semmle.label | [no-match] { ... } : RecordClass2 [property Prop] : Object | +| Patterns.cs:13:31:13:48 | [no-match] { ... } : RecordClass2 [property Prop] : Object | semmle.label | [no-match] { ... } : RecordClass2 [property Prop] : Object | | Patterns.cs:13:39:13:46 | Object p : Object | semmle.label | Object p : Object | | Patterns.cs:13:39:13:46 | Object p : Object | semmle.label | Object p : Object | | Patterns.cs:15:18:15:18 | access to local variable p | semmle.label | access to local variable p | @@ -65,20 +141,86 @@ nodes | Patterns.cs:22:17:22:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | semmle.label | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | | Patterns.cs:22:34:22:34 | access to local variable o : Object | semmle.label | access to local variable o : Object | | Patterns.cs:22:34:22:34 | access to local variable o : Object | semmle.label | access to local variable o : Object | -| Patterns.cs:23:17:23:17 | access to local variable r : RecordClass2 [property Prop] : Object | semmle.label | access to local variable r : RecordClass2 [property Prop] : Object | -| Patterns.cs:23:17:23:17 | access to local variable r : RecordClass2 [property Prop] : Object | semmle.label | access to local variable r : RecordClass2 [property Prop] : Object | +| Patterns.cs:25:31:25:48 | [match] { ... } : RecordClass2 [property Prop] : Object | semmle.label | [match] { ... } : RecordClass2 [property Prop] : Object | +| Patterns.cs:25:31:25:48 | [match] { ... } : RecordClass2 [property Prop] : Object | semmle.label | [match] { ... } : RecordClass2 [property Prop] : Object | +| Patterns.cs:25:31:25:48 | [no-match] { ... } : RecordClass2 [property Prop] : Object | semmle.label | [no-match] { ... } : RecordClass2 [property Prop] : Object | +| Patterns.cs:25:31:25:48 | [no-match] { ... } : RecordClass2 [property Prop] : Object | semmle.label | [no-match] { ... } : RecordClass2 [property Prop] : Object | | Patterns.cs:25:39:25:46 | Object p : Object | semmle.label | Object p : Object | | Patterns.cs:25:39:25:46 | Object p : Object | semmle.label | Object p : Object | | Patterns.cs:26:22:26:22 | access to local variable p | semmle.label | access to local variable p | | Patterns.cs:26:22:26:22 | access to local variable p | semmle.label | access to local variable p | +| Patterns.cs:33:13:33:13 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| Patterns.cs:33:13:33:13 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| Patterns.cs:33:17:33:33 | call to method Source : Object | semmle.label | call to method Source : Object | +| Patterns.cs:33:17:33:33 | call to method Source : Object | semmle.label | call to method Source : Object | +| Patterns.cs:34:13:34:13 | access to local variable s : Nested [property Record, property Prop] : Object | semmle.label | access to local variable s : Nested [property Record, property Prop] : Object | +| Patterns.cs:34:13:34:13 | access to local variable s : Nested [property Record, property Prop] : Object | semmle.label | access to local variable s : Nested [property Record, property Prop] : Object | +| Patterns.cs:34:17:34:47 | object creation of type Nested : Nested [property Record, property Prop] : Object | semmle.label | object creation of type Nested : Nested [property Record, property Prop] : Object | +| Patterns.cs:34:17:34:47 | object creation of type Nested : Nested [property Record, property Prop] : Object | semmle.label | object creation of type Nested : Nested [property Record, property Prop] : Object | +| Patterns.cs:34:28:34:46 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | semmle.label | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | +| Patterns.cs:34:28:34:46 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | semmle.label | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | +| Patterns.cs:34:45:34:45 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| Patterns.cs:34:45:34:45 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| Patterns.cs:35:25:35:54 | [match] { ... } : Nested [property Record, property Prop] : Object | semmle.label | [match] { ... } : Nested [property Record, property Prop] : Object | +| Patterns.cs:35:25:35:54 | [match] { ... } : Nested [property Record, property Prop] : Object | semmle.label | [match] { ... } : Nested [property Record, property Prop] : Object | +| Patterns.cs:35:25:35:54 | [no-match] { ... } : Nested [property Record, property Prop] : Object | semmle.label | [no-match] { ... } : Nested [property Record, property Prop] : Object | +| Patterns.cs:35:25:35:54 | [no-match] { ... } : Nested [property Record, property Prop] : Object | semmle.label | [no-match] { ... } : Nested [property Record, property Prop] : Object | +| Patterns.cs:35:35:35:52 | [match] { ... } : null [property Prop] : Object | semmle.label | [match] { ... } : null [property Prop] : Object | +| Patterns.cs:35:35:35:52 | [match] { ... } : null [property Prop] : Object | semmle.label | [match] { ... } : null [property Prop] : Object | +| Patterns.cs:35:35:35:52 | [match] { ... } : null [property Prop] : Object | semmle.label | [match] { ... } : null [property Prop] : Object | +| Patterns.cs:35:35:35:52 | [match] { ... } : null [property Prop] : Object | semmle.label | [match] { ... } : null [property Prop] : Object | +| Patterns.cs:35:35:35:52 | [no-match] { ... } : null [property Prop] : Object | semmle.label | [no-match] { ... } : null [property Prop] : Object | +| Patterns.cs:35:35:35:52 | [no-match] { ... } : null [property Prop] : Object | semmle.label | [no-match] { ... } : null [property Prop] : Object | +| Patterns.cs:35:35:35:52 | [no-match] { ... } : null [property Prop] : Object | semmle.label | [no-match] { ... } : null [property Prop] : Object | +| Patterns.cs:35:35:35:52 | [no-match] { ... } : null [property Prop] : Object | semmle.label | [no-match] { ... } : null [property Prop] : Object | +| Patterns.cs:35:43:35:50 | Object p : Object | semmle.label | Object p : Object | +| Patterns.cs:35:43:35:50 | Object p : Object | semmle.label | Object p : Object | +| Patterns.cs:37:18:37:18 | access to local variable p | semmle.label | access to local variable p | +| Patterns.cs:37:18:37:18 | access to local variable p | semmle.label | access to local variable p | +| Patterns.cs:43:13:43:13 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| Patterns.cs:43:13:43:13 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| Patterns.cs:43:17:43:33 | call to method Source : Object | semmle.label | call to method Source : Object | +| Patterns.cs:43:17:43:33 | call to method Source : Object | semmle.label | call to method Source : Object | +| Patterns.cs:44:13:44:13 | access to local variable s : Nested [property Record, property Prop] : Object | semmle.label | access to local variable s : Nested [property Record, property Prop] : Object | +| Patterns.cs:44:13:44:13 | access to local variable s : Nested [property Record, property Prop] : Object | semmle.label | access to local variable s : Nested [property Record, property Prop] : Object | +| Patterns.cs:44:17:44:47 | object creation of type Nested : Nested [property Record, property Prop] : Object | semmle.label | object creation of type Nested : Nested [property Record, property Prop] : Object | +| Patterns.cs:44:17:44:47 | object creation of type Nested : Nested [property Record, property Prop] : Object | semmle.label | object creation of type Nested : Nested [property Record, property Prop] : Object | +| Patterns.cs:44:28:44:46 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | semmle.label | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | +| Patterns.cs:44:28:44:46 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | semmle.label | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | +| Patterns.cs:44:45:44:45 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| Patterns.cs:44:45:44:45 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| Patterns.cs:45:25:45:49 | [match] { ... } : Nested [property Record, property Prop] : Object | semmle.label | [match] { ... } : Nested [property Record, property Prop] : Object | +| Patterns.cs:45:25:45:49 | [match] { ... } : Nested [property Record, property Prop] : Object | semmle.label | [match] { ... } : Nested [property Record, property Prop] : Object | +| Patterns.cs:45:25:45:49 | [no-match] { ... } : Nested [property Record, property Prop] : Object | semmle.label | [no-match] { ... } : Nested [property Record, property Prop] : Object | +| Patterns.cs:45:25:45:49 | [no-match] { ... } : Nested [property Record, property Prop] : Object | semmle.label | [no-match] { ... } : Nested [property Record, property Prop] : Object | +| Patterns.cs:45:27:45:32 | [match] { ... } : null [property Prop] : Object | semmle.label | [match] { ... } : null [property Prop] : Object | +| Patterns.cs:45:27:45:32 | [match] { ... } : null [property Prop] : Object | semmle.label | [match] { ... } : null [property Prop] : Object | +| Patterns.cs:45:27:45:32 | [no-match] { ... } : null [property Prop] : Object | semmle.label | [no-match] { ... } : null [property Prop] : Object | +| Patterns.cs:45:27:45:32 | [no-match] { ... } : null [property Prop] : Object | semmle.label | [no-match] { ... } : null [property Prop] : Object | +| Patterns.cs:45:40:45:47 | Object p : Object | semmle.label | Object p : Object | +| Patterns.cs:45:40:45:47 | Object p : Object | semmle.label | Object p : Object | +| Patterns.cs:47:18:47:18 | access to local variable p | semmle.label | access to local variable p | +| Patterns.cs:47:18:47:18 | access to local variable p | semmle.label | access to local variable p | subpaths | Patterns.cs:12:34:12:34 | access to local variable o : Object | Patterns.cs:3:41:3:44 | Prop : Object | Patterns.cs:3:21:3:32 | this [Return] : RecordClass2 [property Prop] : Object | Patterns.cs:12:17:12:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | | Patterns.cs:12:34:12:34 | access to local variable o : Object | Patterns.cs:3:41:3:44 | Prop : Object | Patterns.cs:3:21:3:32 | this [Return] : RecordClass2 [property Prop] : Object | Patterns.cs:12:17:12:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | | Patterns.cs:22:34:22:34 | access to local variable o : Object | Patterns.cs:3:41:3:44 | Prop : Object | Patterns.cs:3:21:3:32 | this [Return] : RecordClass2 [property Prop] : Object | Patterns.cs:22:17:22:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | | Patterns.cs:22:34:22:34 | access to local variable o : Object | Patterns.cs:3:41:3:44 | Prop : Object | Patterns.cs:3:21:3:32 | this [Return] : RecordClass2 [property Prop] : Object | Patterns.cs:22:17:22:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | +| Patterns.cs:34:28:34:46 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | Patterns.cs:5:41:5:46 | Record : RecordClass2 [property Prop] : Object | Patterns.cs:5:21:5:26 | this [Return] : Nested [property Record, property Prop] : Object | Patterns.cs:34:17:34:47 | object creation of type Nested : Nested [property Record, property Prop] : Object | +| Patterns.cs:34:28:34:46 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | Patterns.cs:5:41:5:46 | Record : RecordClass2 [property Prop] : Object | Patterns.cs:5:21:5:26 | this [Return] : Nested [property Record, property Prop] : Object | Patterns.cs:34:17:34:47 | object creation of type Nested : Nested [property Record, property Prop] : Object | +| Patterns.cs:34:45:34:45 | access to local variable o : Object | Patterns.cs:3:41:3:44 | Prop : Object | Patterns.cs:3:21:3:32 | this [Return] : RecordClass2 [property Prop] : Object | Patterns.cs:34:28:34:46 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | +| Patterns.cs:34:45:34:45 | access to local variable o : Object | Patterns.cs:3:41:3:44 | Prop : Object | Patterns.cs:3:21:3:32 | this [Return] : RecordClass2 [property Prop] : Object | Patterns.cs:34:28:34:46 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | +| Patterns.cs:44:28:44:46 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | Patterns.cs:5:41:5:46 | Record : RecordClass2 [property Prop] : Object | Patterns.cs:5:21:5:26 | this [Return] : Nested [property Record, property Prop] : Object | Patterns.cs:44:17:44:47 | object creation of type Nested : Nested [property Record, property Prop] : Object | +| Patterns.cs:44:28:44:46 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | Patterns.cs:5:41:5:46 | Record : RecordClass2 [property Prop] : Object | Patterns.cs:5:21:5:26 | this [Return] : Nested [property Record, property Prop] : Object | Patterns.cs:44:17:44:47 | object creation of type Nested : Nested [property Record, property Prop] : Object | +| Patterns.cs:44:45:44:45 | access to local variable o : Object | Patterns.cs:3:41:3:44 | Prop : Object | Patterns.cs:3:21:3:32 | this [Return] : RecordClass2 [property Prop] : Object | Patterns.cs:44:28:44:46 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | +| Patterns.cs:44:45:44:45 | access to local variable o : Object | Patterns.cs:3:41:3:44 | Prop : Object | Patterns.cs:3:21:3:32 | this [Return] : RecordClass2 [property Prop] : Object | Patterns.cs:44:28:44:46 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | testFailures #select | Patterns.cs:15:18:15:18 | access to local variable p | Patterns.cs:11:17:11:33 | call to method Source : Object | Patterns.cs:15:18:15:18 | access to local variable p | $@ | Patterns.cs:11:17:11:33 | call to method Source : Object | call to method Source : Object | | Patterns.cs:15:18:15:18 | access to local variable p | Patterns.cs:11:17:11:33 | call to method Source : Object | Patterns.cs:15:18:15:18 | access to local variable p | $@ | Patterns.cs:11:17:11:33 | call to method Source : Object | call to method Source : Object | | Patterns.cs:26:22:26:22 | access to local variable p | Patterns.cs:21:17:21:33 | call to method Source : Object | Patterns.cs:26:22:26:22 | access to local variable p | $@ | Patterns.cs:21:17:21:33 | call to method Source : Object | call to method Source : Object | | Patterns.cs:26:22:26:22 | access to local variable p | Patterns.cs:21:17:21:33 | call to method Source : Object | Patterns.cs:26:22:26:22 | access to local variable p | $@ | Patterns.cs:21:17:21:33 | call to method Source : Object | call to method Source : Object | +| Patterns.cs:37:18:37:18 | access to local variable p | Patterns.cs:33:17:33:33 | call to method Source : Object | Patterns.cs:37:18:37:18 | access to local variable p | $@ | Patterns.cs:33:17:33:33 | call to method Source : Object | call to method Source : Object | +| Patterns.cs:37:18:37:18 | access to local variable p | Patterns.cs:33:17:33:33 | call to method Source : Object | Patterns.cs:37:18:37:18 | access to local variable p | $@ | Patterns.cs:33:17:33:33 | call to method Source : Object | call to method Source : Object | +| Patterns.cs:47:18:47:18 | access to local variable p | Patterns.cs:43:17:43:33 | call to method Source : Object | Patterns.cs:47:18:47:18 | access to local variable p | $@ | Patterns.cs:43:17:43:33 | call to method Source : Object | call to method Source : Object | +| Patterns.cs:47:18:47:18 | access to local variable p | Patterns.cs:43:17:43:33 | call to method Source : Object | Patterns.cs:47:18:47:18 | access to local variable p | $@ | Patterns.cs:43:17:43:33 | call to method Source : Object | call to method Source : Object | diff --git a/csharp/ql/test/library-tests/dataflow/patterns/Patterns.cs b/csharp/ql/test/library-tests/dataflow/patterns/Patterns.cs index 9b760eee90f0..58ba3c05238f 100644 --- a/csharp/ql/test/library-tests/dataflow/patterns/Patterns.cs +++ b/csharp/ql/test/library-tests/dataflow/patterns/Patterns.cs @@ -34,7 +34,7 @@ private void M3() var s = new Nested(new RecordClass2(o)); if (s is Nested { Record: { Prop: object p } }) { - Sink(p); // $ MISSING: hasValueFlow=3 + Sink(p); // $ hasValueFlow=3 } } @@ -44,7 +44,7 @@ private void M4() var s = new Nested(new RecordClass2(o)); if (s is Nested { Record.Prop: object p }) { - Sink(p); // $ MISSING: hasValueFlow=4 + Sink(p); // $ hasValueFlow=4 } } From 9595fc21aceaca89c4579093678ee154dc69a434 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 18 Feb 2025 14:28:16 +0100 Subject: [PATCH 06/12] C#: Some more precise flow. --- .../ql/lib/semmle/code/csharp/Assignable.qll | 27 ++++++++++-- .../semmle/code/csharp/dataflow/Nullness.qll | 2 +- .../dataflow/internal/DataFlowPrivate.qll | 41 +++++++++---------- 3 files changed, 44 insertions(+), 26 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/Assignable.qll b/csharp/ql/lib/semmle/code/csharp/Assignable.qll index bcc592bf91bd..b986ac8af2a0 100644 --- a/csharp/ql/lib/semmle/code/csharp/Assignable.qll +++ b/csharp/ql/lib/semmle/code/csharp/Assignable.qll @@ -286,6 +286,9 @@ module AssignableInternal { /** Holds if the local variable definition is at the top level of the pattern. */ predicate isTopLevel() { this = pm.getPattern().(BindingPatternExpr).getVariableDeclExpr() } + /** Holds of this local variable definition is a part of a tuple pattern. */ + predicate isInTuple() { this.getParent() instanceof TuplePatternExpr } + /** Gets the pattern match that this local variable declaration (pattern) belongs to. */ PatternMatch getMatch() { result = pm } } @@ -720,12 +723,30 @@ module AssignableDefinitions { /** Gets the underlying local variable declaration. */ LocalVariableDeclExpr getDeclaration() { result = lvpd } - override Expr getSource() { this.isTopLevel() and result = this.getMatch().getExpr() } + override Expr getSource() { result = this.getMatch().getExpr() } override string toString() { result = this.getDeclaration().toString() } + } - /** Holds if the local variable definition is at the top level of the pattern. */ - predicate isTopLevel() { lvpd.isTopLevel() } + /** + * A local variable definition at the top level of a pattern. + */ + class TopLevelPatternDefinition extends PatternDefinition { + TopLevelPatternDefinition() { lvpd.isTopLevel() } + } + + /** + * A local variable definition in a tuple pattern. + */ + class TuplePatternDefinition extends PatternDefinition { + TuplePatternDefinition() { lvpd.isInTuple() } + } + + /** + * A local variable definition in a property pattern. + */ + class PropertyPatternDefinition extends PatternDefinition { + PropertyPatternDefinition() { lvpd.getParent() instanceof PropertyPatternExpr } } /** diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/Nullness.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/Nullness.qll index a990455f4307..65011db445f6 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/Nullness.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/Nullness.qll @@ -104,7 +104,7 @@ private predicate nonNullDef(Ssa::ExplicitDefinition def) { def.getADefinition().getSource() instanceof NonNullExpr or exists(AssignableDefinition ad | ad = def.getADefinition() | - ad instanceof AssignableDefinitions::PatternDefinition + ad instanceof AssignableDefinitions::TopLevelPatternDefinition or ad = any(AssignableDefinitions::LocalVariableDefinition d | 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 0bb1472ccc1d..6b210dc46ef3 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -640,20 +640,22 @@ module LocalFlow { def.getSource() = e and ( scope = def.getExpr() and - isSuccessor = true + isSuccessor = true and + ( + not def instanceof AssignableDefinitions::PatternDefinition or + def instanceof AssignableDefinitions::TopLevelPatternDefinition + ) + or + scope = def.(AssignableDefinitions::TopLevelPatternDefinition).getMatch().(IsExpr) and + isSuccessor = false or - exists(AssignableDefinitions::PatternDefinition def0 | def = def0 and def0.isTopLevel() | - scope = def0.getMatch().(IsExpr) and - isSuccessor = false + exists(Switch s | + s.getACase() = def.(AssignableDefinitions::TopLevelPatternDefinition).getMatch() and + isSuccessor = true + | + scope = s.getExpr() or - exists(Switch s | - s.getACase() = def0.getMatch() and - isSuccessor = true - | - scope = s.getExpr() - or - scope = s.getACase() - ) + scope = s.getACase() ) ) or @@ -661,10 +663,7 @@ module LocalFlow { scope = def.getExpr() and exactScope = false and isSuccessor = false and - def = - any(AssignableDefinitions::PatternDefinition apd | - e = apd.getDeclaration() and not apd.isTopLevel() - ) + e = def.(AssignableDefinitions::PropertyPatternDefinition).getDeclaration() } } @@ -2508,7 +2507,7 @@ private class ReadStepConfiguration extends ControlFlowReachabilityConfiguration or scope = any(TuplePatternExpr te | - te.getAnArgument() = defTo.(AssignableDefinitions::PatternDefinition).getDeclaration() and + te.getAnArgument() = defTo.(AssignableDefinitions::TuplePatternDefinition).getDeclaration() and e = te and exactScope = false and isSuccessor = false @@ -2558,7 +2557,7 @@ private predicate readContentStep(Node node1, Content c, Node node2) { or // item = variable in node1 = (..., variable, ...) in a case/is var (..., ...) te = any(TuplePatternExpr pe).getAChildExpr*() and - exists(AssignableDefinitions::PatternDefinition lvd | + exists(AssignableDefinitions::TuplePatternDefinition lvd | node2.(AssignableDefinitionNode).getDefinition() = lvd and lvd.getDeclaration() = item and hasNodePath(x, node1, node2) @@ -2990,10 +2989,8 @@ class CastNode extends Node { CastNode() { this.asExpr() instanceof Cast or - this.(AssignableDefinitionNode) - .getDefinition() - .(AssignableDefinitions::PatternDefinition) - .isTopLevel() + this.(AssignableDefinitionNode).getDefinition() instanceof + AssignableDefinitions::TopLevelPatternDefinition } } From 9e35c01147bd1fdfabb856f79981a4a02a614797 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 18 Feb 2025 14:35:41 +0100 Subject: [PATCH 07/12] C#: Update expected test output. --- .../library-tests/csharp7/LocalTaintFlow.expected | 14 ++++++++++++++ .../dataflow/local/DataFlowStep.expected | 4 ++++ .../dataflow/local/TaintTrackingStep.expected | 4 ++++ .../dataflow/tuples/DataFlowStep.expected | 13 +++---------- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected index 4a16e2491dfe..8fef5ce69f6f 100644 --- a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected +++ b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected @@ -241,6 +241,7 @@ | CSharp7.cs:232:16:232:23 | SSA def(o) | CSharp7.cs:233:13:233:13 | access to local variable o | | CSharp7.cs:232:20:232:23 | null | CSharp7.cs:232:16:232:16 | access to local variable o | | CSharp7.cs:233:13:233:13 | access to local variable o | CSharp7.cs:233:18:233:23 | Int32 i1 | +| CSharp7.cs:233:13:233:13 | access to local variable o | CSharp7.cs:233:18:233:23 | Int32 i1 | | CSharp7.cs:233:13:233:13 | access to local variable o | CSharp7.cs:235:13:235:42 | [input] SSA phi read(o) | | CSharp7.cs:233:13:233:13 | access to local variable o | CSharp7.cs:237:18:237:18 | access to local variable o | | CSharp7.cs:233:13:233:23 | [false] ... is ... | CSharp7.cs:233:13:233:33 | [false] ... && ... | @@ -256,6 +257,7 @@ | CSharp7.cs:235:33:235:36 | "int " | CSharp7.cs:235:31:235:41 | $"..." | | CSharp7.cs:235:38:235:39 | access to local variable i1 | CSharp7.cs:235:31:235:41 | $"..." | | CSharp7.cs:237:18:237:18 | access to local variable o | CSharp7.cs:237:23:237:31 | String s1 | +| CSharp7.cs:237:18:237:18 | access to local variable o | CSharp7.cs:237:23:237:31 | String s1 | | CSharp7.cs:237:18:237:18 | access to local variable o | CSharp7.cs:239:13:239:45 | [input] SSA phi read(o) | | CSharp7.cs:237:18:237:18 | access to local variable o | CSharp7.cs:241:18:241:18 | access to local variable o | | CSharp7.cs:237:23:237:31 | SSA def(s1) | CSharp7.cs:239:41:239:42 | access to local variable s1 | @@ -263,23 +265,34 @@ | CSharp7.cs:239:13:239:45 | [input] SSA phi read(o) | CSharp7.cs:248:9:274:9 | SSA phi read(o) | | CSharp7.cs:239:33:239:39 | "string " | CSharp7.cs:239:31:239:44 | $"..." | | CSharp7.cs:239:41:239:42 | access to local variable s1 | CSharp7.cs:239:31:239:44 | $"..." | +| CSharp7.cs:241:18:241:18 | access to local variable o | CSharp7.cs:241:23:241:28 | access to type Double | | CSharp7.cs:241:18:241:18 | access to local variable o | CSharp7.cs:242:9:243:9 | [input] SSA phi read(o) | | CSharp7.cs:241:18:241:18 | access to local variable o | CSharp7.cs:244:18:244:18 | access to local variable o | | CSharp7.cs:242:9:243:9 | [input] SSA phi read(o) | CSharp7.cs:248:9:274:9 | SSA phi read(o) | | CSharp7.cs:244:18:244:18 | access to local variable o | CSharp7.cs:244:18:244:28 | [input] SSA phi read(o) | | CSharp7.cs:244:18:244:18 | access to local variable o | CSharp7.cs:244:23:244:28 | Object v1 | +| CSharp7.cs:244:18:244:18 | access to local variable o | CSharp7.cs:244:23:244:28 | Object v1 | | CSharp7.cs:244:18:244:18 | access to local variable o | CSharp7.cs:245:9:246:9 | [input] SSA phi read(o) | | CSharp7.cs:244:18:244:28 | [input] SSA phi read(o) | CSharp7.cs:248:9:274:9 | SSA phi read(o) | | CSharp7.cs:245:9:246:9 | [input] SSA phi read(o) | CSharp7.cs:248:9:274:9 | SSA phi read(o) | | CSharp7.cs:248:9:274:9 | SSA phi read(o) | CSharp7.cs:248:17:248:17 | access to local variable o | +| CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:250:18:250:22 | "xyz" | +| CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:252:18:252:19 | "" | +| CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:254:18:254:20 | "x" | | CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:254:27:254:27 | access to local variable o | | CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:257:18:257:23 | Int32 i2 | +| CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:257:18:257:23 | Int32 i2 | +| CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:260:18:260:23 | Int32 i3 | | CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:260:18:260:23 | Int32 i3 | | CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:263:18:263:26 | String s2 | +| CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:263:18:263:26 | String s2 | +| CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:266:18:266:23 | access to type Double | +| CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:269:18:269:23 | Object v2 | | CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:269:18:269:23 | Object v2 | | CSharp7.cs:252:26:252:26 | 1 | CSharp7.cs:252:26:252:30 | ... < ... | | CSharp7.cs:252:30:252:30 | 2 | CSharp7.cs:252:26:252:30 | ... < ... | | CSharp7.cs:254:27:254:27 | access to local variable o | CSharp7.cs:254:32:254:40 | String s4 | +| CSharp7.cs:254:27:254:27 | access to local variable o | CSharp7.cs:254:32:254:40 | String s4 | | CSharp7.cs:254:32:254:40 | SSA def(s4) | CSharp7.cs:255:40:255:41 | access to local variable s4 | | CSharp7.cs:254:32:254:40 | String s4 | CSharp7.cs:254:32:254:40 | SSA def(s4) | | CSharp7.cs:255:37:255:38 | "x " | CSharp7.cs:255:35:255:43 | $"..." | @@ -321,6 +334,7 @@ | CSharp7.cs:297:25:297:30 | ... < ... | CSharp7.cs:297:25:297:44 | [false] ... && ... | | CSharp7.cs:297:25:297:30 | ... < ... | CSharp7.cs:297:25:297:44 | [true] ... && ... | | CSharp7.cs:297:35:297:35 | access to local variable x | CSharp7.cs:297:40:297:44 | Int32 y | +| CSharp7.cs:297:35:297:35 | access to local variable x | CSharp7.cs:297:40:297:44 | Int32 y | | CSharp7.cs:297:35:297:35 | access to local variable x | CSharp7.cs:297:49:297:49 | access to local variable x | | CSharp7.cs:297:35:297:44 | [false] ... is ... | CSharp7.cs:297:25:297:44 | [false] ... && ... | | CSharp7.cs:297:35:297:44 | [true] ... is ... | CSharp7.cs:297:25:297:44 | [true] ... && ... | diff --git a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected index a8b0a4d0cd55..fba6a256048d 100644 --- a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected @@ -464,17 +464,21 @@ | LocalDataFlow.cs:286:15:286:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | | LocalDataFlow.cs:286:15:286:22 | access to local variable nonSink0 | LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | | LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | LocalDataFlow.cs:289:23:289:35 | String sink71 | +| LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | LocalDataFlow.cs:289:23:289:35 | String sink71 | | LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | LocalDataFlow.cs:297:17:297:22 | access to local variable sink70 | | LocalDataFlow.cs:289:23:289:35 | SSA def(sink71) | LocalDataFlow.cs:290:19:290:24 | access to local variable sink71 | | LocalDataFlow.cs:289:23:289:35 | String sink71 | LocalDataFlow.cs:289:23:289:35 | SSA def(sink71) | | LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | LocalDataFlow.cs:293:25:293:40 | String nonSink16 | +| LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | LocalDataFlow.cs:293:25:293:40 | String nonSink16 | | LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | | LocalDataFlow.cs:293:25:293:40 | SSA def(nonSink16) | LocalDataFlow.cs:294:19:294:27 | access to local variable nonSink16 | | LocalDataFlow.cs:293:25:293:40 | String nonSink16 | LocalDataFlow.cs:293:25:293:40 | SSA def(nonSink16) | | LocalDataFlow.cs:297:17:297:22 | access to local variable sink70 | LocalDataFlow.cs:299:18:299:30 | String sink72 | +| LocalDataFlow.cs:297:17:297:22 | access to local variable sink70 | LocalDataFlow.cs:299:18:299:30 | String sink72 | | LocalDataFlow.cs:299:18:299:30 | SSA def(sink72) | LocalDataFlow.cs:300:23:300:28 | access to local variable sink72 | | LocalDataFlow.cs:299:18:299:30 | String sink72 | LocalDataFlow.cs:299:18:299:30 | SSA def(sink72) | | LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | LocalDataFlow.cs:307:18:307:33 | String nonSink17 | +| LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | LocalDataFlow.cs:307:18:307:33 | String nonSink17 | | LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | LocalDataFlow.cs:313:22:313:29 | access to local variable nonSink0 | | LocalDataFlow.cs:307:18:307:33 | SSA def(nonSink17) | LocalDataFlow.cs:308:23:308:31 | access to local variable nonSink17 | | LocalDataFlow.cs:307:18:307:33 | String nonSink17 | LocalDataFlow.cs:307:18:307:33 | SSA def(nonSink17) | diff --git a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected index ff7d8b0f6ba2..5af2f3e2ced1 100644 --- a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected @@ -573,17 +573,21 @@ | LocalDataFlow.cs:286:15:286:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | | LocalDataFlow.cs:286:15:286:22 | access to local variable nonSink0 | LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | | LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | LocalDataFlow.cs:289:23:289:35 | String sink71 | +| LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | LocalDataFlow.cs:289:23:289:35 | String sink71 | | LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | LocalDataFlow.cs:297:17:297:22 | access to local variable sink70 | | LocalDataFlow.cs:289:23:289:35 | SSA def(sink71) | LocalDataFlow.cs:290:19:290:24 | access to local variable sink71 | | LocalDataFlow.cs:289:23:289:35 | String sink71 | LocalDataFlow.cs:289:23:289:35 | SSA def(sink71) | | LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | LocalDataFlow.cs:293:25:293:40 | String nonSink16 | +| LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | LocalDataFlow.cs:293:25:293:40 | String nonSink16 | | LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | | LocalDataFlow.cs:293:25:293:40 | SSA def(nonSink16) | LocalDataFlow.cs:294:19:294:27 | access to local variable nonSink16 | | LocalDataFlow.cs:293:25:293:40 | String nonSink16 | LocalDataFlow.cs:293:25:293:40 | SSA def(nonSink16) | | LocalDataFlow.cs:297:17:297:22 | access to local variable sink70 | LocalDataFlow.cs:299:18:299:30 | String sink72 | +| LocalDataFlow.cs:297:17:297:22 | access to local variable sink70 | LocalDataFlow.cs:299:18:299:30 | String sink72 | | LocalDataFlow.cs:299:18:299:30 | SSA def(sink72) | LocalDataFlow.cs:300:23:300:28 | access to local variable sink72 | | LocalDataFlow.cs:299:18:299:30 | String sink72 | LocalDataFlow.cs:299:18:299:30 | SSA def(sink72) | | LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | LocalDataFlow.cs:307:18:307:33 | String nonSink17 | +| LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | LocalDataFlow.cs:307:18:307:33 | String nonSink17 | | LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | LocalDataFlow.cs:313:22:313:29 | access to local variable nonSink0 | | LocalDataFlow.cs:307:18:307:33 | SSA def(nonSink17) | LocalDataFlow.cs:308:23:308:31 | access to local variable nonSink17 | | LocalDataFlow.cs:307:18:307:33 | String nonSink17 | LocalDataFlow.cs:307:18:307:33 | SSA def(nonSink17) | diff --git a/csharp/ql/test/library-tests/dataflow/tuples/DataFlowStep.expected b/csharp/ql/test/library-tests/dataflow/tuples/DataFlowStep.expected index 2ad11331e908..aca5fc42c8ff 100644 --- a/csharp/ql/test/library-tests/dataflow/tuples/DataFlowStep.expected +++ b/csharp/ql/test/library-tests/dataflow/tuples/DataFlowStep.expected @@ -106,6 +106,7 @@ | Tuples.cs:59:13:59:32 | SSA def(x) | Tuples.cs:60:17:60:17 | access to local variable x | | Tuples.cs:59:17:59:32 | (..., ...) | Tuples.cs:59:13:59:13 | access to local variable x | | Tuples.cs:60:17:60:17 | access to local variable x | Tuples.cs:62:18:62:57 | (String,(Int32,String),Int32) t | +| Tuples.cs:60:17:60:17 | access to local variable x | Tuples.cs:62:18:62:57 | (String,(Int32,String),Int32) t | | Tuples.cs:60:17:60:17 | access to local variable x | Tuples.cs:67:18:67:35 | (..., ...) | | Tuples.cs:60:17:60:17 | access to local variable x | Tuples.cs:67:18:67:35 | (..., ...) | | Tuples.cs:60:17:60:17 | access to local variable x | Tuples.cs:87:13:87:13 | access to local variable x | @@ -126,13 +127,10 @@ | Tuples.cs:65:22:65:34 | access to field Item1 | Tuples.cs:65:22:65:34 | (...) ... | | Tuples.cs:67:23:67:23 | SSA def(a) | Tuples.cs:68:22:68:22 | access to local variable a | | Tuples.cs:67:23:67:23 | String a | Tuples.cs:67:23:67:23 | SSA def(a) | -| Tuples.cs:67:23:67:23 | String a | Tuples.cs:67:23:67:23 | String a | -| Tuples.cs:67:27:67:27 | Int32 b | Tuples.cs:67:27:67:27 | Int32 b | | Tuples.cs:67:27:67:27 | Int32 b | Tuples.cs:67:27:67:27 | SSA def(b) | | Tuples.cs:67:27:67:27 | SSA def(b) | Tuples.cs:70:22:70:22 | access to local variable b | | Tuples.cs:67:30:67:30 | SSA def(c) | Tuples.cs:69:22:69:22 | access to local variable c | | Tuples.cs:67:30:67:30 | String c | Tuples.cs:67:30:67:30 | SSA def(c) | -| Tuples.cs:67:30:67:30 | String c | Tuples.cs:67:30:67:30 | String c | | Tuples.cs:70:22:70:22 | access to local variable b | Tuples.cs:70:22:70:22 | (...) ... | | Tuples.cs:74:13:74:14 | access to local variable o3 | Tuples.cs:74:13:74:34 | SSA def(o3) | | Tuples.cs:74:13:74:34 | SSA def(o3) | Tuples.cs:78:51:78:52 | access to local variable o3 | @@ -146,17 +144,17 @@ | Tuples.cs:75:13:75:30 | SSA qualifier def(y.Item2.Item2) | Tuples.cs:80:22:80:34 | access to field Item2 | | Tuples.cs:75:17:75:30 | (..., ...) | Tuples.cs:75:13:75:13 | access to local variable y | | Tuples.cs:75:18:75:18 | access to parameter s | Tuples.cs:75:25:75:25 | access to parameter s | +| Tuples.cs:76:17:76:17 | access to local variable y | Tuples.cs:78:18:78:39 | [match] { ... } | +| Tuples.cs:76:17:76:17 | access to local variable y | Tuples.cs:78:18:78:39 | [no-match] { ... } | | Tuples.cs:76:17:76:17 | access to local variable y | Tuples.cs:78:26:78:35 | (..., ...) | | Tuples.cs:76:17:76:17 | access to local variable y | Tuples.cs:79:22:79:22 | access to local variable y | | Tuples.cs:78:19:78:23 | SSA def(a) | Tuples.cs:78:46:78:46 | access to local variable a | | Tuples.cs:78:19:78:23 | String a | Tuples.cs:78:19:78:23 | SSA def(a) | | Tuples.cs:78:19:78:23 | String a | Tuples.cs:78:19:78:23 | String a | -| Tuples.cs:78:31:78:31 | Int32 b | Tuples.cs:78:31:78:31 | Int32 b | | Tuples.cs:78:31:78:31 | Int32 b | Tuples.cs:78:31:78:31 | SSA def(b) | | Tuples.cs:78:31:78:31 | SSA def(b) | Tuples.cs:83:22:83:22 | access to local variable b | | Tuples.cs:78:34:78:34 | SSA def(c) | Tuples.cs:81:22:81:22 | access to local variable c | | Tuples.cs:78:34:78:34 | String c | Tuples.cs:78:34:78:34 | SSA def(c) | -| Tuples.cs:78:34:78:34 | String c | Tuples.cs:78:34:78:34 | String c | | Tuples.cs:79:22:79:22 | [post] access to local variable y | Tuples.cs:80:22:80:22 | access to local variable y | | Tuples.cs:79:22:79:22 | access to local variable y | Tuples.cs:80:22:80:22 | access to local variable y | | Tuples.cs:80:22:80:22 | [post] access to local variable y | Tuples.cs:82:22:82:22 | access to local variable y | @@ -169,13 +167,10 @@ | Tuples.cs:87:13:87:13 | access to local variable x | Tuples.cs:87:18:87:35 | (..., ...) | | Tuples.cs:87:23:87:23 | SSA def(p) | Tuples.cs:89:18:89:18 | access to local variable p | | Tuples.cs:87:23:87:23 | String p | Tuples.cs:87:23:87:23 | SSA def(p) | -| Tuples.cs:87:23:87:23 | String p | Tuples.cs:87:23:87:23 | String p | -| Tuples.cs:87:27:87:27 | Int32 q | Tuples.cs:87:27:87:27 | Int32 q | | Tuples.cs:87:27:87:27 | Int32 q | Tuples.cs:87:27:87:27 | SSA def(q) | | Tuples.cs:87:27:87:27 | SSA def(q) | Tuples.cs:91:18:91:18 | access to local variable q | | Tuples.cs:87:30:87:30 | SSA def(r) | Tuples.cs:90:18:90:18 | access to local variable r | | Tuples.cs:87:30:87:30 | String r | Tuples.cs:87:30:87:30 | SSA def(r) | -| Tuples.cs:87:30:87:30 | String r | Tuples.cs:87:30:87:30 | String r | | Tuples.cs:91:18:91:18 | access to local variable q | Tuples.cs:91:18:91:18 | (...) ... | | Tuples.cs:95:12:95:13 | this | Tuples.cs:95:22:95:22 | this | | Tuples.cs:95:22:95:22 | [post] this | Tuples.cs:95:29:95:29 | this | @@ -200,8 +195,6 @@ | Tuples.cs:107:17:107:17 | access to local variable r | Tuples.cs:109:18:109:27 | (..., ...) | | Tuples.cs:109:23:109:23 | SSA def(x) | Tuples.cs:110:22:110:22 | access to local variable x | | Tuples.cs:109:23:109:23 | String x | Tuples.cs:109:23:109:23 | SSA def(x) | -| Tuples.cs:109:23:109:23 | String x | Tuples.cs:109:23:109:23 | String x | -| Tuples.cs:109:26:109:26 | Int32 y | Tuples.cs:109:26:109:26 | Int32 y | | Tuples.cs:109:26:109:26 | Int32 y | Tuples.cs:109:26:109:26 | SSA def(y) | | Tuples.cs:109:26:109:26 | SSA def(y) | Tuples.cs:111:22:111:22 | access to local variable y | | Tuples.cs:111:22:111:22 | access to local variable y | Tuples.cs:111:22:111:22 | (...) ... | From 945ac9648e4ce4a9b91a165dbb071526af884e23 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 19 Feb 2025 13:49:16 +0100 Subject: [PATCH 08/12] Fixup of tuples test case. --- .../ql/test/library-tests/dataflow/tuples/DataFlowStep.expected | 1 - 1 file changed, 1 deletion(-) diff --git a/csharp/ql/test/library-tests/dataflow/tuples/DataFlowStep.expected b/csharp/ql/test/library-tests/dataflow/tuples/DataFlowStep.expected index aca5fc42c8ff..e8178964106f 100644 --- a/csharp/ql/test/library-tests/dataflow/tuples/DataFlowStep.expected +++ b/csharp/ql/test/library-tests/dataflow/tuples/DataFlowStep.expected @@ -150,7 +150,6 @@ | Tuples.cs:76:17:76:17 | access to local variable y | Tuples.cs:79:22:79:22 | access to local variable y | | Tuples.cs:78:19:78:23 | SSA def(a) | Tuples.cs:78:46:78:46 | access to local variable a | | Tuples.cs:78:19:78:23 | String a | Tuples.cs:78:19:78:23 | SSA def(a) | -| Tuples.cs:78:19:78:23 | String a | Tuples.cs:78:19:78:23 | String a | | Tuples.cs:78:31:78:31 | Int32 b | Tuples.cs:78:31:78:31 | SSA def(b) | | Tuples.cs:78:31:78:31 | SSA def(b) | Tuples.cs:83:22:83:22 | access to local variable b | | Tuples.cs:78:34:78:34 | SSA def(c) | Tuples.cs:81:22:81:22 | access to local variable c | From 368b232e6374f3c6e32efd737ad8f625bf41010e Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 20 Feb 2025 13:10:49 +0100 Subject: [PATCH 09/12] C#: Remove the no-match steps (they occur due to control flow splitting). --- .../code/csharp/controlflow/ControlFlowGraph.qll | 7 +++++++ .../code/csharp/dataflow/internal/DataFlowPrivate.qll | 11 +++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowGraph.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowGraph.qll index 2334d240935f..b3b0a63cc6c1 100644 --- a/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowGraph.qll +++ b/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowGraph.qll @@ -225,6 +225,13 @@ module ControlFlow { result = this.getASuccessorByType(any(BooleanSuccessor t | t.getValue() = false)) } + /** + * Gets an immediate `match` predecessor, if any. + */ + Node getAMatchPredecessor() { + result = this.getAPredecessorByType(any(MatchingSuccessor t | t.isMatch())) + } + /** Gets the enclosing callable of this control flow node. */ final Callable getEnclosingCallable() { result = Impl::getNodeCfgScope(this) } } 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 6b210dc46ef3..f88d4f3b356d 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -2597,12 +2597,19 @@ predicate readStep(Node node1, ContentSet c, Node node2) { or dynamicPropertyRead(node1.asExpr(), c, node2.asExpr()) or - patternPropertyRead(node1.asExpr(), c, node2.asExpr()) - or node2.asExpr().(AwaitExpr).getExpr() = node1.asExpr() and c = getResultContent() ) or + exists(ReadStepConfiguration x, ControlFlow::Node cfn1, ControlFlow::Node cfn2 | + cfn1 = node1.getControlFlowNode() and + cfn2 = node2.getControlFlowNode() and + cfn1.getAMatchPredecessor() = cfn2 and + x.hasExprPath(_, cfn1, _, cfn2) + | + patternPropertyRead(node1.asExpr(), c, node2.asExpr()) + ) + or FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), c, node2.(FlowSummaryNode).getSummaryNode()) or From bf66d2c37355e092f27f7952274784e2fe99eefa Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 20 Feb 2025 13:12:56 +0100 Subject: [PATCH 10/12] C#: Update test expected output. --- .../dataflow/patterns/PatternFlow.expected | 36 ------------------- 1 file changed, 36 deletions(-) diff --git a/csharp/ql/test/library-tests/dataflow/patterns/PatternFlow.expected b/csharp/ql/test/library-tests/dataflow/patterns/PatternFlow.expected index c1fed9d0ce54..66018636b4af 100644 --- a/csharp/ql/test/library-tests/dataflow/patterns/PatternFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/patterns/PatternFlow.expected @@ -10,8 +10,6 @@ edges | Patterns.cs:11:17:11:33 | call to method Source : Object | Patterns.cs:11:13:11:13 | access to local variable o : Object | provenance | | | Patterns.cs:12:13:12:13 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:13:31:13:48 | [match] { ... } : RecordClass2 [property Prop] : Object | provenance | | | Patterns.cs:12:13:12:13 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:13:31:13:48 | [match] { ... } : RecordClass2 [property Prop] : Object | provenance | | -| Patterns.cs:12:13:12:13 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:13:31:13:48 | [no-match] { ... } : RecordClass2 [property Prop] : Object | provenance | | -| Patterns.cs:12:13:12:13 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:13:31:13:48 | [no-match] { ... } : RecordClass2 [property Prop] : Object | provenance | | | Patterns.cs:12:17:12:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | Patterns.cs:12:13:12:13 | access to local variable r : RecordClass2 [property Prop] : Object | provenance | | | Patterns.cs:12:17:12:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | Patterns.cs:12:13:12:13 | access to local variable r : RecordClass2 [property Prop] : Object | provenance | | | Patterns.cs:12:34:12:34 | access to local variable o : Object | Patterns.cs:3:41:3:44 | Prop : Object | provenance | | @@ -20,8 +18,6 @@ edges | Patterns.cs:12:34:12:34 | access to local variable o : Object | Patterns.cs:12:17:12:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | provenance | | | Patterns.cs:13:31:13:48 | [match] { ... } : RecordClass2 [property Prop] : Object | Patterns.cs:13:39:13:46 | Object p : Object | provenance | | | Patterns.cs:13:31:13:48 | [match] { ... } : RecordClass2 [property Prop] : Object | Patterns.cs:13:39:13:46 | Object p : Object | provenance | | -| Patterns.cs:13:31:13:48 | [no-match] { ... } : RecordClass2 [property Prop] : Object | Patterns.cs:13:39:13:46 | Object p : Object | provenance | | -| Patterns.cs:13:31:13:48 | [no-match] { ... } : RecordClass2 [property Prop] : Object | Patterns.cs:13:39:13:46 | Object p : Object | provenance | | | Patterns.cs:13:39:13:46 | Object p : Object | Patterns.cs:15:18:15:18 | access to local variable p | provenance | | | Patterns.cs:13:39:13:46 | Object p : Object | Patterns.cs:15:18:15:18 | access to local variable p | provenance | | | Patterns.cs:21:13:21:13 | access to local variable o : Object | Patterns.cs:22:34:22:34 | access to local variable o : Object | provenance | | @@ -30,8 +26,6 @@ edges | Patterns.cs:21:17:21:33 | call to method Source : Object | Patterns.cs:21:13:21:13 | access to local variable o : Object | provenance | | | Patterns.cs:22:13:22:13 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:25:31:25:48 | [match] { ... } : RecordClass2 [property Prop] : Object | provenance | | | Patterns.cs:22:13:22:13 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:25:31:25:48 | [match] { ... } : RecordClass2 [property Prop] : Object | provenance | | -| Patterns.cs:22:13:22:13 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:25:31:25:48 | [no-match] { ... } : RecordClass2 [property Prop] : Object | provenance | | -| Patterns.cs:22:13:22:13 | access to local variable r : RecordClass2 [property Prop] : Object | Patterns.cs:25:31:25:48 | [no-match] { ... } : RecordClass2 [property Prop] : Object | provenance | | | Patterns.cs:22:17:22:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | Patterns.cs:22:13:22:13 | access to local variable r : RecordClass2 [property Prop] : Object | provenance | | | Patterns.cs:22:17:22:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | Patterns.cs:22:13:22:13 | access to local variable r : RecordClass2 [property Prop] : Object | provenance | | | Patterns.cs:22:34:22:34 | access to local variable o : Object | Patterns.cs:3:41:3:44 | Prop : Object | provenance | | @@ -40,8 +34,6 @@ edges | Patterns.cs:22:34:22:34 | access to local variable o : Object | Patterns.cs:22:17:22:35 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | provenance | | | Patterns.cs:25:31:25:48 | [match] { ... } : RecordClass2 [property Prop] : Object | Patterns.cs:25:39:25:46 | Object p : Object | provenance | | | Patterns.cs:25:31:25:48 | [match] { ... } : RecordClass2 [property Prop] : Object | Patterns.cs:25:39:25:46 | Object p : Object | provenance | | -| Patterns.cs:25:31:25:48 | [no-match] { ... } : RecordClass2 [property Prop] : Object | Patterns.cs:25:39:25:46 | Object p : Object | provenance | | -| Patterns.cs:25:31:25:48 | [no-match] { ... } : RecordClass2 [property Prop] : Object | Patterns.cs:25:39:25:46 | Object p : Object | provenance | | | Patterns.cs:25:39:25:46 | Object p : Object | Patterns.cs:26:22:26:22 | access to local variable p | provenance | | | Patterns.cs:25:39:25:46 | Object p : Object | Patterns.cs:26:22:26:22 | access to local variable p | provenance | | | Patterns.cs:33:13:33:13 | access to local variable o : Object | Patterns.cs:34:45:34:45 | access to local variable o : Object | provenance | | @@ -50,8 +42,6 @@ edges | Patterns.cs:33:17:33:33 | call to method Source : Object | Patterns.cs:33:13:33:13 | access to local variable o : Object | provenance | | | Patterns.cs:34:13:34:13 | access to local variable s : Nested [property Record, property Prop] : Object | Patterns.cs:35:25:35:54 | [match] { ... } : Nested [property Record, property Prop] : Object | provenance | | | Patterns.cs:34:13:34:13 | access to local variable s : Nested [property Record, property Prop] : Object | Patterns.cs:35:25:35:54 | [match] { ... } : Nested [property Record, property Prop] : Object | provenance | | -| Patterns.cs:34:13:34:13 | access to local variable s : Nested [property Record, property Prop] : Object | Patterns.cs:35:25:35:54 | [no-match] { ... } : Nested [property Record, property Prop] : Object | provenance | | -| Patterns.cs:34:13:34:13 | access to local variable s : Nested [property Record, property Prop] : Object | Patterns.cs:35:25:35:54 | [no-match] { ... } : Nested [property Record, property Prop] : Object | provenance | | | Patterns.cs:34:17:34:47 | object creation of type Nested : Nested [property Record, property Prop] : Object | Patterns.cs:34:13:34:13 | access to local variable s : Nested [property Record, property Prop] : Object | provenance | | | Patterns.cs:34:17:34:47 | object creation of type Nested : Nested [property Record, property Prop] : Object | Patterns.cs:34:13:34:13 | access to local variable s : Nested [property Record, property Prop] : Object | provenance | | | Patterns.cs:34:28:34:46 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | Patterns.cs:5:41:5:46 | Record : RecordClass2 [property Prop] : Object | provenance | | @@ -64,16 +54,10 @@ edges | Patterns.cs:34:45:34:45 | access to local variable o : Object | Patterns.cs:34:28:34:46 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | provenance | | | Patterns.cs:35:25:35:54 | [match] { ... } : Nested [property Record, property Prop] : Object | Patterns.cs:35:35:35:52 | [match] { ... } : null [property Prop] : Object | provenance | | | Patterns.cs:35:25:35:54 | [match] { ... } : Nested [property Record, property Prop] : Object | Patterns.cs:35:35:35:52 | [match] { ... } : null [property Prop] : Object | provenance | | -| Patterns.cs:35:25:35:54 | [no-match] { ... } : Nested [property Record, property Prop] : Object | Patterns.cs:35:35:35:52 | [no-match] { ... } : null [property Prop] : Object | provenance | | -| Patterns.cs:35:25:35:54 | [no-match] { ... } : Nested [property Record, property Prop] : Object | Patterns.cs:35:35:35:52 | [no-match] { ... } : null [property Prop] : Object | provenance | | | Patterns.cs:35:35:35:52 | [match] { ... } : null [property Prop] : Object | Patterns.cs:35:35:35:52 | [match] { ... } : null [property Prop] : Object | provenance | | | Patterns.cs:35:35:35:52 | [match] { ... } : null [property Prop] : Object | Patterns.cs:35:35:35:52 | [match] { ... } : null [property Prop] : Object | provenance | | | Patterns.cs:35:35:35:52 | [match] { ... } : null [property Prop] : Object | Patterns.cs:35:43:35:50 | Object p : Object | provenance | | | Patterns.cs:35:35:35:52 | [match] { ... } : null [property Prop] : Object | Patterns.cs:35:43:35:50 | Object p : Object | provenance | | -| Patterns.cs:35:35:35:52 | [no-match] { ... } : null [property Prop] : Object | Patterns.cs:35:35:35:52 | [no-match] { ... } : null [property Prop] : Object | provenance | | -| Patterns.cs:35:35:35:52 | [no-match] { ... } : null [property Prop] : Object | Patterns.cs:35:35:35:52 | [no-match] { ... } : null [property Prop] : Object | provenance | | -| Patterns.cs:35:35:35:52 | [no-match] { ... } : null [property Prop] : Object | Patterns.cs:35:43:35:50 | Object p : Object | provenance | | -| Patterns.cs:35:35:35:52 | [no-match] { ... } : null [property Prop] : Object | Patterns.cs:35:43:35:50 | Object p : Object | provenance | | | Patterns.cs:35:43:35:50 | Object p : Object | Patterns.cs:37:18:37:18 | access to local variable p | provenance | | | Patterns.cs:35:43:35:50 | Object p : Object | Patterns.cs:37:18:37:18 | access to local variable p | provenance | | | Patterns.cs:43:13:43:13 | access to local variable o : Object | Patterns.cs:44:45:44:45 | access to local variable o : Object | provenance | | @@ -82,8 +66,6 @@ edges | Patterns.cs:43:17:43:33 | call to method Source : Object | Patterns.cs:43:13:43:13 | access to local variable o : Object | provenance | | | Patterns.cs:44:13:44:13 | access to local variable s : Nested [property Record, property Prop] : Object | Patterns.cs:45:25:45:49 | [match] { ... } : Nested [property Record, property Prop] : Object | provenance | | | Patterns.cs:44:13:44:13 | access to local variable s : Nested [property Record, property Prop] : Object | Patterns.cs:45:25:45:49 | [match] { ... } : Nested [property Record, property Prop] : Object | provenance | | -| Patterns.cs:44:13:44:13 | access to local variable s : Nested [property Record, property Prop] : Object | Patterns.cs:45:25:45:49 | [no-match] { ... } : Nested [property Record, property Prop] : Object | provenance | | -| Patterns.cs:44:13:44:13 | access to local variable s : Nested [property Record, property Prop] : Object | Patterns.cs:45:25:45:49 | [no-match] { ... } : Nested [property Record, property Prop] : Object | provenance | | | Patterns.cs:44:17:44:47 | object creation of type Nested : Nested [property Record, property Prop] : Object | Patterns.cs:44:13:44:13 | access to local variable s : Nested [property Record, property Prop] : Object | provenance | | | Patterns.cs:44:17:44:47 | object creation of type Nested : Nested [property Record, property Prop] : Object | Patterns.cs:44:13:44:13 | access to local variable s : Nested [property Record, property Prop] : Object | provenance | | | Patterns.cs:44:28:44:46 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | Patterns.cs:5:41:5:46 | Record : RecordClass2 [property Prop] : Object | provenance | | @@ -96,12 +78,8 @@ edges | Patterns.cs:44:45:44:45 | access to local variable o : Object | Patterns.cs:44:28:44:46 | object creation of type RecordClass2 : RecordClass2 [property Prop] : Object | provenance | | | Patterns.cs:45:25:45:49 | [match] { ... } : Nested [property Record, property Prop] : Object | Patterns.cs:45:27:45:32 | [match] { ... } : null [property Prop] : Object | provenance | | | Patterns.cs:45:25:45:49 | [match] { ... } : Nested [property Record, property Prop] : Object | Patterns.cs:45:27:45:32 | [match] { ... } : null [property Prop] : Object | provenance | | -| Patterns.cs:45:25:45:49 | [no-match] { ... } : Nested [property Record, property Prop] : Object | Patterns.cs:45:27:45:32 | [no-match] { ... } : null [property Prop] : Object | provenance | | -| Patterns.cs:45:25:45:49 | [no-match] { ... } : Nested [property Record, property Prop] : Object | Patterns.cs:45:27:45:32 | [no-match] { ... } : null [property Prop] : Object | provenance | | | Patterns.cs:45:27:45:32 | [match] { ... } : null [property Prop] : Object | Patterns.cs:45:40:45:47 | Object p : Object | provenance | | | Patterns.cs:45:27:45:32 | [match] { ... } : null [property Prop] : Object | Patterns.cs:45:40:45:47 | Object p : Object | provenance | | -| Patterns.cs:45:27:45:32 | [no-match] { ... } : null [property Prop] : Object | Patterns.cs:45:40:45:47 | Object p : Object | provenance | | -| Patterns.cs:45:27:45:32 | [no-match] { ... } : null [property Prop] : Object | Patterns.cs:45:40:45:47 | Object p : Object | provenance | | | Patterns.cs:45:40:45:47 | Object p : Object | Patterns.cs:47:18:47:18 | access to local variable p | provenance | | | Patterns.cs:45:40:45:47 | Object p : Object | Patterns.cs:47:18:47:18 | access to local variable p | provenance | | nodes @@ -125,8 +103,6 @@ nodes | Patterns.cs:12:34:12:34 | access to local variable o : Object | semmle.label | access to local variable o : Object | | Patterns.cs:13:31:13:48 | [match] { ... } : RecordClass2 [property Prop] : Object | semmle.label | [match] { ... } : RecordClass2 [property Prop] : Object | | Patterns.cs:13:31:13:48 | [match] { ... } : RecordClass2 [property Prop] : Object | semmle.label | [match] { ... } : RecordClass2 [property Prop] : Object | -| Patterns.cs:13:31:13:48 | [no-match] { ... } : RecordClass2 [property Prop] : Object | semmle.label | [no-match] { ... } : RecordClass2 [property Prop] : Object | -| Patterns.cs:13:31:13:48 | [no-match] { ... } : RecordClass2 [property Prop] : Object | semmle.label | [no-match] { ... } : RecordClass2 [property Prop] : Object | | Patterns.cs:13:39:13:46 | Object p : Object | semmle.label | Object p : Object | | Patterns.cs:13:39:13:46 | Object p : Object | semmle.label | Object p : Object | | Patterns.cs:15:18:15:18 | access to local variable p | semmle.label | access to local variable p | @@ -143,8 +119,6 @@ nodes | Patterns.cs:22:34:22:34 | access to local variable o : Object | semmle.label | access to local variable o : Object | | Patterns.cs:25:31:25:48 | [match] { ... } : RecordClass2 [property Prop] : Object | semmle.label | [match] { ... } : RecordClass2 [property Prop] : Object | | Patterns.cs:25:31:25:48 | [match] { ... } : RecordClass2 [property Prop] : Object | semmle.label | [match] { ... } : RecordClass2 [property Prop] : Object | -| Patterns.cs:25:31:25:48 | [no-match] { ... } : RecordClass2 [property Prop] : Object | semmle.label | [no-match] { ... } : RecordClass2 [property Prop] : Object | -| Patterns.cs:25:31:25:48 | [no-match] { ... } : RecordClass2 [property Prop] : Object | semmle.label | [no-match] { ... } : RecordClass2 [property Prop] : Object | | Patterns.cs:25:39:25:46 | Object p : Object | semmle.label | Object p : Object | | Patterns.cs:25:39:25:46 | Object p : Object | semmle.label | Object p : Object | | Patterns.cs:26:22:26:22 | access to local variable p | semmle.label | access to local variable p | @@ -163,16 +137,10 @@ nodes | Patterns.cs:34:45:34:45 | access to local variable o : Object | semmle.label | access to local variable o : Object | | Patterns.cs:35:25:35:54 | [match] { ... } : Nested [property Record, property Prop] : Object | semmle.label | [match] { ... } : Nested [property Record, property Prop] : Object | | Patterns.cs:35:25:35:54 | [match] { ... } : Nested [property Record, property Prop] : Object | semmle.label | [match] { ... } : Nested [property Record, property Prop] : Object | -| Patterns.cs:35:25:35:54 | [no-match] { ... } : Nested [property Record, property Prop] : Object | semmle.label | [no-match] { ... } : Nested [property Record, property Prop] : Object | -| Patterns.cs:35:25:35:54 | [no-match] { ... } : Nested [property Record, property Prop] : Object | semmle.label | [no-match] { ... } : Nested [property Record, property Prop] : Object | | Patterns.cs:35:35:35:52 | [match] { ... } : null [property Prop] : Object | semmle.label | [match] { ... } : null [property Prop] : Object | | Patterns.cs:35:35:35:52 | [match] { ... } : null [property Prop] : Object | semmle.label | [match] { ... } : null [property Prop] : Object | | Patterns.cs:35:35:35:52 | [match] { ... } : null [property Prop] : Object | semmle.label | [match] { ... } : null [property Prop] : Object | | Patterns.cs:35:35:35:52 | [match] { ... } : null [property Prop] : Object | semmle.label | [match] { ... } : null [property Prop] : Object | -| Patterns.cs:35:35:35:52 | [no-match] { ... } : null [property Prop] : Object | semmle.label | [no-match] { ... } : null [property Prop] : Object | -| Patterns.cs:35:35:35:52 | [no-match] { ... } : null [property Prop] : Object | semmle.label | [no-match] { ... } : null [property Prop] : Object | -| Patterns.cs:35:35:35:52 | [no-match] { ... } : null [property Prop] : Object | semmle.label | [no-match] { ... } : null [property Prop] : Object | -| Patterns.cs:35:35:35:52 | [no-match] { ... } : null [property Prop] : Object | semmle.label | [no-match] { ... } : null [property Prop] : Object | | Patterns.cs:35:43:35:50 | Object p : Object | semmle.label | Object p : Object | | Patterns.cs:35:43:35:50 | Object p : Object | semmle.label | Object p : Object | | Patterns.cs:37:18:37:18 | access to local variable p | semmle.label | access to local variable p | @@ -191,12 +159,8 @@ nodes | Patterns.cs:44:45:44:45 | access to local variable o : Object | semmle.label | access to local variable o : Object | | Patterns.cs:45:25:45:49 | [match] { ... } : Nested [property Record, property Prop] : Object | semmle.label | [match] { ... } : Nested [property Record, property Prop] : Object | | Patterns.cs:45:25:45:49 | [match] { ... } : Nested [property Record, property Prop] : Object | semmle.label | [match] { ... } : Nested [property Record, property Prop] : Object | -| Patterns.cs:45:25:45:49 | [no-match] { ... } : Nested [property Record, property Prop] : Object | semmle.label | [no-match] { ... } : Nested [property Record, property Prop] : Object | -| Patterns.cs:45:25:45:49 | [no-match] { ... } : Nested [property Record, property Prop] : Object | semmle.label | [no-match] { ... } : Nested [property Record, property Prop] : Object | | Patterns.cs:45:27:45:32 | [match] { ... } : null [property Prop] : Object | semmle.label | [match] { ... } : null [property Prop] : Object | | Patterns.cs:45:27:45:32 | [match] { ... } : null [property Prop] : Object | semmle.label | [match] { ... } : null [property Prop] : Object | -| Patterns.cs:45:27:45:32 | [no-match] { ... } : null [property Prop] : Object | semmle.label | [no-match] { ... } : null [property Prop] : Object | -| Patterns.cs:45:27:45:32 | [no-match] { ... } : null [property Prop] : Object | semmle.label | [no-match] { ... } : null [property Prop] : Object | | Patterns.cs:45:40:45:47 | Object p : Object | semmle.label | Object p : Object | | Patterns.cs:45:40:45:47 | Object p : Object | semmle.label | Object p : Object | | Patterns.cs:47:18:47:18 | access to local variable p | semmle.label | access to local variable p | From 917179bffdacf082de2c3d60a8567b5b7e9268b4 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 20 Feb 2025 14:41:32 +0100 Subject: [PATCH 11/12] C#: Exclude patterns without variable declarations and top level declarations as local step targets. --- .../csharp/dataflow/internal/DataFlowPrivate.qll | 16 ++++++++++++++-- 1 file changed, 14 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 f88d4f3b356d..3b87538a6f36 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -520,6 +520,16 @@ module SsaFlow { /** Provides predicates related to local data flow. */ module LocalFlow { + /** + * Holds if the pattern `e` is a top level variable pattern expression or + * if the pattern doesn't contain any variable pattern expressions. + */ + private predicate basicPattern(PatternExpr e) { + e instanceof VariablePatternExpr + or + not exists(VariablePatternExpr vpe | e.getAChild*() = vpe) + } + class LocalExprStepConfiguration extends ControlFlowReachabilityConfiguration { LocalExprStepConfiguration() { this = "LocalExprStepConfiguration" } @@ -615,14 +625,16 @@ module LocalFlow { scope = any(IsExpr ie | e1 = ie.getExpr() and - e2 = ie.getPattern() + e2 = ie.getPattern() and + not basicPattern(e2) ) or isSuccessor = true and scope = any(Switch e | e1 = e.getExpr() and - e2 = e.getACase().getPattern() + e2 = e.getACase().getPattern() and + not basicPattern(e2) ) or isSuccessor = false and From 713c8042dc31267efaf5580fb1d73f61609660e2 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 20 Feb 2025 14:49:31 +0100 Subject: [PATCH 12/12] C#: Update test expected output. --- .../library-tests/csharp7/LocalTaintFlow.expected | 14 -------------- .../dataflow/local/DataFlowStep.expected | 4 ---- .../dataflow/local/TaintTrackingStep.expected | 4 ---- .../dataflow/tuples/DataFlowStep.expected | 1 - 4 files changed, 23 deletions(-) diff --git a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected index 8fef5ce69f6f..4a16e2491dfe 100644 --- a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected +++ b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected @@ -241,7 +241,6 @@ | CSharp7.cs:232:16:232:23 | SSA def(o) | CSharp7.cs:233:13:233:13 | access to local variable o | | CSharp7.cs:232:20:232:23 | null | CSharp7.cs:232:16:232:16 | access to local variable o | | CSharp7.cs:233:13:233:13 | access to local variable o | CSharp7.cs:233:18:233:23 | Int32 i1 | -| CSharp7.cs:233:13:233:13 | access to local variable o | CSharp7.cs:233:18:233:23 | Int32 i1 | | CSharp7.cs:233:13:233:13 | access to local variable o | CSharp7.cs:235:13:235:42 | [input] SSA phi read(o) | | CSharp7.cs:233:13:233:13 | access to local variable o | CSharp7.cs:237:18:237:18 | access to local variable o | | CSharp7.cs:233:13:233:23 | [false] ... is ... | CSharp7.cs:233:13:233:33 | [false] ... && ... | @@ -257,7 +256,6 @@ | CSharp7.cs:235:33:235:36 | "int " | CSharp7.cs:235:31:235:41 | $"..." | | CSharp7.cs:235:38:235:39 | access to local variable i1 | CSharp7.cs:235:31:235:41 | $"..." | | CSharp7.cs:237:18:237:18 | access to local variable o | CSharp7.cs:237:23:237:31 | String s1 | -| CSharp7.cs:237:18:237:18 | access to local variable o | CSharp7.cs:237:23:237:31 | String s1 | | CSharp7.cs:237:18:237:18 | access to local variable o | CSharp7.cs:239:13:239:45 | [input] SSA phi read(o) | | CSharp7.cs:237:18:237:18 | access to local variable o | CSharp7.cs:241:18:241:18 | access to local variable o | | CSharp7.cs:237:23:237:31 | SSA def(s1) | CSharp7.cs:239:41:239:42 | access to local variable s1 | @@ -265,34 +263,23 @@ | CSharp7.cs:239:13:239:45 | [input] SSA phi read(o) | CSharp7.cs:248:9:274:9 | SSA phi read(o) | | CSharp7.cs:239:33:239:39 | "string " | CSharp7.cs:239:31:239:44 | $"..." | | CSharp7.cs:239:41:239:42 | access to local variable s1 | CSharp7.cs:239:31:239:44 | $"..." | -| CSharp7.cs:241:18:241:18 | access to local variable o | CSharp7.cs:241:23:241:28 | access to type Double | | CSharp7.cs:241:18:241:18 | access to local variable o | CSharp7.cs:242:9:243:9 | [input] SSA phi read(o) | | CSharp7.cs:241:18:241:18 | access to local variable o | CSharp7.cs:244:18:244:18 | access to local variable o | | CSharp7.cs:242:9:243:9 | [input] SSA phi read(o) | CSharp7.cs:248:9:274:9 | SSA phi read(o) | | CSharp7.cs:244:18:244:18 | access to local variable o | CSharp7.cs:244:18:244:28 | [input] SSA phi read(o) | | CSharp7.cs:244:18:244:18 | access to local variable o | CSharp7.cs:244:23:244:28 | Object v1 | -| CSharp7.cs:244:18:244:18 | access to local variable o | CSharp7.cs:244:23:244:28 | Object v1 | | CSharp7.cs:244:18:244:18 | access to local variable o | CSharp7.cs:245:9:246:9 | [input] SSA phi read(o) | | CSharp7.cs:244:18:244:28 | [input] SSA phi read(o) | CSharp7.cs:248:9:274:9 | SSA phi read(o) | | CSharp7.cs:245:9:246:9 | [input] SSA phi read(o) | CSharp7.cs:248:9:274:9 | SSA phi read(o) | | CSharp7.cs:248:9:274:9 | SSA phi read(o) | CSharp7.cs:248:17:248:17 | access to local variable o | -| CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:250:18:250:22 | "xyz" | -| CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:252:18:252:19 | "" | -| CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:254:18:254:20 | "x" | | CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:254:27:254:27 | access to local variable o | | CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:257:18:257:23 | Int32 i2 | -| CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:257:18:257:23 | Int32 i2 | -| CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:260:18:260:23 | Int32 i3 | | CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:260:18:260:23 | Int32 i3 | | CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:263:18:263:26 | String s2 | -| CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:263:18:263:26 | String s2 | -| CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:266:18:266:23 | access to type Double | -| CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:269:18:269:23 | Object v2 | | CSharp7.cs:248:17:248:17 | access to local variable o | CSharp7.cs:269:18:269:23 | Object v2 | | CSharp7.cs:252:26:252:26 | 1 | CSharp7.cs:252:26:252:30 | ... < ... | | CSharp7.cs:252:30:252:30 | 2 | CSharp7.cs:252:26:252:30 | ... < ... | | CSharp7.cs:254:27:254:27 | access to local variable o | CSharp7.cs:254:32:254:40 | String s4 | -| CSharp7.cs:254:27:254:27 | access to local variable o | CSharp7.cs:254:32:254:40 | String s4 | | CSharp7.cs:254:32:254:40 | SSA def(s4) | CSharp7.cs:255:40:255:41 | access to local variable s4 | | CSharp7.cs:254:32:254:40 | String s4 | CSharp7.cs:254:32:254:40 | SSA def(s4) | | CSharp7.cs:255:37:255:38 | "x " | CSharp7.cs:255:35:255:43 | $"..." | @@ -334,7 +321,6 @@ | CSharp7.cs:297:25:297:30 | ... < ... | CSharp7.cs:297:25:297:44 | [false] ... && ... | | CSharp7.cs:297:25:297:30 | ... < ... | CSharp7.cs:297:25:297:44 | [true] ... && ... | | CSharp7.cs:297:35:297:35 | access to local variable x | CSharp7.cs:297:40:297:44 | Int32 y | -| CSharp7.cs:297:35:297:35 | access to local variable x | CSharp7.cs:297:40:297:44 | Int32 y | | CSharp7.cs:297:35:297:35 | access to local variable x | CSharp7.cs:297:49:297:49 | access to local variable x | | CSharp7.cs:297:35:297:44 | [false] ... is ... | CSharp7.cs:297:25:297:44 | [false] ... && ... | | CSharp7.cs:297:35:297:44 | [true] ... is ... | CSharp7.cs:297:25:297:44 | [true] ... && ... | diff --git a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected index fba6a256048d..a8b0a4d0cd55 100644 --- a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected @@ -464,21 +464,17 @@ | LocalDataFlow.cs:286:15:286:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | | LocalDataFlow.cs:286:15:286:22 | access to local variable nonSink0 | LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | | LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | LocalDataFlow.cs:289:23:289:35 | String sink71 | -| LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | LocalDataFlow.cs:289:23:289:35 | String sink71 | | LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | LocalDataFlow.cs:297:17:297:22 | access to local variable sink70 | | LocalDataFlow.cs:289:23:289:35 | SSA def(sink71) | LocalDataFlow.cs:290:19:290:24 | access to local variable sink71 | | LocalDataFlow.cs:289:23:289:35 | String sink71 | LocalDataFlow.cs:289:23:289:35 | SSA def(sink71) | | LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | LocalDataFlow.cs:293:25:293:40 | String nonSink16 | -| LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | LocalDataFlow.cs:293:25:293:40 | String nonSink16 | | LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | | LocalDataFlow.cs:293:25:293:40 | SSA def(nonSink16) | LocalDataFlow.cs:294:19:294:27 | access to local variable nonSink16 | | LocalDataFlow.cs:293:25:293:40 | String nonSink16 | LocalDataFlow.cs:293:25:293:40 | SSA def(nonSink16) | | LocalDataFlow.cs:297:17:297:22 | access to local variable sink70 | LocalDataFlow.cs:299:18:299:30 | String sink72 | -| LocalDataFlow.cs:297:17:297:22 | access to local variable sink70 | LocalDataFlow.cs:299:18:299:30 | String sink72 | | LocalDataFlow.cs:299:18:299:30 | SSA def(sink72) | LocalDataFlow.cs:300:23:300:28 | access to local variable sink72 | | LocalDataFlow.cs:299:18:299:30 | String sink72 | LocalDataFlow.cs:299:18:299:30 | SSA def(sink72) | | LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | LocalDataFlow.cs:307:18:307:33 | String nonSink17 | -| LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | LocalDataFlow.cs:307:18:307:33 | String nonSink17 | | LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | LocalDataFlow.cs:313:22:313:29 | access to local variable nonSink0 | | LocalDataFlow.cs:307:18:307:33 | SSA def(nonSink17) | LocalDataFlow.cs:308:23:308:31 | access to local variable nonSink17 | | LocalDataFlow.cs:307:18:307:33 | String nonSink17 | LocalDataFlow.cs:307:18:307:33 | SSA def(nonSink17) | diff --git a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected index 5af2f3e2ced1..ff7d8b0f6ba2 100644 --- a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected @@ -573,21 +573,17 @@ | LocalDataFlow.cs:286:15:286:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | | LocalDataFlow.cs:286:15:286:22 | access to local variable nonSink0 | LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | | LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | LocalDataFlow.cs:289:23:289:35 | String sink71 | -| LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | LocalDataFlow.cs:289:23:289:35 | String sink71 | | LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | LocalDataFlow.cs:297:17:297:22 | access to local variable sink70 | | LocalDataFlow.cs:289:23:289:35 | SSA def(sink71) | LocalDataFlow.cs:290:19:290:24 | access to local variable sink71 | | LocalDataFlow.cs:289:23:289:35 | String sink71 | LocalDataFlow.cs:289:23:289:35 | SSA def(sink71) | | LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | LocalDataFlow.cs:293:25:293:40 | String nonSink16 | -| LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | LocalDataFlow.cs:293:25:293:40 | String nonSink16 | | LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | | LocalDataFlow.cs:293:25:293:40 | SSA def(nonSink16) | LocalDataFlow.cs:294:19:294:27 | access to local variable nonSink16 | | LocalDataFlow.cs:293:25:293:40 | String nonSink16 | LocalDataFlow.cs:293:25:293:40 | SSA def(nonSink16) | | LocalDataFlow.cs:297:17:297:22 | access to local variable sink70 | LocalDataFlow.cs:299:18:299:30 | String sink72 | -| LocalDataFlow.cs:297:17:297:22 | access to local variable sink70 | LocalDataFlow.cs:299:18:299:30 | String sink72 | | LocalDataFlow.cs:299:18:299:30 | SSA def(sink72) | LocalDataFlow.cs:300:23:300:28 | access to local variable sink72 | | LocalDataFlow.cs:299:18:299:30 | String sink72 | LocalDataFlow.cs:299:18:299:30 | SSA def(sink72) | | LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | LocalDataFlow.cs:307:18:307:33 | String nonSink17 | -| LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | LocalDataFlow.cs:307:18:307:33 | String nonSink17 | | LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | LocalDataFlow.cs:313:22:313:29 | access to local variable nonSink0 | | LocalDataFlow.cs:307:18:307:33 | SSA def(nonSink17) | LocalDataFlow.cs:308:23:308:31 | access to local variable nonSink17 | | LocalDataFlow.cs:307:18:307:33 | String nonSink17 | LocalDataFlow.cs:307:18:307:33 | SSA def(nonSink17) | diff --git a/csharp/ql/test/library-tests/dataflow/tuples/DataFlowStep.expected b/csharp/ql/test/library-tests/dataflow/tuples/DataFlowStep.expected index e8178964106f..f09e303bf3cf 100644 --- a/csharp/ql/test/library-tests/dataflow/tuples/DataFlowStep.expected +++ b/csharp/ql/test/library-tests/dataflow/tuples/DataFlowStep.expected @@ -106,7 +106,6 @@ | Tuples.cs:59:13:59:32 | SSA def(x) | Tuples.cs:60:17:60:17 | access to local variable x | | Tuples.cs:59:17:59:32 | (..., ...) | Tuples.cs:59:13:59:13 | access to local variable x | | Tuples.cs:60:17:60:17 | access to local variable x | Tuples.cs:62:18:62:57 | (String,(Int32,String),Int32) t | -| Tuples.cs:60:17:60:17 | access to local variable x | Tuples.cs:62:18:62:57 | (String,(Int32,String),Int32) t | | Tuples.cs:60:17:60:17 | access to local variable x | Tuples.cs:67:18:67:35 | (..., ...) | | Tuples.cs:60:17:60:17 | access to local variable x | Tuples.cs:67:18:67:35 | (..., ...) | | Tuples.cs:60:17:60:17 | access to local variable x | Tuples.cs:87:13:87:13 | access to local variable x |