1 /* PR middle-end/63272 - GCC should warn when using pointer to dead scoped
2 variable within the same function
3 Exercise basic cases of -Wdangling-pointer with optimization.
4 { dg-do compile }
5 { dg-options "-O2 -Wall -Wno-uninitialized -Wno-return-local-addr -ftrack-macro-expansion=0" }
6 { dg-require-effective-target alloca } */
7
8 typedef __INTPTR_TYPE__ intptr_t;
9 typedef __SIZE_TYPE__ size_t;
10
11 #if __cplusplus
12 # define EXTERN_C extern "C"
13 #else
14 # define EXTERN_C extern
15 #endif
16
17 #define NOIPA __attribute__ ((noipa))
18
19 EXTERN_C void* alloca (size_t);
20 EXTERN_C void* malloc (size_t);
21 EXTERN_C void* memchr (const void*, int, size_t);
22 EXTERN_C char* strchr (const char*, int);
23
24 int sink (const void*, ...);
25 #define sink(...) sink (0, __VA_ARGS__)
26
27
28 NOIPA void nowarn_addr (void)
29 {
30 int *p;
31 {
32 int a[] = { 1, 2, 3 };
33 p = a;
34 }
35
36 // This is suspect but not a clear error.
37 sink (&p);
38 }
39
40
41 NOIPA char* nowarn_ptr (void)
42 {
43 char *p;
44 sink (&p);
45 return p;
46 }
47
48
49 NOIPA char* nowarn_cond_ptr (void)
50 {
51 // Distilled from a false positive in Glibc dlerror.c.
52 char *q;
53 if (sink (&q))
54 return q;
55
56 return 0;
57 }
58
59
60 NOIPA void nowarn_loop_ptr (int n, int *p)
61 {
62 // Distilled from a false positive in Glibc td_thr_get_info.c.
63 for (int i = 0; i != 2; ++i)
64 {
65 int x;
66 sink (&x);
67 *p++ = x;
68 }
69
70 /* With the loop unrolled, Q is clobbered just before the call to
71 sink(), making it indistinguishable from passing it a pointer
72 to an out-of-scope variable. Verify that the warning doesn't
73 suffer from false positives due to this.
74 int * q;
75 int * q.1_17;
76 int * q.1_26;
77
78 <bb 2>:
79 f (&q);
80 q.1_17 = q;
81 *p_5(D) = q.1_17;
82 q ={v} {CLOBBER};
83 f (&q);
84 q.1_26 = q;
85 MEM[(void * *)p_5(D) + 8B] = q.1_26;
86 q ={v} {CLOBBER};
87 return;
88 */
89 }
90
91
92 NOIPA void nowarn_intptr_t (void)
93 {
94 intptr_t ip;
95 {
96 int a[] = { 1, 2, 3 };
97 ip = (intptr_t)a;
98 }
99
100 // Using an intptr_t is not diagnosed.
101 sink (0, ip);
102 }
103
104
105 NOIPA void nowarn_string_literal (void)
106 {
107 const char *s;
108 {
109 s = "123";
110 }
111
112 sink (s);
113 }
114
115
116 NOIPA void nowarn_extern_array (int x)
117 {
118 {
119 /* This is a silly sanity check. */
120 extern int eia[];
121 int *p;
122 {
123 p = eia;
124 }
125 sink (p);
126 }
127 }
128
129
130 NOIPA void nowarn_static_array (int x)
131 {
132 {
133 const char *s;
134 {
135 static const char sca[] = "123";
136 s = sca;
137 }
138
139 sink (s);
140 }
141 {
142 const int *p;
143 {
144 static const int sia[] = { 1, 2, 3 };
145 p = sia;
146 }
147
148 sink (p);
149 }
150 {
151 const int *p;
152 {
153 static const int sia[] = { 1, 2, 3 };
154 p = (const int*)memchr (sia, x, sizeof sia);
155 }
156
157 sink (p);
158 }
159 }
160
161
162 NOIPA void nowarn_alloca (unsigned n)
163 {
164 {
165 char *p;
166 {
167 p = (char*)alloca (n);
168 }
169 sink (p);
170 }
171 {
172 int *p;
173 {
174 p = (int*)alloca (n * sizeof *p);
175 sink (p);
176 }
177 sink (p);
178 }
179 {
180 long *p;
181 {
182 p = (long*)alloca (n * sizeof *p);
183 sink (p);
184 p = p + 1;
185 }
186 sink (p);
187 }
188 }
189
190
191 #pragma GCC diagnostic push
192 /* Verify that -Wdangling-pointer works with #pragma diagnostic. */
193 #pragma GCC diagnostic ignored "-Wdangling-pointer"
194
195
196 NOIPA void* nowarn_return_local_addr (void)
197 {
198 int a[] = { 1, 2, 3 };
199 int *p = a;
200
201 /* This is a likely bug but it's not really one of using a dangling
202 pointer but rather of returning the address of a local variable
203 which is diagnosed by -Wreturn-local-addr. */
204 return p;
205 }
206
207 NOIPA void* warn_return_local_addr (void)
208 {
209 int *p = 0;
210 {
211 int a[] = { 1, 2, 3 };
212 sink (a);
213 p = a;
214 }
215
216 /* Unlike the above case, here the pointer is dangling when it's
217 used. */
218 return p; // { dg-warning "using dangling pointer 'p' to 'a'" "pr??????" { xfail *-*-* } }
219 }
220
221
222 NOIPA void* nowarn_return_alloca (int n)
223 {
224 int *p = (int*)alloca (n);
225 sink (p);
226
227 /* This is a likely bug but it's not really one of using a dangling
228 pointer but rather of returning the address of a local variable
229 which is diagnosed by -Wreturn-local-addr. */
230 return p;
231 }
232
233
234 NOIPA void nowarn_scalar_call_ignored (void *vp)
235 {
236 int *p;
237 {
238 int i;
239 p = &i;
240 }
241 sink (p);
242 }
243
244 #pragma GCC diagnostic pop
245
246 NOIPA void warn_scalar_call (void)
247 {
248 int *p;
249 {
250 int i; // { dg-message "'i' declared" "note" }
251 p = &i;
252 }
253 // When the 'p' is optimized away it's not mentioned in the warning.
254 sink (p); // { dg-warning "using \(a \)?dangling pointer \('p' \)?to 'i'" "array" }
255 }
256
257
258 NOIPA void warn_array_call (void)
259 {
260 int *p;
261 {
262 int a[] = { 1, 2, 3 }; // { dg-message "'a' declared" "note" }
263 p = a;
264 }
265 sink (p); // { dg-warning "using \(a \)?dangling pointer \('p' \)?to 'a'" "array" }
266 }
267
268
269 NOIPA void* warn_array_return (void)
270 {
271 int *p;
272 {
273 int a[] = { 1, 2, 3 }; // { dg-message "'a' declared" "note" }
274 p = a;
275 }
276
277 return p; // { dg-warning "using \(a \)?dangling pointer \('p' \)?to 'a'" "array" }
278 }
279
280
281 NOIPA void warn_pr63272_c1 (int i)
282 {
283 int *p = 0;
284
285 if (i)
286 {
287 int k = i; // { dg-message "'k' declared" "note" }
288 p = &k;
289 }
290
291 sink (p ? *p : 0); // { dg-warning "dangling pointer 'p' to 'k' may be used" }
292 }
293
294
295 NOIPA void warn_pr63272_c4 (void)
296 {
297 int *p = 0;
298
299 {
300 int b; // { dg-message "'b' declared" "note" }
301 p = &b;
302 }
303
304 sink (p); // { dg-warning "using \(a \)?dangling pointer \('p' \)?to 'b'" "scalar" }
305 }
306
307
308 NOIPA void warn_cond_if (int i, int n)
309 {
310 int *p;
311 if (i)
312 {
313 int a[] = { 1, 2 }; // { dg-message "'a' declared" "note" }
314 sink (a);
315 p = a;
316 }
317 else
318 {
319 int *b = (int*)malloc (n);
320 sink (b);
321 p = b;
322 }
323
324 sink (p); // { dg-warning "dangling pointer 'p' to 'a' may be used" }
325 }
326
327
328 NOIPA void warn_cond_else (int i, int n)
329 {
330 int *p;
331 if (i)
332 {
333 int *a = (int*)malloc (n);
334 sink (a);
335 p = a;
336 }
337 else
338 {
339 int b[] = { 2, 3 };
340 sink (b);
341 p = b;
342 }
343
344 sink (p); // { dg-warning "dangling pointer 'p' to 'b' may be used" }
345 }
346
347
348 NOIPA void warn_cond_if_else (int i)
349 {
350 int *p;
351 if (i)
352 {
353 int a[] = { 1, 2 }; // { dg-message "'a' declared" "note" }
354 sink (a);
355 p = a;
356 }
357 else
358 {
359 int b[] = { 3, 4 }; // { dg-message "'b' declared" "pr??????" { xfail *-*-* } }
360 sink (b);
361 p = b;
362 }
363
364 /* With a PHI with more than invalid argument, only one use is diagnosed
365 because after the first diagnostic the code suppresses subsequent
366 ones for the same use. This needs to be fixed. */
367 sink (p); // { dg-warning "dangling pointer 'p' to 'a' may be used" }
368 // { dg-warning "dangling pointer 'p' to 'b' may be used" "pr??????" { xfail *-*-* } .-1 }
369 }
370
371
372 NOIPA void nowarn_gcc_i386 (int i)
373 {
374 // Regression test reduced from gcc's i386.c.
375 char a[32], *p;
376
377 if (i != 1)
378 p = a;
379 else
380 p = 0;
381
382 if (i == 2)
383 sink (p);
384 else
385 {
386 if (p)
387 {
388 sink (p);
389 return;
390 }
391 sink (p);
392 }
393 }
394
395
396 NOIPA void warn_memchr (char c1, char c2, char c3, char c4)
397 {
398 char *p = 0;
399 {
400 char a[] = { c1, c2, c3 };// { dg-message "'a' declared" "note" }
401 p = (char*)memchr (a, c4, 3);
402 if (!p)
403 return;
404 }
405
406 sink (p); // { dg-warning "using dangling pointer 'p' to 'a'" }
407 }
408
409
410 NOIPA void warn_strchr (char c1, char c2, char c3, char c4)
411 {
412 char *p = 0;
413 {
414 char a[] = { c1, c2, c3 }; // { dg-message "'a' declared" "note" }
415 p = (char*)strchr (a, c4);
416 if (!p)
417 return;
418 }
419
420 sink (p); // { dg-warning "using dangling pointer 'p' to 'a'" }
421 }
422
423
424 static inline int* return_arg (int *p)
425 {
426 return p;
427 }
428
429 NOIPA void warn_inline (int i1, int i2, int i3)
430 {
431 int *p;
432 {
433 int a[] = { i1, i2, i3 }; // { dg-message "'a' declared" "note" }
434 p = return_arg (a);
435 }
436
437 sink (p); // { dg-warning "using \(a \)?dangling pointer \('p' \)?to 'a'" "inline" }
438 }