1 // RUN: %clang_cc1 -fsyntax-only -Wdangling -Wdangling-field -Wreturn-stack-address -verify %s
2 struct [[gsl::Owner(int)]] MyIntOwner {
3 MyIntOwner();
4 int &operator*();
5 };
6
7 struct [[gsl::Pointer(int)]] MyIntPointer {
8 MyIntPointer(int *p = nullptr);
9 // Conversion operator and constructor conversion will result in two
10 // different ASTs. The former is tested with another owner and
11 // pointer type.
12 MyIntPointer(const MyIntOwner &);
13 int &operator*();
14 MyIntOwner toOwner();
15 };
16
17 struct MySpecialIntPointer : MyIntPointer {
18 };
19
20 // We did see examples in the wild when a derived class changes
21 // the ownership model. So we have a test for it.
22 struct [[gsl::Owner(int)]] MyOwnerIntPointer : MyIntPointer {
23 };
24
25 struct [[gsl::Pointer(long)]] MyLongPointerFromConversion {
26 MyLongPointerFromConversion(long *p = nullptr);
27 long &operator*();
28 };
29
30 struct [[gsl::Owner(long)]] MyLongOwnerWithConversion {
31 MyLongOwnerWithConversion();
32 operator MyLongPointerFromConversion();
33 long &operator*();
34 MyIntPointer releaseAsMyPointer();
35 long *releaseAsRawPointer();
36 };
37
danglingHeapObject()38 void danglingHeapObject() {
39 new MyLongPointerFromConversion(MyLongOwnerWithConversion{}); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
40 new MyIntPointer(MyIntOwner{}); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
41 }
42
intentionalFalseNegative()43 void intentionalFalseNegative() {
44 int i;
45 MyIntPointer p{&i};
46 // In this case we do not have enough information in a statement local
47 // analysis to detect the problem.
48 new MyIntPointer(p);
49 new MyIntPointer(MyIntPointer{p});
50 }
51
ownershipTransferToMyPointer()52 MyIntPointer ownershipTransferToMyPointer() {
53 MyLongOwnerWithConversion t;
54 return t.releaseAsMyPointer(); // ok
55 }
56
ownershipTransferToRawPointer()57 long *ownershipTransferToRawPointer() {
58 MyLongOwnerWithConversion t;
59 return t.releaseAsRawPointer(); // ok
60 }
61
62 struct Y {
63 int a[4];
64 };
65
dangligGslPtrFromTemporary()66 void dangligGslPtrFromTemporary() {
67 MyIntPointer p = Y{}.a; // TODO
68 (void)p;
69 }
70
71 struct DanglingGslPtrField {
72 MyIntPointer p; // expected-note {{pointer member declared here}}
73 MyLongPointerFromConversion p2; // expected-note {{pointer member declared here}}
DanglingGslPtrFieldDanglingGslPtrField74 DanglingGslPtrField(int i) : p(&i) {} // TODO
DanglingGslPtrFieldDanglingGslPtrField75 DanglingGslPtrField() : p2(MyLongOwnerWithConversion{}) {} // expected-warning {{initializing pointer member 'p2' to point to a temporary object whose lifetime is shorter than the lifetime of the constructed object}}
DanglingGslPtrFieldDanglingGslPtrField76 DanglingGslPtrField(double) : p(MyIntOwner{}) {} // expected-warning {{initializing pointer member 'p' to point to a temporary object whose lifetime is shorter than the lifetime of the constructed object}}
77 };
78
danglingGslPtrFromLocal()79 MyIntPointer danglingGslPtrFromLocal() {
80 int j;
81 return &j; // TODO
82 }
83
returningLocalPointer()84 MyIntPointer returningLocalPointer() {
85 MyIntPointer localPointer;
86 return localPointer; // ok
87 }
88
daglingGslPtrFromLocalOwner()89 MyIntPointer daglingGslPtrFromLocalOwner() {
90 MyIntOwner localOwner;
91 return localOwner; // expected-warning {{address of stack memory associated with local variable 'localOwner' returned}}
92 }
93
daglingGslPtrFromLocalOwnerConv()94 MyLongPointerFromConversion daglingGslPtrFromLocalOwnerConv() {
95 MyLongOwnerWithConversion localOwner;
96 return localOwner; // expected-warning {{address of stack memory associated with local variable 'localOwner' returned}}
97 }
98
danglingGslPtrFromTemporary()99 MyIntPointer danglingGslPtrFromTemporary() {
100 return MyIntOwner{}; // expected-warning {{returning address of local temporary object}}
101 }
102
103 MyIntOwner makeTempOwner();
104
danglingGslPtrFromTemporary2()105 MyIntPointer danglingGslPtrFromTemporary2() {
106 return makeTempOwner(); // expected-warning {{returning address of local temporary object}}
107 }
108
danglingGslPtrFromTemporaryConv()109 MyLongPointerFromConversion danglingGslPtrFromTemporaryConv() {
110 return MyLongOwnerWithConversion{}; // expected-warning {{returning address of local temporary object}}
111 }
112
noFalsePositive(MyIntOwner & o)113 int *noFalsePositive(MyIntOwner &o) {
114 MyIntPointer p = o;
115 return &*p; // ok
116 }
117
118 MyIntPointer global;
119 MyLongPointerFromConversion global2;
120
initLocalGslPtrWithTempOwner()121 void initLocalGslPtrWithTempOwner() {
122 MyIntPointer p = MyIntOwner{}; // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
123 p = MyIntOwner{}; // TODO ?
124 global = MyIntOwner{}; // TODO ?
125 MyLongPointerFromConversion p2 = MyLongOwnerWithConversion{}; // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
126 p2 = MyLongOwnerWithConversion{}; // TODO ?
127 global2 = MyLongOwnerWithConversion{}; // TODO ?
128 }
129
130 namespace __gnu_cxx {
131 template <typename T>
132 struct basic_iterator {
133 basic_iterator operator++();
134 T& operator*() const;
135 T* operator->() const;
136 };
137
138 template<typename T>
139 bool operator!=(basic_iterator<T>, basic_iterator<T>);
140 }
141
142 namespace std {
143 template<typename T> struct remove_reference { typedef T type; };
144 template<typename T> struct remove_reference<T &> { typedef T type; };
145 template<typename T> struct remove_reference<T &&> { typedef T type; };
146
147 template<typename T>
148 typename remove_reference<T>::type &&move(T &&t) noexcept;
149
150 template <typename C>
151 auto data(const C &c) -> decltype(c.data());
152
153 template <typename C>
154 auto begin(C &c) -> decltype(c.begin());
155
156 template<typename T, int N>
157 T *begin(T (&array)[N]);
158
159 template <typename T>
160 struct vector {
161 typedef __gnu_cxx::basic_iterator<T> iterator;
162 iterator begin();
163 iterator end();
164 const T *data() const;
165 T &at(int n);
166 };
167
168 template<typename T>
169 struct basic_string_view {
170 basic_string_view(const T *);
171 const T *begin() const;
172 };
173
174 template<typename T>
175 struct basic_string {
176 basic_string();
177 basic_string(const T *);
178 const T *c_str() const;
179 operator basic_string_view<T> () const;
180 };
181
182
183 template<typename T>
184 struct unique_ptr {
185 T &operator*();
186 T *get() const;
187 };
188
189 template<typename T>
190 struct optional {
191 optional();
192 optional(const T&);
193 T &operator*() &;
194 T &&operator*() &&;
195 T &value() &;
196 T &&value() &&;
197 };
198
199 template<typename T>
200 struct stack {
201 T &top();
202 };
203
204 struct any {};
205
206 template<typename T>
207 T any_cast(const any& operand);
208
209 template<typename T>
210 struct reference_wrapper {
211 template<typename U>
212 reference_wrapper(U &&);
213 };
214
215 template<typename T>
216 reference_wrapper<T> ref(T& t) noexcept;
217 }
218
219 struct Unannotated {
220 typedef std::vector<int>::iterator iterator;
221 iterator begin();
222 operator iterator() const;
223 };
224
modelIterators()225 void modelIterators() {
226 std::vector<int>::iterator it = std::vector<int>().begin(); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
227 (void)it;
228 }
229
modelIteratorReturn()230 std::vector<int>::iterator modelIteratorReturn() {
231 return std::vector<int>().begin(); // expected-warning {{returning address of local temporary object}}
232 }
233
modelFreeFunctions()234 const int *modelFreeFunctions() {
235 return std::data(std::vector<int>()); // expected-warning {{returning address of local temporary object}}
236 }
237
modelAnyCast()238 int &modelAnyCast() {
239 return std::any_cast<int&>(std::any{}); // expected-warning {{returning reference to local temporary object}}
240 }
241
modelAnyCast2()242 int modelAnyCast2() {
243 return std::any_cast<int>(std::any{}); // ok
244 }
245
modelAnyCast3()246 int modelAnyCast3() {
247 return std::any_cast<int&>(std::any{}); // ok
248 }
249
danglingRawPtrFromLocal()250 const char *danglingRawPtrFromLocal() {
251 std::basic_string<char> s;
252 return s.c_str(); // expected-warning {{address of stack memory associated with local variable 's' returned}}
253 }
254
danglingRawPtrFromLocal2()255 int &danglingRawPtrFromLocal2() {
256 std::optional<int> o;
257 return o.value(); // expected-warning {{reference to stack memory associated with local variable 'o' returned}}
258 }
259
danglingRawPtrFromLocal3()260 int &danglingRawPtrFromLocal3() {
261 std::optional<int> o;
262 return *o; // expected-warning {{reference to stack memory associated with local variable 'o' returned}}
263 }
264
danglingRawPtrFromTemp()265 const char *danglingRawPtrFromTemp() {
266 return std::basic_string<char>().c_str(); // expected-warning {{returning address of local temporary object}}
267 }
268
269 std::unique_ptr<int> getUniquePtr();
270
danglingUniquePtrFromTemp()271 int *danglingUniquePtrFromTemp() {
272 return getUniquePtr().get(); // expected-warning {{returning address of local temporary object}}
273 }
274
danglingUniquePtrFromTemp2()275 int *danglingUniquePtrFromTemp2() {
276 return std::unique_ptr<int>().get(); // expected-warning {{returning address of local temporary object}}
277 }
278
danglingReferenceFromTempOwner()279 void danglingReferenceFromTempOwner() {
280 int &&r = *std::optional<int>(); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
281 int &&r2 = *std::optional<int>(5); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
282 int &&r3 = std::optional<int>(5).value(); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
283 int &r4 = std::vector<int>().at(3); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
284 }
285
286 std::vector<int> getTempVec();
287 std::optional<std::vector<int>> getTempOptVec();
288
testLoops()289 void testLoops() {
290 for (auto i : getTempVec()) // ok
291 ;
292 for (auto i : *getTempOptVec()) // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
293 ;
294 }
295
usedToBeFalsePositive(std::vector<int> & v)296 int &usedToBeFalsePositive(std::vector<int> &v) {
297 std::vector<int>::iterator it = v.begin();
298 int& value = *it;
299 return value; // ok
300 }
301
doNotFollowReferencesForLocalOwner()302 int &doNotFollowReferencesForLocalOwner() {
303 std::unique_ptr<int> localOwner;
304 int &p = *localOwner.get();
305 // In real world code localOwner is usually moved here.
306 return p; // ok
307 }
308
trackThroughMultiplePointer()309 const char *trackThroughMultiplePointer() {
310 return std::basic_string_view<char>(std::basic_string<char>()).begin(); // expected-warning {{returning address of local temporary object}}
311 }
312
313 struct X {
XX314 X(std::unique_ptr<int> up) :
315 pointee(*up), pointee2(up.get()), pointer(std::move(up)) {}
316 int &pointee;
317 int *pointee2;
318 std::unique_ptr<int> pointer;
319 };
320
321 std::vector<int>::iterator getIt();
322 std::vector<int> getVec();
323
handleGslPtrInitsThroughReference()324 const int &handleGslPtrInitsThroughReference() {
325 const auto &it = getIt(); // Ok, it is lifetime extended.
326 return *it;
327 }
328
handleGslPtrInitsThroughReference2()329 void handleGslPtrInitsThroughReference2() {
330 const std::vector<int> &v = getVec();
331 const int *val = v.data(); // Ok, it is lifetime extended.
332 }
333
handleTernaryOperator(bool cond)334 void handleTernaryOperator(bool cond) {
335 std::basic_string<char> def;
336 std::basic_string_view<char> v = cond ? def : ""; // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
337 }
338
danglingPtrFromNonOwnerLocal()339 std::reference_wrapper<int> danglingPtrFromNonOwnerLocal() {
340 int i = 5;
341 return i; // TODO
342 }
343
danglingPtrFromNonOwnerLocal2()344 std::reference_wrapper<int> danglingPtrFromNonOwnerLocal2() {
345 int i = 5;
346 return std::ref(i); // TODO
347 }
348
danglingPtrFromNonOwnerLocal3()349 std::reference_wrapper<int> danglingPtrFromNonOwnerLocal3() {
350 int i = 5;
351 return std::reference_wrapper<int>(i); // TODO
352 }
353
danglingPtrFromNonOwnerLocal4()354 std::reference_wrapper<Unannotated> danglingPtrFromNonOwnerLocal4() {
355 Unannotated i;
356 return std::reference_wrapper<Unannotated>(i); // TODO
357 }
358
danglingPtrFromNonOwnerLocal5()359 std::reference_wrapper<Unannotated> danglingPtrFromNonOwnerLocal5() {
360 Unannotated i;
361 return std::ref(i); // TODO
362 }
363
returnPtrToLocalArray()364 int *returnPtrToLocalArray() {
365 int a[5];
366 return std::begin(a); // TODO
367 }
368
369 struct ptr_wrapper {
370 std::vector<int>::iterator member;
371 };
372
373 ptr_wrapper getPtrWrapper();
374
returnPtrFromWrapper()375 std::vector<int>::iterator returnPtrFromWrapper() {
376 ptr_wrapper local = getPtrWrapper();
377 return local.member;
378 }
379
returnPtrFromWrapperThroughRef()380 std::vector<int>::iterator returnPtrFromWrapperThroughRef() {
381 ptr_wrapper local = getPtrWrapper();
382 ptr_wrapper &local2 = local;
383 return local2.member;
384 }
385
returnPtrFromWrapperThroughRef2()386 std::vector<int>::iterator returnPtrFromWrapperThroughRef2() {
387 ptr_wrapper local = getPtrWrapper();
388 std::vector<int>::iterator &local2 = local.member;
389 return local2;
390 }
391
checkPtrMemberFromAggregate()392 void checkPtrMemberFromAggregate() {
393 std::vector<int>::iterator local = getPtrWrapper().member; // OK.
394 }
395
doNotInterferWithUnannotated()396 std::vector<int>::iterator doNotInterferWithUnannotated() {
397 Unannotated value;
398 // Conservative choice for now. Probably not ok, but we do not warn.
399 return std::begin(value);
400 }
401
doNotInterferWithUnannotated2()402 std::vector<int>::iterator doNotInterferWithUnannotated2() {
403 Unannotated value;
404 return value;
405 }
406
supportDerefAddrofChain(int a,std::vector<int>::iterator value)407 std::vector<int>::iterator supportDerefAddrofChain(int a, std::vector<int>::iterator value) {
408 switch (a) {
409 default:
410 return value;
411 case 1:
412 return *&value;
413 case 2:
414 return *&*&value;
415 case 3:
416 return *&*&*&value;
417 }
418 }
419
supportDerefAddrofChain2(int a,std::vector<int>::iterator value)420 int &supportDerefAddrofChain2(int a, std::vector<int>::iterator value) {
421 switch (a) {
422 default:
423 return *value;
424 case 1:
425 return **&value;
426 case 2:
427 return **&*&value;
428 case 3:
429 return **&*&*&value;
430 }
431 }
432
supportDerefAddrofChain3(int a,std::vector<int>::iterator value)433 int *supportDerefAddrofChain3(int a, std::vector<int>::iterator value) {
434 switch (a) {
435 default:
436 return &*value;
437 case 1:
438 return &*&*value;
439 case 2:
440 return &*&**&value;
441 case 3:
442 return &*&**&*&value;
443 }
444 }
445
handleDerivedToBaseCast1(MySpecialIntPointer ptr)446 MyIntPointer handleDerivedToBaseCast1(MySpecialIntPointer ptr) {
447 return ptr;
448 }
449
handleDerivedToBaseCast2(MyOwnerIntPointer ptr)450 MyIntPointer handleDerivedToBaseCast2(MyOwnerIntPointer ptr) {
451 return ptr; // expected-warning {{address of stack memory associated with parameter 'ptr' returned}}
452 }
453
noFalsePositiveWithVectorOfPointers()454 std::vector<int>::iterator noFalsePositiveWithVectorOfPointers() {
455 std::vector<std::vector<int>::iterator> iters;
456 return iters.at(0);
457 }
458