| // 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 | |
| } | |
| } |