| /* PR middle-end/63272 - GCC should warn when using pointer to dead scoped | |
| variable within the same function | |
| Exercise basic cases of -Wdangling-pointer with optimization. | |
| { dg-do compile } | |
| { dg-options "-O2 -Wall -Wno-uninitialized -Wno-return-local-addr -ftrack-macro-expansion=0" } | |
| { dg-require-effective-target alloca } */ | |
| typedef __INTPTR_TYPE__ intptr_t; | |
| typedef __SIZE_TYPE__ size_t; | |
| #if __cplusplus | |
| # define EXTERN_C extern "C" | |
| #else | |
| # define EXTERN_C extern | |
| #endif | |
| #define NOIPA __attribute__ ((noipa)) | |
| EXTERN_C void* alloca (size_t); | |
| EXTERN_C void* malloc (size_t); | |
| EXTERN_C void* memchr (const void*, int, size_t); | |
| EXTERN_C char* strchr (const char*, int); | |
| int sink (const void*, ...); | |
| #define sink(...) sink (0, __VA_ARGS__) | |
| NOIPA void nowarn_addr (void) | |
| { | |
| int *p; | |
| { | |
| int a[] = { 1, 2, 3 }; | |
| p = a; | |
| } | |
| // This is suspect but not a clear error. | |
| sink (&p); | |
| } | |
| NOIPA char* nowarn_ptr (void) | |
| { | |
| char *p; | |
| sink (&p); | |
| return p; | |
| } | |
| NOIPA char* nowarn_cond_ptr (void) | |
| { | |
| // Distilled from a false positive in Glibc dlerror.c. | |
| char *q; | |
| if (sink (&q)) | |
| return q; | |
| return 0; | |
| } | |
| NOIPA void nowarn_loop_ptr (int n, int *p) | |
| { | |
| // Distilled from a false positive in Glibc td_thr_get_info.c. | |
| for (int i = 0; i != 2; ++i) | |
| { | |
| int x; | |
| sink (&x); | |
| *p++ = x; | |
| } | |
| /* With the loop unrolled, Q is clobbered just before the call to | |
| sink(), making it indistinguishable from passing it a pointer | |
| to an out-of-scope variable. Verify that the warning doesn't | |
| suffer from false positives due to this. | |
| int * q; | |
| int * q.1_17; | |
| int * q.1_26; | |
| <bb 2>: | |
| f (&q); | |
| q.1_17 = q; | |
| *p_5(D) = q.1_17; | |
| q ={v} {CLOBBER}; | |
| f (&q); | |
| q.1_26 = q; | |
| MEM[(void * *)p_5(D) + 8B] = q.1_26; | |
| q ={v} {CLOBBER}; | |
| return; | |
| */ | |
| } | |
| NOIPA void nowarn_intptr_t (void) | |
| { | |
| intptr_t ip; | |
| { | |
| int a[] = { 1, 2, 3 }; | |
| ip = (intptr_t)a; | |
| } | |
| // Using an intptr_t is not diagnosed. | |
| sink (0, ip); | |
| } | |
| NOIPA void nowarn_string_literal (void) | |
| { | |
| const char *s; | |
| { | |
| s = "123"; | |
| } | |
| sink (s); | |
| } | |
| NOIPA void nowarn_extern_array (int x) | |
| { | |
| { | |
| /* This is a silly sanity check. */ | |
| extern int eia[]; | |
| int *p; | |
| { | |
| p = eia; | |
| } | |
| sink (p); | |
| } | |
| } | |
| NOIPA void nowarn_static_array (int x) | |
| { | |
| { | |
| const char *s; | |
| { | |
| static const char sca[] = "123"; | |
| s = sca; | |
| } | |
| sink (s); | |
| } | |
| { | |
| const int *p; | |
| { | |
| static const int sia[] = { 1, 2, 3 }; | |
| p = sia; | |
| } | |
| sink (p); | |
| } | |
| { | |
| const int *p; | |
| { | |
| static const int sia[] = { 1, 2, 3 }; | |
| p = (const int*)memchr (sia, x, sizeof sia); | |
| } | |
| sink (p); | |
| } | |
| } | |
| NOIPA void nowarn_alloca (unsigned n) | |
| { | |
| { | |
| char *p; | |
| { | |
| p = (char*)alloca (n); | |
| } | |
| sink (p); | |
| } | |
| { | |
| int *p; | |
| { | |
| p = (int*)alloca (n * sizeof *p); | |
| sink (p); | |
| } | |
| sink (p); | |
| } | |
| { | |
| long *p; | |
| { | |
| p = (long*)alloca (n * sizeof *p); | |
| sink (p); | |
| p = p + 1; | |
| } | |
| sink (p); | |
| } | |
| } | |
| #pragma GCC diagnostic push | |
| /* Verify that -Wdangling-pointer works with #pragma diagnostic. */ | |
| #pragma GCC diagnostic ignored "-Wdangling-pointer" | |
| NOIPA void* nowarn_return_local_addr (void) | |
| { | |
| int a[] = { 1, 2, 3 }; | |
| int *p = a; | |
| /* This is a likely bug but it's not really one of using a dangling | |
| pointer but rather of returning the address of a local variable | |
| which is diagnosed by -Wreturn-local-addr. */ | |
| return p; | |
| } | |
| NOIPA void* warn_return_local_addr (void) | |
| { | |
| int *p = 0; | |
| { | |
| int a[] = { 1, 2, 3 }; | |
| sink (a); | |
| p = a; | |
| } | |
| /* Unlike the above case, here the pointer is dangling when it's | |
| used. */ | |
| return p; // { dg-warning "using dangling pointer 'p' to 'a'" "pr??????" { xfail *-*-* } } | |
| } | |
| NOIPA void* nowarn_return_alloca (int n) | |
| { | |
| int *p = (int*)alloca (n); | |
| sink (p); | |
| /* This is a likely bug but it's not really one of using a dangling | |
| pointer but rather of returning the address of a local variable | |
| which is diagnosed by -Wreturn-local-addr. */ | |
| return p; | |
| } | |
| NOIPA void nowarn_scalar_call_ignored (void *vp) | |
| { | |
| int *p; | |
| { | |
| int i; | |
| p = &i; | |
| } | |
| sink (p); | |
| } | |
| #pragma GCC diagnostic pop | |
| NOIPA void warn_scalar_call (void) | |
| { | |
| int *p; | |
| { | |
| int i; // { dg-message "'i' declared" "note" } | |
| p = &i; | |
| } | |
| // When the 'p' is optimized away it's not mentioned in the warning. | |
| sink (p); // { dg-warning "using \(a \)?dangling pointer \('p' \)?to 'i'" "array" } | |
| } | |
| NOIPA void warn_array_call (void) | |
| { | |
| int *p; | |
| { | |
| int a[] = { 1, 2, 3 }; // { dg-message "'a' declared" "note" } | |
| p = a; | |
| } | |
| sink (p); // { dg-warning "using \(a \)?dangling pointer \('p' \)?to 'a'" "array" } | |
| } | |
| NOIPA void* warn_array_return (void) | |
| { | |
| int *p; | |
| { | |
| int a[] = { 1, 2, 3 }; // { dg-message "'a' declared" "note" } | |
| p = a; | |
| } | |
| return p; // { dg-warning "using \(a \)?dangling pointer \('p' \)?to 'a'" "array" } | |
| } | |
| NOIPA void warn_pr63272_c1 (int i) | |
| { | |
| int *p = 0; | |
| if (i) | |
| { | |
| int k = i; // { dg-message "'k' declared" "note" } | |
| p = &k; | |
| } | |
| sink (p ? *p : 0); // { dg-warning "dangling pointer 'p' to 'k' may be used" } | |
| } | |
| NOIPA void warn_pr63272_c4 (void) | |
| { | |
| int *p = 0; | |
| { | |
| int b; // { dg-message "'b' declared" "note" } | |
| p = &b; | |
| } | |
| sink (p); // { dg-warning "using \(a \)?dangling pointer \('p' \)?to 'b'" "scalar" } | |
| } | |
| NOIPA void warn_cond_if (int i, int n) | |
| { | |
| int *p; | |
| if (i) | |
| { | |
| int a[] = { 1, 2 }; // { dg-message "'a' declared" "note" } | |
| sink (a); | |
| p = a; | |
| } | |
| else | |
| { | |
| int *b = (int*)malloc (n); | |
| sink (b); | |
| p = b; | |
| } | |
| sink (p); // { dg-warning "dangling pointer 'p' to 'a' may be used" } | |
| } | |
| NOIPA void warn_cond_else (int i, int n) | |
| { | |
| int *p; | |
| if (i) | |
| { | |
| int *a = (int*)malloc (n); | |
| sink (a); | |
| p = a; | |
| } | |
| else | |
| { | |
| int b[] = { 2, 3 }; | |
| sink (b); | |
| p = b; | |
| } | |
| sink (p); // { dg-warning "dangling pointer 'p' to 'b' may be used" } | |
| } | |
| NOIPA void warn_cond_if_else (int i) | |
| { | |
| int *p; | |
| if (i) | |
| { | |
| int a[] = { 1, 2 }; // { dg-message "'a' declared" "note" } | |
| sink (a); | |
| p = a; | |
| } | |
| else | |
| { | |
| int b[] = { 3, 4 }; // { dg-message "'b' declared" "pr??????" { xfail *-*-* } } | |
| sink (b); | |
| p = b; | |
| } | |
| /* With a PHI with more than invalid argument, only one use is diagnosed | |
| because after the first diagnostic the code suppresses subsequent | |
| ones for the same use. This needs to be fixed. */ | |
| sink (p); // { dg-warning "dangling pointer 'p' to 'a' may be used" } | |
| // { dg-warning "dangling pointer 'p' to 'b' may be used" "pr??????" { xfail *-*-* } .-1 } | |
| } | |
| NOIPA void nowarn_gcc_i386 (int i) | |
| { | |
| // Regression test reduced from gcc's i386.c. | |
| char a[32], *p; | |
| if (i != 1) | |
| p = a; | |
| else | |
| p = 0; | |
| if (i == 2) | |
| sink (p); | |
| else | |
| { | |
| if (p) | |
| { | |
| sink (p); | |
| return; | |
| } | |
| sink (p); | |
| } | |
| } | |
| NOIPA void warn_memchr (char c1, char c2, char c3, char c4) | |
| { | |
| char *p = 0; | |
| { | |
| char a[] = { c1, c2, c3 };// { dg-message "'a' declared" "note" } | |
| p = (char*)memchr (a, c4, 3); | |
| if (!p) | |
| return; | |
| } | |
| sink (p); // { dg-warning "using dangling pointer 'p' to 'a'" } | |
| } | |
| NOIPA void warn_strchr (char c1, char c2, char c3, char c4) | |
| { | |
| char *p = 0; | |
| { | |
| char a[] = { c1, c2, c3 }; // { dg-message "'a' declared" "note" } | |
| p = (char*)strchr (a, c4); | |
| if (!p) | |
| return; | |
| } | |
| sink (p); // { dg-warning "using dangling pointer 'p' to 'a'" } | |
| } | |
| static inline int* return_arg (int *p) | |
| { | |
| return p; | |
| } | |
| NOIPA void warn_inline (int i1, int i2, int i3) | |
| { | |
| int *p; | |
| { | |
| int a[] = { i1, i2, i3 }; // { dg-message "'a' declared" "note" } | |
| p = return_arg (a); | |
| } | |
| sink (p); // { dg-warning "using \(a \)?dangling pointer \('p' \)?to 'a'" "inline" } | |
| } |