• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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