1 // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -w -std=c++03 %s
2 // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -w -std=c++11 %s
3 // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -DTEMPORARY_DTORS -verify -w -analyzer-config cfg-temporary-dtors=true %s
4
5 extern bool clang_analyzer_eval(bool);
6
7 struct Trivial {
TrivialTrivial8 Trivial(int x) : value(x) {}
9 int value;
10 };
11
12 struct NonTrivial : public Trivial {
NonTrivialNonTrivial13 NonTrivial(int x) : Trivial(x) {}
14 ~NonTrivial();
15 };
16
17
getTrivial()18 Trivial getTrivial() {
19 return Trivial(42); // no-warning
20 }
21
getTrivialRef()22 const Trivial &getTrivialRef() {
23 return Trivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'Trivial' returned to caller}}
24 }
25
26
getNonTrivial()27 NonTrivial getNonTrivial() {
28 return NonTrivial(42); // no-warning
29 }
30
getNonTrivialRef()31 const NonTrivial &getNonTrivialRef() {
32 return NonTrivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'NonTrivial' returned to caller}}
33 }
34
35 namespace rdar13265460 {
36 struct TrivialSubclass : public Trivial {
TrivialSubclassrdar13265460::TrivialSubclass37 TrivialSubclass(int x) : Trivial(x), anotherValue(-x) {}
38 int anotherValue;
39 };
40
getTrivialSub()41 TrivialSubclass getTrivialSub() {
42 TrivialSubclass obj(1);
43 obj.value = 42;
44 obj.anotherValue = -42;
45 return obj;
46 }
47
testImmediate()48 void testImmediate() {
49 TrivialSubclass obj = getTrivialSub();
50
51 clang_analyzer_eval(obj.value == 42); // expected-warning{{TRUE}}
52 clang_analyzer_eval(obj.anotherValue == -42); // expected-warning{{TRUE}}
53
54 clang_analyzer_eval(getTrivialSub().value == 42); // expected-warning{{TRUE}}
55 clang_analyzer_eval(getTrivialSub().anotherValue == -42); // expected-warning{{TRUE}}
56 }
57
testMaterializeTemporaryExpr()58 void testMaterializeTemporaryExpr() {
59 const TrivialSubclass &ref = getTrivialSub();
60 clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}}
61
62 const Trivial &baseRef = getTrivialSub();
63 clang_analyzer_eval(baseRef.value == 42); // expected-warning{{TRUE}}
64 }
65 }
66
67 namespace rdar13281951 {
68 struct Derived : public Trivial {
Derivedrdar13281951::Derived69 Derived(int value) : Trivial(value), value2(-value) {}
70 int value2;
71 };
72
test()73 void test() {
74 Derived obj(1);
75 obj.value = 42;
76 const Trivial * const &pointerRef = &obj;
77 clang_analyzer_eval(pointerRef->value == 42); // expected-warning{{TRUE}}
78 }
79 }
80
81 namespace compound_literals {
82 struct POD {
83 int x, y;
84 };
85 struct HasCtor {
HasCtorcompound_literals::HasCtor86 HasCtor(int x, int y) : x(x), y(y) {}
87 int x, y;
88 };
89 struct HasDtor {
90 int x, y;
91 ~HasDtor();
92 };
93 struct HasCtorDtor {
HasCtorDtorcompound_literals::HasCtorDtor94 HasCtorDtor(int x, int y) : x(x), y(y) {}
95 ~HasCtorDtor();
96 int x, y;
97 };
98
test()99 void test() {
100 clang_analyzer_eval(((POD){1, 42}).y == 42); // expected-warning{{TRUE}}
101 clang_analyzer_eval(((HasDtor){1, 42}).y == 42); // expected-warning{{TRUE}}
102
103 #if __cplusplus >= 201103L
104 clang_analyzer_eval(((HasCtor){1, 42}).y == 42); // expected-warning{{TRUE}}
105
106 // FIXME: should be TRUE, but we don't inline the constructors of
107 // temporaries because we can't model their destructors yet.
108 clang_analyzer_eval(((HasCtorDtor){1, 42}).y == 42); // expected-warning{{UNKNOWN}}
109 #endif
110 }
111 }
112
113 namespace destructors {
testPR16664andPR18159Crash()114 void testPR16664andPR18159Crash() {
115 struct Dtor {
116 ~Dtor();
117 };
118 extern bool coin();
119 extern bool check(const Dtor &);
120
121 // Regression test: we used to assert here when tmp dtors are enabled.
122 // PR16664 and PR18159
123 if (coin() && (coin() || coin() || check(Dtor()))) {
124 Dtor();
125 }
126 }
127
128 #ifdef TEMPORARY_DTORS
129 struct NoReturnDtor {
130 ~NoReturnDtor() __attribute__((noreturn));
131 };
132
noReturnTemp(int * x)133 void noReturnTemp(int *x) {
134 if (! x) NoReturnDtor();
135 *x = 47; // no warning
136 }
137
noReturnInline(int ** x)138 void noReturnInline(int **x) {
139 NoReturnDtor();
140 }
141
callNoReturn()142 void callNoReturn() {
143 int *x;
144 noReturnInline(&x);
145 *x = 47; // no warning
146 }
147
148 extern bool check(const NoReturnDtor &);
149
testConsistencyIf(int i)150 void testConsistencyIf(int i) {
151 if (i != 5)
152 return;
153 if (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) {
154 clang_analyzer_eval(true); // no warning, unreachable code
155 }
156 }
157
testConsistencyTernary(int i)158 void testConsistencyTernary(int i) {
159 (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) ? 1 : 0;
160
161 clang_analyzer_eval(true); // expected-warning{{TRUE}}
162
163 if (i != 5)
164 return;
165
166 (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) ? 1 : 0;
167
168 clang_analyzer_eval(true); // no warning, unreachable code
169 }
170
171 // Regression test: we used to assert here.
172 // PR16664 and PR18159
testConsistencyNested(int i)173 void testConsistencyNested(int i) {
174 extern bool compute(bool);
175
176 if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor())))
177 clang_analyzer_eval(true); // expected-warning{{TRUE}}
178
179 if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor())))
180 clang_analyzer_eval(true); // expected-warning{{TRUE}}
181
182 if (i != 5)
183 return;
184
185 if (compute(i == 5 &&
186 (i == 4 || compute(true) ||
187 compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) ||
188 i != 4) {
189 clang_analyzer_eval(true); // expected-warning{{TRUE}}
190 }
191
192 if (compute(i == 5 &&
193 (i == 4 || i == 4 ||
194 compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) ||
195 i != 4) {
196 // FIXME: This shouldn't cause a warning.
197 clang_analyzer_eval(true); // expected-warning{{TRUE}}
198 }
199 }
200
201 // PR16664 and PR18159
testConsistencyNestedSimple(bool value)202 void testConsistencyNestedSimple(bool value) {
203 if (value) {
204 if (!value || check(NoReturnDtor())) {
205 clang_analyzer_eval(true); // no warning, unreachable code
206 }
207 }
208 }
209
210 // PR16664 and PR18159
testConsistencyNestedComplex(bool value)211 void testConsistencyNestedComplex(bool value) {
212 if (value) {
213 if (!value || !value || check(NoReturnDtor())) {
214 // FIXME: This shouldn't cause a warning.
215 clang_analyzer_eval(true); // expected-warning{{TRUE}}
216 }
217 }
218 }
219
220 // PR16664 and PR18159
testConsistencyNestedWarning(bool value)221 void testConsistencyNestedWarning(bool value) {
222 if (value) {
223 if (!value || value || check(NoReturnDtor())) {
224 clang_analyzer_eval(true); // expected-warning{{TRUE}}
225 }
226 }
227 }
228
testBinaryOperatorShortcut(bool value)229 void testBinaryOperatorShortcut(bool value) {
230 if (value) {
231 if (false && false && check(NoReturnDtor()) && true) {
232 clang_analyzer_eval(true);
233 }
234 }
235 }
236
237 #endif // TEMPORARY_DTORS
238 }
239
testStaticMaterializeTemporaryExpr()240 void testStaticMaterializeTemporaryExpr() {
241 static const Trivial &ref = getTrivial();
242 clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}}
243
244 static const Trivial &directRef = Trivial(42);
245 clang_analyzer_eval(directRef.value == 42); // expected-warning{{TRUE}}
246
247 #if __has_feature(cxx_thread_local)
248 thread_local static const Trivial &threadRef = getTrivial();
249 clang_analyzer_eval(threadRef.value == 42); // expected-warning{{TRUE}}
250
251 thread_local static const Trivial &threadDirectRef = Trivial(42);
252 clang_analyzer_eval(threadDirectRef.value == 42); // expected-warning{{TRUE}}
253 #endif
254 }
255
256 namespace PR16629 {
257 struct A {
APR16629::A258 explicit A(int* p_) : p(p_) {}
259 int* p;
260 };
261
262 extern void escape(const A*[]);
263 extern void check(int);
264
callEscape(const A & a)265 void callEscape(const A& a) {
266 const A* args[] = { &a };
267 escape(args);
268 }
269
testNoWarning()270 void testNoWarning() {
271 int x;
272 callEscape(A(&x));
273 check(x); // Analyzer used to give a "x is uninitialized warning" here
274 }
275
set(const A * a[])276 void set(const A*a[]) {
277 *a[0]->p = 47;
278 }
279
callSet(const A & a)280 void callSet(const A& a) {
281 const A* args[] = { &a };
282 set(args);
283 }
284
testConsistency()285 void testConsistency() {
286 int x;
287 callSet(A(&x));
288 clang_analyzer_eval(x == 47); // expected-warning{{TRUE}}
289 }
290 }
291