blob: f21795d1739aac323ab939227bdf3cffcf9e2fb6 [file] [log] [blame]
George Karpenkova393e682018-08-29 20:29:17 +00001// 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
Artem Dergachev55796302018-01-17 22:34:23 +00002
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 Recursive
21};
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{{UNKNOWN}}
55 clang_analyzer_eval(s->x == 1); // expected-warning{{UNKNOWN}}
56 // FIXME: This should warn, but MallocChecker doesn't default-bind regions
57 // returned by standard operator new to garbage.
58 s->x += 1; // no-warning
59 delete s;
60}
61
62
63void testChainedOperatorNew() {
64 S *s;
65 // * Evaluate standard new.
66 // * Evaluate constructor S(3).
67 // * Bind value for standard new.
68 // * Evaluate our custom new.
69 // * Evaluate constructor S(Garbage).
70 // * Bind value for our custom new.
71 s = new (new S(3)) S(ConstructionKind::Garbage);
72 clang_analyzer_eval(s->x == 3); // expected-warning{{TRUE}}
73 // expected-warning@+9{{Potential leak of memory pointed to by 's'}}
74
75 // * Evaluate standard new.
76 // * Evaluate constructor S(Garbage).
77 // * Bind value for standard new.
78 // * Evaluate our custom new.
79 // * Evaluate constructor S(4).
80 // * Bind value for our custom new.
81 s = new (new S(ConstructionKind::Garbage)) S(4);
82 clang_analyzer_eval(s->x == 4); // expected-warning{{TRUE}}
83 delete s;
84
85 // -> Enter our custom new (nullptr).
86 // * Evaluate standard new.
87 // * Inline constructor S().
88 // * Bind value for standard new.
89 // <- Exit our custom new (nullptr).
90 // * Evaluate constructor S(Garbage).
91 // * Bind value for our custom new.
92 s = new (nullptr) S(ConstructionKind::Garbage);
93 clang_analyzer_eval(s->x == 1); // expected-warning{{TRUE}}
94 delete s;
95
96 // -> Enter our custom new (nullptr).
97 // * Evaluate standard new.
98 // * Inline constructor S().
99 // * Bind value for standard new.
100 // <- Exit our custom new (nullptr).
101 // -> Enter constructor S(Recursive).
102 // -> Enter our custom new (nullptr).
103 // * Evaluate standard new.
104 // * Inline constructor S().
105 // * Bind value for standard new.
106 // <- Exit our custom new (nullptr).
107 // * Evaluate constructor S(5).
108 // * Bind value for our custom new (nullptr).
109 // * Assign that value to global_s.
110 // <- Exit constructor S(Recursive).
111 // * Bind value for our custom new (nullptr).
112 global_s = nullptr;
113 s = new (nullptr) S(ConstructionKind::Recursive);
114 clang_analyzer_eval(global_s); // expected-warning{{TRUE}}
115 clang_analyzer_eval(global_s->x == 5); // expected-warning{{TRUE}}
116 clang_analyzer_eval(s->x == 6); // expected-warning{{TRUE}}
117 delete s;
118}