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
272 lines
5.3 KiB
C++
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
|