C++: getter/setter performance in StructLikeClass

The predicates `getter` and `setter` in `StructLikeClass.qll` were very
slow on some snapshots. On https://github.com/dotnet/coreclr they had
this performance:

    StructLikeClass::getter#fff#antijoin_rhs ........... 3m55s
    Variable::Variable::getAnAssignedValue_dispred#bb .. 3m36s
    StructLikeClass::setter#fff#antijoin_rhs ........... 20.5s

The `getAnAssignedValue_dispred` predicate in the middle was slow due to
magic propagated from `setter`.

With this commit, performance is instead:

   StructLikeClass::getter#fff#antijoin_rhs ........... 497ms
   Variable::Variable::getAnAssignedValue_dispred#ff .. 617ms
   StructLikeClass::setter#fff#antijoin_rhs ........... 158ms

Instead of hand-optimizing the QL for performance, I simplified `setter`
and `getter` to require slightly stronger conditions. Previously, a
function was only considered a setter if it had no writes to other
fields on the same class. That requirement is now relaxed by dropping
the "on the same class" part. I made the corresponding change for what
defines a getter. I think that still captures the spirit of what getters
and setters are.

I also changed the double-negation with `exists` into a `forall`.
This commit is contained in:
Jonas Jensen
2019-07-02 13:35:06 +02:00
parent 5ad0b39f0c
commit 2a6000c270

View File

@@ -53,10 +53,10 @@ predicate setter(MemberVariable v, MemberFunction f, Class c) {
v.getDeclaringType() = c and
f.getName().matches("set%") and
v.getAnAssignedValue().getEnclosingFunction() = f and
not exists(MemberVariable v2 |
v2.getDeclaringType() = c and
v2.getAnAssignedValue().getEnclosingFunction() = f and
v2 != v
forall(MemberVariable v2 |
v2.getAnAssignedValue().getEnclosingFunction() = f
|
v2 = v
) and
f.getNumberOfParameters() = 1 and
f.getParameter(0).getType().stripType() = v.getType().stripType()
@@ -71,10 +71,10 @@ predicate getter(MemberVariable v, MemberFunction f, Class c) {
v.getDeclaringType() = c and
f.getName().matches("get%") and
v.getAnAccess().getEnclosingFunction() = f and
not exists(MemberVariable v2 |
v2.getDeclaringType() = c and
v2.getAnAccess().getEnclosingFunction() = f and
v2 != v
forall(MemberVariable v2 |
v2.getAnAccess().getEnclosingFunction() = f
|
v2 = v
) and
f.getNumberOfParameters() = 0 and
f.getType().stripType() = v.getType().stripType()