Hello,
I'm running Clang static analyzer on LLVM, trying to help by fixing
the errors reported by scan-build.
Some of these errors look like false positives to me after reading
through the code.
Is there a way to report/declare such false positives in order to
filter them out in the subsequent runs of the static analyser ?
Cheers.
Unfortunately, there is not a holistic mechanism for suppressing false positives from subsequent analyzer runs.
For many false positives, there is some underlying invariant that the analyzer doesn’t understand. For these, you can often add a carefully-placed assert() to then code to tell the analyzer about the invariant (and get dynamic checking of the invariant when assertions are enabled!). You can also hide code from the analyzer with:
#ifndef __clang_analyzer__
// Code not to be analyzed
#endif
There is a FAQ describing these suppression mechanisms and others at <http://clang-analyzer.llvm.org/faq.html>\.
Devin
I remember seeing something about the static analyzer checking asserts in the docs, how well does that actually work?
You should probably have a look at GitHub - Ericsson/codechecker: CodeChecker is an analyzer tooling, defect database and viewer extension for the Clang Static Analyzer and Clang Tidy - a web interface for the analyzer that provides a database for storing positives.
I remember seeing something about the static analyzer checking asserts in the docs, how well does that actually work?
It needs you to compile with asserts enabled for analysis, and the assertion mechanism should be supported by the core checkers (eg. __assert(), __assert2(), _wassert(), __assert_fail(), exit(), etc., or a macro that expands to one of those - the complete list is in lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp , you can probably add your custom implementation of assert here).
As long as it realizes that a no-return function is called, the analyzer should stop analysis along the respective path.
Just to be clear, unlike many verification tools, the analyzer doesn’t “check” asserts. In verification-speak, it treats an assert like an assume. That is, if you have:
1: int *x = NULL;
2: assert(x != NULL);
3: *x = 7;
The analyzer will not warn that the assertion will definitely fail at line 2.
Instead, because assert(condition) is typically defined as a macro to expand to something like:
if (!condition) {
…
exit(-1);
}
The assert will cause the analyzer to explore two paths: one where the condition doesn’t hold and exit() is called and one where the condition is assumed to hold and execution continues.
As Artem described, the analyzer will stop exploring the exit() path because exit() is noreturn. But in this case, the analyzer will also stop exploring the path where the condition holds (i.e., x != NULL). This is because along that path the analyzer also knows x == NULL (from line 1). This is a contradiction, which the analyzer interprets to mean the path is infeasible and so it will stop exploring this path as well. Ultimately this means the analyzer will not warn about the null pointer dereference at line 3.
By the way, there is a webpage describing how the analyzer deals with custom assertions at <http://clang-analyzer.llvm.org/annotations.html#custom_assertions>.
Devin
Just to be clear, unlike many verification tools, the analyzer doesn’t “check” asserts. In verification-speak, it treats an assert like an assume. That is, if you have:
1: int *x = NULL;
2: assert(x != NULL);
3: *x = 7;
The analyzer will *not* warn that the assertion will definitely fail at line 2.
This is exactly one kind of situation where I would like to add some
suppression mechanism.
Speaking of custom assertion handlers and their specific suppression
mechanism ('noreturn' and 'analyzer_noreturn' attributes), documentation says:
"Note that, currently, clang does not support these attributes on
Objective-C methods and C++ methods."
Does the above statement still hold true at the moment ?
I found custom assertion handlers defined as C++ methods and not being
able to suppress the analyzer warnings would be a pity.
How hard would it be to extend the aforementioned attributes to C++
methods if needed ?
Instead, because assert(condition) is typically defined as a macro to expand to something like:
if (!condition) {
...
exit(-1);
}
The assert will cause the analyzer to explore two paths: one where the condition doesn’t hold and exit() is called and one where the condition is assumed to hold and execution continues.
As Artem described, the analyzer will stop exploring the exit() path because exit() is noreturn. But in this case, the analyzer will also stop exploring the path where the condition holds (i.e., x != NULL). This is because along that path the analyzer also knows x == NULL (from line 1). This is a contradiction, which the analyzer interprets to mean the path is infeasible and so it will stop exploring this path as well. Ultimately this means the analyzer will not warn about the null pointer dereference at line 3.
By the way, there is a webpage describing how the analyzer deals with custom assertions at <Source Annotations.
Very informative indeed, thank you very much for the insight.
Cheers.
Has anybody considered somehow configuring the analyzer to treat asserts like calls to clang_analyzer_eval? If I understand correctly, that would enable it to report when assertions were obviously false? (of course, then it’d produce a ton of TRUEs and UNKNOWNs too…)