[analyzer] Suppress reports reported in std::list
The motivation is to suppresses false use-after-free reports that occur when calling std::list::pop_front() or std::list::pop_back() twice. The analyzer does not reason about the internal invariants of the list implementation, so just do not report any of warnings in std::list. Fixes radar://14317928. llvm-svn: 185609
This commit is contained in:
parent
5673b6567a
commit
a42fb525e4
|
@ -1521,18 +1521,33 @@ LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC,
|
|||
BugReport &BR) {
|
||||
// Here we suppress false positives coming from system headers. This list is
|
||||
// based on known issues.
|
||||
|
||||
// Skip reports within the 'std' namespace. Although these can sometimes be
|
||||
// the user's fault, we currently don't report them very well, and
|
||||
// Note that this will not help for any other data structure libraries, like
|
||||
// TR1, Boost, or llvm/ADT.
|
||||
ExprEngine &Eng = BRC.getBugReporter().getEngine();
|
||||
AnalyzerOptions &Options = Eng.getAnalysisManager().options;
|
||||
if (Options.shouldSuppressFromCXXStandardLibrary()) {
|
||||
const LocationContext *LCtx = N->getLocationContext();
|
||||
if (isInStdNamespace(LCtx->getDecl())) {
|
||||
const Decl *D = N->getLocationContext()->getDecl();
|
||||
|
||||
if (isInStdNamespace(D)) {
|
||||
// Skip reports within the 'std' namespace. Although these can sometimes be
|
||||
// the user's fault, we currently don't report them very well, and
|
||||
// Note that this will not help for any other data structure libraries, like
|
||||
// TR1, Boost, or llvm/ADT.
|
||||
if (Options.shouldSuppressFromCXXStandardLibrary()) {
|
||||
BR.markInvalid(getTag(), 0);
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
// If the the complete 'std' suppression is not enabled, suppress reports
|
||||
// from the 'std' namespace that are known to produce false positives.
|
||||
|
||||
// The analyzer issues a false use-after-free when std::list::pop_front
|
||||
// or std::list::pop_back are called multiple times because we cannot
|
||||
// reason about the internal invariants of the datastructure.
|
||||
const DeclContext *DC =
|
||||
D->getDeclContext()->getEnclosingNamespaceContext();
|
||||
const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC);
|
||||
if (ND && ND->getName() == "list") {
|
||||
BR.markInvalid(getTag(), 0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -86,6 +86,23 @@ namespace std {
|
|||
struct forward_iterator_tag : public input_iterator_tag { };
|
||||
struct bidirectional_iterator_tag : public forward_iterator_tag { };
|
||||
struct random_access_iterator_tag : public bidirectional_iterator_tag { };
|
||||
|
||||
template <class _Tp>
|
||||
class allocator {};
|
||||
|
||||
template <class _Tp, class _Alloc>
|
||||
class __list_imp
|
||||
{};
|
||||
|
||||
template <class _Tp, class _Alloc = allocator<_Tp> >
|
||||
class list
|
||||
: private __list_imp<_Tp, _Alloc>
|
||||
{
|
||||
public:
|
||||
void pop_front();
|
||||
bool empty() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void* operator new(std::size_t, const std::nothrow_t&) throw();
|
||||
|
|
|
@ -27,3 +27,9 @@ void testException(std::exception e) {
|
|||
// expected-warning@-4 {{UNKNOWN}}
|
||||
#endif
|
||||
}
|
||||
|
||||
void testList_pop_front(std::list<int> list) {
|
||||
while(!list.empty())
|
||||
list.pop_front(); // no-warning
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue