Skip to content

Commit 5102fcd

Browse files
committed
C#: Rewrite predicates from using forall to using unique
This avoids generation of expensive anti-join predicates with Cartesian products.
1 parent 2361476 commit 5102fcd

File tree

2 files changed

+50
-16
lines changed

2 files changed

+50
-16
lines changed

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

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,8 +1466,10 @@ module Internal {
14661466
PreSsa::Definition def, AssignableRead read
14671467
) {
14681468
read = def.getAFirstRead() and
1469-
not exists(AssignableRead other | PreSsa::adjacentReadPairSameVar(other, read) |
1470-
other != read
1469+
(
1470+
not PreSsa::adjacentReadPairSameVar(_, read)
1471+
or
1472+
read = unique(AssignableRead read0 | PreSsa::adjacentReadPairSameVar(read0, read))
14711473
)
14721474
}
14731475

@@ -1651,10 +1653,14 @@ module Internal {
16511653
AssignableRead read1, AssignableRead read2
16521654
) {
16531655
PreSsa::adjacentReadPairSameVar(read1, read2) and
1654-
not exists(AssignableRead other |
1655-
PreSsa::adjacentReadPairSameVar(other, read2) and
1656-
other != read1 and
1657-
other != read2
1656+
(
1657+
read1 = read2 and
1658+
read1 = unique(AssignableRead other | PreSsa::adjacentReadPairSameVar(other, read2))
1659+
or
1660+
read1 =
1661+
unique(AssignableRead other |
1662+
PreSsa::adjacentReadPairSameVar(other, read2) and other != read2
1663+
)
16581664
)
16591665
}
16601666

@@ -1887,10 +1893,14 @@ module Internal {
18871893
Ssa::Definition def, ControlFlow::Node cfn1, ControlFlow::Node cfn2
18881894
) {
18891895
SsaImpl::adjacentReadPairSameVar(def, cfn1, cfn2) and
1890-
not exists(ControlFlow::Node other |
1891-
SsaImpl::adjacentReadPairSameVar(def, other, cfn2) and
1892-
other != cfn1 and
1893-
other != cfn2
1896+
(
1897+
cfn1 = cfn2 and
1898+
cfn1 = unique(ControlFlow::Node other | SsaImpl::adjacentReadPairSameVar(def, other, cfn2))
1899+
or
1900+
cfn1 =
1901+
unique(ControlFlow::Node other |
1902+
SsaImpl::adjacentReadPairSameVar(def, other, cfn2) and other != cfn2
1903+
)
18941904
)
18951905
}
18961906

csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplSpecific.qll

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,37 @@ class ExitBasicBlock extends BasicBlock {
1515
ExitBasicBlock() { scopeLast(_, this.getLastElement(), _) }
1616
}
1717

18-
pragma[noinline]
18+
/** Holds if `a` is assigned in non-constructor callable `c`. */
19+
pragma[nomagic]
20+
private predicate assignableDefinition(Assignable a, Callable c) {
21+
exists(AssignableDefinition def | def.getTarget() = a |
22+
c = def.getEnclosingCallable() and
23+
not c instanceof Constructor
24+
)
25+
}
26+
27+
/** Holds if `a` is accessed in callable `c`. */
28+
pragma[nomagic]
29+
private predicate assignableAccess(Assignable a, Callable c) {
30+
exists(AssignableAccess aa | aa.getTarget() = a | c = aa.getEnclosingCallable())
31+
}
32+
33+
pragma[nomagic]
1934
private predicate assignableNoCapturing(Assignable a, Callable c) {
20-
exists(AssignableAccess aa | aa.getTarget() = a | c = aa.getEnclosingCallable()) and
21-
forall(AssignableDefinition def | def.getTarget() = a |
22-
c = def.getEnclosingCallable()
35+
assignableAccess(a, c) and
36+
/*
37+
* The code below is equivalent to
38+
* ```ql
39+
* not exists(Callable other | assignableDefinition(a, other) | other != c)
40+
* ```
41+
* but it avoids a Cartesian product in the compiler generated antijoin
42+
* predicate.
43+
*/
44+
45+
(
46+
not assignableDefinition(a, _)
2347
or
24-
def.getEnclosingCallable() instanceof Constructor
48+
c = unique(Callable c0 | assignableDefinition(a, c0) | c0)
2549
)
2650
}
2751

@@ -41,7 +65,7 @@ class SourceVariable extends Assignable {
4165
(
4266
this instanceof LocalScopeVariable
4367
or
44-
this instanceof Field
68+
this = any(Field f | not f.isVolatile())
4569
or
4670
this = any(TrivialProperty tp | not tp.isOverridableOrImplementable())
4771
) and

0 commit comments

Comments
 (0)