Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions csharp/ql/lib/change-notes/2024-02-21-getonly-properties.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* C#: Data flow via get only properties like `public object Obj { get; }` is now captured by the data flow library.
28 changes: 23 additions & 5 deletions csharp/ql/lib/semmle/code/csharp/Property.qll
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,13 @@ class Property extends DotNet::Property, DeclarationWithGetSetAccessors, @proper
properties(this, _, _, getTypeRef(result), _)
}

private predicate isAutoPartial() {
this.fromSource() and
not this.isExtern() and
not this.isAbstract() and
not this.getAnAccessor().hasBody()
}

/**
* Holds if this property is automatically implemented. For example, `P1`
* on line 2 is automatically implemented, while `P2` on line 5 is not in
Expand All @@ -147,11 +154,22 @@ class Property extends DotNet::Property, DeclarationWithGetSetAccessors, @proper
* code.
*/
predicate isAutoImplemented() {
this.fromSource() and
this.isReadWrite() and
not this.isExtern() and
not this.isAbstract() and
not this.getAnAccessor().hasBody()
this.isAutoPartial() and
this.isReadWrite()
}

/**
* Holds if this property is automatically implemented and read-only. For
* example, `P1` on line 2 is automatically implemented and read-only
* ```csharp
* class C {
* public int P1 { get; }
* }
* ```
*/
predicate isAutoImplementedReadOnly() {
this.isAutoPartial() and
this.isReadOnly()
}

