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