Skip to content

Commit bf94a75

Browse files
authored
Merge pull request github#15502 from michaelnebel/csharp/refstructdataflow
C#: Inter-procedural dataflow for `ref` structs when used as arguments.
2 parents 6df313b + 551a7f9 commit bf94a75

File tree

3 files changed

+74
-1
lines changed

3 files changed

+74
-1
lines changed

csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,8 @@ module LocalFlow {
540540
not t instanceof NullType
541541
or
542542
t = any(TypeParameter tp | not tp.isValueType())
543+
or
544+
t.(Struct).isRef()
543545
) and
544546
not exists(getALastEvalNode(result))
545547
}
@@ -2015,6 +2017,14 @@ predicate clearsContent(Node n, ContentSet c) {
20152017
f = oi.getAMemberInitializer().getInitializedMember() and
20162018
c = f.getContent()
20172019
)
2020+
or
2021+
exists(Argument a, Struct s, Field f |
2022+
a = n.(PostUpdateNode).getPreUpdateNode().asExpr() and
2023+
a.getType() = s and
2024+
f = s.getAField() and
2025+
c.(FieldContent).getField() = f.getUnboundDeclaration() and
2026+
not f.isRef()
2027+
)
20182028
}
20192029

20202030
/**

csharp/ql/test/library-tests/dataflow/fields/E.cs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ static void NotASetter(S s, object o)
1717
s.Field = o;
1818
}
1919

20-
private void M()
20+
private void M1()
2121
{
2222
var o = Source<object>(1);
2323
var s = CreateS(o);
@@ -28,6 +28,35 @@ private void M()
2828
Sink(s.Field); // no flow
2929
}
3030

31+
ref struct RefS
32+
{
33+
public object Field;
34+
public ref object RefField;
35+
36+
public RefS(object o1, ref object o2)
37+
{
38+
Field = o1;
39+
RefField = ref o2;
40+
}
41+
}
42+
43+
static void PartialSetter(RefS s, object o)
44+
{
45+
s.Field = o;
46+
s.RefField = o;
47+
}
48+
49+
private void M2()
50+
{
51+
var o1 = new object();
52+
var o2 = new object();
53+
var refs = new RefS(o1, ref o2);
54+
var taint = Source<object>(2);
55+
PartialSetter(refs, taint);
56+
Sink(refs.Field); // no flow
57+
Sink(refs.RefField); // $ hasValueFlow=2
58+
}
59+
3160
public static void Sink(object o) { }
3261

3362
static T Source<T>(object source) => throw null;

csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,20 @@ edges
438438
| E.cs:23:25:23:25 | access to local variable o : Object | E.cs:23:17:23:26 | call to method CreateS : S [field Field] : Object |
439439
| E.cs:24:14:24:14 | access to local variable s : S [field Field] : Object | E.cs:24:14:24:20 | access to field Field |
440440
| E.cs:24:14:24:14 | access to local variable s : S [field Field] : Object | E.cs:24:14:24:20 | access to field Field |
441+
| E.cs:43:46:43:46 | o : Object | E.cs:46:22:46:22 | access to parameter o : Object |
442+
| E.cs:43:46:43:46 | o : Object | E.cs:46:22:46:22 | access to parameter o : Object |
443+
| E.cs:46:22:46:22 | access to parameter o : Object | E.cs:46:9:46:9 | [post] access to parameter s : RefS [field RefField] : Object |
444+
| E.cs:46:22:46:22 | access to parameter o : Object | E.cs:46:9:46:9 | [post] access to parameter s : RefS [field RefField] : Object |
445+
| E.cs:54:21:54:37 | call to method Source<Object> : Object | E.cs:55:29:55:33 | access to local variable taint : Object |
446+
| E.cs:54:21:54:37 | call to method Source<Object> : Object | E.cs:55:29:55:33 | access to local variable taint : Object |
447+
| E.cs:55:23:55:26 | [post] access to local variable refs : RefS [field RefField] : Object | E.cs:57:14:57:17 | access to local variable refs : RefS [field RefField] : Object |
448+
| E.cs:55:23:55:26 | [post] access to local variable refs : RefS [field RefField] : Object | E.cs:57:14:57:17 | access to local variable refs : RefS [field RefField] : Object |
449+
| E.cs:55:29:55:33 | access to local variable taint : Object | E.cs:43:46:43:46 | o : Object |
450+
| E.cs:55:29:55:33 | access to local variable taint : Object | E.cs:43:46:43:46 | o : Object |
451+
| E.cs:55:29:55:33 | access to local variable taint : Object | E.cs:55:23:55:26 | [post] access to local variable refs : RefS [field RefField] : Object |
452+
| E.cs:55:29:55:33 | access to local variable taint : Object | E.cs:55:23:55:26 | [post] access to local variable refs : RefS [field RefField] : Object |
453+
| E.cs:57:14:57:17 | access to local variable refs : RefS [field RefField] : Object | E.cs:57:14:57:26 | access to field RefField |
454+
| E.cs:57:14:57:17 | access to local variable refs : RefS [field RefField] : Object | E.cs:57:14:57:26 | access to field RefField |
441455
| F.cs:6:28:6:29 | o1 : Object | F.cs:6:65:6:66 | access to parameter o1 : Object |
442456
| F.cs:6:28:6:29 | o1 : Object | F.cs:6:65:6:66 | access to parameter o1 : Object |
443457
| F.cs:6:39:6:40 | o2 : Object | F.cs:6:78:6:79 | access to parameter o2 : Object |
@@ -1403,6 +1417,22 @@ nodes
14031417
| E.cs:24:14:24:14 | access to local variable s : S [field Field] : Object | semmle.label | access to local variable s : S [field Field] : Object |
14041418
| E.cs:24:14:24:20 | access to field Field | semmle.label | access to field Field |
14051419
| E.cs:24:14:24:20 | access to field Field | semmle.label | access to field Field |
1420+
| E.cs:43:46:43:46 | o : Object | semmle.label | o : Object |
1421+
| E.cs:43:46:43:46 | o : Object | semmle.label | o : Object |
1422+
| E.cs:46:9:46:9 | [post] access to parameter s : RefS [field RefField] : Object | semmle.label | [post] access to parameter s : RefS [field RefField] : Object |
1423+
| E.cs:46:9:46:9 | [post] access to parameter s : RefS [field RefField] : Object | semmle.label | [post] access to parameter s : RefS [field RefField] : Object |
1424+
| E.cs:46:22:46:22 | access to parameter o : Object | semmle.label | access to parameter o : Object |
1425+
| E.cs:46:22:46:22 | access to parameter o : Object | semmle.label | access to parameter o : Object |
1426+
| E.cs:54:21:54:37 | call to method Source<Object> : Object | semmle.label | call to method Source<Object> : Object |
1427+
| E.cs:54:21:54:37 | call to method Source<Object> : Object | semmle.label | call to method Source<Object> : Object |
1428+
| E.cs:55:23:55:26 | [post] access to local variable refs : RefS [field RefField] : Object | semmle.label | [post] access to local variable refs : RefS [field RefField] : Object |
1429+
| E.cs:55:23:55:26 | [post] access to local variable refs : RefS [field RefField] : Object | semmle.label | [post] access to local variable refs : RefS [field RefField] : Object |
1430+
| E.cs:55:29:55:33 | access to local variable taint : Object | semmle.label | access to local variable taint : Object |
1431+
| E.cs:55:29:55:33 | access to local variable taint : Object | semmle.label | access to local variable taint : Object |
1432+
| E.cs:57:14:57:17 | access to local variable refs : RefS [field RefField] : Object | semmle.label | access to local variable refs : RefS [field RefField] : Object |
1433+
| E.cs:57:14:57:17 | access to local variable refs : RefS [field RefField] : Object | semmle.label | access to local variable refs : RefS [field RefField] : Object |
1434+
| E.cs:57:14:57:26 | access to field RefField | semmle.label | access to field RefField |
1435+
| E.cs:57:14:57:26 | access to field RefField | semmle.label | access to field RefField |
14061436
| F.cs:6:28:6:29 | o1 : Object | semmle.label | o1 : Object |
14071437
| F.cs:6:28:6:29 | o1 : Object | semmle.label | o1 : Object |
14081438
| F.cs:6:39:6:40 | o2 : Object | semmle.label | o2 : Object |
@@ -2004,6 +2034,8 @@ subpaths
20042034
| D.cs:47:14:47:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:14:9:14:11 | this : D [field trivialPropField] : Object | D.cs:14:22:14:42 | access to field trivialPropField : Object | D.cs:47:14:47:26 | access to property ComplexProp |
20052035
| E.cs:23:25:23:25 | access to local variable o : Object | E.cs:8:29:8:29 | o : Object | E.cs:12:16:12:18 | access to local variable ret : S [field Field] : Object | E.cs:23:17:23:26 | call to method CreateS : S [field Field] : Object |
20062036
| E.cs:23:25:23:25 | access to local variable o : Object | E.cs:8:29:8:29 | o : Object | E.cs:12:16:12:18 | access to local variable ret : S [field Field] : Object | E.cs:23:17:23:26 | call to method CreateS : S [field Field] : Object |
2037+
| E.cs:55:29:55:33 | access to local variable taint : Object | E.cs:43:46:43:46 | o : Object | E.cs:46:9:46:9 | [post] access to parameter s : RefS [field RefField] : Object | E.cs:55:23:55:26 | [post] access to local variable refs : RefS [field RefField] : Object |
2038+
| E.cs:55:29:55:33 | access to local variable taint : Object | E.cs:43:46:43:46 | o : Object | E.cs:46:9:46:9 | [post] access to parameter s : RefS [field RefField] : Object | E.cs:55:23:55:26 | [post] access to local variable refs : RefS [field RefField] : Object |
20072039
| F.cs:11:24:11:24 | access to local variable o : Object | F.cs:6:28:6:29 | o1 : Object | F.cs:6:46:6:81 | object creation of type F : F [field Field1] : Object | F.cs:11:17:11:31 | call to method Create : F [field Field1] : Object |
20082040
| F.cs:11:24:11:24 | access to local variable o : Object | F.cs:6:28:6:29 | o1 : Object | F.cs:6:46:6:81 | object creation of type F : F [field Field1] : Object | F.cs:11:17:11:31 | call to method Create : F [field Field1] : Object |
20092041
| F.cs:15:26:15:42 | call to method Source<Object> : Object | F.cs:6:39:6:40 | o2 : Object | F.cs:6:46:6:81 | object creation of type F : F [field Field2] : Object | F.cs:15:13:15:43 | call to method Create : F [field Field2] : Object |
@@ -2109,6 +2141,8 @@ subpaths
21092141
| D.cs:47:14:47:26 | access to property ComplexProp | D.cs:43:32:43:48 | call to method Source<Object> : Object | D.cs:47:14:47:26 | access to property ComplexProp | $@ | D.cs:43:32:43:48 | call to method Source<Object> : Object | call to method Source<Object> : Object |
21102142
| E.cs:24:14:24:20 | access to field Field | E.cs:22:17:22:33 | call to method Source<Object> : Object | E.cs:24:14:24:20 | access to field Field | $@ | E.cs:22:17:22:33 | call to method Source<Object> : Object | call to method Source<Object> : Object |
21112143
| E.cs:24:14:24:20 | access to field Field | E.cs:22:17:22:33 | call to method Source<Object> : Object | E.cs:24:14:24:20 | access to field Field | $@ | E.cs:22:17:22:33 | call to method Source<Object> : Object | call to method Source<Object> : Object |
2144+
| E.cs:57:14:57:26 | access to field RefField | E.cs:54:21:54:37 | call to method Source<Object> : Object | E.cs:57:14:57:26 | access to field RefField | $@ | E.cs:54:21:54:37 | call to method Source<Object> : Object | call to method Source<Object> : Object |
2145+
| E.cs:57:14:57:26 | access to field RefField | E.cs:54:21:54:37 | call to method Source<Object> : Object | E.cs:57:14:57:26 | access to field RefField | $@ | E.cs:54:21:54:37 | call to method Source<Object> : Object | call to method Source<Object> : Object |
21122146
| F.cs:12:14:12:21 | access to field Field1 | F.cs:10:17:10:33 | call to method Source<Object> : Object | F.cs:12:14:12:21 | access to field Field1 | $@ | F.cs:10:17:10:33 | call to method Source<Object> : Object | call to method Source<Object> : Object |
21132147
| F.cs:12:14:12:21 | access to field Field1 | F.cs:10:17:10:33 | call to method Source<Object> : Object | F.cs:12:14:12:21 | access to field Field1 | $@ | F.cs:10:17:10:33 | call to method Source<Object> : Object | call to method Source<Object> : Object |
21142148
| F.cs:17:14:17:21 | access to field Field2 | F.cs:15:26:15:42 | call to method Source<Object> : Object | F.cs:17:14:17:21 | access to field Field2 | $@ | F.cs:15:26:15:42 | call to method Source<Object> : Object | call to method Source<Object> : Object |

0 commit comments

Comments
 (0)