[cfe-dev] [analyzer] Temporaries.
Artem Dergachev via cfe-dev
cfe-dev at lists.llvm.org
Fri Mar 16 14:22:19 PDT 2018
A bit of an update. Previous messages for easier navigation through this
thread:
http://lists.llvm.org/pipermail/cfe-dev/2018-January/056691.html
http://lists.llvm.org/pipermail/cfe-dev/2018-February/056813.html
http://lists.llvm.org/pipermail/cfe-dev/2018-February/056898.html
http://lists.llvm.org/pipermail/cfe-dev/2018-February/056909.html
http://lists.llvm.org/pipermail/cfe-dev/2018-February/056929.html
== Overall status ==
Previous changes had minimal effects on the false positives i observed.
However, once return-by-value and construction-conversion support has
landed, improved modeling has finally yielded significant results,
fixing at least 150 false positives (around 40% of all positives) on a
few sub-projects of WebKit (incl. WebCore, JavaScriptCore).
Large chunks of the remaining false positives are related to brace
initialization constructors which i'll try to support at least in simple
cases (eg. a single layer of braces).
Many of the remaining reports are hard to understand - it seems that
trackNullOrUndefValue isn't always doing a good job. Other reports are
over-saturated with inlined temporary destructors: path pruning may be
working incorrectly.
On other projects i've seen interesting bug reports against code that
works incorrectly when copy elision isn't happening (of a poorly
implemented class that performs memory management). We're capable of
finding such bugs because we don't model copy elision yet. Such code is
not portable, but many users that use just one compiler can afford
relying on its implementation details, and copy elision is usually
supported by most major compilers. These reports would probably go away
because i'd like to model copy elision anyway because it's generally a
good thing: it improves analyzer performance and reduces path lengths.
And we'd still catch these bugs when non-elidable copies will be made.
These results are with temporary destructor inlining turned on. I'm
holding off on destructor inlining for now because i'm seeing false
positives on other projects, even though the reference counting
suppression is working fairly well.
Lack of default argument support is still causing a small but noticeable
coverage drop. The CFG for this syntax seems usable but i guess full
support would require introducing a new LocationContext sub-class.
Binary conditional operators are still not supported (even in CFG), but
it doesn't seem to cause many problems.
== C++17 problems ==
> http://en.cppreference.com/w/cpp/language/copy_elision
> (since C++17)
> Under the following circumstances, the compilers are REQUIRED to omit
the copy- and move- construction of class objects even if the copy/move
constructor and the destructor have observable side-effects. They need
not be present or accessible, as the language rules ensure that no
copy/move operation takes place, even conceptually:
> In initialization, if the initializer expression is a prvalue and the
cv-unqualified version of the source type is the same class as the class
of the destination, the initializer expression is used to initialize the
destination object...
> In a function call, if the operand of a return statement is a prvalue
and the return type of the function is the same as the type of that
prvalue...
This is going to be fun to support. Specifically, this means that
neither initialization 'C c = C();' nor return-statement 'return C()'
(where 'C()' may as well be replaced with a function call of type 'C')
contains an elidable copy in the AST anymore, but only a single
constructor of variable 'c' (or the returned-to object) - probably with
an intermediate CXXBindTemporaryExpr if the class has a non-trivial
destructor. A few consequences of this change:
* For now the CFG itself is broken in this case because it includes a
temporary destructor that shouldn't be there.
* The construction context for a function that returns an object by
value may now be not only a temporary object context, but also a simple
variable context or a returned value context - we'll need to handle
these cases.
* Liveness does not work correctly - previously it was relying on
CXXBindTemporaryExpr or MaterializeTemporaryExpr but now these aren't
guaranteed to even exist, so by the time we reach 'c' from 'C()' we may
already destroy bindings to the not-yet-alive variable 'c' we've added
in the constructor. This is especially obvious for the conditional
operator case, i.e. 'C c = x ? C(1) : C(2);' - in this case in C++17
there is just one constructor happening on every particular path.
* Returned values may now chain together - the target object of a
constructor that's called as part of the return statement may be
multiple stack frames above the constructor call, which we'd need to
unwind recursively.
For now i'll disable temporary- and returned-value- construction
contexts in C++17.
More information about the cfe-dev
mailing list