Skip to content

Commit 08f5c2b

Browse files
authored
Merge pull request #567 from hvitved/csharp/guards-splitting
C#: Account for split SSA definitions in guards library
2 parents 60076cb + 3eb163f commit 08f5c2b

File tree

5 files changed

+32
-13
lines changed

5 files changed

+32
-13
lines changed

csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ class AccessOrCallExpr extends Expr {
285285
Declaration getTarget() { result = target }
286286

287287
/**
288-
* Gets the (non-trivial) SSA definition corresponding to the longest
288+
* Gets a (non-trivial) SSA definition corresponding to the longest
289289
* qualifier chain of this expression, if any.
290290
*
291291
* This includes the case where this expression is itself an access to an
@@ -299,25 +299,23 @@ class AccessOrCallExpr extends Expr {
299299
* x.Foo().Bar(); // SSA qualifier: SSA definition for `x`
300300
* x; // SSA qualifier: SSA definition for `x`
301301
* ```
302+
*
303+
* An expression can have more than one SSA qualifier in the presence
304+
* of control flow splitting.
302305
*/
303-
Ssa::Definition getSsaQualifier() { result = getSsaQualifier(this) }
304-
305-
/**
306-
* Holds if this expression has an SSA qualifier.
307-
*/
308-
predicate hasSsaQualifier() { exists(this.getSsaQualifier()) }
306+
Ssa::Definition getAnSsaQualifier() { result = getAnSsaQualifier(this) }
309307
}
310308

311309
private Declaration getDeclarationTarget(Expr e) {
312310
e = any(AssignableRead ar | result = ar.getTarget()) or
313311
result = e.(Call).getTarget()
314312
}
315313

316-
private Ssa::Definition getSsaQualifier(Expr e) {
314+
private Ssa::Definition getAnSsaQualifier(Expr e) {
317315
e = getATrackedRead(result)
318316
or
319317
not e = getATrackedRead(_) and
320-
result = getSsaQualifier(e.(QualifiableExpr).getQualifier())
318+
result = getAnSsaQualifier(e.(QualifiableExpr).getQualifier())
321319
}
322320

323321
private AssignableRead getATrackedRead(Ssa::Definition def) {
@@ -688,10 +686,9 @@ module Internal {
688686
predicate isGuardedBy(AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, AbstractValue v) {
689687
isGuardedBy1(guarded, g, sub, v) and
690688
sub = g.getAChildExpr*() and
691-
(
692-
not guarded.hasSsaQualifier() and not sub.hasSsaQualifier()
693-
or
694-
guarded.getSsaQualifier() = sub.getSsaQualifier()
689+
forall(Ssa::Definition def |
690+
def = sub.getAnSsaQualifier() |
691+
def = guarded.getAnSsaQualifier()
695692
)
696693
}
697694
}

csharp/ql/test/library-tests/controlflow/guards/BooleanGuardedExpr.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,4 @@
8282
| Splitting.cs:117:9:117:9 | access to parameter o | Splitting.cs:116:22:116:30 | ... != ... | Splitting.cs:116:22:116:22 | access to parameter o | true |
8383
| Splitting.cs:119:13:119:13 | access to parameter o | Splitting.cs:116:22:116:30 | ... != ... | Splitting.cs:116:22:116:22 | access to parameter o | true |
8484
| Splitting.cs:120:16:120:16 | access to parameter o | Splitting.cs:116:22:116:30 | ... != ... | Splitting.cs:116:22:116:22 | access to parameter o | true |
85+
| Splitting.cs:132:25:132:25 | access to parameter b | Splitting.cs:130:21:130:21 | access to parameter b | Splitting.cs:130:21:130:21 | access to parameter b | false |

csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,3 +195,4 @@
195195
| Splitting.cs:119:13:119:13 | access to parameter o | Splitting.cs:116:22:116:30 | ... != ... | Splitting.cs:116:22:116:22 | access to parameter o | true |
196196
| Splitting.cs:120:16:120:16 | access to parameter o | Splitting.cs:116:22:116:22 | access to parameter o | Splitting.cs:116:22:116:22 | access to parameter o | non-null |
197197
| Splitting.cs:120:16:120:16 | access to parameter o | Splitting.cs:116:22:116:30 | ... != ... | Splitting.cs:116:22:116:22 | access to parameter o | true |
198+
| Splitting.cs:132:25:132:25 | access to parameter b | Splitting.cs:130:21:130:21 | access to parameter b | Splitting.cs:130:21:130:21 | access to parameter b | false |

csharp/ql/test/library-tests/controlflow/guards/Implications.expected

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,3 +224,7 @@
224224
| Splitting.cs:105:22:105:30 | ... != ... | true | Splitting.cs:105:22:105:22 | access to parameter o | non-null |
225225
| Splitting.cs:116:22:116:30 | ... != ... | false | Splitting.cs:116:22:116:22 | access to parameter o | null |
226226
| Splitting.cs:116:22:116:30 | ... != ... | true | Splitting.cs:116:22:116:22 | access to parameter o | non-null |
227+
| Splitting.cs:128:17:128:25 | ... != ... | false | Splitting.cs:128:17:128:17 | access to local variable o | null |
228+
| Splitting.cs:128:17:128:25 | ... != ... | true | Splitting.cs:128:17:128:17 | access to local variable o | non-null |
229+
| Splitting.cs:133:17:133:17 | access to local variable o | non-null | Splitting.cs:132:21:132:29 | call to method M11 | non-null |
230+
| Splitting.cs:133:17:133:17 | access to local variable o | null | Splitting.cs:132:21:132:29 | call to method M11 | null |

csharp/ql/test/library-tests/controlflow/guards/Splitting.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,4 +119,20 @@ string M11(bool b, object o)
119119
o.ToString(); // null guarded
120120
return o.ToString(); // null guarded
121121
}
122+
123+
public void M12(int i, bool b)
124+
{
125+
object o = null;
126+
do
127+
{
128+
if (o != null)
129+
{
130+
if (b)
131+
return;
132+
o = M11(b, o);
133+
o.GetHashCode(); // not null guarded
134+
}
135+
}
136+
while (i > 0);
137+
}
122138
}

0 commit comments

Comments
 (0)