117 lines · cpp
1// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,debug.ExprInspection -analyzer-config c++-allocator-inlining=true -std=c++11 -verify -analyzer-config eagerly-assume=false %s2 3void clang_analyzer_eval(bool);4void clang_analyzer_dump(int);5 6typedef __typeof__(sizeof(int)) size_t;7 8void *conjure();9void exit(int);10 11struct S;12 13S *global_s;14 15// Recursive operator kinda placement new.16void *operator new(size_t size, S *place);17 18enum class ConstructionKind : char {19 Garbage,20 Recursive21};22 23struct S {24public:25 int x;26 S(): x(1) {}27 S(int y): x(y) {}28 29 S(ConstructionKind k) {30 switch (k) {31 case ConstructionKind::Recursive: { // Call one more operator new 'r'ecursively.32 S *s = new (nullptr) S(5);33 x = s->x + 1;34 global_s = s;35 return;36 }37 case ConstructionKind::Garbage: {38 // Leaves garbage in 'x'.39 }40 }41 }42 ~S() {}43};44 45// Do not try this at home!46void *operator new(size_t size, S *place) {47 if (!place)48 return new S();49 return place;50}51 52void testThatCharConstructorIndeedYieldsGarbage() {53 S *s = new S(ConstructionKind::Garbage);54 clang_analyzer_eval(s->x == 0); // expected-warning{{The left operand of '==' is a garbage value [core.UndefinedBinaryOperatorResult]}}55 clang_analyzer_eval(s->x == 1);56 s->x += 1;57 delete s;58}59 60 61void testChainedOperatorNew() {62 S *s;63 // * Evaluate standard new.64 // * Evaluate constructor S(3).65 // * Bind value for standard new.66 // * Evaluate our custom new.67 // * Evaluate constructor S(Garbage).68 // * Bind value for our custom new.69 s = new (new S(3)) S(ConstructionKind::Garbage);70 clang_analyzer_eval(s->x == 3); // expected-warning{{TRUE}}71 // expected-warning@+9{{Potential leak of memory pointed to by 's'}}72 73 // * Evaluate standard new.74 // * Evaluate constructor S(Garbage).75 // * Bind value for standard new.76 // * Evaluate our custom new.77 // * Evaluate constructor S(4).78 // * Bind value for our custom new.79 s = new (new S(ConstructionKind::Garbage)) S(4);80 clang_analyzer_eval(s->x == 4); // expected-warning{{TRUE}}81 delete s;82 83 // -> Enter our custom new (nullptr).84 // * Evaluate standard new.85 // * Inline constructor S().86 // * Bind value for standard new.87 // <- Exit our custom new (nullptr).88 // * Evaluate constructor S(Garbage).89 // * Bind value for our custom new.90 s = new (nullptr) S(ConstructionKind::Garbage);91 clang_analyzer_eval(s->x == 1); // expected-warning{{TRUE}}92 delete s;93 94 // -> Enter our custom new (nullptr).95 // * Evaluate standard new.96 // * Inline constructor S().97 // * Bind value for standard new.98 // <- Exit our custom new (nullptr).99 // -> Enter constructor S(Recursive).100 // -> Enter our custom new (nullptr).101 // * Evaluate standard new.102 // * Inline constructor S().103 // * Bind value for standard new.104 // <- Exit our custom new (nullptr).105 // * Evaluate constructor S(5).106 // * Bind value for our custom new (nullptr).107 // * Assign that value to global_s.108 // <- Exit constructor S(Recursive).109 // * Bind value for our custom new (nullptr).110 global_s = nullptr;111 s = new (nullptr) S(ConstructionKind::Recursive);112 clang_analyzer_eval(global_s); // expected-warning{{TRUE}}113 clang_analyzer_eval(global_s->x == 5); // expected-warning{{TRUE}}114 clang_analyzer_eval(s->x == 6); // expected-warning{{TRUE}}115 delete s;116}117