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 %s 2 3 void clang_analyzer_eval(bool); 4 void clang_analyzer_dump(int); 5 6 typedef __typeof__(sizeof(int)) size_t; 7 8 void *conjure(); 9 void exit(int); 10 11 struct S; 12 13 S *global_s; 14 15 // Recursive operator kinda placement new. 16 void *operator new(size_t size, S *place); 17 18 enum class ConstructionKind : char { 19 Garbage, 20 Recursive 21 }; 22 23 struct S { 24 public: 25 int x; SS26 S(): x(1) {} SS27 S(int y): x(y) {} 28 SS29 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 } ~SS42 ~S() {} 43 }; 44 45 // Do not try this at home! operator new(size_t size,S * place)46void *operator new(size_t size, S *place) { 47 if (!place) 48 return new S(); 49 return place; 50 } 51 testThatCharConstructorIndeedYieldsGarbage()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 testChainedOperatorNew()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