override Property getUnboundDeclaration() { properties(this, _, _, _, result) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1899,6 +1899,8 @@ class FieldOrProperty extends Assignable, Modifiable {
(
p.isAutoImplemented()
or
p.isAutoImplementedReadOnly()
or
p.matchesHandle(any(CIL::TrivialProperty tp))
or
p.getDeclaringType() instanceof AnonymousClass
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,20 @@ edges
| Constructors.cs:112:25:112:27 | access to local variable o31 : Object | Constructors.cs:112:18:112:28 | object creation of type C3 : C3 [parameter o31param] : Object | provenance | |
| Constructors.cs:113:14:113:15 | access to local variable c3 : C3 [parameter o31param] : Object | Constructors.cs:106:32:106:39 | this : C3 [parameter o31param] : Object | provenance | |
| Constructors.cs:113:14:113:15 | access to local variable c3 : C3 [parameter o31param] : Object | Constructors.cs:113:14:113:21 | access to property Obj31 | provenance | |
| Constructors.cs:121:26:121:28 | oc1 : Object | Constructors.cs:123:20:123:22 | access to parameter oc1 : Object | provenance | |
| Constructors.cs:121:38:121:40 | oc2 : Object | Constructors.cs:124:20:124:22 | access to parameter oc2 : Object | provenance | |
| Constructors.cs:123:20:123:22 | access to parameter oc1 : Object | Constructors.cs:123:13:123:16 | [post] this access : C4 [property Obj1] : Object | provenance | |
| Constructors.cs:124:20:124:22 | access to parameter oc2 : Object | Constructors.cs:124:13:124:16 | [post] this access : C4 [property Obj2] : Object | provenance | |
| Constructors.cs:130:18:130:34 | call to method Source<Object> : Object | Constructors.cs:132:25:132:26 | access to local variable o1 : Object | provenance | |
| Constructors.cs:131:18:131:34 | call to method Source<Object> : Object | Constructors.cs:132:29:132:30 | access to local variable o2 : Object | provenance | |
| Constructors.cs:132:18:132:31 | object creation of type C4 : C4 [property Obj1] : Object | Constructors.cs:133:14:133:15 | access to local variable c4 : C4 [property Obj1] : Object | provenance | |
| Constructors.cs:132:18:132:31 | object creation of type C4 : C4 [property Obj2] : Object | Constructors.cs:134:14:134:15 | access to local variable c4 : C4 [property Obj2] : Object | provenance | |
| Constructors.cs:132:25:132:26 | access to local variable o1 : Object | Constructors.cs:121:26:121:28 | oc1 : Object | provenance | |
| Constructors.cs:132:25:132:26 | access to local variable o1 : Object | Constructors.cs:132:18:132:31 | object creation of type C4 : C4 [property Obj1] : Object | provenance | |
| Constructors.cs:132:29:132:30 | access to local variable o2 : Object | Constructors.cs:121:38:121:40 | oc2 : Object | provenance | |
| Constructors.cs:132:29:132:30 | access to local variable o2 : Object | Constructors.cs:132:18:132:31 | object creation of type C4 : C4 [property Obj2] : Object | provenance | |
| Constructors.cs:133:14:133:15 | access to local variable c4 : C4 [property Obj1] : Object | Constructors.cs:133:14:133:20 | access to property Obj1 | provenance | |
| Constructors.cs:134:14:134:15 | access to local variable c4 : C4 [property Obj2] : Object | Constructors.cs:134:14:134:20 | access to property Obj2 | provenance | |
nodes
| Constructors.cs:5:24:5:25 | [post] this access : C_no_ctor [field s1] : Object | semmle.label | [post] this access : C_no_ctor [field s1] : Object |
| Constructors.cs:5:29:5:45 | call to method Source<Object> : Object | semmle.label | call to method Source<Object> : Object |
Expand Down Expand Up @@ -134,6 +148,22 @@ nodes
| Constructors.cs:112:25:112:27 | access to local variable o31 : Object | semmle.label | access to local variable o31 : Object |
| Constructors.cs:113:14:113:15 | access to local variable c3 : C3 [parameter o31param] : Object | semmle.label | access to local variable c3 : C3 [parameter o31param] : Object |
| Constructors.cs:113:14:113:21 | access to property Obj31 | semmle.label | access to property Obj31 |
| Constructors.cs:121:26:121:28 | oc1 : Object | semmle.label | oc1 : Object |
| Constructors.cs:121:38:121:40 | oc2 : Object | semmle.label | oc2 : Object |
| Constructors.cs:123:13:123:16 | [post] this access : C4 [property Obj1] : Object | semmle.label | [post] this access : C4 [property Obj1] : Object |
| Constructors.cs:123:20:123:22 | access to parameter oc1 : Object | semmle.label | access to parameter oc1 : Object |
| Constructors.cs:124:13:124:16 | [post] this access : C4 [property Obj2] : Object | semmle.label | [post] this access : C4 [property Obj2] : Object |
| Constructors.cs:124:20:124:22 | access to parameter oc2 : Object | semmle.label | access to parameter oc2 : Object |
| Constructors.cs:130:18:130:34 | call to method Source<Object> : Object | semmle.label | call to method Source<Object> : Object |
| Constructors.cs:131:18:131:34 | call to method Source<Object> : Object | semmle.label | call to method Source<Object> : Object |
| Constructors.cs:132:18:132:31 | object creation of type C4 : C4 [property Obj1] : Object | semmle.label | object creation of type C4 : C4 [property Obj1] : Object |
| Constructors.cs:132:18:132:31 | object creation of type C4 : C4 [property Obj2] : Object | semmle.label | object creation of type C4 : C4 [property Obj2] : Object |
| Constructors.cs:132:25:132:26 | access to local variable o1 : Object | semmle.label | access to local variable o1 : Object |
| Constructors.cs:132:29:132:30 | access to local variable o2 : Object | semmle.label | access to local variable o2 : Object |
| Constructors.cs:133:14:133:15 | access to local variable c4 : C4 [property Obj1] : Object | semmle.label | access to local variable c4 : C4 [property Obj1] : Object |
| Constructors.cs:133:14:133:20 | access to property Obj1 | semmle.label | access to property Obj1 |
| Constructors.cs:134:14:134:15 | access to local variable c4 : C4 [property Obj2] : Object | semmle.label | access to local variable c4 : C4 [property Obj2] : Object |
| Constructors.cs:134:14:134:20 | access to property Obj2 | semmle.label | access to property Obj2 |
subpaths
| Constructors.cs:64:37:64:37 | access to parameter o : Object | Constructors.cs:57:54:57:55 | o2 : Object | Constructors.cs:59:13:59:19 | SSA def(o1) : Object | Constructors.cs:64:27:64:34 | SSA def(o22param) : Object |
| Constructors.cs:71:25:71:25 | access to local variable o : Object | Constructors.cs:41:26:41:26 | o : Object | Constructors.cs:41:32:41:34 | [post] this access : C1 [field Obj] : Object | Constructors.cs:71:18:71:26 | object creation of type C1 : C1 [field Obj] : Object |
Expand All @@ -147,6 +177,8 @@ subpaths
| Constructors.cs:101:14:101:15 | access to local variable c2 : C2 [parameter o22param] : Object | Constructors.cs:48:32:48:39 | this : C2 [parameter o22param] : Object | Constructors.cs:48:32:48:39 | access to parameter o22param : Object | Constructors.cs:101:14:101:21 | access to property Obj22 |
| Constructors.cs:112:25:112:27 | access to local variable o31 : Object | Constructors.cs:104:28:104:35 | o31param : Object | Constructors.cs:104:28:104:35 | o31param : Object | Constructors.cs:112:18:112:28 | object creation of type C3 : C3 [parameter o31param] : Object |
| Constructors.cs:113:14:113:15 | access to local variable c3 : C3 [parameter o31param] : Object | Constructors.cs:106:32:106:39 | this : C3 [parameter o31param] : Object | Constructors.cs:106:32:106:39 | access to parameter o31param : Object | Constructors.cs:113:14:113:21 | access to property Obj31 |
| Constructors.cs:132:25:132:26 | access to local variable o1 : Object | Constructors.cs:121:26:121:28 | oc1 : Object | Constructors.cs:123:13:123:16 | [post] this access : C4 [property Obj1] : Object | Constructors.cs:132:18:132:31 | object creation of type C4 : C4 [property Obj1] : Object |
| Constructors.cs:132:29:132:30 | access to local variable o2 : Object | Constructors.cs:121:38:121:40 | oc2 : Object | Constructors.cs:124:13:124:16 | [post] this access : C4 [property Obj2] : Object | Constructors.cs:132:18:132:31 | object creation of type C4 : C4 [property Obj2] : Object |
#select
| Constructors.cs:15:18:15:19 | access to field s1 | Constructors.cs:5:29:5:45 | call to method Source<Object> : Object | Constructors.cs:15:18:15:19 | access to field s1 | $@ | Constructors.cs:5:29:5:45 | call to method Source<Object> : Object | call to method Source<Object> : Object |
| Constructors.cs:33:18:33:19 | access to field s1 | Constructors.cs:21:29:21:45 | call to method Source<Object> : Object | Constructors.cs:33:18:33:19 | access to field s1 | $@ | Constructors.cs:21:29:21:45 | call to method Source<Object> : Object | call to method Source<Object> : Object |
Expand All @@ -157,3 +189,5 @@ subpaths
| Constructors.cs:93:14:93:21 | access to property Obj22 | Constructors.cs:91:21:91:37 | call to method Source<Object> : Object | Constructors.cs:93:14:93:21 | access to property Obj22 | $@ | Constructors.cs:91:21:91:37 | call to method Source<Object> : Object | call to method Source<Object> : Object |
| Constructors.cs:101:14:101:21 | access to property Obj22 | Constructors.cs:99:21:99:37 | call to method Source<Object> : Object | Constructors.cs:101:14:101:21 | access to property Obj22 | $@ | Constructors.cs:99:21:99:37 | call to method Source<Object> : Object | call to method Source<Object> : Object |
| Constructors.cs:113:14:113:21 | access to property Obj31 | Constructors.cs:111:19:111:35 | call to method Source<Object> : Object | Constructors.cs:113:14:113:21 | access to property Obj31 | $@ | Constructors.cs:111:19:111:35 | call to method Source<Object> : Object | call to method Source<Object> : Object |
| Constructors.cs:133:14:133:20 | access to property Obj1 | Constructors.cs:130:18:130:34 | call to method Source<Object> : Object | Constructors.cs:133:14:133:20 | access to property Obj1 | $@ | Constructors.cs:130:18:130:34 | call to method Source<Object> : Object | call to method Source<Object> : Object |
| Constructors.cs:134:14:134:20 | access to property Obj2 | Constructors.cs:131:18:131:34 | call to method Source<Object> : Object | Constructors.cs:134:14:134:20 | access to property Obj2 | $@ | Constructors.cs:131:18:131:34 | call to method Source<Object> : Object | call to method Source<Object> : Object |
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,27 @@ public void M5()
Sink(c3.Obj31); // $ hasValueFlow=6
}

public class C4
{
public object Obj1 { get; init; }
public object Obj2 { get; }

public C4(object oc1, object oc2)
{
Obj1 = oc1;
Obj2 = oc2;
}
}

public void M6()
{
var o1 = Source<object>(7);
var o2 = Source<object>(8);
var c4 = new C4(o1, o2);
Sink(c4.Obj1); // $ hasValueFlow=7
Sink(c4.Obj2); // $ hasValueFlow=8
}

public static void Sink(object o) { }

public static T Source<T>(object source) => throw null;
Expand Down