/* PR middle-end/63272 - GCC should warn when using pointer to dead scoped variable within the same function Exercise basic cases of -Wdangling-pointer without optimization. { dg-do compile } { dg-options "-O0 -Wall -Wno-uninitialized -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 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__) /* Verify that integer assignments don't cause bogus warnings. Reduced from GFlibc's s_nextafter.c. */ int nowarn_integer (float x) { int i; { union { float x; int i; } u; u.x = x; i = u.i; } return i; } void nowarn_addr (void) { int *p; { int a[] = { 1, 2, 3 }; p = a; } // This is suspect but not a clear error. sink (&p); } char* nowarn_ptr (void) { char *p; sink (&p); return p; } char* nowarn_cond_ptr (void) { // Distilled from a false positive in Glibc dlerror.c. char *q; if (sink (&q)) return q; return 0; } 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; } } 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); } void nowarn_string_literal (void) { const char *s; { s = "123"; } sink (s); } void nowarn_extern_array (int x) { { /* This is a silly sanity check. */ extern int eia[]; int *p; { p = eia; } sink (p); } } 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); } } 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" void nowarn_scalar_call_ignored (void *vp) { int *p; { int i; p = &i; } sink (p); } #pragma GCC diagnostic pop 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; } void* warn_return_local_addr (void) { int *p = 0; { int a[] = { 1, 2, 3 }; 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'" "array" } } 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; } void warn_scalar_call (void) { int *p; { int i; // { dg-message "'i' declared" "note" } p = &i; } sink (p); // { dg-warning "using dangling pointer 'p' to 'i'" "array" } } void warn_array_call (void) { int *p; { int a[] = { 1, 2, 3 }; // { dg-message "'a' declared" "note" } p = a; } sink (p); // { dg-warning "using dangling pointer 'p' to 'a'" "array" } } void* warn_array_return (void) { int *p; { int a[] = { 1, 2, 3 }; // { dg-message "'a' declared" "note" } p = a; } return p; // { dg-warning "using dangling pointer 'p' to 'a'" "array" } } 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" } } void warn_pr63272_c4 (void) { int *p = 0; { int b; // { dg-message "'b' declared" "note" } p = &b; } sink (p); // { dg-warning "using dangling pointer 'p' to 'b'" "scalar" } } void nowarn_cond_if (int i, int n) { int *p; if (i) { int a[] = { 1, 2 }; p = a; sink (p); } else { int *b = (int*)malloc (n); p = b; sink (p); } p = 0; } 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" } } 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" } } 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" "note" { 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 } } 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); } } 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'" } } 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'" } }