forked from OSchip/llvm-project
380 lines
8.5 KiB
C++
380 lines
8.5 KiB
C++
// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config c++-inlining=destructors -verify -std=c++11 %s
|
|
// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config c++-inlining=destructors -verify -std=c++17 %s
|
|
|
|
using size_t = __typeof(sizeof(int));
|
|
|
|
void clang_analyzer_eval(bool);
|
|
void clang_analyzer_checkInlined(bool);
|
|
void clang_analyzer_warnIfReached();
|
|
void clang_analyzer_explain(int);
|
|
|
|
int a, b, c, d;
|
|
|
|
struct InlineDtor {
|
|
static int cnt;
|
|
static int dtorCalled;
|
|
~InlineDtor() {
|
|
switch (dtorCalled % 4) {
|
|
case 0:
|
|
a = cnt++;
|
|
break;
|
|
case 1:
|
|
b = cnt++;
|
|
break;
|
|
case 2:
|
|
c = cnt++;
|
|
break;
|
|
case 3:
|
|
d = cnt++;
|
|
break;
|
|
}
|
|
|
|
++dtorCalled;
|
|
}
|
|
};
|
|
|
|
int InlineDtor::cnt = 0;
|
|
int InlineDtor::dtorCalled = 0;
|
|
|
|
void foo() {
|
|
InlineDtor::cnt = 0;
|
|
InlineDtor::dtorCalled = 0;
|
|
InlineDtor arr[4];
|
|
}
|
|
|
|
void testAutoDtor() {
|
|
foo();
|
|
|
|
clang_analyzer_eval(a == 0); // expected-warning {{TRUE}}
|
|
clang_analyzer_eval(b == 1); // expected-warning {{TRUE}}
|
|
clang_analyzer_eval(c == 2); // expected-warning {{TRUE}}
|
|
clang_analyzer_eval(d == 3); // expected-warning {{TRUE}}
|
|
}
|
|
|
|
void testDeleteDtor() {
|
|
InlineDtor::cnt = 10;
|
|
InlineDtor::dtorCalled = 0;
|
|
|
|
InlineDtor *arr = new InlineDtor[4];
|
|
delete[] arr;
|
|
|
|
clang_analyzer_eval(a == 10); // expected-warning {{TRUE}}
|
|
clang_analyzer_eval(b == 11); // expected-warning {{TRUE}}
|
|
clang_analyzer_eval(c == 12); // expected-warning {{TRUE}}
|
|
clang_analyzer_eval(d == 13); // expected-warning {{TRUE}}
|
|
}
|
|
|
|
struct MemberDtor {
|
|
InlineDtor arr[4];
|
|
};
|
|
|
|
void testMemberDtor() {
|
|
InlineDtor::cnt = 5;
|
|
InlineDtor::dtorCalled = 0;
|
|
|
|
MemberDtor *MD = new MemberDtor{};
|
|
delete MD;
|
|
|
|
clang_analyzer_eval(a == 5); // expected-warning {{TRUE}}
|
|
clang_analyzer_eval(b == 6); // expected-warning {{TRUE}}
|
|
clang_analyzer_eval(c == 7); // expected-warning {{TRUE}}
|
|
clang_analyzer_eval(d == 8); // expected-warning {{TRUE}}
|
|
}
|
|
|
|
struct MultipleMemberDtor
|
|
{
|
|
InlineDtor arr[4];
|
|
InlineDtor arr2[4];
|
|
};
|
|
|
|
void testMultipleMemberDtor() {
|
|
InlineDtor::cnt = 30;
|
|
InlineDtor::dtorCalled = 0;
|
|
|
|
MultipleMemberDtor *MD = new MultipleMemberDtor{};
|
|
delete MD;
|
|
|
|
clang_analyzer_eval(a == 34); // expected-warning {{TRUE}}
|
|
clang_analyzer_eval(b == 35); // expected-warning {{TRUE}}
|
|
clang_analyzer_eval(c == 36); // expected-warning {{TRUE}}
|
|
clang_analyzer_eval(d == 37); // expected-warning {{TRUE}}
|
|
}
|
|
|
|
int EvalOrderArr[4];
|
|
|
|
struct EvalOrder
|
|
{
|
|
int ctor = 0;
|
|
static int dtorCalled;
|
|
static int ctorCalled;
|
|
|
|
EvalOrder() { ctor = ctorCalled++; };
|
|
|
|
~EvalOrder() { EvalOrderArr[ctor] = dtorCalled++; }
|
|
};
|
|
|
|
int EvalOrder::ctorCalled = 0;
|
|
int EvalOrder::dtorCalled = 0;
|
|
|
|
void dtorEvaluationOrder() {
|
|
EvalOrder::ctorCalled = 0;
|
|
EvalOrder::dtorCalled = 0;
|
|
|
|
EvalOrder* eptr = new EvalOrder[4];
|
|
delete[] eptr;
|
|
|
|
clang_analyzer_eval(EvalOrder::dtorCalled == 4); // expected-warning {{TRUE}}
|
|
clang_analyzer_eval(EvalOrder::dtorCalled == EvalOrder::ctorCalled); // expected-warning {{TRUE}}
|
|
|
|
clang_analyzer_eval(EvalOrderArr[0] == 3); // expected-warning {{TRUE}}
|
|
clang_analyzer_eval(EvalOrderArr[1] == 2); // expected-warning {{TRUE}}
|
|
clang_analyzer_eval(EvalOrderArr[2] == 1); // expected-warning {{TRUE}}
|
|
clang_analyzer_eval(EvalOrderArr[3] == 0); // expected-warning {{TRUE}}
|
|
}
|
|
|
|
struct EmptyDtor {
|
|
~EmptyDtor(){};
|
|
};
|
|
|
|
struct DefaultDtor {
|
|
~DefaultDtor() = default;
|
|
};
|
|
|
|
// This function used to fail on an assertion.
|
|
void no_crash() {
|
|
EmptyDtor* eptr = new EmptyDtor[4];
|
|
delete[] eptr;
|
|
clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
|
|
|
|
DefaultDtor* dptr = new DefaultDtor[4];
|
|
delete[] dptr;
|
|
clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
|
|
}
|
|
|
|
// This snippet used to crash.
|
|
namespace crash2
|
|
{
|
|
template <class _Tp> class unique_ptr {
|
|
typedef _Tp *pointer;
|
|
pointer __ptr_;
|
|
|
|
public:
|
|
unique_ptr(pointer __p) : __ptr_(__p) {}
|
|
~unique_ptr() { reset(); }
|
|
pointer get() { return __ptr_;}
|
|
void reset() {}
|
|
};
|
|
|
|
struct S;
|
|
|
|
S *makeS();
|
|
int bar(S *x, S *y);
|
|
|
|
void foo() {
|
|
unique_ptr<S> x(makeS()), y(makeS());
|
|
bar(x.get(), y.get());
|
|
}
|
|
|
|
void bar() {
|
|
foo();
|
|
clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
|
|
}
|
|
|
|
} // namespace crash2
|
|
|
|
// This snippet used to crash.
|
|
namespace crash3
|
|
{
|
|
struct InlineDtor {
|
|
~InlineDtor() {}
|
|
};
|
|
struct MultipleMemberDtor
|
|
{
|
|
InlineDtor arr[4];
|
|
InlineDtor arr2[4];
|
|
};
|
|
|
|
void foo(){
|
|
auto *arr = new MultipleMemberDtor[4];
|
|
delete[] arr;
|
|
clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
|
|
}
|
|
} // namespace crash3
|
|
|
|
namespace crash4 {
|
|
struct a {
|
|
a *b;
|
|
};
|
|
struct c {
|
|
a d;
|
|
c();
|
|
~c() {
|
|
for (a e = d;; e = *e.b)
|
|
;
|
|
}
|
|
};
|
|
void f() {
|
|
c g;
|
|
clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
|
|
}
|
|
|
|
} // namespace crash4
|
|
|
|
namespace crash5 {
|
|
namespace std {
|
|
template <class _Tp> class unique_ptr {
|
|
_Tp *__ptr_;
|
|
public:
|
|
unique_ptr(_Tp *__p) : __ptr_(__p) {}
|
|
~unique_ptr() {}
|
|
};
|
|
} // namespace std
|
|
|
|
int SSL_use_certificate(int *arg) {
|
|
std::unique_ptr<int> free_x509(arg);
|
|
{
|
|
if (SSL_use_certificate(arg)) {
|
|
return 0;
|
|
}
|
|
}
|
|
clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
|
|
return 1;
|
|
}
|
|
|
|
} // namespace crash5
|
|
|
|
void zeroLength(){
|
|
InlineDtor::dtorCalled = 0;
|
|
|
|
auto *arr = new InlineDtor[0];
|
|
delete[] arr;
|
|
|
|
auto *arr2 = new InlineDtor[2][0][2];
|
|
delete[] arr2;
|
|
|
|
auto *arr3 = new InlineDtor[0][2][2];
|
|
delete[] arr3;
|
|
|
|
auto *arr4 = new InlineDtor[2][2][0];
|
|
delete[] arr4;
|
|
|
|
clang_analyzer_eval(InlineDtor::dtorCalled == 0); // expected-warning {{TRUE}}
|
|
}
|
|
|
|
|
|
void evalOrderPrep() {
|
|
EvalOrderArr[0] = 0;
|
|
EvalOrderArr[1] = 0;
|
|
EvalOrderArr[2] = 0;
|
|
EvalOrderArr[3] = 0;
|
|
|
|
EvalOrder::ctorCalled = 0;
|
|
EvalOrder::dtorCalled = 0;
|
|
}
|
|
|
|
void multidimensionalPrep(){
|
|
EvalOrder::ctorCalled = 0;
|
|
EvalOrder::dtorCalled = 0;
|
|
|
|
EvalOrder arr[2][2];
|
|
}
|
|
|
|
void multidimensional(){
|
|
evalOrderPrep();
|
|
multidimensionalPrep();
|
|
|
|
clang_analyzer_eval(EvalOrder::dtorCalled == 4); // expected-warning {{TRUE}}
|
|
clang_analyzer_eval(EvalOrder::dtorCalled == EvalOrder::ctorCalled); // expected-warning {{TRUE}}
|
|
|
|
clang_analyzer_eval(EvalOrderArr[0] == 3); // expected-warning {{TRUE}}
|
|
clang_analyzer_eval(EvalOrderArr[1] == 2); // expected-warning {{TRUE}}
|
|
clang_analyzer_eval(EvalOrderArr[2] == 1); // expected-warning {{TRUE}}
|
|
clang_analyzer_eval(EvalOrderArr[3] == 0); // expected-warning {{TRUE}}
|
|
}
|
|
|
|
void multidimensionalHeap() {
|
|
evalOrderPrep();
|
|
|
|
auto* eptr = new EvalOrder[2][2];
|
|
delete[] eptr;
|
|
|
|
clang_analyzer_eval(EvalOrder::dtorCalled == 4); // expected-warning {{TRUE}}
|
|
clang_analyzer_eval(EvalOrder::dtorCalled == EvalOrder::ctorCalled); // expected-warning {{TRUE}}
|
|
|
|
clang_analyzer_eval(EvalOrderArr[0] == 3); // expected-warning {{TRUE}}
|
|
clang_analyzer_eval(EvalOrderArr[1] == 2); // expected-warning {{TRUE}}
|
|
clang_analyzer_eval(EvalOrderArr[2] == 1); // expected-warning {{TRUE}}
|
|
clang_analyzer_eval(EvalOrderArr[3] == 0); // expected-warning {{TRUE}}
|
|
}
|
|
|
|
struct MultiWrapper{
|
|
EvalOrder arr[2][2];
|
|
};
|
|
|
|
void multidimensionalMember(){
|
|
evalOrderPrep();
|
|
|
|
auto* mptr = new MultiWrapper;
|
|
delete mptr;
|
|
|
|
clang_analyzer_eval(EvalOrder::dtorCalled == 4); // expected-warning {{TRUE}}
|
|
clang_analyzer_eval(EvalOrder::dtorCalled == EvalOrder::ctorCalled); // expected-warning {{TRUE}}
|
|
|
|
clang_analyzer_eval(EvalOrderArr[0] == 3); // expected-warning {{TRUE}}
|
|
clang_analyzer_eval(EvalOrderArr[1] == 2); // expected-warning {{TRUE}}
|
|
clang_analyzer_eval(EvalOrderArr[2] == 1); // expected-warning {{TRUE}}
|
|
clang_analyzer_eval(EvalOrderArr[3] == 0); // expected-warning {{TRUE}}
|
|
}
|
|
|
|
void *memset(void *, int, size_t);
|
|
void clang_analyzer_dumpElementCount(InlineDtor *);
|
|
|
|
void nonConstantRegionExtent(){
|
|
|
|
InlineDtor::dtorCalled = 0;
|
|
|
|
int x = 3;
|
|
memset(&x, 1, sizeof(x));
|
|
|
|
InlineDtor *arr = new InlineDtor[x];
|
|
clang_analyzer_dumpElementCount(arr); // expected-warning {{conj_$0}}
|
|
delete [] arr;
|
|
|
|
//FIXME: This should be TRUE but memset also sets this
|
|
// region to a conjured symbol.
|
|
clang_analyzer_eval(InlineDtor::dtorCalled == 0); // expected-warning {{TRUE}} expected-warning {{FALSE}}
|
|
}
|
|
|
|
namespace crash6 {
|
|
|
|
struct NonTrivialItem {
|
|
~NonTrivialItem();
|
|
};
|
|
|
|
struct WeirdVec {
|
|
void clear() {
|
|
delete[] data;
|
|
size = 0;
|
|
}
|
|
NonTrivialItem *data;
|
|
unsigned size;
|
|
};
|
|
|
|
void top(int j) {
|
|
WeirdVec *p = new WeirdVec;
|
|
|
|
p[j].size = 0;
|
|
delete[] p->data; // no-crash
|
|
}
|
|
|
|
template <typename T>
|
|
T make_unknown() {
|
|
return reinterpret_cast<T>(static_cast<int>(0.404));
|
|
}
|
|
|
|
void directUnknownSymbol() {
|
|
delete[] make_unknown<NonTrivialItem*>(); // no-crash
|
|
}
|
|
|
|
}
|