Files
clang-p2996/clang/test/Analysis/inlining/containers.cpp
Anna Zaks b8de0c4278 Do not inline methods of C++ containers (coming from headers).
This silences false positives (leaks, use of uninitialized value) in simple
code that uses containers such as std::vector and std::list. The analyzer
cannot reason about the internal invariances of those data structures which
leads to false positives. Until we come up with a better solution to that
problem, let's just not inline the methods of the containers and allow objects
to escape whenever such methods are called.

This just extends an already existing flag "c++-container-inlining" and applies
the heuristic not only to constructors and destructors of the containers, but
to all of their methods.

We have a bunch of distinct user reports all related to this issue
(radar://16058651, radar://16580751, radar://16384286, radar://16795491
[PR19637]).

llvm-svn: 211832
2014-06-27 01:03:05 +00:00

272 lines
5.3 KiB
C++

// RUN: %clang_cc1 -analyze -std=c++11 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-inlining=destructors -analyzer-config c++-container-inlining=false -verify %s
// RUN: %clang_cc1 -analyze -std=c++11 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-inlining=destructors -analyzer-config c++-container-inlining=true -DINLINE=1 -verify %s
#ifndef HEADER
void clang_analyzer_eval(bool);
void clang_analyzer_checkInlined(bool);
#define HEADER
#include "containers.cpp"
#undef HEADER
void test() {
MySet set(0);
clang_analyzer_eval(set.isEmpty());
#if INLINE
// expected-warning@-2 {{TRUE}}
#else
// expected-warning@-4 {{UNKNOWN}}
#endif
clang_analyzer_eval(set.raw_begin() == set.raw_end());
#if INLINE
// expected-warning@-2 {{TRUE}}
#else
// expected-warning@-4 {{UNKNOWN}}
#endif
clang_analyzer_eval(set.begin().impl == set.end().impl);
#if INLINE
// expected-warning@-2 {{TRUE}}
#else
// expected-warning@-4 {{UNKNOWN}}
#endif
}
void testSubclass(MySetSubclass &sub) {
sub.useIterator(sub.begin());
MySetSubclass local;
}
void testWrappers(BeginOnlySet &w1, IteratorStructOnlySet &w2,
IteratorTypedefOnlySet &w3, IteratorUsingOnlySet &w4) {
BeginOnlySet local1;
IteratorStructOnlySet local2;
IteratorTypedefOnlySet local3;
IteratorUsingOnlySet local4;
clang_analyzer_eval(w1.begin().impl.impl == w1.begin().impl.impl);
#if INLINE
// expected-warning@-2 {{TRUE}}
#else
// expected-warning@-4 {{UNKNOWN}}
#endif
clang_analyzer_eval(w2.start().impl == w2.start().impl);
#if INLINE
// expected-warning@-2 {{TRUE}}
#else
// expected-warning@-4 {{UNKNOWN}}
#endif
clang_analyzer_eval(w3.start().impl == w3.start().impl);
#if INLINE
// expected-warning@-2 {{TRUE}}
#else
// expected-warning@-4 {{UNKNOWN}}
#endif
clang_analyzer_eval(w4.start().impl == w4.start().impl);
#if INLINE
// expected-warning@-2 {{TRUE}}
#else
// expected-warning@-4 {{UNKNOWN}}
#endif
}
#else // HEADER
#include "../Inputs/system-header-simulator-cxx.h"
class MySet {
int *storage;
unsigned size;
public:
MySet() : storage(0), size(0) {
clang_analyzer_checkInlined(true);
#if INLINE
// expected-warning@-2 {{TRUE}}
#endif
}
MySet(unsigned n) : storage(new int[n]), size(n) {
clang_analyzer_checkInlined(true);
#if INLINE
// expected-warning@-2 {{TRUE}}
#endif
}
~MySet() { delete[] storage; }
bool isEmpty() {
clang_analyzer_checkInlined(true);
#if INLINE
// expected-warning@-2 {{TRUE}}
#endif
return size == 0;
}
struct iterator {
int *impl;
iterator(int *p) : impl(p) {}
};
iterator begin() {
clang_analyzer_checkInlined(true);
#if INLINE
// expected-warning@-2 {{TRUE}}
#endif
return iterator(storage);
}
iterator end() {
clang_analyzer_checkInlined(true);
#if INLINE
// expected-warning@-2 {{TRUE}}
#endif
return iterator(storage+size);
}
typedef int *raw_iterator;
raw_iterator raw_begin() {
clang_analyzer_checkInlined(true);
#if INLINE
// expected-warning@-2 {{TRUE}}
#endif
return storage;
}
raw_iterator raw_end() {
clang_analyzer_checkInlined(true);
#if INLINE
// expected-warning@-2 {{TRUE}}
#endif
return storage + size;
}
};
class MySetSubclass : public MySet {
public:
MySetSubclass() {
clang_analyzer_checkInlined(true);
#if INLINE
// expected-warning@-2 {{TRUE}}
#endif
}
void useIterator(iterator i) {
clang_analyzer_checkInlined(true);
#if INLINE
// expected-warning@-2 {{TRUE}}
#endif
}
};
class BeginOnlySet {
MySet impl;
public:
struct IterImpl {
MySet::iterator impl;
typedef std::forward_iterator_tag iterator_category;
IterImpl(MySet::iterator i) : impl(i) {
clang_analyzer_checkInlined(true);
#if INLINE
// expected-warning@-2 {{TRUE}}
#endif
}
};
BeginOnlySet() {
clang_analyzer_checkInlined(true);
#if INLINE
// expected-warning@-2 {{TRUE}}
#endif
}
typedef IterImpl wrapped_iterator;
wrapped_iterator begin() {
clang_analyzer_checkInlined(true);
#if INLINE
// expected-warning@-2 {{TRUE}}
#endif
return IterImpl(impl.begin());
}
};
class IteratorTypedefOnlySet {
MySet impl;
public:
IteratorTypedefOnlySet() {
clang_analyzer_checkInlined(true);
#if INLINE
// expected-warning@-2 {{TRUE}}
#endif
}
typedef MySet::iterator iterator;
iterator start() {
clang_analyzer_checkInlined(true);
#if INLINE
// expected-warning@-2 {{TRUE}}
#endif
return impl.begin();
}
};
class IteratorUsingOnlySet {
MySet impl;
public:
IteratorUsingOnlySet() {
clang_analyzer_checkInlined(true);
#if INLINE
// expected-warning@-2 {{TRUE}}
#endif
}
using iterator = MySet::iterator;
iterator start() {
clang_analyzer_checkInlined(true);
#if INLINE
// expected-warning@-2 {{TRUE}}
#endif
return impl.begin();
}
};
class IteratorStructOnlySet {
MySet impl;
public:
IteratorStructOnlySet() {
clang_analyzer_checkInlined(true);
#if INLINE
// expected-warning@-2 {{TRUE}}
#endif
}
struct iterator {
int *impl;
};
iterator start() {
clang_analyzer_checkInlined(true);
#if INLINE
// expected-warning@-2 {{TRUE}}
#endif
return iterator{impl.begin().impl};
}
};
#endif // HEADER